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
--- 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