Commit cd9660f7 authored by yurys@chromium.org's avatar yurys@chromium.org

All hidden properties of an object are stored in a value of a regular property...

All hidden properties of an object are stored in a value of a regular property with empty name. This property may confuse user if returned among regular properties. It should not be exposed directly by ObjectMirror. Should we want an access to these properties from debugger we need to implement an explicit method for that.

Current patch filters the hidden_symbol from property names returned to ObjectMirror.

See http://crbug.com/26491

Review URL: http://codereview.chromium.org/390001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0b0d4efd
...@@ -6002,14 +6002,33 @@ static Object* Runtime_DebugLocalPropertyNames(Arguments args) { ...@@ -6002,14 +6002,33 @@ static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
// Get the property names. // Get the property names.
jsproto = obj; jsproto = obj;
int proto_with_hidden_properties = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
jsproto->GetLocalPropertyNames(*names, jsproto->GetLocalPropertyNames(*names,
i == 0 ? 0 : local_property_count[i - 1]); i == 0 ? 0 : local_property_count[i - 1]);
if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
proto_with_hidden_properties++;
}
if (i < length - 1) { if (i < length - 1) {
jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
} }
} }
// Filter out name of hidden propeties object.
if (proto_with_hidden_properties > 0) {
Handle<FixedArray> old_names = names;
names = Factory::NewFixedArray(
names->length() - proto_with_hidden_properties);
int dest_pos = 0;
for (int i = 0; i < total_property_count; i++) {
Object* name = old_names->get(i);
if (name == Heap::hidden_symbol()) {
continue;
}
names->set(dest_pos++, name);
}
}
DeleteArray(local_property_count); DeleteArray(local_property_count);
return *Factory::NewJSArrayWithElements(names); return *Factory::NewJSArrayWithElements(names);
} }
......
...@@ -3439,6 +3439,75 @@ TEST(NativeGetterThrowingErrorPropertyMirror) { ...@@ -3439,6 +3439,75 @@ TEST(NativeGetterThrowingErrorPropertyMirror) {
} }
// Test that hidden properties object is not returned as an unnamed property
// among regular properties.
// See http://crbug.com/26491
TEST(NoHiddenProperties) {
// Create a V8 environment with debug access.
v8::HandleScope scope;
DebugLocalContext env;
env.ExposeDebug();
// Create an object in the global scope.
const char* source = "var obj = {a: 1};";
v8::Script::Compile(v8::String::New(source))->Run();
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
env->Global()->Get(v8::String::New("obj")));
// Set a hidden property on the object.
obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
v8::Int32::New(11));
// Get mirror for the object with property getter.
CompileRun("var obj_mirror = debug.MakeMirror(obj);");
CHECK(CompileRun(
"obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
CompileRun("var named_names = obj_mirror.propertyNames();");
// There should be exactly one property. But there is also an unnamed
// property whose value is hidden properties dictionary. The latter
// property should not be in the list of reguar properties.
CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
CHECK(CompileRun(
"obj_mirror.property('a').value().value() == 1")->BooleanValue());
// Object created by t0 will become hidden prototype of object 'obj'.
v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
t0->SetHiddenPrototype(true);
v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
// Create proto objects, add hidden properties to them and set them on
// the global object.
v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
v8::Int32::New(12));
env->Global()->Set(v8::String::New("protoObj"), protoObj);
v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
v8::Int32::New(13));
env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
// Setting prototypes: obj->protoObj->grandProtoObj
protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
obj->Set(v8::String::New("__proto__"), protoObj);
// Get mirror for the object with property getter.
CompileRun("var obj_mirror = debug.MakeMirror(obj);");
CHECK(CompileRun(
"obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
CompileRun("var named_names = obj_mirror.propertyNames();");
// There should be exactly two properties - one from the object itself and
// another from its hidden prototype.
CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
"named_names[1] == 'b'")->BooleanValue());
CHECK(CompileRun(
"obj_mirror.property('a').value().value() == 1")->BooleanValue());
CHECK(CompileRun(
"obj_mirror.property('b').value().value() == 2")->BooleanValue());
}
// Multithreaded tests of JSON debugger protocol // Multithreaded tests of JSON debugger protocol
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment