Chromium Code Reviews| Index: src/runtime.cc |
| =================================================================== |
| --- src/runtime.cc (revision 1118) |
| +++ src/runtime.cc (working copy) |
| @@ -758,56 +758,94 @@ |
| int index; |
| PropertyAttributes attributes; |
| - ContextLookupFlags flags = DONT_FOLLOW_CHAINS; |
| + ContextLookupFlags flags = FOLLOW_CHAINS; |
| Handle<Object> holder = |
| context->Lookup(name, flags, &index, &attributes); |
| - // The property should always be present. It is always declared |
| - // before being initialized through DeclareContextSlot. |
| - ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0); |
| - |
| - // If the slot is in the context, we set it but only if it hasn't |
| - // been set before. |
| + // In most situations, the property introduced by the const |
| + // declaration should be present in the context extension object. |
| + // However, because declaration and initialization are separate, the |
| + // property might have been deleted (if it was introduced by eval) |
| + // before we reach the initialization point. |
| + // |
| + // Example: |
| + // |
| + // function f() { eval("delete x; const x;"); } |
| + // |
| + // In that case, the initialization behaves like a normal assignment |
| + // to property 'x'. |
| if (index >= 0) { |
| - // The constant context slot should always be in the function |
| - // context; not in any outer context nor in the arguments object. |
| - ASSERT(holder.is_identical_to(context)); |
| - if (context->get(index)->IsTheHole()) { |
| - context->set(index, *value); |
| + // Property was found in a context. |
| + if (holder->IsContext()) { |
| + // The holder cannot be the function context. If it is, there |
| + // should have been a const redeclaration error when declaring |
| + // the const property. |
| + ASSERT(!holder.is_identical_to(context)); |
| + if ((attributes & READ_ONLY) == 0) { |
| + Handle<Context>::cast(holder)->set(index, *value); |
| + } |
| + } else { |
| + // The holder is an arguments object. |
| + ASSERT((attributes & READ_ONLY) == 0); |
| + Handle<JSObject>::cast(holder)->SetElement(index, *value); |
| } |
| return *value; |
| } |
| - // Otherwise, the slot must be in a JS object extension. |
| - Handle<JSObject> context_ext(JSObject::cast(*holder)); |
| + // The property could not be found, we introduce it in the global |
| + // context. |
| + if (attributes == ABSENT) { |
| + Handle<JSObject> global = Handle<JSObject>(Top::context()->global()); |
| + SetProperty(global, name, value, NONE); |
| + return *value; |
| + } |
| - // We must initialize the value only if it wasn't initialized |
| - // before, e.g. for const declarations in a loop. The property has |
| - // the hole value if it wasn't initialized yet. NOTE: We cannot use |
| - // GetProperty() to get the current value as it 'unholes' the value. |
| - LookupResult lookup; |
| - context_ext->LocalLookupRealNamedProperty(*name, &lookup); |
| - ASSERT(lookup.IsProperty()); // the property was declared |
| - ASSERT(lookup.IsReadOnly()); // and it was declared as read-only |
| + // The property was present in a context extension object. |
| + Handle<JSObject> context_ext = Handle<JSObject>::cast(holder); |
| - PropertyType type = lookup.type(); |
| - if (type == FIELD) { |
| - FixedArray* properties = context_ext->properties(); |
| - int index = lookup.GetFieldIndex(); |
| - if (properties->get(index)->IsTheHole()) { |
| - properties->set(index, *value); |
| + if (*context_ext == context->extension()) { |
| + // This is the property that was introduced by the const |
| + // declaration. Set it if it hasn't been set before. NOTE: We |
| + // cannot use GetProperty() to get the current value as it |
| + // 'unholes' the value. |
| + LookupResult lookup; |
| + context_ext->LocalLookupRealNamedProperty(*name, &lookup); |
| + ASSERT(lookup.IsProperty()); // the property was declared |
| + ASSERT(lookup.IsReadOnly()); // and it was declared as read-only |
| + |
| + PropertyType type = lookup.type(); |
| + if (type == FIELD) { |
| + FixedArray* properties = context_ext->properties(); |
| + int index = lookup.GetFieldIndex(); |
| + if (properties->get(index)->IsTheHole()) { |
| + properties->set(index, *value); |
| + } |
| + } else if (type == NORMAL) { |
| + Dictionary* dictionary = context_ext->property_dictionary(); |
| + int entry = lookup.GetDictionaryEntry(); |
| + if (dictionary->ValueAt(entry)->IsTheHole()) { |
| + dictionary->ValueAtPut(entry, *value); |
| + } |
| + } else { |
| + // We should not reach here. Any real, named property should be |
| + // either a field or a dictionary slot. |
| + UNREACHABLE(); |
| } |
| - } else if (type == NORMAL) { |
| - Dictionary* dictionary = context_ext->property_dictionary(); |
| - int entry = lookup.GetDictionaryEntry(); |
| - if (dictionary->ValueAt(entry)->IsTheHole()) { |
| - dictionary->ValueAtPut(entry, *value); |
| + } else { |
| + // The property was found in a different context extension object. |
| + // Set it if it is not a read_only property. |
|
Kasper Lund
2009/01/22 13:38:47
read-only with a - instead of _?
|
| + if ((attributes & READ_ONLY) == 0) { |
| + Handle<Object> set = SetProperty(context_ext, name, value, attributes); |
| + // Setting a property might throw an exception. Exceptions |
| + // are converted to empty handles in handle operations. We |
| + // need to convert back to excpetions here. |
|
Kasper Lund
2009/01/22 13:38:47
exceptions
|
| + if (set.is_null()) { |
| + ASSERT(Top::has_pending_exception()); |
| + return Failure::Exception(); |
| + } |
| } |
| - } else { |
| - // We should not reach here. Any real, named property should be |
| - // either a field or a dictionary slot. |
| - UNREACHABLE(); |
| } |
| + |
| return *value; |
| } |