Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index a6670bf718795e7069b5198fa8b0493614fa3846..48ff69f5d273071e0615743e2b2760f2abb71e70 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -1051,12 +1051,6 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) { |
// Fall-through and introduce the absent property by using |
// SetProperty. |
} else { |
- // For const properties, we treat a callback with this name |
- // even in the prototype as a conflicting declaration. |
- if (is_const_property && (lookup.type() == CALLBACKS)) { |
- return ThrowRedeclarationError("const", name); |
- } |
- // Otherwise, we check for locally conflicting declarations. |
if (is_local && (is_read_only || is_const_property)) { |
const char* type = (is_read_only) ? "const" : "var"; |
return ThrowRedeclarationError(type, name); |
@@ -1082,20 +1076,30 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) { |
? static_cast<PropertyAttributes>(base | READ_ONLY) |
: base; |
- // There's a local property that we need to overwrite because |
- // we're either declaring a function or there's an interceptor |
- // that claims the property is absent. |
- // |
- // Check for conflicting re-declarations. We cannot have |
- // conflicting types in case of intercepted properties because |
- // they are absent. |
- if (lookup.IsProperty() && |
- (lookup.type() != INTERCEPTOR) && |
- (lookup.IsReadOnly() || is_const_property)) { |
- const char* type = (lookup.IsReadOnly()) ? "const" : "var"; |
- return ThrowRedeclarationError(type, name); |
+ if (lookup.IsProperty()) { |
+ // There's a local property that we need to overwrite because |
+ // we're either declaring a function or there's an interceptor |
+ // that claims the property is absent. |
+ |
+ // Check for conflicting re-declarations. We cannot have |
+ // conflicting types in case of intercepted properties because |
+ // they are absent. |
+ if (lookup.type() != INTERCEPTOR && |
+ (lookup.IsReadOnly() || is_const_property)) { |
+ const char* type = (lookup.IsReadOnly()) ? "const" : "var"; |
+ return ThrowRedeclarationError(type, name); |
+ } |
+ RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes)); |
+ } else { |
+ // If a property with this name does not already exist on the |
+ // global object add the property locally. We take special |
+ // precautions to always add it as a local property even in case |
+ // of callbacks in the prototype chain (this rules out using |
+ // SetProperty). Also, we must use the handle-based version to |
+ // avoid GC issues. |
+ RETURN_IF_EMPTY_HANDLE( |
+ SetLocalPropertyIgnoreAttributes(global, name, value, attributes)); |
} |
- RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes)); |
} |
ASSERT(!Top::has_pending_exception()); |
@@ -1182,20 +1186,6 @@ static MaybeObject* Runtime_DeclareContextSlot(Arguments args) { |
ASSERT(!context_ext->HasLocalProperty(*name)); |
Handle<Object> value(Heap::undefined_value()); |
if (*initial_value != NULL) value = initial_value; |
- // Declaring a const context slot is a conflicting declaration if |
- // there is a callback with that name in a prototype. It is |
- // allowed to introduce const variables in |
- // JSContextExtensionObjects. They are treated specially in |
- // SetProperty and no setters are invoked for those since they are |
- // not real JSObjects. |
- if (initial_value->IsTheHole() && |
- !context_ext->IsJSContextExtensionObject()) { |
- LookupResult lookup; |
- context_ext->Lookup(*name, &lookup); |
- if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) { |
- return ThrowRedeclarationError("const", name); |
- } |
- } |
RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode)); |
} |
@@ -1222,7 +1212,11 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) { |
// there, there is a property with this name in the prototype chain. |
// We follow Safari and Firefox behavior and only set the property |
// locally if there is an explicit initialization value that we have |
- // to assign to the property. |
+ // to assign to the property. When adding the property we take |
+ // special precautions to always add it as a local property even in |
+ // case of callbacks in the prototype chain (this rules out using |
+ // SetProperty). We have SetLocalPropertyIgnoreAttributes 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; |
@@ -1283,7 +1277,11 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) { |
} |
global = Top::context()->global(); |
- if (assign) return global->SetProperty(*name, args[1], attributes); |
+ if (assign) { |
+ return global->SetLocalPropertyIgnoreAttributes(*name, |
+ args[1], |
+ attributes); |
+ } |
return Heap::undefined_value(); |
} |