// - RegExpMirror
// - ErrorMirror
// - PropertyMirror
-// - InterceptorPropertyMirror
-// - AccessorMirror
// - FrameMirror
// - ScriptMirror
}
-/**
- * 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
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);
};
-/**
- * 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.
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();
}
* 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);
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;
}
/**
- * 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());
}
}
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()) {
}
-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:
}
+// 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;
// Perform standard local lookup on the object.
LookupResult result;
- obj->Lookup(*name, &result);
+ obj->LocalLookup(*name, &result);
if (result.IsProperty()) {
- Handle<Object> value(DebugLookupResultValue(&result));
- Handle<FixedArray> details = Factory::NewFixedArray(2);
+ bool caught_exception = false;
+ Handle<Object> 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<FixedArray> 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();
LookupResult result;
obj->Lookup(*name, &result);
if (result.IsProperty()) {
- return DebugLookupResultValue(&result);
+ return DebugLookupResultValue(*obj, *name, &result, NULL);
}
return Heap::undefined_value();
}
HandleScope scope;
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
- RUNTIME_ASSERT(obj->HasNamedInterceptor());
- v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
- if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ if (obj->HasNamedInterceptor()) {
+ v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
+ if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ }
return Heap::undefined_value();
}
HandleScope scope;
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSObject, obj, 0);
- RUNTIME_ASSERT(obj->HasIndexedInterceptor());
- v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
- if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ if (obj->HasIndexedInterceptor()) {
+ v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
+ if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
+ }
return Heap::undefined_value();
}
// 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<char, SMALL_STRING_BUFFER_SIZE> 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<char, SMALL_STRING_BUFFER_SIZE> 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<char, SMALL_STRING_BUFFER_SIZE> 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'";
} 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));
// 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());