Skip to content

Commit 2843258

Browse files
hashseedCommit bot
authored andcommitted
[api] add API for Promise status and result.
Currently, to find out a Promise's status and result, one has to use the debug context. This is for example done in Node.js. This new API is a better replacement, also in the context of the debug context being deprecated eventually. [email protected], [email protected], [email protected] BUG=v8:5764 Review-Url: https://codereview.chromium.org/2589113002 Cr-Commit-Position: refs/heads/master@{#41855}
1 parent 55c88e5 commit 2843258

11 files changed

Lines changed: 79 additions & 29 deletions

File tree

include/v8.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3699,6 +3699,12 @@ class V8_EXPORT Function : public Object {
36993699
*/
37003700
class V8_EXPORT Promise : public Object {
37013701
public:
3702+
/**
3703+
* State of the promise. Each value corresponds to one of the possible values
3704+
* of the [[PromiseState]] field.
3705+
*/
3706+
enum PromiseState { kPending, kFulfilled, kRejected };
3707+
37023708
class V8_EXPORT Resolver : public Object {
37033709
public:
37043710
/**
@@ -3755,6 +3761,17 @@ class V8_EXPORT Promise : public Object {
37553761
*/
37563762
bool HasHandler();
37573763

3764+
/**
3765+
* Returns the content of the [[PromiseResult]] field. The Promise must not
3766+
* be pending.
3767+
*/
3768+
Local<Value> Result();
3769+
3770+
/**
3771+
* Returns the value of the [[PromiseState]] field.
3772+
*/
3773+
PromiseState State();
3774+
37583775
V8_INLINE static Promise* Cast(Value* obj);
37593776

37603777
private:

src/api.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7289,6 +7289,24 @@ bool Promise::HasHandler() {
72897289
return false;
72907290
}
72917291

7292+
Local<Value> Promise::Result() {
7293+
i::Handle<i::JSReceiver> promise = Utils::OpenHandle(this);
7294+
i::Isolate* isolate = promise->GetIsolate();
7295+
LOG_API(isolate, Promise, Result);
7296+
i::Handle<i::JSPromise> js_promise = i::Handle<i::JSPromise>::cast(promise);
7297+
Utils::ApiCheck(js_promise->status() != kPending, "v8_Promise_Result",
7298+
"Promise is still pending");
7299+
i::Handle<i::Object> result(js_promise->result(), isolate);
7300+
return Utils::ToLocal(result);
7301+
}
7302+
7303+
Promise::PromiseState Promise::State() {
7304+
i::Handle<i::JSReceiver> promise = Utils::OpenHandle(this);
7305+
i::Isolate* isolate = promise->GetIsolate();
7306+
LOG_API(isolate, Promise, Status);
7307+
i::Handle<i::JSPromise> js_promise = i::Handle<i::JSPromise>::cast(promise);
7308+
return static_cast<PromiseState>(js_promise->status());
7309+
}
72927310

72937311
Local<Object> Proxy::GetTarget() {
72947312
i::Handle<i::JSProxy> self = Utils::OpenHandle(this);

src/builtins/builtins-promise.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context,
230230
{
231231
Label fulfilled_check(this);
232232
Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset);
233-
GotoUnless(SmiEqual(status, SmiConstant(kPromisePending)),
233+
GotoUnless(SmiEqual(status, SmiConstant(v8::Promise::kPending)),
234234
&fulfilled_check);
235235

236236
Node* const existing_deferred =
@@ -304,12 +304,13 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context,
304304
{
305305
Label reject(this);
306306
Node* const result = LoadObjectField(promise, JSPromise::kResultOffset);
307-
GotoUnless(WordEqual(status, SmiConstant(kPromiseFulfilled)), &reject);
307+
GotoUnless(WordEqual(status, SmiConstant(v8::Promise::kFulfilled)),
308+
&reject);
308309

309310
// TODO(gsathya): Move this to TF.
310311
CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, result,
311312
var_on_resolve.value(), deferred,
312-
SmiConstant(kPromiseFulfilled));
313+
SmiConstant(v8::Promise::kFulfilled));
313314
Goto(&out);
314315

315316
Bind(&reject);
@@ -326,7 +327,7 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context,
326327
{
327328
CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise,
328329
result, var_on_reject.value(), deferred,
329-
SmiConstant(kPromiseRejected));
330+
SmiConstant(v8::Promise::kRejected));
330331

331332
Goto(&out);
332333
}
@@ -415,7 +416,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
415416
LoadObjectField(result, JSPromise::kResultOffset);
416417

417418
Label if_isnotpending(this);
418-
GotoUnless(SmiEqual(SmiConstant(kPromisePending), thenable_status),
419+
GotoUnless(SmiEqual(SmiConstant(v8::Promise::kPending), thenable_status),
419420
&if_isnotpending);
420421

421422
// TODO(gsathya): Use a marker here instead of the actual then
@@ -430,13 +431,13 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
430431
Bind(&if_isnotpending);
431432
{
432433
Label if_fulfilled(this), if_rejected(this);
433-
Branch(SmiEqual(SmiConstant(kPromiseFulfilled), thenable_status),
434+
Branch(SmiEqual(SmiConstant(v8::Promise::kFulfilled), thenable_status),
434435
&if_fulfilled, &if_rejected);
435436

436437
Bind(&if_fulfilled);
437438
{
438439
CallRuntime(Runtime::kPromiseFulfill, context, promise,
439-
SmiConstant(kPromiseFulfilled), thenable_value);
440+
SmiConstant(v8::Promise::kFulfilled), thenable_value);
440441
PromiseSetHasHandler(promise);
441442
Goto(out);
442443
}
@@ -507,7 +508,7 @@ void PromiseBuiltinsAssembler::InternalResolvePromise(Node* context,
507508
Bind(&fulfill);
508509
{
509510
CallRuntime(Runtime::kPromiseFulfill, context, promise,
510-
SmiConstant(kPromiseFulfilled), result);
511+
SmiConstant(v8::Promise::kFulfilled), result);
511512
Goto(out);
512513
}
513514

src/code-stub-assembler.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8340,7 +8340,7 @@ Node* CodeStubAssembler::AllocateJSPromise(Node* context) {
83408340

83418341
void CodeStubAssembler::PromiseInit(Node* promise) {
83428342
StoreObjectField(promise, JSPromise::kStatusOffset,
8343-
SmiConstant(kPromisePending));
8343+
SmiConstant(v8::Promise::kPending));
83448344
StoreObjectField(promise, JSPromise::kFlagsOffset, SmiConstant(0));
83458345
}
83468346

src/counters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,8 @@ class RuntimeCallTimer final {
628628
V(Promise_HasRejectHandler) \
629629
V(Promise_Resolver_New) \
630630
V(Promise_Resolver_Resolve) \
631+
V(Promise_Result) \
632+
V(Promise_Status) \
631633
V(Promise_Then) \
632634
V(Proxy_New) \
633635
V(RangeError_New) \

src/globals.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -607,14 +607,6 @@ enum ParseRestriction {
607607
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
608608
};
609609

610-
// TODO(gsathya): Move this to JSPromise once we create it.
611-
// This should be in sync with the constants in promise.js
612-
enum PromiseStatus {
613-
kPromisePending,
614-
kPromiseFulfilled,
615-
kPromiseRejected,
616-
};
617-
618610
// A CodeDesc describes a buffer holding instructions and relocation
619611
// information. The instructions start at the beginning of the buffer
620612
// and grow forward, the relocation information starts at the end of

src/js/macros.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@
199199
define kRegExpPrototypeOldFlagGetter = 31;
200200

201201
# [[PromiseState]] values:
202-
# These values should be kept in sync with PromiseStatus in globals.h
202+
# These values must be kept in sync with v8::Promise::PromiseState in
203+
# include/v8.h
203204
define kPending = 0;
204205
define kFulfilled = 1;
205206
define kRejected = 2;

src/objects.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16484,11 +16484,11 @@ class StringSharedKey : public HashTableKey {
1648416484
// static
1648516485
const char* JSPromise::Status(int status) {
1648616486
switch (status) {
16487-
case kPromiseFulfilled:
16487+
case v8::Promise::kFulfilled:
1648816488
return "resolved";
16489-
case kPromisePending:
16489+
case v8::Promise::kPending:
1649016490
return "pending";
16491-
case kPromiseRejected:
16491+
case v8::Promise::kRejected:
1649216492
return "rejected";
1649316493
}
1649416494
UNREACHABLE();

src/runtime/runtime-promise.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void PromiseFulfill(Isolate* isolate, Handle<JSPromise> promise,
109109
Handle<Smi> status, Handle<Object> value) {
110110
// Check if there are any callbacks.
111111
if (!promise->deferred()->IsUndefined(isolate)) {
112-
Handle<Object> tasks((status->value() == kPromiseFulfilled)
112+
Handle<Object> tasks((status->value() == v8::Promise::kFulfilled)
113113
? promise->fulfill_reactions()
114114
: promise->reject_reactions(),
115115
isolate);
@@ -131,7 +131,7 @@ RUNTIME_FUNCTION(Runtime_PromiseReject) {
131131

132132
PromiseRejectEvent(isolate, promise, promise, reason, debug_event);
133133

134-
Handle<Smi> status(Smi::FromInt(kPromiseRejected), isolate);
134+
Handle<Smi> status(Smi::FromInt(v8::Promise::kRejected), isolate);
135135
PromiseFulfill(isolate, promise, status, reason);
136136
return isolate->heap()->undefined_value();
137137
}

test/cctest/test-api.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24352,6 +24352,25 @@ TEST(PromiseThen) {
2435224352
.FromJust());
2435324353
}
2435424354

24355+
TEST(PromiseStateAndValue) {
24356+
LocalContext context;
24357+
v8::Isolate* isolate = context->GetIsolate();
24358+
v8::HandleScope scope(isolate);
24359+
v8::Local<v8::Value> result = CompileRun(
24360+
"var resolver;"
24361+
"new Promise((res, rej) => { resolver = res; })");
24362+
v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24363+
CHECK(promise->State() == v8::Promise::PromiseState::kPending);
24364+
24365+
CompileRun("resolver('fulfilled')");
24366+
CHECK(promise->State() == v8::Promise::PromiseState::kFulfilled);
24367+
CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24368+
24369+
result = CompileRun("Promise.reject('rejected')");
24370+
promise = v8::Local<v8::Promise>::Cast(result);
24371+
CHECK(promise->State() == v8::Promise::PromiseState::kRejected);
24372+
CHECK(v8_str("rejected")->SameValue(promise->Result()));
24373+
}
2435524374

2435624375
TEST(DisallowJavascriptExecutionScope) {
2435724376
LocalContext context;

0 commit comments

Comments
 (0)