When processing global vars initialization account for the case of splitted

global object (using hidden prototypes):

1) setters might be not on the global object itself, but on its prototypes;
2) if property on one of prototypes is readonly, we could shadow it.
Review URL: http://codereview.chromium.org/434035

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3362 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
antonm@chromium.org 2009-11-25 15:45:37 +00:00
parent c5052399e4
commit 93d6199de0

View File

@ -788,51 +788,72 @@ static Object* Runtime_InitializeVarGlobal(Arguments args) {
// case of callbacks in the prototype chain (this rules out using // case of callbacks in the prototype chain (this rules out using
// SetProperty). We have IgnoreAttributesAndSetLocalProperty for // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
// this. // this.
// Note that objects can have hidden prototypes, so we need to traverse
// the whole chain of hidden prototypes to do a 'local' lookup.
JSObject* real_holder = global;
LookupResult lookup; LookupResult lookup;
global->LocalLookup(*name, &lookup); while (true) {
if (!lookup.IsProperty()) { real_holder->LocalLookup(*name, &lookup);
if (assign) { if (lookup.IsProperty()) {
return global->IgnoreAttributesAndSetLocalProperty(*name, // Determine if this is a redeclaration of something read-only.
args[1], if (lookup.IsReadOnly()) {
attributes); // If we found readonly property on one of hidden prototypes,
// just shadow it.
if (real_holder != Top::context()->global()) break;
return ThrowRedeclarationError("const", name);
}
// Determine if this is a redeclaration of an intercepted read-only
// property and figure out if the property exists at all.
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
HandleScope handle_scope;
Handle<JSObject> holder(real_holder);
PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
real_holder = *holder;
if (intercepted == ABSENT) {
// The interceptor claims the property isn't there. We need to
// make sure to introduce it.
found = false;
} else if ((intercepted & READ_ONLY) != 0) {
// The property is present, but read-only. Since we're trying to
// overwrite it with a variable declaration we must throw a
// re-declaration error. However if we found readonly property
// on one of hidden prototypes, just shadow it.
if (real_holder != Top::context()->global()) break;
return ThrowRedeclarationError("const", name);
}
}
if (found && !assign) {
// The global property is there and we're not assigning any value
// to it. Just return.
return Heap::undefined_value();
}
// Assign the value (or undefined) to the property.
Object* value = (assign) ? args[1] : Heap::undefined_value();
return real_holder->SetProperty(&lookup, *name, value, attributes);
} }
return Heap::undefined_value();
Object* proto = real_holder->GetPrototype();
if (!proto->IsJSObject())
break;
if (!JSObject::cast(proto)->map()->is_hidden_prototype())
break;
real_holder = JSObject::cast(proto);
} }
// Determine if this is a redeclaration of something read-only. global = Top::context()->global();
if (lookup.IsReadOnly()) { if (assign) {
return ThrowRedeclarationError("const", name); return global->IgnoreAttributesAndSetLocalProperty(*name,
args[1],
attributes);
} }
return Heap::undefined_value();
// Determine if this is a redeclaration of an intercepted read-only
// property and figure out if the property exists at all.
bool found = true;
PropertyType type = lookup.type();
if (type == INTERCEPTOR) {
PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
if (intercepted == ABSENT) {
// The interceptor claims the property isn't there. We need to
// make sure to introduce it.
found = false;
} else if ((intercepted & READ_ONLY) != 0) {
// The property is present, but read-only. Since we're trying to
// overwrite it with a variable declaration we must throw a
// re-declaration error.
return ThrowRedeclarationError("const", name);
}
// Restore global object from context (in case of GC).
global = Top::context()->global();
}
if (found && !assign) {
// The global property is there and we're not assigning any value
// to it. Just return.
return Heap::undefined_value();
}
// Assign the value (or undefined) to the property.
Object* value = (assign) ? args[1] : Heap::undefined_value();
return global->SetProperty(&lookup, *name, value, attributes);
} }