Commit e2ebb2be authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[promises] Reduce size of JSPromise by 1 word

Instead of using a word to store the status of the promise, this
patch uses 2 bit on flags.

Bug: v8:5046
Change-Id: Ic651338230dbe1704c68de8652676f236a3298f0
Reviewed-on: https://chromium-review.googlesource.com/634623
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47628}
parent 70881da0
...@@ -229,9 +229,8 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( ...@@ -229,9 +229,8 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
#if defined(DEBUG) && defined(ENABLE_SLOW_DCHECKS) #if defined(DEBUG) && defined(ENABLE_SLOW_DCHECKS)
Node* const awaited_promise = LoadGeneratorAwaitedPromise(generator); Node* const awaited_promise = LoadGeneratorAwaitedPromise(generator);
CSA_SLOW_ASSERT(this, HasInstanceType(awaited_promise, JS_PROMISE_TYPE)); CSA_SLOW_ASSERT(this, HasInstanceType(awaited_promise, JS_PROMISE_TYPE));
CSA_SLOW_ASSERT(this, SmiNotEqual(LoadObjectField(awaited_promise, CSA_SLOW_ASSERT(this, Word32NotEqual(PromiseStatus(awaited_promise),
JSPromise::kStatusOffset), Int32Constant(v8::Promise::kPending)));
SmiConstant(v8::Promise::kPending)));
#endif #endif
ClearAwaitedPromise(generator); ClearAwaitedPromise(generator);
......
...@@ -28,8 +28,7 @@ Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) { ...@@ -28,8 +28,7 @@ Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
} }
void PromiseBuiltinsAssembler::PromiseInit(Node* promise) { void PromiseBuiltinsAssembler::PromiseInit(Node* promise) {
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kStatusOffset, STATIC_ASSERT(v8::Promise::kPending == 0);
SmiConstant(v8::Promise::kPending));
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
SmiConstant(0)); SmiConstant(0));
for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) { for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
...@@ -56,17 +55,14 @@ Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context, ...@@ -56,17 +55,14 @@ Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context,
return instance; return instance;
} }
Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context, Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(
Node* status, Node* context, v8::Promise::PromiseState status, Node* result) {
Node* result) {
CSA_ASSERT(this, TaggedIsSmi(status));
Node* const instance = AllocateJSPromise(context); Node* const instance = AllocateJSPromise(context);
StoreObjectFieldNoWriteBarrier(instance, JSPromise::kStatusOffset, status);
StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result); StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result);
STATIC_ASSERT(JSPromise::kStatusShift == 0);
StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset, StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
SmiConstant(0)); SmiConstant(status));
for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) { for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) {
int offset = JSPromise::kSize + i * kPointerSize; int offset = JSPromise::kSize + i * kPointerSize;
StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0)); StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0));
...@@ -281,6 +277,29 @@ void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) { ...@@ -281,6 +277,29 @@ void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags); StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
} }
Node* PromiseBuiltinsAssembler::IsPromiseStatus(
Node* actual, v8::Promise::PromiseState expected) {
return Word32Equal(actual, Int32Constant(expected));
}
Node* PromiseBuiltinsAssembler::PromiseStatus(Node* promise) {
STATIC_ASSERT(JSPromise::kStatusShift == 0);
Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
return Word32And(SmiToWord32(flags), Int32Constant(JSPromise::kStatusMask));
}
void PromiseBuiltinsAssembler::PromiseSetStatus(
Node* promise, v8::Promise::PromiseState const status) {
CSA_ASSERT(this,
IsPromiseStatus(PromiseStatus(promise), v8::Promise::kPending));
CHECK(status != v8::Promise::kPending);
Node* mask = SmiConstant(status);
Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
SmiOr(flags, mask));
}
void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) { void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset); Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
Node* const new_flags = Node* const new_flags =
...@@ -461,9 +480,8 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( ...@@ -461,9 +480,8 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
BIND(&append_callbacks); BIND(&append_callbacks);
{ {
Label fulfilled_check(this); Label fulfilled_check(this);
Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); Node* const status = PromiseStatus(promise);
GotoIfNot(SmiEqual(status, SmiConstant(v8::Promise::kPending)), GotoIfNot(IsPromiseStatus(status, v8::Promise::kPending), &fulfilled_check);
&fulfilled_check);
Node* const existing_deferred_promise = Node* const existing_deferred_promise =
LoadObjectField(promise, JSPromise::kDeferredPromiseOffset); LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
...@@ -566,8 +584,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( ...@@ -566,8 +584,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
{ {
Label reject(this); Label reject(this);
Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
GotoIfNot(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)), GotoIfNot(IsPromiseStatus(status, v8::Promise::kFulfilled), &reject);
&reject);
Node* info = AllocatePromiseReactionJobInfo( Node* info = AllocatePromiseReactionJobInfo(
result, var_on_resolve.value(), deferred_promise, deferred_on_resolve, result, var_on_resolve.value(), deferred_promise, deferred_on_resolve,
...@@ -578,6 +595,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( ...@@ -578,6 +595,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
BIND(&reject); BIND(&reject);
{ {
CSA_ASSERT(this, IsPromiseStatus(status, v8::Promise::kRejected));
Node* const has_handler = PromiseHasHandler(promise); Node* const has_handler = PromiseHasHandler(promise);
Label enqueue(this); Label enqueue(this);
...@@ -700,13 +718,12 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, ...@@ -700,13 +718,12 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
// reusing the value from the promise. // reusing the value from the promise.
BIND(&if_nativepromise); BIND(&if_nativepromise);
{ {
Node* const thenable_status = Node* const thenable_status = PromiseStatus(result);
LoadObjectField(result, JSPromise::kStatusOffset);
Node* const thenable_value = Node* const thenable_value =
LoadObjectField(result, JSPromise::kResultOffset); LoadObjectField(result, JSPromise::kResultOffset);
Label if_isnotpending(this); Label if_isnotpending(this);
GotoIfNot(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status), GotoIfNot(IsPromiseStatus(thenable_status, v8::Promise::kPending),
&if_isnotpending); &if_isnotpending);
// TODO(gsathya): Use a marker here instead of the actual then // TODO(gsathya): Use a marker here instead of the actual then
...@@ -720,7 +737,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context, ...@@ -720,7 +737,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
BIND(&if_isnotpending); BIND(&if_isnotpending);
{ {
Label if_fulfilled(this), if_rejected(this); Label if_fulfilled(this), if_rejected(this);
Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status), Branch(IsPromiseStatus(thenable_status, v8::Promise::kFulfilled),
&if_fulfilled, &if_rejected); &if_fulfilled, &if_rejected);
BIND(&if_fulfilled); BIND(&if_fulfilled);
...@@ -837,7 +854,6 @@ void PromiseBuiltinsAssembler::PromiseFulfill( ...@@ -837,7 +854,6 @@ void PromiseBuiltinsAssembler::PromiseFulfill(
v8::Promise::PromiseState status) { v8::Promise::PromiseState status) {
Label do_promisereset(this), debug_async_event_enqueue_recurring(this); Label do_promisereset(this), debug_async_event_enqueue_recurring(this);
Node* const status_smi = SmiConstant(static_cast<int>(status));
Node* const deferred_promise = Node* const deferred_promise =
LoadObjectField(promise, JSPromise::kDeferredPromiseOffset); LoadObjectField(promise, JSPromise::kDeferredPromiseOffset);
...@@ -864,13 +880,13 @@ void PromiseBuiltinsAssembler::PromiseFulfill( ...@@ -864,13 +880,13 @@ void PromiseBuiltinsAssembler::PromiseFulfill(
{ {
GotoIfNot(IsDebugActive(), &do_promisereset); GotoIfNot(IsDebugActive(), &do_promisereset);
CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise, CallRuntime(Runtime::kDebugAsyncEventEnqueueRecurring, context, promise,
status_smi); SmiConstant(status));
Goto(&do_promisereset); Goto(&do_promisereset);
} }
BIND(&do_promisereset); BIND(&do_promisereset);
{ {
StoreObjectField(promise, JSPromise::kStatusOffset, status_smi); PromiseSetStatus(promise, status);
StoreObjectField(promise, JSPromise::kResultOffset, result); StoreObjectField(promise, JSPromise::kResultOffset, result);
StoreObjectFieldRoot(promise, JSPromise::kDeferredPromiseOffset, StoreObjectFieldRoot(promise, JSPromise::kDeferredPromiseOffset,
Heap::kUndefinedValueRootIndex); Heap::kUndefinedValueRootIndex);
...@@ -1517,8 +1533,8 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) { ...@@ -1517,8 +1533,8 @@ TF_BUILTIN(PromiseReject, PromiseBuiltinsAssembler) {
BIND(&if_nativepromise); BIND(&if_nativepromise);
{ {
Node* const promise = AllocateAndSetJSPromise( Node* const promise =
context, SmiConstant(v8::Promise::kRejected), reason); AllocateAndSetJSPromise(context, v8::Promise::kRejected, reason);
CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise, CallRuntime(Runtime::kPromiseRejectEventFromStack, context, promise,
reason); reason);
Return(promise); Return(promise);
......
...@@ -88,7 +88,8 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { ...@@ -88,7 +88,8 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
// This allocates and initializes a promise with the given state and // This allocates and initializes a promise with the given state and
// fields. // fields.
Node* AllocateAndSetJSPromise(Node* context, Node* status, Node* result); Node* AllocateAndSetJSPromise(Node* context, v8::Promise::PromiseState status,
Node* result);
Node* AllocatePromiseResolveThenableJobInfo(Node* result, Node* then, Node* AllocatePromiseResolveThenableJobInfo(Node* result, Node* then,
Node* resolve, Node* reject, Node* resolve, Node* reject,
...@@ -177,7 +178,12 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { ...@@ -177,7 +178,12 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
void SetPromiseHandledByIfTrue(Node* context, Node* condition, Node* promise, void SetPromiseHandledByIfTrue(Node* context, Node* condition, Node* promise,
const NodeGenerator& handled_by); const NodeGenerator& handled_by);
Node* PromiseStatus(Node* promise);
private: private:
Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status);
Node* AllocateJSPromise(Node* context); Node* AllocateJSPromise(Node* context);
}; };
......
...@@ -1004,7 +1004,6 @@ void JSPromise::JSPromiseVerify() { ...@@ -1004,7 +1004,6 @@ void JSPromise::JSPromiseVerify() {
CHECK(IsJSPromise()); CHECK(IsJSPromise());
JSObjectVerify(); JSObjectVerify();
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
VerifySmiField(kStatusOffset);
CHECK(result()->IsUndefined(isolate) || result()->IsObject()); CHECK(result()->IsUndefined(isolate) || result()->IsObject());
CHECK(deferred_promise()->IsUndefined(isolate) || CHECK(deferred_promise()->IsUndefined(isolate) ||
deferred_promise()->IsJSReceiver() || deferred_promise()->IsJSReceiver() ||
......
...@@ -5250,7 +5250,6 @@ ACCESSORS(JSPromiseCapability, promise, Object, kPromiseOffset) ...@@ -5250,7 +5250,6 @@ ACCESSORS(JSPromiseCapability, promise, Object, kPromiseOffset)
ACCESSORS(JSPromiseCapability, resolve, Object, kResolveOffset) ACCESSORS(JSPromiseCapability, resolve, Object, kResolveOffset)
ACCESSORS(JSPromiseCapability, reject, Object, kRejectOffset) ACCESSORS(JSPromiseCapability, reject, Object, kRejectOffset)
SMI_ACCESSORS(JSPromise, status, kStatusOffset)
ACCESSORS(JSPromise, result, Object, kResultOffset) ACCESSORS(JSPromise, result, Object, kResultOffset)
ACCESSORS(JSPromise, deferred_promise, Object, kDeferredPromiseOffset) ACCESSORS(JSPromise, deferred_promise, Object, kDeferredPromiseOffset)
ACCESSORS(JSPromise, deferred_on_resolve, Object, kDeferredOnResolveOffset) ACCESSORS(JSPromise, deferred_on_resolve, Object, kDeferredOnResolveOffset)
......
...@@ -15918,8 +15918,14 @@ class StringSharedKey : public HashTableKey { ...@@ -15918,8 +15918,14 @@ class StringSharedKey : public HashTableKey {
int position_; int position_;
}; };
v8::Promise::PromiseState JSPromise::status() const {
int value = flags() & kStatusMask;
DCHECK(value == 0 || value == 1 || value == 2);
return static_cast<v8::Promise::PromiseState>(value);
}
// static // static
const char* JSPromise::Status(int status) { const char* JSPromise::Status(v8::Promise::PromiseState status) {
switch (status) { switch (status) {
case v8::Promise::kFulfilled: case v8::Promise::kFulfilled:
return "resolved"; return "resolved";
......
...@@ -5357,7 +5357,6 @@ class JSPromiseCapability : public JSObject { ...@@ -5357,7 +5357,6 @@ class JSPromiseCapability : public JSObject {
class JSPromise : public JSObject { class JSPromise : public JSObject {
public: public:
DECL_INT_ACCESSORS(status)
DECL_ACCESSORS(result, Object) DECL_ACCESSORS(result, Object)
// There are 3 possible states for these fields -- // There are 3 possible states for these fields --
...@@ -5388,7 +5387,8 @@ class JSPromise : public JSObject { ...@@ -5388,7 +5387,8 @@ class JSPromise : public JSObject {
// block in an async function. // block in an async function.
DECL_BOOLEAN_ACCESSORS(handled_hint) DECL_BOOLEAN_ACCESSORS(handled_hint)
static const char* Status(int status); static const char* Status(v8::Promise::PromiseState status);
v8::Promise::PromiseState status() const;
DECL_CAST(JSPromise) DECL_CAST(JSPromise)
...@@ -5397,8 +5397,7 @@ class JSPromise : public JSObject { ...@@ -5397,8 +5397,7 @@ class JSPromise : public JSObject {
DECL_VERIFIER(JSPromise) DECL_VERIFIER(JSPromise)
// Layout description. // Layout description.
static const int kStatusOffset = JSObject::kHeaderSize; static const int kResultOffset = JSObject::kHeaderSize;
static const int kResultOffset = kStatusOffset + kPointerSize;
static const int kDeferredPromiseOffset = kResultOffset + kPointerSize; static const int kDeferredPromiseOffset = kResultOffset + kPointerSize;
static const int kDeferredOnResolveOffset = static const int kDeferredOnResolveOffset =
kDeferredPromiseOffset + kPointerSize; kDeferredPromiseOffset + kPointerSize;
...@@ -5414,8 +5413,16 @@ class JSPromise : public JSObject { ...@@ -5414,8 +5413,16 @@ class JSPromise : public JSObject {
kSize + v8::Promise::kEmbedderFieldCount * kPointerSize; kSize + v8::Promise::kEmbedderFieldCount * kPointerSize;
// Flags layout. // Flags layout.
static const int kHasHandlerBit = 0; // The first two bits store the v8::Promise::PromiseState.
static const int kHandledHintBit = 1; static const int kStatusBits = 2;
static const int kHasHandlerBit = 2;
static const int kHandledHintBit = 3;
static const int kStatusShift = 0;
static const int kStatusMask = 0x3;
STATIC_ASSERT(v8::Promise::kPending == 0);
STATIC_ASSERT(v8::Promise::kFulfilled == 1);
STATIC_ASSERT(v8::Promise::kRejected == 2);
}; };
// Regular expressions // Regular expressions
......
...@@ -1972,7 +1972,7 @@ TEST(AllocateAndSetJSPromise) { ...@@ -1972,7 +1972,7 @@ TEST(AllocateAndSetJSPromise) {
Node* const context = m.Parameter(kNumParams + 2); Node* const context = m.Parameter(kNumParams + 2);
Node* const promise = m.AllocateAndSetJSPromise( Node* const promise = m.AllocateAndSetJSPromise(
context, m.SmiConstant(v8::Promise::kPending), m.SmiConstant(1)); context, v8::Promise::kRejected, m.SmiConstant(1));
m.Return(promise); m.Return(promise);
FunctionTester ft(asm_tester.GenerateCode(), kNumParams); FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
...@@ -1980,7 +1980,7 @@ TEST(AllocateAndSetJSPromise) { ...@@ -1980,7 +1980,7 @@ TEST(AllocateAndSetJSPromise) {
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked(); ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
CHECK(result->IsJSPromise()); CHECK(result->IsJSPromise());
Handle<JSPromise> js_promise = Handle<JSPromise>::cast(result); Handle<JSPromise> js_promise = Handle<JSPromise>::cast(result);
CHECK_EQ(v8::Promise::kPending, js_promise->status()); CHECK_EQ(v8::Promise::kRejected, js_promise->status());
CHECK_EQ(Smi::FromInt(1), js_promise->result()); CHECK_EQ(Smi::FromInt(1), js_promise->result());
CHECK(!js_promise->has_handler()); CHECK(!js_promise->has_handler());
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment