Revision: 13245
Author: [email protected]
Date: Wed Dec 19 07:17:01 2012
Log: Fix treatment of hidden prototypes in SetProperty.
[email protected]
BUG=v8:2457
Review URL: https://codereview.chromium.org/11644021
http://code.google.com/p/v8/source/detail?r=13245
Modified:
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/objects.cc Wed Dec 19 05:27:20 2012
+++ /branches/bleeding_edge/src/objects.cc Wed Dec 19 07:17:01 2012
@@ -2919,6 +2919,9 @@
return JSObject::cast(proto)->SetPropertyForResult(
lookup, name_raw, value_raw, attributes, strict_mode, store_mode);
}
+
+ ASSERT(!lookup->IsFound() || lookup->holder() == this ||
+ lookup->holder()->map()->is_hidden_prototype());
// From this point on everything needs to be handlified, because
// SetPropertyViaPrototypes might call back into JavaScript.
@@ -2961,10 +2964,10 @@
MaybeObject* result = *value;
switch (lookup->type()) {
case NORMAL:
- result = self->SetNormalizedProperty(lookup, *value);
+ result = lookup->holder()->SetNormalizedProperty(lookup, *value);
break;
case FIELD:
- result = self->FastPropertyAtPut(
+ result = lookup->holder()->FastPropertyAtPut(
lookup->GetFieldIndex().field_index(), *value);
break;
case CONSTANT_FUNCTION:
@@ -2972,21 +2975,17 @@
if (*value == lookup->GetConstantFunction()) return *value;
// Preserve the attributes of this existing property.
attributes = lookup->GetAttributes();
- result = self->ConvertDescriptorToField(*name, *value, attributes);
+ result =
+ lookup->holder()->ConvertDescriptorToField(*name, *value,
attributes);
break;
case CALLBACKS: {
Object* callback_object = lookup->GetCallbackObject();
- return self->SetPropertyWithCallback(callback_object,
- *name,
- *value,
- lookup->holder(),
- strict_mode);
+ return self->SetPropertyWithCallback(
+ callback_object, *name, *value, lookup->holder(), strict_mode);
}
case INTERCEPTOR:
- result = self->SetPropertyWithInterceptor(*name,
- *value,
- attributes,
- strict_mode);
+ result = lookup->holder()->SetPropertyWithInterceptor(
+ *name, *value, attributes, strict_mode);
break;
case TRANSITION: {
Map* transition_map = lookup->GetTransitionTarget();
@@ -2998,15 +2997,15 @@
if (details.type() == FIELD) {
if (attributes == details.attributes()) {
int field_index = descriptors->GetFieldIndex(descriptor);
- result = self->AddFastPropertyUsingMap(transition_map,
- *name,
- *value,
- field_index);
+ result = lookup->holder()->AddFastPropertyUsingMap(
+ transition_map, *name, *value, field_index);
} else {
- result = self->ConvertDescriptorToField(*name, *value,
attributes);
+ result = lookup->holder()->ConvertDescriptorToField(
+ *name, *value, attributes);
}
} else if (details.type() == CALLBACKS) {
- result = self->ConvertDescriptorToField(*name, *value, attributes);
+ result = lookup->holder()->ConvertDescriptorToField(
+ *name, *value, attributes);
} else {
ASSERT(details.type() == CONSTANT_FUNCTION);
@@ -3014,12 +3013,12 @@
if (constant_function == *value) {
// If the same constant function is being added we can simply
// transition to the target map.
- self->set_map(transition_map);
+ lookup->holder()->set_map(transition_map);
result = constant_function;
} else {
// Otherwise, replace with a map transition to a new map with a
FIELD,
// even if the value is a constant function.
- result = self->ConvertTransitionToMapTransition(
+ result = lookup->holder()->ConvertTransitionToMapTransition(
lookup->GetTransitionIndex(), *name, *value, attributes);
}
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed Dec 19 02:28:36 2012
+++ /branches/bleeding_edge/test/cctest/test-api.cc Wed Dec 19 07:17:01 2012
@@ -8231,6 +8231,66 @@
CHECK(proto->IsObject());
CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
}
+
+
+THREADED_TEST(HiddenPrototypeSet) {
+ v8::HandleScope handle_scope;
+ LocalContext context;
+
+ Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
+ Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
+ ht->SetHiddenPrototype(true);
+ Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
+ ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
+
+ Local<v8::Object> o = ot->GetFunction()->NewInstance();
+ Local<v8::Object> h = ht->GetFunction()->NewInstance();
+ Local<v8::Object> p = pt->GetFunction()->NewInstance();
+ o->Set(v8_str("__proto__"), h);
+ h->Set(v8_str("__proto__"), p);
+
+ // Setting a property that exists on the hidden prototype goes there.
+ o->Set(v8_str("x"), v8_num(7));
+ CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
+ CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
+ CHECK(p->Get(v8_str("x"))->IsUndefined());
+
+ // Setting a new property should not be forwarded to the hidden
prototype.
+ o->Set(v8_str("y"), v8_num(6));
+ CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
+ CHECK(h->Get(v8_str("y"))->IsUndefined());
+ CHECK(p->Get(v8_str("y"))->IsUndefined());
+
+ // Setting a property that only exists on a prototype of the hidden
prototype
+ // is treated normally again.
+ p->Set(v8_str("z"), v8_num(8));
+ CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
+ CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
+ CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
+ o->Set(v8_str("z"), v8_num(9));
+ CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
+ CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
+ CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
+}
+
+
+// Regression test for issue 2457.
+THREADED_TEST(HiddenPrototypeIdentityHash) {
+ v8::HandleScope handle_scope;
+ LocalContext context;
+
+ Handle<FunctionTemplate> t = FunctionTemplate::New();
+ t->SetHiddenPrototype(true);
+ t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
+ Handle<Object> p = t->GetFunction()->NewInstance();
+ Handle<Object> o = Object::New();
+ o->SetPrototype(p);
+
+ int hash = o->GetIdentityHash();
+ USE(hash);
+ o->Set(v8_str("foo"), v8_num(42));
+ ASSERT_EQ(hash, o->GetIdentityHash());
+}
THREADED_TEST(SetPrototype) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev