Bug 1289318 - Part 6: Don't store a reference to the reject function on Promise instances themselves. r?efaust draft
authorTill Schneidereit <till@tillschneidereit.net>
Sat, 06 Aug 2016 01:42:16 +0200
changeset 400699 2d88eea27b4b4e6575a5be0e5f53913de55bfa15
parent 400698 2bf87b24ee110575403ed5496f9eeb6d4262b4ca
child 400700 4ba2419ce2ab2a609fc7d5f20ce785b44fcf7859
push id26245
push userbmo:till@tillschneidereit.net
push dateMon, 15 Aug 2016 14:02:13 +0000
reviewersefaust
bugs1289318
milestone51.0a1
Bug 1289318 - Part 6: Don't store a reference to the reject function on Promise instances themselves. r?efaust The reject function is reachable via the resolve function, so we can save a slot. MozReview-Commit-ID: 9SPdRdnt98T
js/src/builtin/Promise.cpp
js/src/builtin/SelfHostingDefines.h
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -155,17 +155,16 @@ ResolvePromise(JSContext* cx, Handle<Pro
     // Steps 4-5.
     promise->setFixedSlot(PROMISE_REACTIONS_SLOT, UndefinedValue());
 
     // Step 6.
     promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(int32_t(state)));
 
     // Also null out the resolve/reject functions so they can be GC'd.
     promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, UndefinedValue());
-    promise->setFixedSlot(PROMISE_REJECT_FUNCTION_SLOT, UndefinedValue());
 
     // Now that everything else is done, do the things the debugger needs.
     // Step 7 of RejectPromise implemented in onSettled.
     promise->onSettled(cx);
 
     // Step 7 of FulfillPromise.
     // Step 8 of RejectPromise.
     if (reactionsVal.isObject())
@@ -466,27 +465,21 @@ PromiseObject::create(JSContext* cx, Han
     RootedValue rejectVal(cx);
     if (!CreateResolvingFunctions(cx, promiseVal, &resolveVal, &rejectVal))
         return nullptr;
 
     // Need to wrap the resolution functions before storing them on the Promise.
     if (wrappedProto) {
         AutoCompartment ac(cx, promise);
         RootedValue wrappedResolveVal(cx, resolveVal);
-        RootedValue wrappedRejectVal(cx, rejectVal);
-        if (!cx->compartment()->wrap(cx, &wrappedResolveVal) ||
-            !cx->compartment()->wrap(cx, &wrappedRejectVal))
-        {
+        if (!cx->compartment()->wrap(cx, &wrappedResolveVal))
             return nullptr;
-        }
         promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, wrappedResolveVal);
-        promise->setFixedSlot(PROMISE_REJECT_FUNCTION_SLOT, wrappedRejectVal);
     } else {
         promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, resolveVal);
-        promise->setFixedSlot(PROMISE_REJECT_FUNCTION_SLOT, rejectVal);
     }
 
     // Step 9.
     bool success;
     {
         FixedInvokeArgs<2> args(cx);
 
         args[0].set(resolveVal);
@@ -684,33 +677,36 @@ PromiseConstructor(JSContext* cx, unsign
 
 bool
 PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
 {
     if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
         return true;
 
     RootedValue funVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
+    // TODO: ensure that this holds for xray'd promises. (It probably doesn't)
     MOZ_ASSERT(funVal.toObject().is<JSFunction>());
 
     FixedInvokeArgs<1> args(cx);
 
     args[0].set(resolutionValue);
 
     RootedValue dummy(cx);
     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
 }
 
 bool
 PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
 {
     if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
         return true;
 
-    RootedValue funVal(cx, this->getReservedSlot(PROMISE_REJECT_FUNCTION_SLOT));
+    RootedValue resolveVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
+    RootedFunction resolve(cx, &resolveVal.toObject().as<JSFunction>());
+    RootedValue funVal(cx, resolve->getExtendedSlot(ResolutionFunctionSlot_OtherFunction));
     MOZ_ASSERT(funVal.toObject().is<JSFunction>());
 
     FixedInvokeArgs<1> args(cx);
 
     args[0].set(rejectionValue);
 
     RootedValue dummy(cx);
     return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -56,23 +56,22 @@
 #define ITEM_KIND_KEY 0
 #define ITEM_KIND_VALUE 1
 #define ITEM_KIND_KEY_AND_VALUE 2
 
 #define PROMISE_STATE_SLOT             0
 #define PROMISE_RESULT_SLOT            1
 #define PROMISE_REACTIONS_SLOT         2
 #define PROMISE_RESOLVE_FUNCTION_SLOT  3
-#define PROMISE_REJECT_FUNCTION_SLOT   4
-#define PROMISE_ALLOCATION_SITE_SLOT   5
-#define PROMISE_RESOLUTION_SITE_SLOT   6
-#define PROMISE_ALLOCATION_TIME_SLOT   7
-#define PROMISE_RESOLUTION_TIME_SLOT   8
-#define PROMISE_ID_SLOT                9
-#define PROMISE_IS_HANDLED_SLOT       10
+#define PROMISE_ALLOCATION_SITE_SLOT   4
+#define PROMISE_RESOLUTION_SITE_SLOT   5
+#define PROMISE_ALLOCATION_TIME_SLOT   6
+#define PROMISE_RESOLUTION_TIME_SLOT   7
+#define PROMISE_ID_SLOT                8
+#define PROMISE_IS_HANDLED_SLOT        9
 
 #define PROMISE_STATE_PENDING   0
 #define PROMISE_STATE_FULFILLED 1
 #define PROMISE_STATE_REJECTED  2
 
 #define PROMISE_IS_HANDLED_STATE_HANDLED   0
 #define PROMISE_IS_HANDLED_STATE_UNHANDLED 1
 #define PROMISE_IS_HANDLED_STATE_REPORTED  2