Expose promise status through promise mirror.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 25 Apr 2014 14:01:01 +0000 (14:01 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 25 Apr 2014 14:01:01 +0000 (14:01 +0000)
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
src/promise.js
test/mjsunit/es6/mirror-promises.js [new file with mode: 0644]

index d413b09..9cde02b 100644 (file)
@@ -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);
index f77fc5c..b87f9d6 100644 (file)
@@ -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 (file)
index 0000000..c0eb5bf
--- /dev/null
@@ -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("#<Promise>", 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");