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

[promise] Reset promise context slot to undefined after closure is run

We no longer need the kAlreadyVisitedSlot because we can just check
for undefined in the kPromiseSlot to know if the clsoure was already
fulfilled.

This means we save one word per context per promise resolving closure.

Bug: v8:7037
Change-Id: Ib8f0fb445d2e143714d57fe644ba6d7a3f04c1f7
Reviewed-on: https://chromium-review.googlesource.com/756176Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49200}
parent 90217a2e
...@@ -221,8 +221,6 @@ Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( ...@@ -221,8 +221,6 @@ Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext(
Node* promise, Node* debug_event, Node* native_context) { Node* promise, Node* debug_event, Node* native_context) {
Node* const context = Node* const context =
CreatePromiseContext(native_context, kPromiseContextLength); CreatePromiseContext(native_context, kPromiseContextLength);
StoreContextElementNoWriteBarrier(context, kAlreadyVisitedSlot,
SmiConstant(0));
StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise); StoreContextElementNoWriteBarrier(context, kPromiseSlot, promise);
StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event); StoreContextElementNoWriteBarrier(context, kDebugEventSlot, debug_event);
return context; return context;
...@@ -979,37 +977,39 @@ void PromiseBuiltinsAssembler::SetPromiseHandledByIfTrue( ...@@ -979,37 +977,39 @@ void PromiseBuiltinsAssembler::SetPromiseHandledByIfTrue(
BIND(&done); BIND(&done);
} }
// ES#sec-promise-reject-functions void PromiseBuiltinsAssembler::PerformFulfillClosure(Node* context, Node* value,
// Promise Reject Functions bool should_resolve) {
TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue);
Node* const context = Parameter(Descriptor::kContext);
Label out(this); Label out(this);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
int has_already_visited_slot = kAlreadyVisitedSlot;
Node* const has_already_visited =
LoadContextElement(context, has_already_visited_slot);
// 4. If alreadyResolved.[[Value]] is true, return undefined.
GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
// 5.Set alreadyResolved.[[Value]] to true.
StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
SmiConstant(1));
// 2. Let promise be F.[[Promise]]. // 2. Let promise be F.[[Promise]].
Node* const promise = Node* const promise_slot = IntPtrConstant(kPromiseSlot);
LoadContextElement(context, IntPtrConstant(kPromiseSlot)); Node* const promise = LoadContextElement(context, promise_slot);
Node* const debug_event =
LoadContextElement(context, IntPtrConstant(kDebugEventSlot)); // We use `undefined` as a marker to know that this callback was
// already called.
GotoIf(IsUndefined(promise), &out);
if (should_resolve) {
InternalResolvePromise(context, promise, value);
} else {
Node* const debug_event =
LoadContextElement(context, IntPtrConstant(kDebugEventSlot));
InternalPromiseReject(context, promise, value, debug_event);
}
InternalPromiseReject(context, promise, value, debug_event); StoreContextElement(context, promise_slot, UndefinedConstant());
Return(UndefinedConstant()); Goto(&out);
BIND(&out); BIND(&out);
}
// ES#sec-promise-reject-functions
// Promise Reject Functions
TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue);
Node* const context = Parameter(Descriptor::kContext);
PerformFulfillClosure(context, value, false);
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
...@@ -1153,29 +1153,7 @@ TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { ...@@ -1153,29 +1153,7 @@ TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue); Node* const value = Parameter(Descriptor::kValue);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Label out(this); PerformFulfillClosure(context, value, true);
// 3. Let alreadyResolved be F.[[AlreadyResolved]].
int has_already_visited_slot = kAlreadyVisitedSlot;
Node* const has_already_visited =
LoadContextElement(context, has_already_visited_slot);
// 4. If alreadyResolved.[[Value]] is true, return undefined.
GotoIf(SmiEqual(has_already_visited, SmiConstant(1)), &out);
// 5.Set alreadyResolved.[[Value]] to true.
StoreContextElementNoWriteBarrier(context, has_already_visited_slot,
SmiConstant(1));
// 2. Let promise be F.[[Promise]].
Node* const promise =
LoadContextElement(context, IntPtrConstant(kPromiseSlot));
InternalResolvePromise(context, promise, value);
Return(UndefinedConstant());
BIND(&out);
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
......
...@@ -16,11 +16,10 @@ typedef compiler::CodeAssemblerState CodeAssemblerState; ...@@ -16,11 +16,10 @@ typedef compiler::CodeAssemblerState CodeAssemblerState;
class PromiseBuiltinsAssembler : public CodeStubAssembler { class PromiseBuiltinsAssembler : public CodeStubAssembler {
public: public:
enum PromiseResolvingFunctionContextSlot { enum PromiseResolvingFunctionContextSlot {
// Whether the resolve/reject callback was already called. // The promise which resolve/reject callbacks fulfill. If this is
kAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS, // undefined, then we've already visited this callback and it
// should be a no-op.
// The promise which resolve/reject callbacks fulfill. kPromiseSlot = Context::MIN_CONTEXT_SLOTS,
kPromiseSlot,
// Whether to trigger a debug event or not. Used in catch // Whether to trigger a debug event or not. Used in catch
// prediction. // prediction.
...@@ -176,6 +175,7 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { ...@@ -176,6 +175,7 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
const NodeGenerator& handled_by); const NodeGenerator& handled_by);
Node* PromiseStatus(Node* promise); Node* PromiseStatus(Node* promise);
void PerformFulfillClosure(Node* context, Node* value, bool should_resolve);
private: private:
Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected); Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
......
...@@ -2133,8 +2133,6 @@ TEST(CreatePromiseResolvingFunctionsContext) { ...@@ -2133,8 +2133,6 @@ TEST(CreatePromiseResolvingFunctionsContext) {
CHECK_EQ(isolate->native_context()->closure(), context_js->closure()); CHECK_EQ(isolate->native_context()->closure(), context_js->closure());
CHECK_EQ(isolate->heap()->the_hole_value(), context_js->extension()); CHECK_EQ(isolate->heap()->the_hole_value(), context_js->extension());
CHECK_EQ(*isolate->native_context(), context_js->native_context()); CHECK_EQ(*isolate->native_context(), context_js->native_context());
CHECK_EQ(Smi::FromInt(0),
context_js->get(PromiseBuiltinsAssembler::kAlreadyVisitedSlot));
CHECK(context_js->get(PromiseBuiltinsAssembler::kPromiseSlot)->IsJSPromise()); CHECK(context_js->get(PromiseBuiltinsAssembler::kPromiseSlot)->IsJSPromise());
CHECK_EQ(isolate->heap()->false_value(), CHECK_EQ(isolate->heap()->false_value(),
context_js->get(PromiseBuiltinsAssembler::kDebugEventSlot)); context_js->get(PromiseBuiltinsAssembler::kDebugEventSlot));
......
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