From 81a101678fff600b0fd1e4176534cc754dc060b3 Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Fri, 25 Apr 2014 14:01:01 +0000 Subject: [PATCH] Expose promise status through promise mirror. R=aandrey@chromium.org, rossberg@chromium.org, yurys@chromium.org BUG=v8:3093 LOG=Y Review URL: https://codereview.chromium.org/257803005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20988 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mirror-debugger.js | 57 ++++++++++++++++++++++++++++++++--- src/promise.js | 17 +++++++++++ test/mjsunit/es6/mirror-promises.js | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 test/mjsunit/es6/mirror-promises.js diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js index d413b09..9cde02b 100644 --- a/src/mirror-debugger.js +++ b/src/mirror-debugger.js @@ -42,6 +42,18 @@ function ClearMirrorCache() { } +// Wrapper to check whether an object is a Promise. The call may not work +// if promises are not enabled. +// TODO(yangguo): remove this wrapper once promises are enabled by default. +function ObjectIsPromise(value) { + try { + return %IsPromise(value); + } catch (e) { + return false; + } +} + + /** * Returns the mirror for a specified value or object. * @@ -90,6 +102,8 @@ function MakeMirror(value, opt_transient) { mirror = new ErrorMirror(value); } else if (IS_SCRIPT(value)) { mirror = new ScriptMirror(value); + } else if (ObjectIsPromise(value)) { + mirror = new PromiseMirror(value); } else { mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient); } @@ -159,6 +173,7 @@ var FRAME_TYPE = 'frame'; var SCRIPT_TYPE = 'script'; var CONTEXT_TYPE = 'context'; var SCOPE_TYPE = 'scope'; +var PROMISE_TYPE = 'promise'; // Maximum length when sending strings through the JSON protocol. var kMaxProtocolStringLength = 80; @@ -212,6 +227,7 @@ var ScopeType = { Global: 0, // - DateMirror // - RegExpMirror // - ErrorMirror +// - PromiseMirror // - PropertyMirror // - InternalPropertyMirror // - FrameMirror @@ -351,6 +367,15 @@ Mirror.prototype.isError = function() { /** + * Check whether the mirror reflects a promise. + * @returns {boolean} True if the mirror reflects a promise + */ +Mirror.prototype.isPromise = function() { + return this instanceof PromiseMirror; +}; + + +/** * Check whether the mirror reflects a property. * @returns {boolean} True if the mirror reflects a property */ @@ -637,9 +662,9 @@ ObjectMirror.prototype.propertyNames = function(kind, limit) { // Find all the named properties. if (kind & PropertyKind.Named) { - // Get all the local property names. + // Get all the local property names except for private symbols. propertyNames = - %GetLocalPropertyNames(this.value_, PROPERTY_ATTRIBUTES_NONE); + %GetLocalPropertyNames(this.value_, PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL); total += propertyNames.length; // Get names for named interceptor properties if any. @@ -1172,6 +1197,26 @@ ErrorMirror.prototype.toText = function() { /** + * Mirror object for a Promise object. + * @param {Object} data The Promise object + * @constructor + * @extends Mirror + */ +function PromiseMirror(value) { + %_CallFunction(this, value, PROMISE_TYPE, ObjectMirror); +} +inherits(PromiseMirror, ObjectMirror); + + +PromiseMirror.prototype.status = function() { + var status = %GetPromiseStatus(this.value_); + if (status == 0) return "pending"; + if (status == 1) return "resolved"; + return "rejected"; +}; + + +/** * Base mirror object for properties. * @param {ObjectMirror} mirror The mirror object having this property * @param {string} name The name of the property @@ -2350,6 +2395,7 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, case FUNCTION_TYPE: case ERROR_TYPE: case REGEXP_TYPE: + case PROMISE_TYPE: // Add object representation. this.serializeObject_(mirror, content, details); break; @@ -2452,7 +2498,6 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, content.indexedInterceptor = true; } - // Add function specific properties. if (mirror.isFunction()) { // Add function specific properties. content.name = mirror.name(); @@ -2480,12 +2525,16 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, } } - // Add date specific properties. if (mirror.isDate()) { // Add date specific properties. content.value = mirror.value(); } + if (mirror.isPromise()) { + // Add promise specific properties. + content.status = mirror.status(); + } + // Add actual properties - named properties followed by indexed properties. var propertyNames = mirror.propertyNames(PropertyKind.Named); var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed); diff --git a/src/promise.js b/src/promise.js index f77fc5c..b87f9d6 100644 --- a/src/promise.js +++ b/src/promise.js @@ -338,3 +338,20 @@ function SetUpPromise() { } SetUpPromise(); + +// Functions to expose promise details to the debugger. +function GetPromiseStatus(promise) { + return GET_PRIVATE(promise, promiseStatus); +} + +function GetPromiseOnResolve(promise) { + return GET_PRIVATE(promise, promiseOnResolve); +} + +function GetPromiseOnReject(promise) { + return GET_PRIVATE(promise, promiseOnReject); +} + +function GetPromiseValue(promise) { + return GET_PRIVATE(promise, promiseValue); +} diff --git a/test/mjsunit/es6/mirror-promises.js b/test/mjsunit/es6/mirror-promises.js new file mode 100644 index 0000000..c0eb5bf --- /dev/null +++ b/test/mjsunit/es6/mirror-promises.js @@ -0,0 +1,60 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-debug-as debug --harmony-promises +// Test the mirror object for promises. + +function MirrorRefCache(json_refs) { + var tmp = eval('(' + json_refs + ')'); + this.refs_ = []; + for (var i = 0; i < tmp.length; i++) { + this.refs_[tmp[i].handle] = tmp[i]; + } +} + +MirrorRefCache.prototype.lookup = function(handle) { + return this.refs_[handle]; +} + +function testPromiseMirror(promise, status) { + // Create mirror and JSON representation. + var mirror = debug.MakeMirror(promise); + var serializer = debug.MakeMirrorSerializer(); + var json = JSON.stringify(serializer.serializeValue(mirror)); + var refs = new MirrorRefCache( + JSON.stringify(serializer.serializeReferencedObjects())); + + // Check the mirror hierachy. + assertTrue(mirror instanceof debug.Mirror); + assertTrue(mirror instanceof debug.ValueMirror); + assertTrue(mirror instanceof debug.ObjectMirror); + assertTrue(mirror instanceof debug.PromiseMirror); + + // Check the mirror properties. + assertEquals(status, mirror.status()); + assertTrue(mirror.isPromise()); + assertEquals('promise', mirror.type()); + assertFalse(mirror.isPrimitive()); + assertEquals("Object", mirror.className()); + assertEquals("#", mirror.toText()); + assertSame(promise, mirror.value()); + + // Parse JSON representation and check. + var fromJSON = eval('(' + json + ')'); + assertEquals('promise', fromJSON.type); + assertEquals('Object', fromJSON.className); + assertEquals('function', refs.lookup(fromJSON.constructorFunction.ref).type); + assertEquals('Promise', refs.lookup(fromJSON.constructorFunction.ref).name); + assertEquals(status, fromJSON.status); + +} + +// Test a number of different promises. +var resolved = new Promise(function(resolve, reject) { resolve() }); +var rejected = new Promise(function(resolve, reject) { reject() }); +var pending = new Promise(function(resolve, reject) {}); + +testPromiseMirror(resolved, "resolved"); +testPromiseMirror(rejected, "rejected"); +testPromiseMirror(pending, "pending"); -- 2.7.4