| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 3347)
|
| +++ src/runtime.cc (working copy)
|
| @@ -788,51 +788,72 @@
|
| // case of callbacks in the prototype chain (this rules out using
|
| // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
|
| // 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;
|
| - global->LocalLookup(*name, &lookup);
|
| - if (!lookup.IsProperty()) {
|
| - if (assign) {
|
| - return global->IgnoreAttributesAndSetLocalProperty(*name,
|
| - args[1],
|
| - attributes);
|
| + while (true) {
|
| + real_holder->LocalLookup(*name, &lookup);
|
| + if (lookup.IsProperty()) {
|
| + // Determine if this is a redeclaration of something read-only.
|
| + if (lookup.IsReadOnly()) {
|
| + // 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();
|
| - }
|
|
|
| - // Determine if this is a redeclaration of something read-only.
|
| - if (lookup.IsReadOnly()) {
|
| - return ThrowRedeclarationError("const", name);
|
| - }
|
| + Object* proto = real_holder->GetPrototype();
|
| + if (!proto->IsJSObject())
|
| + break;
|
|
|
| - // 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 (!JSObject::cast(proto)->map()->is_hidden_prototype())
|
| + break;
|
| +
|
| + real_holder = JSObject::cast(proto);
|
| }
|
|
|
| - if (found && !assign) {
|
| - // The global property is there and we're not assigning any value
|
| - // to it. Just return.
|
| - return Heap::undefined_value();
|
| + global = Top::context()->global();
|
| + if (assign) {
|
| + return global->IgnoreAttributesAndSetLocalProperty(*name,
|
| + args[1],
|
| + attributes);
|
| }
|
| -
|
| - // Assign the value (or undefined) to the property.
|
| - Object* value = (assign) ? args[1] : Heap::undefined_value();
|
| - return global->SetProperty(&lookup, *name, value, attributes);
|
| + return Heap::undefined_value();
|
| }
|
|
|
|
|
|
|