diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js index 94e616a7f5..a5331a014d 100644 --- a/src/mirror-debugger.js +++ b/src/mirror-debugger.js @@ -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":}, * "namedInterceptor":, * "indexedInterceptor":, - * "properties":[]} + * "properties":[], + * "internalProperties":[]} */ 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":"", + * "ref":} + * + * {"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()); diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js index d4d228cf07..8bf8a2d4f8 100644 --- a/test/mjsunit/mirror-object.js +++ b/test/mjsunit/mirror-object.js @@ -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);