Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(768)

Unified Diff: src/js/promise.js

Issue 2554013002: Revert of Create JSPromise (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/js/async-await.js ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/js/promise.js
diff --git a/src/js/promise.js b/src/js/promise.js
index b78f68c4f71c367365a8a149803c3091a9e55f75..25c8beaa9e0aef86dd966faa3af89d8e342c04a3 100644
--- a/src/js/promise.js
+++ b/src/js/promise.js
@@ -20,6 +20,12 @@
utils.ImportNow("promise_forwarding_handler_symbol");
var promiseHasHandlerSymbol =
utils.ImportNow("promise_has_handler_symbol");
+var promiseRejectReactionsSymbol =
+ utils.ImportNow("promise_reject_reactions_symbol");
+var promiseFulfillReactionsSymbol =
+ utils.ImportNow("promise_fulfill_reactions_symbol");
+var promiseDeferredReactionSymbol =
+ utils.ImportNow("promise_deferred_reaction_symbol");
var promiseHandledHintSymbol =
utils.ImportNow("promise_handled_hint_symbol");
var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
@@ -30,7 +36,6 @@
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
var ObjectHasOwnProperty;
var GlobalPromise = global.Promise;
-var PromiseThen = GlobalPromise.prototype.then;
utils.Import(function(from) {
ObjectHasOwnProperty = from.ObjectHasOwnProperty;
@@ -40,6 +45,42 @@
// -------------------------------------------------------------------
// Core functionality.
+
+function PromiseSet(promise, status, value) {
+ SET_PRIVATE(promise, promiseStateSymbol, status);
+ SET_PRIVATE(promise, promiseResultSymbol, value);
+
+ // There are 3 possible states for the resolve, reject symbols when we add
+ // a new callback --
+ // 1) UNDEFINED -- This is the zero state where there is no callback
+ // registered. When we see this state, we directly attach the callbacks to
+ // the symbol.
+ // 2) !IS_ARRAY -- There is a single callback directly attached to the
+ // symbols. We need to create a new array to store additional callbacks.
+ // 3) IS_ARRAY -- There are multiple callbacks already registered,
+ // therefore we can just push the new callback to the existing array.
+ SET_PRIVATE(promise, promiseFulfillReactionsSymbol, UNDEFINED);
+ SET_PRIVATE(promise, promiseRejectReactionsSymbol, UNDEFINED);
+
+ // This symbol is used only when one deferred needs to be attached. When more
+ // than one deferred need to be attached the promise, we attach them directly
+ // to the promiseFulfillReactionsSymbol and promiseRejectReactionsSymbol and
+ // reset this back to UNDEFINED.
+ SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED);
+
+ return promise;
+}
+
+function PromiseCreateAndSet(status, value) {
+ var promise = %promise_internal_constructor();
+ // If debug is active, notify about the newly created promise first.
+ if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED);
+ return PromiseSet(promise, status, value);
+}
+
+function PromiseInit(promise) {
+ return PromiseSet(promise, kPending, UNDEFINED);
+}
function PromiseHandle(value, handler, deferred) {
var debug_is_active = DEBUG_IS_ACTIVE;
@@ -57,6 +98,7 @@
// Pass false for debugEvent so .then chaining or throwaway promises
// in async functions do not trigger redundant ExceptionEvents.
%PromiseReject(deferred.promise, exception, false);
+ PromiseSet(deferred.promise, kRejected, exception);
} else {
%_Call(deferred.reject, UNDEFINED, exception);
}
@@ -92,6 +134,34 @@
return [id, name];
}
+function PromiseAttachCallbacks(promise, deferred, onResolve, onReject) {
+ var maybeResolveCallbacks =
+ GET_PRIVATE(promise, promiseFulfillReactionsSymbol);
+ if (IS_UNDEFINED(maybeResolveCallbacks)) {
+ SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve);
+ SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject);
+ SET_PRIVATE(promise, promiseDeferredReactionSymbol, deferred);
+ } else if (!IS_ARRAY(maybeResolveCallbacks)) {
+ var resolveCallbacks = new InternalArray();
+ var rejectCallbacks = new InternalArray();
+ var existingDeferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol);
+
+ resolveCallbacks.push(
+ maybeResolveCallbacks, existingDeferred, onResolve, deferred);
+ rejectCallbacks.push(GET_PRIVATE(promise, promiseRejectReactionsSymbol),
+ existingDeferred,
+ onReject,
+ deferred);
+
+ SET_PRIVATE(promise, promiseFulfillReactionsSymbol, resolveCallbacks);
+ SET_PRIVATE(promise, promiseRejectReactionsSymbol, rejectCallbacks);
+ SET_PRIVATE(promise, promiseDeferredReactionSymbol, UNDEFINED);
+ } else {
+ maybeResolveCallbacks.push(onResolve, deferred);
+ GET_PRIVATE(promise, promiseRejectReactionsSymbol).push(onReject, deferred);
+ }
+}
+
function PromiseIdResolveHandler(x) { return x; }
function PromiseIdRejectHandler(r) { %_ReThrow(r); }
SET_PRIVATE(PromiseIdRejectHandler, promiseForwardingHandlerSymbol, true);
@@ -101,9 +171,8 @@
// For bootstrapper.
-// This is used by utils and v8-extras.
function PromiseCreate() {
- return %promise_internal_constructor();
+ return PromiseInit(%promise_internal_constructor());
}
// ES#sec-promise-resolve-functions
@@ -112,6 +181,7 @@
if (resolution === promise) {
var exception = %make_type_error(kPromiseCyclic, resolution);
%PromiseReject(promise, exception, true);
+ PromiseSet(promise, kRejected, exception);
return;
}
if (IS_RECEIVER(resolution)) {
@@ -120,6 +190,7 @@
var then = resolution.then;
} catch (e) {
%PromiseReject(promise, e, true);
+ PromiseSet(promise, kRejected, e);
return;
}
@@ -127,16 +198,18 @@
// rejected, shortcircuit the resolution procedure by directly
// reusing the value from the promise.
if (%is_promise(resolution) && then === PromiseThen) {
- var thenableState = %PromiseStatus(resolution);
+ var thenableState = GET_PRIVATE(resolution, promiseStateSymbol);
if (thenableState === kFulfilled) {
// This goes inside the if-else to save one symbol lookup in
// the slow path.
- var thenableValue = %PromiseResult(resolution);
- %PromiseFulfill(promise, kFulfilled, thenableValue);
+ var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
+ %PromiseFulfill(promise, kFulfilled, thenableValue,
+ promiseFulfillReactionsSymbol);
+ PromiseSet(promise, kFulfilled, thenableValue);
SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
return;
} else if (thenableState === kRejected) {
- var thenableValue = %PromiseResult(resolution);
+ var thenableValue = GET_PRIVATE(resolution, promiseResultSymbol);
if (!HAS_DEFINED_PRIVATE(resolution, promiseHasHandlerSymbol)) {
// Promise has already been rejected, but had no handler.
// Revoke previously triggered reject event.
@@ -144,6 +217,7 @@
}
// Don't cause a debug event as this case is forwarding a rejection
%PromiseReject(promise, thenableValue, false);
+ PromiseSet(promise, kRejected, thenableValue);
SET_PRIVATE(resolution, promiseHasHandlerSymbol, true);
return;
}
@@ -158,17 +232,21 @@
return;
}
}
- %PromiseFulfill(promise, kFulfilled, resolution);
+ %PromiseFulfill(promise, kFulfilled, resolution,
+ promiseFulfillReactionsSymbol);
+ PromiseSet(promise, kFulfilled, resolution);
}
// Only used by async-await.js
function RejectPromise(promise, reason, debugEvent) {
%PromiseReject(promise, reason, debugEvent);
+ PromiseSet(promise, kRejected, reason);
}
// Export to bindings
function DoRejectPromise(promise, reason) {
%PromiseReject(promise, reason, true);
+ PromiseSet(promise, kRejected, reason);
}
// The resultCapability.promise is only ever fulfilled internally,
@@ -176,7 +254,7 @@
// calling them multiple times.
function CreateInternalPromiseCapability() {
return {
- promise: %promise_internal_constructor(),
+ promise: PromiseCreate(),
resolve: UNDEFINED,
reject: UNDEFINED
};
@@ -187,7 +265,7 @@
function NewPromiseCapability(C, debugEvent) {
if (C === GlobalPromise) {
// Optimized case, avoid extra closure.
- var promise = %promise_internal_constructor();
+ var promise = PromiseCreate();
// TODO(gsathya): Remove container for callbacks when this is
// moved to CPP/TF.
var callbacks = %create_resolving_functions(promise, debugEvent);
@@ -220,7 +298,7 @@
}
if (this === GlobalPromise) {
// Optimized case, avoid extra closure.
- var promise = %promise_create_and_set(kRejected, r);
+ var promise = PromiseCreateAndSet(kRejected, r);
// Trigger debug events if the debugger is on, as Promise.reject is
// equivalent to throwing an exception directly.
%PromiseRejectEventFromStack(promise, r);
@@ -232,6 +310,55 @@
}
}
+function PerformPromiseThen(promise, onResolve, onReject, resultCapability) {
+ if (!IS_CALLABLE(onResolve)) onResolve = PromiseIdResolveHandler;
+ if (!IS_CALLABLE(onReject)) onReject = PromiseIdRejectHandler;
+
+ var status = GET_PRIVATE(promise, promiseStateSymbol);
+ switch (status) {
+ case kPending:
+ PromiseAttachCallbacks(promise, resultCapability, onResolve, onReject);
+ break;
+ case kFulfilled:
+ %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol),
+ onResolve, resultCapability, kFulfilled);
+ break;
+ case kRejected:
+ if (!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
+ // Promise has already been rejected, but had no handler.
+ // Revoke previously triggered reject event.
+ %PromiseRevokeReject(promise);
+ }
+ %EnqueuePromiseReactionJob(GET_PRIVATE(promise, promiseResultSymbol),
+ onReject, resultCapability, kRejected);
+ break;
+ }
+
+ // Mark this promise as having handler.
+ SET_PRIVATE(promise, promiseHasHandlerSymbol, true);
+ return resultCapability.promise;
+}
+
+// ES#sec-promise.prototype.then
+// Promise.prototype.then ( onFulfilled, onRejected )
+// Multi-unwrapped chaining with thenable coercion.
+function PromiseThen(onResolve, onReject) {
+ if (!%is_promise(this)) {
+ throw %make_type_error(kNotAPromise, this);
+ }
+
+ var constructor = SpeciesConstructor(this, GlobalPromise);
+ var resultCapability;
+ if (constructor === GlobalPromise) {
+ resultCapability = CreateInternalPromiseCapability();
+ } else {
+ // Pass false for debugEvent so .then chaining does not trigger
+ // redundant ExceptionEvents.
+ resultCapability = NewPromiseCapability(constructor, false);
+ }
+ return PerformPromiseThen(this, onResolve, onReject, resultCapability);
+}
+
// ES#sec-promise.prototype.catch
// Promise.prototype.catch ( onRejected )
function PromiseCatch(onReject) {
@@ -250,7 +377,7 @@
// Avoid creating resolving functions.
if (this === GlobalPromise) {
- var promise = %promise_internal_constructor();
+ var promise = PromiseCreate();
ResolvePromise(promise, x);
return promise;
}
@@ -393,10 +520,8 @@
return true;
}
- if (!%is_promise(promise)) return false;
-
- var queue = %PromiseRejectReactions(promise);
- var deferred = %PromiseDeferred(promise);
+ var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol);
+ var deferred = GET_PRIVATE(promise, promiseDeferredReactionSymbol);
if (IS_UNDEFINED(queue)) return false;
@@ -404,8 +529,8 @@
return PromiseHasUserDefinedRejectHandlerCheck(queue, deferred);
}
- for (var i = 0; i < queue.length; i++) {
- if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], deferred[i])) {
+ for (var i = 0; i < queue.length; i += 2) {
+ if (PromiseHasUserDefinedRejectHandlerCheck(queue[i], queue[i + 1])) {
return true;
}
}
@@ -443,6 +568,7 @@
utils.InstallGetter(GlobalPromise, speciesSymbol, PromiseSpecies);
utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
+ "then", PromiseThen,
"catch", PromiseCatch
]);
@@ -456,11 +582,7 @@
"promise_resolve", ResolvePromise,
"promise_then", PromiseThen,
"promise_handle", PromiseHandle,
- "promise_debug_get_info", PromiseDebugGetInfo,
- "new_promise_capability", NewPromiseCapability,
- "internal_promise_capability", CreateInternalPromiseCapability,
- "promise_id_resolve_handler", PromiseIdResolveHandler,
- "promise_id_reject_handler", PromiseIdRejectHandler
+ "promise_debug_get_info", PromiseDebugGetInfo
]);
// This allows extras to create promises quickly without building extra
@@ -478,6 +600,7 @@
to.PromiseThen = PromiseThen;
to.CreateInternalPromiseCapability = CreateInternalPromiseCapability;
+ to.PerformPromiseThen = PerformPromiseThen;
to.ResolvePromise = ResolvePromise;
to.RejectPromise = RejectPromise;
});
« no previous file with comments | « src/js/async-await.js ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698