зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1289318 - Part 8: Combine Promise state and rejection handling info into a single flags field. r=efaust
The rejection handling state will be required even without devtools being open once projection rejection tracking events[1] are implemented, so it should always be tracked on the Promise itself. The other debugging state will be moved into a debug-only object referenced via a slot on Promise. MozReview-Commit-ID: LM10qruLDxz
This commit is contained in:
Родитель
e2d055ae6b
Коммит
36380475eb
|
@ -160,7 +160,11 @@ ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueO
|
|||
promise->setFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT, valueOrReason);
|
||||
|
||||
// Step 6.
|
||||
promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(int32_t(state)));
|
||||
int32_t flags = promise->getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
|
||||
flags |= PROMISE_FLAG_RESOLVED;
|
||||
if (state == JS::PromiseState::Fulfilled)
|
||||
flags |= PROMISE_FLAG_FULFILLED;
|
||||
promise->setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(flags));
|
||||
|
||||
// Also null out the resolve/reject functions so they can be GC'd.
|
||||
promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, UndefinedValue());
|
||||
|
@ -435,14 +439,13 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
|
|||
return nullptr;
|
||||
|
||||
// Step 4.
|
||||
promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_PENDING));
|
||||
promise->setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(0));
|
||||
|
||||
// Steps 5-6.
|
||||
// Omitted, we allocate our single list of reaction records lazily.
|
||||
|
||||
// Step 7.
|
||||
promise->setFixedSlot(PROMISE_IS_HANDLED_SLOT,
|
||||
Int32Value(PROMISE_IS_HANDLED_STATE_UNHANDLED));
|
||||
// Implicit, the handled flag is unset by default.
|
||||
|
||||
// Store an allocation stack so we can later figure out what the
|
||||
// control flow was for some unexpected results. Frightfully expensive,
|
||||
|
@ -685,7 +688,7 @@ PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
bool
|
||||
PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
|
||||
{
|
||||
if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
|
||||
if (state() != JS::PromiseState::Pending)
|
||||
return true;
|
||||
|
||||
RootedValue funVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
|
||||
|
@ -703,7 +706,7 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
|
|||
bool
|
||||
PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
|
||||
{
|
||||
if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
|
||||
if (state() != JS::PromiseState::Pending)
|
||||
return true;
|
||||
|
||||
RootedValue resolveVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
|
||||
|
@ -733,12 +736,8 @@ PromiseObject::onSettled(JSContext* cx)
|
|||
promise->setFixedSlot(PROMISE_RESOLUTION_SITE_SLOT, ObjectOrNullValue(stack));
|
||||
promise->setFixedSlot(PROMISE_RESOLUTION_TIME_SLOT, DoubleValue(MillisecondsSinceStartup()));
|
||||
|
||||
if (promise->state() == JS::PromiseState::Rejected &&
|
||||
promise->getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() !=
|
||||
PROMISE_IS_HANDLED_STATE_HANDLED)
|
||||
{
|
||||
if (promise->state() == JS::PromiseState::Rejected && promise->isUnhandled())
|
||||
cx->runtime()->addUnhandledRejectedPromise(cx, promise);
|
||||
}
|
||||
|
||||
JS::dbg::onPromiseSettled(cx, promise);
|
||||
}
|
||||
|
|
|
@ -17,16 +17,21 @@ class AutoSetNewObjectMetadata;
|
|||
class PromiseObject : public NativeObject
|
||||
{
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 12;
|
||||
static const unsigned RESERVED_SLOTS = 8;
|
||||
static const Class class_;
|
||||
static const Class protoClass_;
|
||||
static PromiseObject* create(JSContext* cx, HandleObject executor,
|
||||
HandleObject proto = nullptr);
|
||||
|
||||
JS::PromiseState state() {
|
||||
int32_t state = getFixedSlot(PROMISE_STATE_SLOT).toInt32();
|
||||
MOZ_ASSERT(state >= 0 && state <= int32_t(JS::PromiseState::Rejected));
|
||||
return JS::PromiseState(state);
|
||||
int32_t flags = getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
|
||||
if (!(flags & PROMISE_FLAG_RESOLVED)) {
|
||||
MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
|
||||
return JS::PromiseState::Pending;
|
||||
}
|
||||
if (flags & PROMISE_FLAG_FULFILLED)
|
||||
return JS::PromiseState::Fulfilled;
|
||||
return JS::PromiseState::Rejected;
|
||||
}
|
||||
Value value() {
|
||||
MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
|
||||
|
@ -57,13 +62,14 @@ class PromiseObject : public NativeObject
|
|||
}
|
||||
MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
|
||||
uint64_t getID();
|
||||
bool markedAsUncaught() {
|
||||
return getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() != PROMISE_IS_HANDLED_STATE_HANDLED;
|
||||
bool isUnhandled() {
|
||||
MOZ_ASSERT(state() == JS::PromiseState::Rejected);
|
||||
return !(getFixedSlot(PROMISE_FLAGS_SLOT).toInt32() & PROMISE_FLAG_HANDLED);
|
||||
}
|
||||
void markAsReported() {
|
||||
MOZ_ASSERT(getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() ==
|
||||
PROMISE_IS_HANDLED_STATE_UNHANDLED);
|
||||
setFixedSlot(PROMISE_IS_HANDLED_SLOT, Int32Value(PROMISE_IS_HANDLED_STATE_REPORTED));
|
||||
MOZ_ASSERT(isUnhandled());
|
||||
int32_t flags = getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
|
||||
setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(flags | PROMISE_FLAG_REPORTED));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -736,6 +736,7 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
|
|||
|
||||
// Step 7.
|
||||
let state = GetPromiseState(promise);
|
||||
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
|
||||
if (state === PROMISE_STATE_PENDING) {
|
||||
// Steps 7.a,b.
|
||||
// We only have a single list for fulfill and reject reactions.
|
||||
|
@ -764,18 +765,15 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
|
|||
let reason = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
|
||||
|
||||
// Step 9.c.
|
||||
if (UnsafeGetInt32FromReservedSlot(promise, PROMISE_IS_HANDLED_SLOT) !==
|
||||
PROMISE_IS_HANDLED_STATE_HANDLED)
|
||||
{
|
||||
if (!(flags & PROMISE_FLAG_HANDLED))
|
||||
HostPromiseRejectionTracker(promise, PROMISE_REJECTION_TRACKER_OPERATION_HANDLE);
|
||||
}
|
||||
|
||||
// Step 9.d.
|
||||
EnqueuePromiseReactionJob(reaction, PROMISE_JOB_TYPE_REJECT, reason);
|
||||
}
|
||||
|
||||
// Step 10.
|
||||
UnsafeSetReservedSlot(promise, PROMISE_IS_HANDLED_SLOT, PROMISE_IS_HANDLED_STATE_HANDLED);
|
||||
UnsafeSetReservedSlot(promise, PROMISE_FLAGS_SLOT, flags | PROMISE_FLAG_HANDLED);
|
||||
|
||||
// Step 11.
|
||||
return resultCapability.promise;
|
||||
|
@ -791,5 +789,12 @@ function IsPromiseCapability(capability) {
|
|||
}
|
||||
|
||||
function GetPromiseState(promise) {
|
||||
return UnsafeGetInt32FromReservedSlot(promise, PROMISE_STATE_SLOT);
|
||||
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
|
||||
if (!(flags & PROMISE_FLAG_RESOLVED)) {
|
||||
assert(!(flags & PROMISE_STATE_FULFILLED), "Fulfilled promises are resolved, too");
|
||||
return PROMISE_STATE_PENDING;
|
||||
}
|
||||
if (flags & PROMISE_FLAG_FULFILLED)
|
||||
return PROMISE_STATE_FULFILLED;
|
||||
return PROMISE_STATE_REJECTED;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
#define ITEM_KIND_VALUE 1
|
||||
#define ITEM_KIND_KEY_AND_VALUE 2
|
||||
|
||||
#define PROMISE_STATE_SLOT 0
|
||||
#define PROMISE_FLAGS_SLOT 0
|
||||
#define PROMISE_REACTIONS_OR_RESULT_SLOT 1
|
||||
#define PROMISE_RESOLVE_FUNCTION_SLOT 2
|
||||
#define PROMISE_ALLOCATION_SITE_SLOT 3
|
||||
|
@ -65,15 +65,15 @@
|
|||
#define PROMISE_ALLOCATION_TIME_SLOT 5
|
||||
#define PROMISE_RESOLUTION_TIME_SLOT 6
|
||||
#define PROMISE_ID_SLOT 7
|
||||
#define PROMISE_IS_HANDLED_SLOT 8
|
||||
|
||||
#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
|
||||
#define PROMISE_FLAG_RESOLVED 0x1
|
||||
#define PROMISE_FLAG_FULFILLED 0x2
|
||||
#define PROMISE_FLAG_HANDLED 0x4
|
||||
#define PROMISE_FLAG_REPORTED 0x8
|
||||
|
||||
#define PROMISE_HANDLER_IDENTITY 0
|
||||
#define PROMISE_HANDLER_THROWER 1
|
||||
|
|
|
@ -1444,8 +1444,10 @@ SettlePromiseNow(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
RootedNativeObject promise(cx, &args[0].toObject().as<NativeObject>());
|
||||
promise->setReservedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_FULFILLED));
|
||||
promise->setReservedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT, UndefinedValue());
|
||||
int32_t flags = promise->getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
|
||||
promise->setFixedSlot(PROMISE_FLAGS_SLOT,
|
||||
Int32Value(flags | PROMISE_FLAG_RESOLVED | PROMISE_FLAG_FULFILLED));
|
||||
promise->setFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT, UndefinedValue());
|
||||
|
||||
JS::dbg::onPromiseSettled(cx, promise);
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче