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
This commit is contained in:
parent
a2a002be0d
commit
75dac95604
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -8233,6 +8233,66 @@ THREADED_TEST(HiddenPrototype) {
|
||||
}
|
||||
|
||||
|
||||
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::HandleScope handle_scope;
|
||||
LocalContext context;
|
||||
|
Loading…
Reference in New Issue
Block a user