From: rossberg@chromium.org Date: Wed, 19 Dec 2012 15:17:01 +0000 (+0000) Subject: Fix treatment of hidden prototypes in SetProperty. X-Git-Tag: upstream/4.7.83~15408 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=75dac956045fd896549c56eca3051904057297d0;p=platform%2Fupstream%2Fv8.git Fix treatment of hidden prototypes in SetProperty. R=svenpanne@chromium.org BUG=v8:2457 Review URL: https://codereview.chromium.org/11644021 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13245 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/objects.cc b/src/objects.cc index cea724f..8175341 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2920,6 +2920,9 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, 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. HandleScope scope(isolate); @@ -2961,10 +2964,10 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, 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 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, 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 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, 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 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, 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); } } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 60405a6..a30fbda 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -8233,6 +8233,66 @@ THREADED_TEST(HiddenPrototype) { } +THREADED_TEST(HiddenPrototypeSet) { + v8::HandleScope handle_scope; + LocalContext context; + + Local ot = v8::FunctionTemplate::New(); + Local ht = v8::FunctionTemplate::New(); + ht->SetHiddenPrototype(true); + Local pt = v8::FunctionTemplate::New(); + ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); + + Local o = ot->GetFunction()->NewInstance(); + Local h = ht->GetFunction()->NewInstance(); + Local 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 t = FunctionTemplate::New(); + t->SetHiddenPrototype(true); + t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); + Handle p = t->GetFunction()->NewInstance(); + Handle 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::HandleScope handle_scope; LocalContext context;