Permalink
Browse files

Fix memory leak

Fixes the memory described at
promises-aplus/promises-spec#179
  • Loading branch information...
petkaantonov committed Dec 28, 2014
1 parent 3e4bbe3 commit 8c1edaf0a77a6d46a7527b2873e456d3ff62fab8
Showing with 445 additions and 269 deletions.
  1. +1 −1 src/cancel.js
  2. +1 −4 src/constants.js
  3. +2 −0 src/finally.js
  4. +5 −4 src/join.js
  5. +5 −4 src/map.js
  6. +2 −4 src/progress.js
  7. +108 −100 src/promise.js
  8. +11 −9 src/promise_array.js
  9. +15 −12 src/reduce.js
  10. +62 −17 src/synchronous_inspection.js
  11. +0 −1 src/thenables.js
  12. +4 −3 src/timers.js
  13. +3 −3 src/using.js
  14. +212 −94 test/mocha/following.js
  15. +14 −13 test/mocha/generator.js
@@ -18,7 +18,7 @@ Promise.prototype._cancel = function (reason) {
ASSERT(promiseToReject.isCancellable());
this._unsetCancellable();
promiseToReject._attachExtraTrace(reason);
promiseToReject._rejectUnchecked(reason);
promiseToReject._target()._rejectUnchecked(reason);
};

Promise.prototype.cancel = function (reason) {
@@ -27,7 +27,7 @@ CONSTANT(CALLBACK_PROMISE_OFFSET, 3);
CONSTANT(CALLBACK_RECEIVER_OFFSET, 4);
CONSTANT(CALLBACK_SIZE, 5);
//Layout for ._bitField
//QQWF NCTR BPHS UDLL LLLL LLLL LLLL LLLL
//QQWF NCTR B[R]HS UDLL LLLL LLLL LLLL LLLL
//Q = isSettlePromisesQueued (Both bits are either on or off to represent
// 1 bit due to 31-bit integers in 32-bit v8)
//W = isFollowing (The promise that is being followed is not stored explicitly)
@@ -36,8 +36,6 @@ CONSTANT(CALLBACK_SIZE, 5);
//C = isCancellable
//T = isFinal (used for .done() implementation)
//B = isBound
//P = isProxied (optimization when .then listeners on a promise are
// just respective fate sealers on some other promise)
//H = isRejectionUnhandled
//S = isCarryingStackTrace
//U = isUnhanldedRejectionNotified
@@ -52,7 +50,6 @@ CONSTANT(IS_REJECTED, 0x8000000|0);
CONSTANT(IS_CANCELLABLE, 0x4000000|0);
CONSTANT(IS_FINAL, 0x2000000|0);
CONSTANT(IS_BOUND, 0x800000|0);
CONSTANT(IS_PROXIED, 0x400000|0);
CONSTANT(IS_REJECTION_UNHANDLED, 0x200000|0);
CONSTANT(IS_CARRYING_STACK_TRACE, 0x100000|0);
CONSTANT(IS_UNHANDLED_REJECTION_NOTIFIED, 0x80000|0);
@@ -43,6 +43,7 @@ function finallyHandler(reasonOrValue) {
if (ret !== undefined) {
var maybePromise = tryConvertToPromise(ret, undefined);
if (maybePromise instanceof Promise) {
maybePromise = maybePromise._target();
return promisedFinally(maybePromise, reasonOrValue,
promise.isFulfilled());
}
@@ -70,6 +71,7 @@ function tapHandler(value) {
if (ret !== undefined) {
var maybePromise = tryConvertToPromise(ret, undefined);
if (maybePromise instanceof Promise) {
maybePromise = maybePromise._target();
return promisedFinally(maybePromise, value, true);
}
}
@@ -75,14 +75,15 @@ Promise.join = function () {
for (var i = 0; i < last; ++i) {
var maybePromise = tryConvertToPromise(arguments[i], undefined);
if (maybePromise instanceof Promise) {
if (maybePromise.isPending()) {
maybePromise = maybePromise._target();
if (maybePromise._isPending()) {
maybePromise._then(callbacks[i], reject,
undefined, ret, holder);
} else if (maybePromise.isFulfilled()) {
} else if (maybePromise._isFulfilled()) {
callbacks[i].call(ret,
maybePromise._settledValue, holder);
maybePromise._value(), holder);
} else {
ret._reject(maybePromise._settledValue);
ret._reject(maybePromise._reason());
maybePromise._unsetRejectionIsUnhandled();
}
} else {
@@ -67,15 +67,16 @@ MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
// anymore), the marker PENDING is put at that index
var maybePromise = tryConvertToPromise(ret, this._promise);
if (maybePromise instanceof Promise) {
if (maybePromise.isPending()) {
maybePromise = maybePromise._target();
if (maybePromise._isPending()) {
if (limit >= 1) this._inFlight++;
values[index] = PENDING;
return maybePromise._proxyPromiseArray(this, index);
} else if (maybePromise.isFulfilled()) {
ret = maybePromise._settledValue;
} else if (maybePromise._isFulfilled()) {
ret = maybePromise._value();
} else {
maybePromise._unsetRejectionIsUnhandled();
return this._reject(maybePromise._settledValue);
return this._reject(maybePromise._reason());
}
}
values[index] = ret;
@@ -13,7 +13,7 @@ Promise.prototype.progressed = function (handler) {

Promise.prototype._progress = function (progressValue) {
if (this._isFollowingOrFulfilledOrRejected()) return;
this._progressUnchecked(progressValue);
this._target()._progressUnchecked(progressValue);

};

@@ -67,7 +67,7 @@ Promise.prototype._doProgressWith = function (progression) {


Promise.prototype._progressUnchecked = function (progressValue) {
if (!this.isPending()) return;
ASSERT(!this._isFollowingOrFulfilledOrRejected());
var len = this._length();
var progress = this._progress;
for (var i = 0; i < len; i++) {
@@ -79,8 +79,6 @@ Promise.prototype._progressUnchecked = function (progressValue) {
var receiver = this._receiverAt(i);
if (typeof handler === "function") {
handler.call(receiver, progressValue, promise);
} else if (receiver instanceof Promise && receiver._isProxied()) {
receiver._progressUnchecked(progressValue);
} else if (receiver instanceof PromiseArray &&
!receiver._isResolved()) {
receiver._promiseProgressed(progressValue, promise);
Oops, something went wrong.

0 comments on commit 8c1edaf

Please sign in to comment.