From 25112aba4482228f571dea6d7de1ab12524b9f7e Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Tue, 13 Jan 2009 14:38:44 +0000 Subject: [PATCH] Refactored the mirror representation of properties. Removed the AssessorMirror and InterceptorPropertyMirror and moved all reflection for properties to PropertyMirror. From a PropertyMirror it can be checked whether a property has getter/setter defined in JavaScript and information on the getter/setter functions are now available. If calling the getter resulted in an exception this is reflected as well. Properties from interceptors are also reflected through PropertyMirror as the distinction did not make sense seen from a JavaScript debugging perspective. The isNative function on a PropertyMirror can be used to check whether a property is defined natively by the host (or V8). Simplified the local property lookup in the debug runtime call to just call GetProperty as the property is known to be a local property. Review URL: http://codereview.chromium.org/17377 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1068 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mirror-delay.js | 246 ++++++++++++---------------------- src/runtime.cc | 88 ++++++++---- test/cctest/test-debug.cc | 72 ++++++---- test/mjsunit/mirror-object.js | 42 ++++-- 4 files changed, 216 insertions(+), 232 deletions(-) diff --git a/src/mirror-delay.js b/src/mirror-delay.js index e7ff91071..7e25501e0 100644 --- a/src/mirror-delay.js +++ b/src/mirror-delay.js @@ -135,8 +135,6 @@ PropertyAttribute.DontDelete = DONT_DELETE; // - RegExpMirror // - ErrorMirror // - PropertyMirror -// - InterceptorPropertyMirror -// - AccessorMirror // - FrameMirror // - ScriptMirror @@ -273,25 +271,6 @@ Mirror.prototype.isProperty = function() { } -/** - * Check whether the mirror reflects a property from an interceptor. - * @returns {boolean} True if the mirror reflects a property from an - * interceptor - */ -Mirror.prototype.isInterceptorProperty = function() { - return this instanceof InterceptorPropertyMirror; -} - - -/** - * Check whether the mirror reflects an accessor. - * @returns {boolean} True if the mirror reflects an accessor - */ -Mirror.prototype.isAccessor = function() { - return this instanceof AccessorMirror; -} - - /** * Check whether the mirror reflects a stack frame. * @returns {boolean} True if the mirror reflects a stack frame @@ -519,13 +498,39 @@ ObjectMirror.prototype.propertyNames = function(kind, limit) { var propertyNames; var elementNames; var total = 0; + + // Find all the named properties. if (kind & PropertyKind.Named) { + // Get the local property names. propertyNames = %DebugLocalPropertyNames(this.value_); total += propertyNames.length; + + // Get names for named interceptor properties if any. + if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) { + var namedInterceptorNames = + %DebugNamedInterceptorPropertyNames(this.value_); + if (namedInterceptorNames) { + propertyNames = propertyNames.concat(namedInterceptorNames); + total += namedInterceptorNames.length; + } + } } + + // Find all the indexed properties. if (kind & PropertyKind.Indexed) { - elementNames = %DebugLocalElementNames(this.value_) + // Get the local element names. + elementNames = %DebugLocalElementNames(this.value_); total += elementNames.length; + + // Get names for indexed interceptor properties. + if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) { + var indexedInterceptorNames = + %DebugIndexedInterceptorElementNames(this.value_); + if (indexedInterceptorNames) { + elementNames = elementNames.concat(indexedInterceptorNames); + total += indexedInterceptorNames.length; + } + } } limit = Math.min(limit || total, total); @@ -569,95 +574,10 @@ ObjectMirror.prototype.properties = function(kind, limit) { }; -/** - * Return the interceptor property names for this object. - * @param {number} kind Indicate whether named, indexed or both kinds of - * interceptor properties are requested - * @param {number} limit Limit the number of names returend to the specified - value - * @return {Array} interceptor property names for this object - */ -ObjectMirror.prototype.interceptorPropertyNames = function(kind, limit) { - // Find kind. - kind = kind || PropertyKind.Named | PropertyKind.Indexed; - var namedInterceptorNames; - var indexedInterceptorNames; - - // Get names for named interceptor properties. - if (this.hasNamedInterceptor() && kind & PropertyKind.Named) { - namedInterceptorNames = %DebugNamedInterceptorPropertyNames(this.value_); - } - - // Get names for indexed interceptor properties. - if (this.hasIndexedInterceptor() && kind & PropertyKind.Indexed) { - indexedInterceptorNames = %DebugIndexedInterceptorElementNames(this.value_); - } - - // Return either retult or both concattenated. - if (namedInterceptorNames && indexedInterceptorNames) { - return namedInterceptorNames.concat(indexedInterceptorNames); - } else if (namedInterceptorNames) { - return namedInterceptorNames; - } else if (indexedInterceptorNames) { - return indexedInterceptorNames; - } else { - return new Array(0); - } -}; - - -/** - * Return interceptor properties this object. - * @param {number} opt_kind Indicate whether named, indexed or both kinds of - * interceptor properties are requested - * @param {Array} opt_names Limit the number of properties returned to the - specified value - * @return {Array} properties this object as an array of PropertyMirror objects - */ -ObjectMirror.prototype.interceptorProperties = function(opt_kind, opt_names) { - // Find kind. - var kind = opt_kind || PropertyKind.Named | PropertyKind.Indexed; - var namedInterceptorProperties; - var indexedInterceptorProperties; - - // Get values for named interceptor properties. - if (kind & PropertyKind.Named) { - var names = opt_names || this.interceptorPropertyNames(PropertyKind.Named); - namedInterceptorProperties = new Array(names.length); - for (i = 0; i < names.length; i++) { - var value = %DebugNamedInterceptorPropertyValue(this.value_, names[i]); - namedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value); - } - } - - // Get values for indexed interceptor properties. - if (kind & PropertyKind.Indexed) { - var names = opt_names || this.interceptorPropertyNames(PropertyKind.Indexed); - indexedInterceptorProperties = new Array(names.length); - for (i = 0; i < names.length; i++) { - // Don't try to get the value if the name is not a number. - if (IS_NUMBER(names[i])) { - var value = %DebugIndexedInterceptorElementValue(this.value_, names[i]); - indexedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value); - } - } - } - - // Return either result or both concattenated. - if (namedInterceptorProperties && indexedInterceptorProperties) { - return namedInterceptorProperties.concat(indexedInterceptorProperties); - } else if (namedInterceptorProperties) { - return namedInterceptorProperties; - } else { - return indexedInterceptorProperties; - } -}; - - ObjectMirror.prototype.property = function(name) { var details = %DebugGetPropertyDetails(this.value_, %ToString(name)); if (details) { - return new PropertyMirror(this, name, details[0], details[1]); + return new PropertyMirror(this, name, details); } // Nothing found. @@ -893,7 +813,7 @@ ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_ var details = %DebugGetPropertyDetails(this.value_, %ToString(i)); var value; if (details) { - value = new PropertyMirror(this, i, details[0], details[1]); + value = new PropertyMirror(this, i, details); } else { value = new UndefinedMirror(); } @@ -1011,16 +931,21 @@ ErrorMirror.prototype.toText = function() { * Base mirror object for properties. * @param {ObjectMirror} mirror The mirror object having this property * @param {string} name The name of the property - * @param {Object} value The value of the property + * @param {Array} details Details about the property * @constructor * @extends Mirror */ -function PropertyMirror(mirror, name, value, details) { +function PropertyMirror(mirror, name, details) { Mirror.call(this, PROPERTY_TYPE); this.mirror_ = mirror; this.name_ = name; - this.value_ = value; - this.details_ = details; + this.value_ = details[0]; + this.details_ = details[1]; + if (details.length > 2) { + this.exception_ = details[2] + this.getter_ = details[3]; + this.setter_ = details[4]; + } } inherits(PropertyMirror, Mirror); @@ -1056,14 +981,16 @@ PropertyMirror.prototype.isIndexed = function() { PropertyMirror.prototype.value = function() { - if (this.propertyType() == PropertyType.Callbacks) { - // TODO(1242933): AccessorMirror should have getter/setter values. - return new AccessorMirror(); - } else if (this.type() == PropertyType.Interceptor) { - return new UndefinedMirror(); - } else { - return MakeMirror(this.value_); - } + return MakeMirror(this.value_); +} + + +/** + * Returns whether this property value is an exception. + * @return {booolean} True if this property value is an exception + */ +PropertyMirror.prototype.isException = function() { + return this.exception_ ? true : false; } @@ -1083,62 +1010,61 @@ PropertyMirror.prototype.insertionIndex = function() { /** - * Mirror object for interceptor named properties. - * @param {ObjectMirror} mirror The mirror object having this property - * @param {String} name The name of the property - * @param {value} value The value of the property - * @constructor - * @extends PropertyMirror + * Returns whether this property has a getter defined through __defineGetter__. + * @return {booolean} True if this property has a getter */ -function InterceptorPropertyMirror(mirror, name, value) { - PropertyMirror.call(this, mirror, name, value, PropertyType.Interceptor); +PropertyMirror.prototype.hasGetter = function() { + return this.getter_ ? true : false; } -inherits(InterceptorPropertyMirror, PropertyMirror); /** - * Mirror object for property accessors. - * @param {Function} getter The getter function for this accessor - * @param {Function} setter The setter function for this accessor - * @constructor - * @extends Mirror + * Returns whether this property has a setter defined through __defineSetter__. + * @return {booolean} True if this property has a setter */ -function AccessorMirror(getter, setter) { - Mirror.call(this, ACCESSOR_TYPE); - this.getter_ = getter; - this.setter_ = setter; +PropertyMirror.prototype.hasSetter = function() { + return this.setter_ ? true : false; } -inherits(AccessorMirror, Mirror); /** - * Returns whether this accessor is native or not. A native accessor is either - * a VM buildin or provided through the API. A non native accessor is defined - * in JavaScript using the __defineGetter__ and/or __defineGetter__ functions. - * @return {boolean} True is the accessor is native + * Returns the getter for this property defined through __defineGetter__. + * @return {Mirror} FunctionMirror reflecting the getter function or + * UndefinedMirror if there is no getter for this property */ -AccessorMirror.prototype.isNative = function() { - return IS_UNDEFINED(this.getter_) && IS_UNDEFINED(this.setter_); +PropertyMirror.prototype.getter = function() { + if (this.hasGetter()) { + return MakeMirror(this.getter_); + } else { + return new UndefinedMirror(); + } } /** - * Returns a mirror for the function of a non native getter. - * @return {FunctionMirror} Function mirror for the getter set using - * __defineGetter__. + * Returns the setter for this property defined through __defineSetter__. + * @return {Mirror} FunctionMirror reflecting the setter function or + * UndefinedMirror if there is no setter for this property */ -AccessorMirror.prototype.getter = function(details) { - return MakeMirror(this.getter_); +PropertyMirror.prototype.setter = function() { + if (this.hasSetter()) { + return MakeMirror(this.setter_); + } else { + return new UndefinedMirror(); + } } /** - * Returns a mirror for the function of a non native setter. - * @return {FunctionMirror} Function mirror for the getter set using - * __defineSetter__. + * Returns whether this property is natively implemented by the host or a set + * through JavaScript code. + * @return {boolean} True if the property is + * UndefinedMirror if there is no setter for this property */ -AccessorMirror.prototype.setter = function(details) { - return MakeMirror(this.setter_); +PropertyMirror.prototype.isNative = function() { + return (this.propertyType() == PropertyType.Interceptor) || + ((this.propertyType() == PropertyType.Callbacks) && + !this.hasGetter() && !this.hasSetter()); } @@ -1732,14 +1658,6 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content) { } content.push(MakeJSONPair_('properties', ArrayToJSONArray_(x))); - // Add interceptor properties. - propertyNames = mirror.interceptorPropertyNames(); - var x = new Array(propertyNames.length); - for (var i = 0; i < propertyNames.length; i++) { - x[i] = properties[i].toJSONProtocol(details); - } - content.push(MakeJSONPair_('interceptorProperties', ArrayToJSONArray_(x))); - // For arrays the indexed properties are added separately and the length is // added as well. if (mirror.isArray()) { diff --git a/src/runtime.cc b/src/runtime.cc index d2b62a422..326921770 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -4503,30 +4503,32 @@ static Object* Runtime_Break(Arguments args) { } -static Object* DebugLookupResultValue(LookupResult* result) { - Object* value; +static Object* DebugLookupResultValue(Object* obj, String* name, + LookupResult* result, + bool* caught_exception) { switch (result->type()) { - case NORMAL: { - Dictionary* dict = - JSObject::cast(result->holder())->property_dictionary(); - value = dict->ValueAt(result->GetDictionaryEntry()); - if (value->IsTheHole()) { - return Heap::undefined_value(); - } - return value; - } + case NORMAL: case FIELD: - value = - JSObject::cast( - result->holder())->FastPropertyAt(result->GetFieldIndex()); - if (value->IsTheHole()) { - return Heap::undefined_value(); + case CONSTANT_FUNCTION: + return obj->GetProperty(name); + case CALLBACKS: { + // Get the property value. If there is an exception it must be thown from + // a JavaScript getter. + Object* value; + value = obj->GetProperty(name); + if (value->IsException()) { + if (caught_exception != NULL) { + *caught_exception = true; + } + value = Top::pending_exception(); + Top::optional_reschedule_exception(true); } + ASSERT(!Top::has_pending_exception()); + ASSERT(!Top::external_caught_exception()); return value; - case CONSTANT_FUNCTION: - return result->GetConstantFunction(); - case CALLBACKS: + } case INTERCEPTOR: + return obj->GetProperty(name); case MAP_TRANSITION: case CONSTANT_TRANSITION: case NULL_DESCRIPTOR: @@ -4539,6 +4541,18 @@ static Object* DebugLookupResultValue(LookupResult* result) { } +// Get debugger related details for an object property. +// args[0]: object holding property +// args[1]: name of the property +// +// The array returned contains the following information: +// 0: Property value +// 1: Property details +// 2: Property value is exception +// 3: Getter function if defined +// 4: Setter function if defined +// Items 2-4 are only filled if the property has either a getter or a setter +// defined through __defineGetter__ and/or __defineSetter__. static Object* Runtime_DebugGetPropertyDetails(Arguments args) { HandleScope scope; @@ -4559,12 +4573,26 @@ static Object* Runtime_DebugGetPropertyDetails(Arguments args) { // Perform standard local lookup on the object. LookupResult result; - obj->Lookup(*name, &result); + obj->LocalLookup(*name, &result); if (result.IsProperty()) { - Handle value(DebugLookupResultValue(&result)); - Handle details = Factory::NewFixedArray(2); + bool caught_exception = false; + Handle value(DebugLookupResultValue(*obj, *name, &result, + &caught_exception)); + // If the callback object is a fixed array then it contains JavaScript + // getter and/or setter. + bool hasJavaScriptAccessors = result.type() == CALLBACKS && + result.GetCallbackObject()->IsFixedArray(); + Handle details = + Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2); details->set(0, *value); details->set(1, result.GetPropertyDetails().AsSmi()); + if (hasJavaScriptAccessors) { + details->set(2, + caught_exception ? Heap::true_value() : Heap::false_value()); + details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0)); + details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1)); + } + return *Factory::NewJSArrayWithElements(details); } return Heap::undefined_value(); @@ -4582,7 +4610,7 @@ static Object* Runtime_DebugGetProperty(Arguments args) { LookupResult result; obj->Lookup(*name, &result); if (result.IsProperty()) { - return DebugLookupResultValue(&result); + return DebugLookupResultValue(*obj, *name, &result, NULL); } return Heap::undefined_value(); } @@ -4676,10 +4704,11 @@ static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) { HandleScope scope; ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, obj, 0); - RUNTIME_ASSERT(obj->HasNamedInterceptor()); - v8::Handle result = GetKeysForNamedInterceptor(obj, obj); - if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + if (obj->HasNamedInterceptor()) { + v8::Handle result = GetKeysForNamedInterceptor(obj, obj); + if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + } return Heap::undefined_value(); } @@ -4690,10 +4719,11 @@ static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) { HandleScope scope; ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSObject, obj, 0); - RUNTIME_ASSERT(obj->HasIndexedInterceptor()); - v8::Handle result = GetKeysForIndexedInterceptor(obj, obj); - if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + if (obj->HasIndexedInterceptor()) { + v8::Handle result = GetKeysForIndexedInterceptor(obj, obj); + if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); + } return Heap::undefined_value(); } diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 924eeecda..6c8c28f38 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -2660,58 +2660,76 @@ TEST(InterceptorPropertyMirror) { // Get the property names from the interceptors CompileRun( - "named_names = named_mirror.interceptorPropertyNames();" - "indexed_names = indexed_mirror.interceptorPropertyNames();" - "both_names = both_mirror.interceptorPropertyNames()"); + "named_names = named_mirror.propertyNames();" + "indexed_names = indexed_mirror.propertyNames();" + "both_names = both_mirror.propertyNames()"); CHECK_EQ(3, CompileRun("named_names.length")->Int32Value()); CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value()); CHECK_EQ(5, CompileRun("both_names.length")->Int32Value()); // Check the expected number of properties. const char* source; - source = "named_mirror.interceptorProperties().length"; + source = "named_mirror.properties().length"; CHECK_EQ(3, CompileRun(source)->Int32Value()); - source = "indexed_mirror.interceptorProperties().length"; + source = "indexed_mirror.properties().length"; CHECK_EQ(2, CompileRun(source)->Int32Value()); - source = "both_mirror.interceptorProperties().length"; + source = "both_mirror.properties().length"; CHECK_EQ(5, CompileRun(source)->Int32Value()); - source = "both_mirror.interceptorProperties(1).length"; + // 1 is PropertyKind.Named; + source = "both_mirror.properties(1).length"; CHECK_EQ(3, CompileRun(source)->Int32Value()); - source = "both_mirror.interceptorProperties(2).length"; + // 2 is PropertyKind.Indexed; + source = "both_mirror.properties(2).length"; CHECK_EQ(2, CompileRun(source)->Int32Value()); - source = "both_mirror.interceptorProperties(3).length"; + // 3 is PropertyKind.Named | PropertyKind.Indexed; + source = "both_mirror.properties(3).length"; CHECK_EQ(5, CompileRun(source)->Int32Value()); - // Get the interceptor properties for the object with both types of - // interceptors. - CompileRun("both_values = both_mirror.interceptorProperties()"); + // Get the interceptor properties for the object with only named interceptor. + CompileRun("named_values = named_mirror.properties()"); - // Check the mirror hierachy - source = "both_values[0] instanceof debug.PropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // Check that the properties are interceptor properties. + for (int i = 0; i < 3; i++) { + EmbeddedVector buffer; + OS::SNPrintF(buffer, + "named_values[%d] instanceof debug.PropertyMirror", i); + CHECK(CompileRun(buffer.start())->BooleanValue()); - source = "both_values[0] instanceof debug.InterceptorPropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // 4 is PropertyType.Interceptor + OS::SNPrintF(buffer, "named_values[%d].propertyType()", i); + CHECK_EQ(4, CompileRun(buffer.start())->Int32Value()); - source = "both_values[1] instanceof debug.InterceptorPropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + OS::SNPrintF(buffer, "named_values[%d].isNative()", i); + CHECK(CompileRun(buffer.start())->BooleanValue()); + } - source = "both_values[2] instanceof debug.InterceptorPropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // Get the interceptor properties for the object with only indexed + // interceptor. + CompileRun("indexed_values = indexed_mirror.properties()"); - source = "both_values[3] instanceof debug.PropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // Check that the properties are interceptor properties. + for (int i = 0; i < 2; i++) { + EmbeddedVector buffer; + OS::SNPrintF(buffer, + "indexed_values[%d] instanceof debug.PropertyMirror", i); + CHECK(CompileRun(buffer.start())->BooleanValue()); + } - source = "both_values[3] instanceof debug.InterceptorPropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // Get the interceptor properties for the object with both types of + // interceptors. + CompileRun("both_values = both_mirror.properties()"); - source = "both_values[4] instanceof debug.InterceptorPropertyMirror"; - CHECK(CompileRun(source)->BooleanValue()); + // Check that the properties are interceptor properties. + for (int i = 0; i < 5; i++) { + EmbeddedVector buffer; + OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i); + CHECK(CompileRun(buffer.start())->BooleanValue()); + } // Check the property names. source = "both_values[0].name() == 'a'"; diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js index ff896fc23..5f86acdfd 100644 --- a/test/mjsunit/mirror-object.js +++ b/test/mjsunit/mirror-object.js @@ -107,8 +107,7 @@ function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) { } else { assertTrue(typeof(fromJSON.properties[i].attributes) === 'undefined'); } - if (!properties[i].value() instanceof debug.AccessorMirror && - properties[i].value().isPrimitive()) { + if (!properties[i].value().isPrimitive()) { // NaN is not equal to NaN. if (isNaN(properties[i].value().value())) { assertTrue(isNaN(fromJSON.properties[i].value.value)); @@ -157,27 +156,46 @@ assertFalse(math_mirror.property("E").canDelete()); // Test objects with JavaScript accessors. o = {} -o.__defineGetter__('a', function(){throw 'a';}) -o.__defineSetter__('b', function(){throw 'b';}) -o.__defineGetter__('c', function(){throw 'c';}) -o.__defineSetter__('c', function(){throw 'c';}) +o.__defineGetter__('a', function(){return 'a';}); +o.__defineSetter__('b', function(){}); +o.__defineGetter__('c', function(){throw 'c';}); +o.__defineSetter__('c', function(){throw 'c';}); testObjectMirror(o, 'Object', 'Object'); mirror = debug.MakeMirror(o); // a has getter but no setter. -assertTrue(mirror.property('a').value() instanceof debug.AccessorMirror); +assertTrue(mirror.property('a').hasGetter()); +assertFalse(mirror.property('a').hasSetter()); assertEquals(debug.PropertyType.Callbacks, mirror.property('a').propertyType()); +assertEquals('function', mirror.property('a').getter().type()); +assertEquals('undefined', mirror.property('a').setter().type()); +assertEquals('function (){return \'a\';}', mirror.property('a').getter().source()); +assertEquals('a', mirror.property('a').value().value()); +assertFalse(mirror.property('a').isException()); // b has setter but no getter. -assertTrue(mirror.property('b').value() instanceof debug.AccessorMirror); +assertFalse(mirror.property('b').hasGetter()); +assertTrue(mirror.property('b').hasSetter()); assertEquals(debug.PropertyType.Callbacks, mirror.property('b').propertyType()); -// c has both getter and setter. -assertTrue(mirror.property('c').value() instanceof debug.AccessorMirror); +assertEquals('undefined', mirror.property('b').getter().type()); +assertEquals('function', mirror.property('b').setter().type()); +assertEquals('function (){}', mirror.property('b').setter().source()); +assertFalse(mirror.property('b').isException()); +// c has both getter and setter. The getter throws an exception. +assertTrue(mirror.property('c').hasGetter()); +assertTrue(mirror.property('c').hasSetter()); assertEquals(debug.PropertyType.Callbacks, mirror.property('c').propertyType()); +assertEquals('function', mirror.property('c').getter().type()); +assertEquals('function', mirror.property('c').setter().type()); +assertEquals('function (){throw \'c\';}', mirror.property('c').getter().source()); +assertEquals('function (){throw \'c\';}', mirror.property('c').setter().source()); +assertEquals('c', mirror.property('c').value().value()); +assertTrue(mirror.property('c').isException()); // Test objects with native accessors. mirror = debug.MakeMirror(new String('abc')); assertTrue(mirror instanceof debug.ObjectMirror); -assertTrue(mirror.property('length').value() instanceof debug.AccessorMirror); -assertTrue(mirror.property('length').value().isNative()); +assertFalse(mirror.property('length').hasGetter()); +assertFalse(mirror.property('length').hasSetter()); +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()); -- 2.34.1