Skip to content

Commit

Permalink
util: use V8 C++ API for inspecting Promises
Browse files Browse the repository at this point in the history
PR-URL: nodejs#12254
Refs: nodejs#11875
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Josh Gavant <josh.gavant@outlook.com>
  • Loading branch information
TimothyGu committed Apr 8, 2017
1 parent afd5966 commit a37273c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 38 deletions.
62 changes: 24 additions & 38 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,16 +302,6 @@ function ensureDebugIsInitialized() {
}


function inspectPromise(p) {
// Only create a mirror if the object is a Promise.
if (!binding.isPromise(p))
return null;
ensureDebugIsInitialized();
const mirror = Debug.MakeMirror(p, true);
return {status: mirror.status(), value: mirror.promiseValue().value_};
}


function formatValue(ctx, value, recurseTimes) {
if (ctx.showProxy &&
((typeof value === 'object' && value !== null) ||
Expand Down Expand Up @@ -527,30 +517,25 @@ function formatValue(ctx, value, recurseTimes) {
'byteOffset',
'buffer');
}
} else if (binding.isPromise(value)) {
braces = ['{', '}'];
formatter = formatPromise;
} else if (binding.isMapIterator(value)) {
constructor = { name: 'MapIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else if (binding.isSetIterator(value)) {
constructor = { name: 'SetIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else {
var promiseInternals = inspectPromise(value);
if (promiseInternals) {
braces = ['{', '}'];
formatter = formatPromise;
} else {
if (binding.isMapIterator(value)) {
constructor = { name: 'MapIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else if (binding.isSetIterator(value)) {
constructor = { name: 'SetIterator' };
braces = ['{', '}'];
empty = false;
formatter = formatCollectionIterator;
} else {
// Unset the constructor to prevent "Object {...}" for ordinary objects.
if (constructor && constructor.name === 'Object')
constructor = null;
braces = ['{', '}'];
empty = true; // No other data than keys.
}
}
// Unset the constructor to prevent "Object {...}" for ordinary objects.
if (constructor && constructor.name === 'Object')
constructor = null;
braces = ['{', '}'];
empty = true; // No other data than keys.
}

empty = empty === true && keys.length === 0;
Expand Down Expand Up @@ -779,14 +764,15 @@ function formatCollectionIterator(ctx, value, recurseTimes, visibleKeys, keys) {
}

function formatPromise(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
var internals = inspectPromise(value);
if (internals.status === 'pending') {
const output = [];
const [state, result] = binding.getPromiseDetails(value);

if (state === binding.kPending) {
output.push('<pending>');
} else {
var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1;
var str = formatValue(ctx, internals.value, nextRecurseTimes);
if (internals.status === 'rejected') {
var str = formatValue(ctx, result, nextRecurseTimes);
if (state === binding.kRejected) {
output.push('<rejected> ' + str);
} else {
output.push(str);
Expand Down
30 changes: 30 additions & 0 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ using v8::Integer;
using v8::Local;
using v8::Object;
using v8::Private;
using v8::Promise;
using v8::Proxy;
using v8::Value;

Expand Down Expand Up @@ -43,6 +44,24 @@ using v8::Value;
VALUE_METHOD_MAP(V)
#undef V

static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
// Return undefined if it's not a Promise.
if (!args[0]->IsPromise())
return;

auto isolate = args.GetIsolate();

Local<Promise> promise = args[0].As<Promise>();
Local<Array> ret = Array::New(isolate, 2);

int state = promise->State();
ret->Set(0, Integer::New(isolate, state));
if (state != Promise::PromiseState::kPending)
ret->Set(1, promise->Result());

args.GetReturnValue().Set(ret);
}

static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
// Return undefined if it's not a proxy.
if (!args[0]->IsProxy())
Expand Down Expand Up @@ -148,8 +167,19 @@ void Initialize(Local<Object> target,
Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX),
v8::ReadOnly).FromJust();

#define V(name) \
target->Set(context, \
FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
Integer::New(env->isolate(), Promise::PromiseState::name)) \
.FromJust()
V(kPending);
V(kFulfilled);
V(kRejected);
#undef V

env->SetMethod(target, "getHiddenValue", GetHiddenValue);
env->SetMethod(target, "setHiddenValue", SetHiddenValue);
env->SetMethod(target, "getPromiseDetails", GetPromiseDetails);
env->SetMethod(target, "getProxyDetails", GetProxyDetails);

env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
Expand Down

0 comments on commit a37273c

Please sign in to comment.