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
This commit is contained in:
parent
ce673ec9ad
commit
25112aba44
@ -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);
|
||||
}
|
||||
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
|
||||
*/
|
||||
function AccessorMirror(getter, setter) {
|
||||
Mirror.call(this, ACCESSOR_TYPE);
|
||||
this.getter_ = getter;
|
||||
this.setter_ = setter;
|
||||
}
|
||||
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
|
||||
*/
|
||||
AccessorMirror.prototype.isNative = function() {
|
||||
return IS_UNDEFINED(this.getter_) && IS_UNDEFINED(this.setter_);
|
||||
PropertyMirror.prototype.hasGetter = function() {
|
||||
return this.getter_ ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a mirror for the function of a non native getter.
|
||||
* @return {FunctionMirror} Function mirror for the getter set using
|
||||
* __defineGetter__.
|
||||
* Returns whether this property has a setter defined through __defineSetter__.
|
||||
* @return {booolean} True if this property has a setter
|
||||
*/
|
||||
AccessorMirror.prototype.getter = function(details) {
|
||||
return MakeMirror(this.getter_);
|
||||
PropertyMirror.prototype.hasSetter = function() {
|
||||
return this.setter_ ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a mirror for the function of a non native setter.
|
||||
* @return {FunctionMirror} Function mirror for the getter set using
|
||||
* __defineSetter__.
|
||||
* 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.setter = function(details) {
|
||||
return MakeMirror(this.setter_);
|
||||
PropertyMirror.prototype.getter = function() {
|
||||
if (this.hasGetter()) {
|
||||
return MakeMirror(this.getter_);
|
||||
} else {
|
||||
return new UndefinedMirror();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
PropertyMirror.prototype.setter = function() {
|
||||
if (this.hasSetter()) {
|
||||
return MakeMirror(this.setter_);
|
||||
} else {
|
||||
return new UndefinedMirror();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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()) {
|
||||
|
@ -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();
|
||||
case NORMAL:
|
||||
case FIELD:
|
||||
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 FIELD:
|
||||
value =
|
||||
JSObject::cast(
|
||||
result->holder())->FastPropertyAt(result->GetFieldIndex());
|
||||
if (value->IsTheHole()) {
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
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<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();
|
||||
@ -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<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();
|
||||
}
|
||||
|
||||
@ -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<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();
|
||||
}
|
||||
|
||||
|
@ -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 only named interceptor.
|
||||
CompileRun("named_values = named_mirror.properties()");
|
||||
|
||||
// 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());
|
||||
|
||||
// 4 is PropertyType.Interceptor
|
||||
OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
|
||||
CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
|
||||
|
||||
OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
|
||||
CHECK(CompileRun(buffer.start())->BooleanValue());
|
||||
}
|
||||
|
||||
// Get the interceptor properties for the object with only indexed
|
||||
// interceptor.
|
||||
CompileRun("indexed_values = indexed_mirror.properties()");
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
// Get the interceptor properties for the object with both types of
|
||||
// interceptors.
|
||||
CompileRun("both_values = both_mirror.interceptorProperties()");
|
||||
CompileRun("both_values = both_mirror.properties()");
|
||||
|
||||
// Check the mirror hierachy
|
||||
source = "both_values[0] instanceof debug.PropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
source = "both_values[0] instanceof debug.InterceptorPropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
source = "both_values[1] instanceof debug.InterceptorPropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
source = "both_values[2] instanceof debug.InterceptorPropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
source = "both_values[3] instanceof debug.PropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
source = "both_values[3] instanceof debug.InterceptorPropertyMirror";
|
||||
CHECK(CompileRun(source)->BooleanValue());
|
||||
|
||||
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'";
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user