Commit 9b136709 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[promise] Make re-fulfilling a promise a no op.

Previously the API allowed the embedder to re fulfill a non pending
promise. This was changed as part of
c0412961.

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I53dc028fecdcc6ab05c05cfc7795e89519ed9633
Reviewed-on: https://chromium-review.googlesource.com/932968
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51536}
parent 263aa3ed
......@@ -7314,10 +7314,14 @@ Maybe<bool> Promise::Resolver::Resolve(Local<Context> context,
ENTER_V8(isolate, context, Promise_Resolver, Resolve, Nothing<bool>(),
i::HandleScope);
auto self = Utils::OpenHandle(this);
auto promise = i::Handle<i::JSPromise>::cast(self);
if (promise->status() != Promise::kPending) {
return Just(true);
}
has_pending_exception =
i::JSPromise::Resolve(i::Handle<i::JSPromise>::cast(self),
Utils::OpenHandle(*value))
.is_null();
i::JSPromise::Resolve(promise, Utils::OpenHandle(*value)).is_null();
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return Just(true);
}
......@@ -7335,10 +7339,14 @@ Maybe<bool> Promise::Resolver::Reject(Local<Context> context,
ENTER_V8(isolate, context, Promise_Resolver, Reject, Nothing<bool>(),
i::HandleScope);
auto self = Utils::OpenHandle(this);
auto promise = i::Handle<i::JSPromise>::cast(self);
if (promise->status() != Promise::kPending) {
return Just(true);
}
has_pending_exception =
i::JSPromise::Reject(i::Handle<i::JSPromise>::cast(self),
Utils::OpenHandle(*value))
.is_null();
i::JSPromise::Reject(promise, Utils::OpenHandle(*value)).is_null();
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return Just(true);
}
......
......@@ -15907,6 +15907,7 @@ Handle<Object> JSPromise::Fulfill(Handle<JSPromise> promise,
Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
Handle<Object> reason, bool debug_event) {
Isolate* const isolate = promise->GetIsolate();
if (debug_event) isolate->debug()->OnPromiseReject(promise, reason);
isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
isolate->factory()->undefined_value());
......@@ -15940,6 +15941,7 @@ Handle<Object> JSPromise::Reject(Handle<JSPromise> promise,
MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
Handle<Object> resolution) {
Isolate* const isolate = promise->GetIsolate();
isolate->RunPromiseHook(PromiseHookType::kResolve, promise,
isolate->factory()->undefined_value());
......
......@@ -24139,6 +24139,60 @@ TEST(PromiseStateAndValue) {
CHECK(v8_str("rejected")->SameValue(promise->Result()));
}
TEST(ResolvedPromiseReFulfill) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::String> value1 = v8::String::NewFromUtf8(isolate, "foo");
v8::Local<v8::String> value2 = v8::String::NewFromUtf8(isolate, "bar");
v8::Local<v8::Promise::Resolver> resolver =
v8::Promise::Resolver::New(context.local()).ToLocalChecked();
v8::Local<v8::Promise> promise = resolver->GetPromise();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
resolver->Resolve(context.local(), value1).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
CHECK_EQ(promise->Result(), value1);
// This should be a no-op.
resolver->Resolve(context.local(), value2).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
CHECK_EQ(promise->Result(), value1);
// This should be a no-op.
resolver->Reject(context.local(), value2).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
CHECK_EQ(promise->Result(), value1);
}
TEST(RejectedPromiseReFulfill) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::String> value1 = v8::String::NewFromUtf8(isolate, "foo");
v8::Local<v8::String> value2 = v8::String::NewFromUtf8(isolate, "bar");
v8::Local<v8::Promise::Resolver> resolver =
v8::Promise::Resolver::New(context.local()).ToLocalChecked();
v8::Local<v8::Promise> promise = resolver->GetPromise();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
resolver->Reject(context.local(), value1).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
CHECK_EQ(promise->Result(), value1);
// This should be a no-op.
resolver->Reject(context.local(), value2).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
CHECK_EQ(promise->Result(), value1);
// This should be a no-op.
resolver->Resolve(context.local(), value2).ToChecked();
CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
CHECK_EQ(promise->Result(), value1);
}
TEST(DisallowJavascriptExecutionScope) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
......
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