Always check the prototype chain for a setter, when setting a property
that does not exist locally. Previously, map transitions broke this check. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@25 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
dceb5f6a8f
commit
0a7584af2c
@ -297,14 +297,18 @@ enum InlineCacheState {
|
||||
|
||||
|
||||
// Type of properties.
|
||||
// Order of properties is significant.
|
||||
// Must fit in the BitField PropertyDetails::TypeField.
|
||||
// A copy of this is in mirror-delay.js.
|
||||
enum PropertyType {
|
||||
NORMAL = 0, // only in slow mode
|
||||
MAP_TRANSITION = 1, // only in fast mode
|
||||
FIELD = 1, // only in fast mode
|
||||
CONSTANT_FUNCTION = 2, // only in fast mode
|
||||
FIELD = 3, // only in fast mode
|
||||
CALLBACKS = 4,
|
||||
CONSTANT_TRANSITION = 5, // only in fast mode
|
||||
INTERCEPTOR = 6,
|
||||
CALLBACKS = 3,
|
||||
INTERCEPTOR = 4, // only in lookup results, not in descriptors.
|
||||
FIRST_PHANTOM_PROPERTY_TYPE = 5, // All properties before this are real.
|
||||
MAP_TRANSITION = 5, // only in fast mode
|
||||
CONSTANT_TRANSITION = 6, // only in fast mode
|
||||
NULL_DESCRIPTOR = 7 // only in fast mode
|
||||
};
|
||||
|
||||
|
@ -94,14 +94,17 @@ PropertyKind.Named = 1;
|
||||
PropertyKind.Indexed = 2;
|
||||
|
||||
|
||||
// Different types of properties. NOTE value 1 is missing as it is used
|
||||
// internally for map transition.
|
||||
// A copy of the PropertyType enum from global.h
|
||||
PropertyType = {};
|
||||
PropertyType.Normal = 0;
|
||||
PropertyType.Field = 1;
|
||||
PropertyType.ConstantFunction = 2;
|
||||
PropertyType.Field = 3;
|
||||
PropertyType.Callbacks = 4;
|
||||
PropertyType.Interceptor = 5;
|
||||
PropertyType.Callbacks = 3;
|
||||
PropertyType.Interceptor = 4;
|
||||
PropertyType.MapTransition = 5;
|
||||
PropertyType.ConstantTransition = 6;
|
||||
PropertyType.NullDescriptor = 7;
|
||||
|
||||
|
||||
|
||||
// Different attributes for a property.
|
||||
|
@ -1507,12 +1507,27 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
||||
return SetPropertyWithFailedAccessCheck(result, name, value);
|
||||
}
|
||||
|
||||
if (result->IsValid()) {
|
||||
if (result->IsNotFound() || !result->IsProperty()) {
|
||||
// We could not find a local property so let's check whether there is an
|
||||
// accessor that wants to handle the property.
|
||||
LookupResult accessor_result;
|
||||
LookupCallbackSetterInPrototypes(name, &accessor_result);
|
||||
if (accessor_result.IsValid()) {
|
||||
return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
|
||||
name,
|
||||
value,
|
||||
accessor_result.holder());
|
||||
}
|
||||
}
|
||||
if (result->IsNotFound()) {
|
||||
return AddProperty(name, value, attributes);
|
||||
}
|
||||
if (!result->IsLoaded()) {
|
||||
return SetLazyProperty(result, name, value, attributes);
|
||||
}
|
||||
if (result->IsReadOnly() && !result->IsTransitionType()) return value;
|
||||
if (result->IsReadOnly() && result->IsProperty()) return value;
|
||||
// This is a real property that is not read-only, or it is a
|
||||
// transition or null descriptor and there are no setters in the prototypes.
|
||||
switch (result->type()) {
|
||||
case NORMAL:
|
||||
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
|
||||
@ -1522,7 +1537,7 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
return value;
|
||||
case MAP_TRANSITION:
|
||||
if (attributes == result->GetAttributes()) {
|
||||
// Only use map transition if attributes matches.
|
||||
// Only use map transition if the attributes match.
|
||||
return AddFastPropertyUsingMap(result->GetTransitionMap(),
|
||||
name,
|
||||
value);
|
||||
@ -1550,21 +1565,8 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// We could not find a local property so let's check whether there is an
|
||||
// accessor that wants to handle the property.
|
||||
LookupResult accessor_result;
|
||||
LookupCallbackSetterInPrototypes(name, &accessor_result);
|
||||
if (accessor_result.IsValid()) {
|
||||
return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
|
||||
name,
|
||||
value,
|
||||
accessor_result.holder());
|
||||
}
|
||||
|
||||
// The property was not found
|
||||
return AddProperty(name, value, attributes);
|
||||
UNREACHABLE();
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,11 +231,12 @@ class LookupResult BASE_EMBEDDED {
|
||||
bool IsDontEnum() { return details_.IsDontEnum(); }
|
||||
|
||||
bool IsValid() { return lookup_type_ != NOT_FOUND; }
|
||||
bool IsNotFound() { return lookup_type_ == NOT_FOUND; }
|
||||
|
||||
// Tells whether the result is a property.
|
||||
// Excluding transitions.
|
||||
// Excluding transitions and the null descriptor.
|
||||
bool IsProperty() {
|
||||
return IsValid() && !IsTransitionType();
|
||||
return IsValid() && type() < FIRST_PHANTOM_PROPERTY_TYPE;
|
||||
}
|
||||
|
||||
bool IsCacheable() { return cacheable_; }
|
||||
|
Loading…
Reference in New Issue
Block a user