From 8f39dbc699a3a20f9be47823e9012854cb144b12 Mon Sep 17 00:00:00 2001 From: Petka Antonov Date: Sun, 26 May 2019 11:36:48 +0300 Subject: [PATCH] Fixes #1326 --- .jshintrc | 2 ++ src/constants.js | 5 ++++- src/promise.js | 10 +++++++++- src/reduce.js | 7 +++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.jshintrc b/.jshintrc index 601adc6ff..bc1449713 100644 --- a/.jshintrc +++ b/.jshintrc @@ -88,7 +88,9 @@ "CALLBACK_PROMISE_OFFSET": false, "CALLBACK_RECEIVER_OFFSET": false, "CALLBACK_SIZE": false, + "ASYNC_GUARANTEE_SHIFT": false, "NO_STATE": false, + "NO_ASYNC_GUARANTEE": false, "RETURNED_NON_UNDEFINED": false, "IS_ASYNC_GUARANTEED": false, "IS_FOLLOWING": false, diff --git a/src/constants.js b/src/constants.js index 63ad1b3d6..a011036cf 100644 --- a/src/constants.js +++ b/src/constants.js @@ -28,10 +28,11 @@ CONSTANT(CALLBACK_PROMISE_OFFSET, 2); CONSTANT(CALLBACK_RECEIVER_OFFSET, 3); CONSTANT(CALLBACK_SIZE, 4); //Layout for ._bitField -//[RR]RO GWFN CTBH IUDE LLLL LLLL LLLL LLLL +//[RR]XO GWFN CTBH IUDE LLLL LLLL LLLL LLLL //[RR] = [Reserved] (Both bits are either on or off to represent // 1 bit due to 31-bit integers in 32-bit v8) //R = [Reserved] +//X = noAsyncGuarantee //O = returnedNonUndefined //G = isAsyncGuaranteed //W = isFollowing (The promise that is being followed is not stored explicitly) @@ -46,7 +47,9 @@ CONSTANT(CALLBACK_SIZE, 4); //D = isDisposable //E = isCancelled //L = Length, 16 bit unsigned +CONSTANT(ASYNC_GUARANTEE_SHIFT, 2) CONSTANT(NO_STATE, 0x0|0); +CONSTANT(NO_ASYNC_GUARANTEE, 0x20000000|0); CONSTANT(RETURNED_NON_UNDEFINED, 0x10000000|0); CONSTANT(IS_ASYNC_GUARANTEED, 0x8000000|0); CONSTANT(IS_FOLLOWING, 0x4000000|0); diff --git a/src/promise.js b/src/promise.js index c1f5d251d..f511f4856 100644 --- a/src/promise.js +++ b/src/promise.js @@ -360,7 +360,15 @@ Promise.prototype._setWillBeCancelled = function() { Promise.prototype._setAsyncGuaranteed = function() { if (async.hasCustomScheduler()) return; - this._bitField = this._bitField | IS_ASYNC_GUARANTEED; + var bitField = this._bitField; + this._bitField = bitField | + (((bitField & NO_ASYNC_GUARANTEE) >> ASYNC_GUARANTEE_SHIFT) ^ + IS_ASYNC_GUARANTEED); +}; + +Promise.prototype._setNoAsyncGuarantee = function() { + this._bitField = (this._bitField | NO_ASYNC_GUARANTEE) & + (~IS_ASYNC_GUARANTEED); }; Promise.prototype._receiverAt = function (index) { diff --git a/src/reduce.js b/src/reduce.js index 57da37c26..51f86aab9 100644 --- a/src/reduce.js +++ b/src/reduce.js @@ -110,7 +110,14 @@ ReductionPromiseArray.prototype._iterate = function (values) { length: length, array: this }; + value = value._then(gotAccum, undefined, undefined, ctx, undefined); + + // Too many promises chained with asyncGuaranteed will result in + // stack overflow. Break up long chains to reset stack. + if ((i & 127) === 0) { + value._setNoAsyncGuarantee(); + } } }