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

Unified Diff: src/promise.js

Issue 292173011: Harden a few builtins (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: rebased Created 6 years, 7 months 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/objects.cc ('k') | src/uri.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/promise.js
diff --git a/src/promise.js b/src/promise.js
index d202f2886166af38985140786888831c0ba25be5..aa9da2e59495fd83610dac9fcb371f81ee7d6269 100644
--- a/src/promise.js
+++ b/src/promise.js
@@ -9,28 +9,18 @@
// var $Object = global.Object
// var $WeakMap = global.WeakMap
+// For bootstrapper.
-var $Promise = function Promise(resolver) {
- if (resolver === promiseRaw) return;
- if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
- if (!IS_SPEC_FUNCTION(resolver))
- throw MakeTypeError('resolver_not_a_function', [resolver]);
- var promise = PromiseInit(this);
- try {
- %DebugPromiseHandlePrologue(function() { return promise });
- resolver(function(x) { PromiseResolve(promise, x) },
- function(r) { PromiseReject(promise, r) });
- } catch (e) {
- PromiseReject(promise, e);
- } finally {
- %DebugPromiseHandleEpilogue();
- }
-}
-
-
-//-------------------------------------------------------------------
+var IsPromise;
+var PromiseCreate;
+var PromiseResolve;
+var PromiseReject;
+var PromiseChain;
+var PromiseCatch;
-// Core functionality.
+// mirror-debugger.js currently uses builtins.promiseStatus. It would be nice
+// if we could move these property names into the closure below.
+// TODO(jkummerow/rossberg/yangguo): Find a better solution.
// Status values: 0 = pending, +1 = resolved, -1 = rejected
var promiseStatus = GLOBAL_PRIVATE("Promise#status");
@@ -39,250 +29,274 @@ var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");
var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");
var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
-function IsPromise(x) {
- return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus);
-}
-
-function PromiseSet(promise, status, value, onResolve, onReject) {
- SET_PRIVATE(promise, promiseStatus, status);
- SET_PRIVATE(promise, promiseValue, value);
- SET_PRIVATE(promise, promiseOnResolve, onResolve);
- SET_PRIVATE(promise, promiseOnReject, onReject);
- return promise;
-}
-
-function PromiseInit(promise) {
- return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray)
-}
-
-function PromiseDone(promise, status, value, promiseQueue) {
- if (GET_PRIVATE(promise, promiseStatus) === 0) {
- PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue));
- PromiseSet(promise, status, value);
+(function() {
+
+ var $Promise = function Promise(resolver) {
+ if (resolver === promiseRaw) return;
+ if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
+ if (!IS_SPEC_FUNCTION(resolver))
+ throw MakeTypeError('resolver_not_a_function', [resolver]);
+ var promise = PromiseInit(this);
+ try {
+ %DebugPromiseHandlePrologue(function() { return promise });
+ resolver(function(x) { PromiseResolve(promise, x) },
+ function(r) { PromiseReject(promise, r) });
+ } catch (e) {
+ PromiseReject(promise, e);
+ } finally {
+ %DebugPromiseHandleEpilogue();
+ }
}
-}
-function PromiseResolve(promise, x) {
- PromiseDone(promise, +1, x, promiseOnResolve)
-}
+ // Core functionality.
-function PromiseReject(promise, r) {
- PromiseDone(promise, -1, r, promiseOnReject)
-}
+ function PromiseSet(promise, status, value, onResolve, onReject) {
+ SET_PRIVATE(promise, promiseStatus, status);
+ SET_PRIVATE(promise, promiseValue, value);
+ SET_PRIVATE(promise, promiseOnResolve, onResolve);
+ SET_PRIVATE(promise, promiseOnReject, onReject);
+ return promise;
+ }
+ function PromiseInit(promise) {
+ return PromiseSet(promise, 0, UNDEFINED, new InternalArray,
+ new InternalArray)
+ }
-// For API.
+ function PromiseDone(promise, status, value, promiseQueue) {
+ if (GET_PRIVATE(promise, promiseStatus) === 0) {
+ PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue));
+ PromiseSet(promise, status, value);
+ }
+ }
-function PromiseNopResolver() {}
+ function PromiseCoerce(constructor, x) {
+ if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
+ var then;
+ try {
+ then = x.then;
+ } catch(r) {
+ return %_CallFunction(constructor, r, PromiseRejected);
+ }
+ if (IS_SPEC_FUNCTION(then)) {
+ var deferred = %_CallFunction(constructor, PromiseDeferred);
+ try {
+ %_CallFunction(x, deferred.resolve, deferred.reject, then);
+ } catch(r) {
+ deferred.reject(r);
+ }
+ return deferred.promise;
+ }
+ }
+ return x;
+ }
-function PromiseCreate() {
- return new $Promise(PromiseNopResolver)
-}
+ function PromiseHandle(value, handler, deferred) {
+ try {
+ %DebugPromiseHandlePrologue(
+ function() {
+ var queue = GET_PRIVATE(deferred.promise, promiseOnReject);
+ return (queue && queue.length == 0) ? deferred.promise : UNDEFINED;
+ });
+ var result = handler(value);
+ if (result === deferred.promise)
+ throw MakeTypeError('promise_cyclic', [result]);
+ else if (IsPromise(result))
+ %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
+ else
+ deferred.resolve(result);
+ } catch (exception) {
+ try {
+ %DebugPromiseHandlePrologue(function() { return deferred.promise });
+ deferred.reject(exception);
+ } catch (e) { } finally {
+ %DebugPromiseHandleEpilogue();
+ }
+ } finally {
+ %DebugPromiseHandleEpilogue();
+ }
+ }
+
+ function PromiseEnqueue(value, tasks) {
+ %EnqueueMicrotask(function() {
+ for (var i = 0; i < tasks.length; i += 2) {
+ PromiseHandle(value, tasks[i], tasks[i + 1])
+ }
+ });
+ }
+ function PromiseIdResolveHandler(x) { return x }
+ function PromiseIdRejectHandler(r) { throw r }
-// Convenience.
+ function PromiseNopResolver() {}
-function PromiseDeferred() {
- if (this === $Promise) {
- // Optimized case, avoid extra closure.
- var promise = PromiseInit(new $Promise(promiseRaw));
- return {
- promise: promise,
- resolve: function(x) { PromiseResolve(promise, x) },
- reject: function(r) { PromiseReject(promise, r) }
- };
- } else {
- var result = {};
- result.promise = new this(function(resolve, reject) {
- result.resolve = resolve;
- result.reject = reject;
- })
- return result;
- }
-}
-
-function PromiseResolved(x) {
- if (this === $Promise) {
- // Optimized case, avoid extra closure.
- return PromiseSet(new $Promise(promiseRaw), +1, x);
- } else {
- return new this(function(resolve, reject) { resolve(x) });
+ // -------------------------------------------------------------------
+ // Define exported functions.
+
+ // For bootstrapper.
+
+ IsPromise = function IsPromise(x) {
+ return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus);
}
-}
-
-function PromiseRejected(r) {
- if (this === $Promise) {
- // Optimized case, avoid extra closure.
- return PromiseSet(new $Promise(promiseRaw), -1, r);
- } else {
- return new this(function(resolve, reject) { reject(r) });
+
+ PromiseCreate = function PromiseCreate() {
+ return new $Promise(PromiseNopResolver)
}
-}
-
-
-// Simple chaining.
-
-function PromiseIdResolveHandler(x) { return x }
-function PromiseIdRejectHandler(r) { throw r }
-
-function PromiseChain(onResolve, onReject) { // a.k.a. flatMap
- onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
- onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
- var deferred = %_CallFunction(this.constructor, PromiseDeferred);
- switch (GET_PRIVATE(this, promiseStatus)) {
- case UNDEFINED:
- throw MakeTypeError('not_a_promise', [this]);
- case 0: // Pending
- GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
- GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
- break;
- case +1: // Resolved
- PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onResolve, deferred]);
- break;
- case -1: // Rejected
- PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onReject, deferred]);
- break;
+
+ PromiseResolve = function PromiseResolve(promise, x) {
+ PromiseDone(promise, +1, x, promiseOnResolve)
}
- return deferred.promise;
-}
-function PromiseCatch(onReject) {
- return this.then(UNDEFINED, onReject);
-}
+ PromiseReject = function PromiseReject(promise, r) {
+ PromiseDone(promise, -1, r, promiseOnReject)
+ }
-function PromiseEnqueue(value, tasks) {
- %EnqueueMicrotask(function() {
- for (var i = 0; i < tasks.length; i += 2) {
- PromiseHandle(value, tasks[i], tasks[i + 1])
+ // Convenience.
+
+ function PromiseDeferred() {
+ if (this === $Promise) {
+ // Optimized case, avoid extra closure.
+ var promise = PromiseInit(new $Promise(promiseRaw));
+ return {
+ promise: promise,
+ resolve: function(x) { PromiseResolve(promise, x) },
+ reject: function(r) { PromiseReject(promise, r) }
+ };
+ } else {
+ var result = {};
+ result.promise = new this(function(resolve, reject) {
+ result.resolve = resolve;
+ result.reject = reject;
+ })
+ return result;
}
- });
-}
-
-function PromiseHandle(value, handler, deferred) {
- try {
- %DebugPromiseHandlePrologue(
- function() {
- var queue = GET_PRIVATE(deferred.promise, promiseOnReject);
- return (queue && queue.length == 0) ? deferred.promise : UNDEFINED;
- });
- var result = handler(value);
- if (result === deferred.promise)
- throw MakeTypeError('promise_cyclic', [result]);
- else if (IsPromise(result))
- %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
- else
- deferred.resolve(result);
- } catch (exception) {
- try {
- %DebugPromiseHandlePrologue(function() { return deferred.promise });
- deferred.reject(exception);
- } catch (e) { } finally {
- %DebugPromiseHandleEpilogue();
+ }
+
+ function PromiseResolved(x) {
+ if (this === $Promise) {
+ // Optimized case, avoid extra closure.
+ return PromiseSet(new $Promise(promiseRaw), +1, x);
+ } else {
+ return new this(function(resolve, reject) { resolve(x) });
}
- } finally {
- %DebugPromiseHandleEpilogue();
}
-}
-
-
-// Multi-unwrapped chaining with thenable coercion.
-
-function PromiseThen(onResolve, onReject) {
- onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve : PromiseIdResolveHandler;
- onReject = IS_SPEC_FUNCTION(onReject) ? onReject : PromiseIdRejectHandler;
- var that = this;
- var constructor = this.constructor;
- return %_CallFunction(
- this,
- function(x) {
- x = PromiseCoerce(constructor, x);
- return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
- IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
- },
- onReject,
- PromiseChain
- );
-}
-
-function PromiseCoerce(constructor, x) {
- if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
- var then;
- try {
- then = x.then;
- } catch(r) {
- return %_CallFunction(constructor, r, PromiseRejected);
+
+ function PromiseRejected(r) {
+ if (this === $Promise) {
+ // Optimized case, avoid extra closure.
+ return PromiseSet(new $Promise(promiseRaw), -1, r);
+ } else {
+ return new this(function(resolve, reject) { reject(r) });
}
- if (IS_SPEC_FUNCTION(then)) {
- var deferred = %_CallFunction(constructor, PromiseDeferred);
- try {
- %_CallFunction(x, deferred.resolve, deferred.reject, then);
- } catch(r) {
- deferred.reject(r);
- }
- return deferred.promise;
+ }
+
+ // Simple chaining.
+
+ PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a.
+ // flatMap
+ onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
+ onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
+ var deferred = %_CallFunction(this.constructor, PromiseDeferred);
+ switch (GET_PRIVATE(this, promiseStatus)) {
+ case UNDEFINED:
+ throw MakeTypeError('not_a_promise', [this]);
+ case 0: // Pending
+ GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
+ GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
+ break;
+ case +1: // Resolved
+ PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onResolve, deferred]);
+ break;
+ case -1: // Rejected
+ PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onReject, deferred]);
+ break;
}
+ return deferred.promise;
}
- return x;
-}
+ PromiseCatch = function PromiseCatch(onReject) {
+ return this.then(UNDEFINED, onReject);
+ }
-// Combinators.
+ // Multi-unwrapped chaining with thenable coercion.
+
+ function PromiseThen(onResolve, onReject) {
+ onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve
+ : PromiseIdResolveHandler;
+ onReject = IS_SPEC_FUNCTION(onReject) ? onReject
+ : PromiseIdRejectHandler;
+ var that = this;
+ var constructor = this.constructor;
+ return %_CallFunction(
+ this,
+ function(x) {
+ x = PromiseCoerce(constructor, x);
+ return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
+ IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
+ },
+ onReject,
+ PromiseChain
+ );
+ }
-function PromiseCast(x) {
- // TODO(rossberg): cannot do better until we support @@create.
- return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
-}
+ // Combinators.
-function PromiseAll(values) {
- var deferred = %_CallFunction(this, PromiseDeferred);
- var resolutions = [];
- if (!%_IsArray(values)) {
- deferred.reject(MakeTypeError('invalid_argument'));
+ function PromiseCast(x) {
+ // TODO(rossberg): cannot do better until we support @@create.
+ return IsPromise(x) ? x : new this(function(resolve) { resolve(x) });
+ }
+
+ function PromiseAll(values) {
+ var deferred = %_CallFunction(this, PromiseDeferred);
+ var resolutions = [];
+ if (!%_IsArray(values)) {
+ deferred.reject(MakeTypeError('invalid_argument'));
+ return deferred.promise;
+ }
+ try {
+ var count = values.length;
+ if (count === 0) {
+ deferred.resolve(resolutions);
+ } else {
+ for (var i = 0; i < values.length; ++i) {
+ this.resolve(values[i]).then(
+ function(i, x) {
+ resolutions[i] = x;
+ if (--count === 0) deferred.resolve(resolutions);
+ }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once
+ // available
+ function(r) { deferred.reject(r) }
+ );
+ }
+ }
+ } catch (e) {
+ deferred.reject(e)
+ }
return deferred.promise;
}
- try {
- var count = values.length;
- if (count === 0) {
- deferred.resolve(resolutions);
- } else {
+
+ function PromiseOne(values) {
+ var deferred = %_CallFunction(this, PromiseDeferred);
+ if (!%_IsArray(values)) {
+ deferred.reject(MakeTypeError('invalid_argument'));
+ return deferred.promise;
+ }
+ try {
for (var i = 0; i < values.length; ++i) {
this.resolve(values[i]).then(
- function(i, x) {
- resolutions[i] = x;
- if (--count === 0) deferred.resolve(resolutions);
- }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available
+ function(x) { deferred.resolve(x) },
function(r) { deferred.reject(r) }
);
}
+ } catch (e) {
+ deferred.reject(e)
}
- } catch (e) {
- deferred.reject(e)
- }
- return deferred.promise;
-}
-
-function PromiseOne(values) {
- var deferred = %_CallFunction(this, PromiseDeferred);
- if (!%_IsArray(values)) {
- deferred.reject(MakeTypeError('invalid_argument'));
return deferred.promise;
}
- try {
- for (var i = 0; i < values.length; ++i) {
- this.resolve(values[i]).then(
- function(x) { deferred.resolve(x) },
- function(r) { deferred.reject(r) }
- );
- }
- } catch (e) {
- deferred.reject(e)
- }
- return deferred.promise;
-}
-//-------------------------------------------------------------------
+ // -------------------------------------------------------------------
+ // Install exported functions.
-function SetUpPromise() {
%CheckIsBootstrapping();
%SetProperty(global, 'Promise', $Promise, DONT_ENUM);
InstallFunctions($Promise, DONT_ENUM, [
@@ -298,6 +312,5 @@ function SetUpPromise() {
"then", PromiseThen,
"catch", PromiseCatch
]);
-}
-SetUpPromise();
+})();
« no previous file with comments | « src/objects.cc ('k') | src/uri.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698