Introduce InternalProperty type and expose internal properties for bound functions

Review URL: https://chromiumcodereview.appspot.com/10834376

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12346 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
peter.rybin@gmail.com 2012-08-20 21:49:19 +00:00
parent 1fcddc4456
commit cfc4c37768
2 changed files with 163 additions and 34 deletions

View File

@ -154,6 +154,7 @@ var FUNCTION_TYPE = 'function';
var REGEXP_TYPE = 'regexp';
var ERROR_TYPE = 'error';
var PROPERTY_TYPE = 'property';
var INTERNAL_PROPERTY_TYPE = 'internalProperty';
var FRAME_TYPE = 'frame';
var SCRIPT_TYPE = 'script';
var CONTEXT_TYPE = 'context';
@ -212,6 +213,7 @@ var ScopeType = { Global: 0,
// - RegExpMirror
// - ErrorMirror
// - PropertyMirror
// - InternalPropertyMirror
// - FrameMirror
// - ScriptMirror
@ -357,6 +359,15 @@ Mirror.prototype.isProperty = function() {
};
/**
* Check whether the mirror reflects an internal property.
* @returns {boolean} True if the mirror reflects an internal property
*/
Mirror.prototype.isInternalProperty = function() {
return this instanceof InternalPropertyMirror;
};
/**
* Check whether the mirror reflects a stack frame.
* @returns {boolean} True if the mirror reflects a stack frame
@ -594,23 +605,6 @@ ObjectMirror.prototype.protoObject = function() {
};
/**
* Return the primitive value if this is object of Boolean, Number or String
* type (but not Date). Otherwise return undefined.
*/
ObjectMirror.prototype.primitiveValue = function() {
if (!IS_STRING_WRAPPER(this.value_) && !IS_NUMBER_WRAPPER(this.value_) &&
!IS_BOOLEAN_WRAPPER(this.value_)) {
return void 0;
}
var primitiveValue = %_ValueOf(this.value_);
if (IS_UNDEFINED(primitiveValue)) {
return void 0;
}
return MakeMirror(primitiveValue);
};
ObjectMirror.prototype.hasNamedInterceptor = function() {
// Get information on interceptors for this object.
var x = %GetInterceptorInfo(this.value_);
@ -701,7 +695,7 @@ ObjectMirror.prototype.propertyNames = function(kind, limit) {
* Return the properties for this object as an array of PropertyMirror objects.
* @param {number} kind Indicate whether named, indexed or both kinds of
* properties are requested
* @param {number} limit Limit the number of properties returend to the
* @param {number} limit Limit the number of properties returned to the
specified value
* @return {Array} Property mirrors for this object
*/
@ -716,6 +710,16 @@ ObjectMirror.prototype.properties = function(kind, limit) {
};
/**
* Return the internal properties for this object as an array of
* InternalPropertyMirror objects.
* @return {Array} Property mirrors for this object
*/
ObjectMirror.prototype.internalProperties = function() {
return ObjectMirror.GetInternalProperties(this.value_);
}
ObjectMirror.prototype.property = function(name) {
var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
if (details) {
@ -789,6 +793,37 @@ ObjectMirror.prototype.toText = function() {
};
/**
* Return the internal properties of the value, such as [[PrimitiveValue]] of
* scalar wrapper objects and properties of the bound function.
* This method is done static to be accessible from Debug API with the bare
* values without mirrors.
* @return {Array} array (possibly empty) of InternalProperty instances
*/
ObjectMirror.GetInternalProperties = function(value) {
if (IS_STRING_WRAPPER(value) || IS_NUMBER_WRAPPER(value) ||
IS_BOOLEAN_WRAPPER(value)) {
var primitiveValue = %_ValueOf(value);
return [new InternalPropertyMirror("[[PrimitiveValue]]", primitiveValue)];
} else if (IS_FUNCTION(value)) {
var bindings = %BoundFunctionGetBindings(value);
var result = [];
if (bindings && IS_ARRAY(bindings)) {
result.push(new InternalPropertyMirror("[[TargetFunction]]",
bindings[0]));
result.push(new InternalPropertyMirror("[[BoundThis]]", bindings[1]));
var boundArgs = [];
for (var i = 2; i < bindings.length; i++) {
boundArgs.push(bindings[i]);
}
result.push(new InternalPropertyMirror("[[BoundArgs]]", boundArgs));
}
return result;
}
return [];
}
/**
* Mirror object for functions.
* @param {function} value The function object reflected by this mirror.
@ -1268,6 +1303,33 @@ PropertyMirror.prototype.isNative = function() {
};
/**
* Mirror object for internal properties. Internal property reflects properties
* not accessible from user code such as [[BoundThis]] in bound function.
* Their names are merely symbolic.
* @param {string} name The name of the property
* @param {value} property value
* @constructor
* @extends Mirror
*/
function InternalPropertyMirror(name, value) {
%_CallFunction(this, INTERNAL_PROPERTY_TYPE, Mirror);
this.name_ = name;
this.value_ = value;
}
inherits(InternalPropertyMirror, Mirror);
InternalPropertyMirror.prototype.name = function() {
return this.name_;
};
InternalPropertyMirror.prototype.value = function() {
return MakeMirror(this.value_, false);
};
var kFrameDetailsFrameIdIndex = 0;
var kFrameDetailsReceiverIndex = 1;
var kFrameDetailsFunctionIndex = 2;
@ -2202,7 +2264,8 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
break;
case PROPERTY_TYPE:
throw new Error('PropertyMirror cannot be serialized independeltly');
case INTERNAL_PROPERTY_TYPE:
throw new Error('PropertyMirror cannot be serialized independently');
break;
case FRAME_TYPE:
@ -2278,7 +2341,8 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
* "prototypeObject":{"ref":<number>},
* "namedInterceptor":<boolean>,
* "indexedInterceptor":<boolean>,
* "properties":[<properties>]}
* "properties":[<properties>],
* "internalProperties":[<internal properties>]}
*/
JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
details) {
@ -2289,11 +2353,6 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
content.protoObject = this.serializeReference(mirror.protoObject());
content.prototypeObject = this.serializeReference(mirror.prototypeObject());
var primitiveValue = mirror.primitiveValue();
if (!IS_UNDEFINED(primitiveValue)) {
content.primitiveValue = this.serializeReference(primitiveValue);
}
// Add flags to indicate whether there are interceptors.
if (mirror.hasNamedInterceptor()) {
content.namedInterceptor = true;
@ -2355,6 +2414,15 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
}
}
content.properties = p;
var internalProperties = mirror.internalProperties();
if (internalProperties.length > 0) {
var ip = [];
for (var i = 0; i < internalProperties.length; i++) {
ip.push(this.serializeInternalProperty_(internalProperties[i]));
}
content.internalProperties = ip;
}
};
@ -2422,6 +2490,33 @@ JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
};
/**
* Serialize internal property information to the following JSON format for
* building the array of properties.
*
* {"name":"<property name>",
* "ref":<number>}
*
* {"name":"[[BoundThis]]","ref":117}
*
* @param {InternalPropertyMirror} propertyMirror The property to serialize.
* @returns {Object} Protocol object representing the property.
*/
JSONProtocolSerializer.prototype.serializeInternalProperty_ =
function(propertyMirror) {
var result = {};
result.name = propertyMirror.name();
var propertyValue = propertyMirror.value();
if (this.inlineRefs_() && propertyValue.isValue()) {
result.value = this.serializeReferenceWithDisplayData_(propertyValue);
} else {
result.ref = propertyValue.handle();
}
return result;
};
JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
content.index = mirror.index();
content.receiver = this.serializeReference(mirror.receiver());

View File

@ -1,4 +1,4 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -49,19 +49,19 @@ function testObjectMirror(obj, cls_name, ctor_name, hasSpecialProperties) {
JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertTrue(mirror instanceof debug.ValueMirror, 'Unexpected mirror hierachy');
assertTrue(mirror instanceof debug.ObjectMirror, 'Unexpected mirror hierachy');
assertTrue(mirror instanceof debug.Mirror, 'Unexpected mirror hierarchy');
assertTrue(mirror instanceof debug.ValueMirror, 'Unexpected mirror hierarchy');
assertTrue(mirror instanceof debug.ObjectMirror, 'Unexpected mirror hierarchy');
// Check the mirror properties.
assertTrue(mirror.isObject(), 'Unexpected mirror');
assertEquals('object', mirror.type(), 'Unexpected mirror type');
assertFalse(mirror.isPrimitive(), 'Unexpected primitive mirror');
assertEquals(cls_name, mirror.className(), 'Unexpected mirror class name');
assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror, 'Unexpected mirror hierachy');
assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror, 'Unexpected mirror hierarchy');
assertEquals(ctor_name, mirror.constructorFunction().name(), 'Unexpected constructor function name');
assertTrue(mirror.protoObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertTrue(mirror.prototypeObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertTrue(mirror.protoObject() instanceof debug.Mirror, 'Unexpected mirror hierarchy');
assertTrue(mirror.prototypeObject() instanceof debug.Mirror, 'Unexpected mirror hierarchy');
assertFalse(mirror.hasNamedInterceptor(), 'No named interceptor expected');
assertFalse(mirror.hasIndexedInterceptor(), 'No indexed interceptor expected');
@ -69,12 +69,19 @@ function testObjectMirror(obj, cls_name, ctor_name, hasSpecialProperties) {
var properties = mirror.properties();
assertEquals(names.length, properties.length);
for (var i = 0; i < properties.length; i++) {
assertTrue(properties[i] instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertTrue(properties[i] instanceof debug.PropertyMirror, 'Unexpected mirror hierachy');
assertTrue(properties[i] instanceof debug.Mirror, 'Unexpected mirror hierarchy');
assertTrue(properties[i] instanceof debug.PropertyMirror, 'Unexpected mirror hierarchy');
assertEquals('property', properties[i].type(), 'Unexpected mirror type');
assertEquals(names[i], properties[i].name(), 'Unexpected property name');
}
var internalProperties = mirror.internalProperties();
for (var i = 0; i < internalProperties.length; i++) {
assertTrue(internalProperties[i] instanceof debug.Mirror, 'Unexpected mirror hierarchy');
assertTrue(internalProperties[i] instanceof debug.InternalPropertyMirror, 'Unexpected mirror hierarchy');
assertEquals('internalProperty', internalProperties[i].type(), 'Unexpected mirror type');
}
for (var p in obj) {
var property_mirror = mirror.property(p);
assertTrue(property_mirror instanceof debug.PropertyMirror);
@ -172,6 +179,7 @@ testObjectMirror(this, 'global', '', true); // Global object has special proper
testObjectMirror(this.__proto__, 'Object', '');
testObjectMirror([], 'Array', 'Array');
testObjectMirror([1,2], 'Array', 'Array');
testObjectMirror(Object(17), 'Number', 'Number');
// Test circular references.
o = {};
@ -230,3 +238,29 @@ assertTrue(mirror.property('length').isNative());
assertEquals('a', mirror.property(0).value().value());
assertEquals('b', mirror.property(1).value().value());
assertEquals('c', mirror.property(2).value().value());
// Test value wrapper internal properties.
mirror = debug.MakeMirror(Object("Capybara"));
var ip = mirror.internalProperties();
assertEquals(1, ip.length);
assertEquals("[[PrimitiveValue]]", ip[0].name());
assertEquals("string", ip[0].value().type());
assertEquals("Capybara", ip[0].value().value());
// Test bound function internal properties.
mirror = debug.MakeMirror(Number.bind(Array, 2));
ip = mirror.internalProperties();
assertEquals(3, ip.length);
var property_map = {};
for (var i = 0; i < ip.length; i++) {
property_map[ip[i].name()] = ip[i];
}
assertTrue("[[BoundThis]]" in property_map);
assertEquals("function", property_map["[[BoundThis]]"].value().type());
assertEquals(Array, property_map["[[BoundThis]]"].value().value());
assertTrue("[[TargetFunction]]" in property_map);
assertEquals("function", property_map["[[TargetFunction]]"].value().type());
assertEquals(Number, property_map["[[TargetFunction]]"].value().value());
assertTrue("[[BoundArgs]]" in property_map);
assertEquals("object", property_map["[[BoundArgs]]"].value().type());
assertEquals(1, property_map["[[BoundArgs]]"].value().value().length);