From cad9414a191b3443978ec1456ef43a4128311146 Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Wed, 3 Aug 2016 20:01:10 +0200 Subject: [PATCH] Bug 1289318 - Part 4: Only allocate the Promise reactions array once the first reaction record is added. r=efaust Saves 96 bytes on reaction-less promises. It also saves 32 bytes on promises that have up to two reactions: empty arrays are initialized with an allocated length of 8, whereas providing an initial element initializes to 2. MozReview-Commit-ID: 3PtT7LDwL3k --- js/src/builtin/Promise.cpp | 6 +----- js/src/builtin/Promise.js | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 670fc1dd3107..c12d4103646f 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -115,11 +115,7 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto / promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_PENDING)); // Steps 5-6. - // We only have a single list of reaction records. - RootedArrayObject reactions(cx, NewDenseEmptyArray(cx)); - if (!reactions) - return nullptr; - promise->setFixedSlot(PROMISE_REACTIONS_SLOT, ObjectValue(*reactions)); + // Omitted, we allocate our single list of reaction records lazily. // Step 7. promise->setFixedSlot(PROMISE_IS_HANDLED_SLOT, diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js index a68cac125383..c543177a5dbd 100644 --- a/js/src/builtin/Promise.js +++ b/js/src/builtin/Promise.js @@ -147,7 +147,7 @@ function ResolvePromise(promise, valueOrReason, state) { // instead of getting the right list of reactions, we determine the // resolution type to retrieve the right information from the // reaction records. - var reactions = UnsafeGetObjectFromReservedSlot(promise, PROMISE_REACTIONS_SLOT); + var reactions = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_SLOT); let jobType = state === PROMISE_STATE_FULFILLED ? PROMISE_JOB_TYPE_FULFILL : PROMISE_JOB_TYPE_REJECT; @@ -171,7 +171,8 @@ function ResolvePromise(promise, valueOrReason, state) { // Step 7 of FulfillPromise. // Step 8 of RejectPromise. - return TriggerPromiseReactions(reactions, jobType, valueOrReason); + if (reactions) + TriggerPromiseReactions(reactions, jobType, valueOrReason); } // Used to verify that an object is a PromiseCapability record. @@ -647,10 +648,11 @@ function AddDependentPromise(dependentPromise) { let reactions = UnsafeGetReservedSlot(this, PROMISE_REACTIONS_SLOT); - // The reactions slot might've been reset because the Promise was resolved. + // The reactions list might not have been allocated yet or been reset + // because the Promise was resolved. if (!reactions) { - assert(GetPromiseState(this) !== PROMISE_STATE_PENDING, - "Pending promises must have reactions lists."); + if (GetPromiseState(this) === PROMISE_STATE_PENDING) + UnsafeSetReservedSlot(promise, PROMISE_REACTIONS_SLOT, [reaction]); return; } _DefineDataProperty(reactions, reactions.length, reaction); @@ -900,8 +902,11 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability) if (state === PROMISE_STATE_PENDING) { // Steps 7.a,b. // We only have a single list for fulfill and reject reactions. - let reactions = UnsafeGetObjectFromReservedSlot(promise, PROMISE_REACTIONS_SLOT); - _DefineDataProperty(reactions, reactions.length, reaction); + let reactions = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_SLOT); + if (!reactions) + UnsafeSetReservedSlot(promise, PROMISE_REACTIONS_SLOT, [reaction]); + else + _DefineDataProperty(reactions, reactions.length, reaction); } // Step 8.