From a37273c1e4b93ed048e1d45818fe6c525480b121 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Wed, 5 Apr 2017 22:30:25 -0700 Subject: util: use V8 C++ API for inspecting Promises PR-URL: https://github.com/nodejs/node/pull/12254 Refs: https://github.com/nodejs/node/issues/11875 Reviewed-By: Ben Noordhuis Reviewed-By: Evan Lucas Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Josh Gavant --- lib/util.js | 62 ++++++++++++++++++++++---------------------------------- src/node_util.cc | 30 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/lib/util.js b/lib/util.js index a0e8bb3c1d..12280e412a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -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) || @@ -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; @@ -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(''); } 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(' ' + str); } else { output.push(str); diff --git a/src/node_util.cc b/src/node_util.cc index 813995de79..fe01717131 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -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; @@ -43,6 +44,24 @@ using v8::Value; VALUE_METHOD_MAP(V) #undef V +static void GetPromiseDetails(const FunctionCallbackInfo& args) { + // Return undefined if it's not a Promise. + if (!args[0]->IsPromise()) + return; + + auto isolate = args.GetIsolate(); + + Local promise = args[0].As(); + Local 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& args) { // Return undefined if it's not a proxy. if (!args[0]->IsProxy()) @@ -148,8 +167,19 @@ void Initialize(Local 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); -- cgit v1.2.3