Avoid calling inherited setters when creating object literals and their boilerplates.
Fix issue 1015. Review URL: http://codereview.chromium.org/6118001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6205 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
dde853a4ad
commit
a50e69bda5
@ -126,7 +126,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
|
||||
// This means one of the object's prototypes is a JSArray and
|
||||
// the object does not have a 'length' property.
|
||||
// Calling SetProperty causes an infinite loop.
|
||||
return object->IgnoreAttributesAndSetLocalProperty(Heap::length_symbol(),
|
||||
return object->SetLocalPropertyIgnoreAttributes(Heap::length_symbol(),
|
||||
value, NONE);
|
||||
}
|
||||
}
|
||||
|
@ -280,13 +280,13 @@ Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> IgnoreAttributesAndSetLocalProperty(
|
||||
Handle<Object> SetLocalPropertyIgnoreAttributes(
|
||||
Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes) {
|
||||
CALL_HEAP_FUNCTION(object->
|
||||
IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
|
||||
SetLocalPropertyIgnoreAttributes(*key, *value, attributes), Object);
|
||||
}
|
||||
|
||||
|
||||
@ -422,6 +422,15 @@ Handle<Object> SetElement(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> SetOwnElement(Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
Handle<Object> value) {
|
||||
ASSERT(!object->HasPixelElements());
|
||||
ASSERT(!object->HasExternalArrayElements());
|
||||
CALL_HEAP_FUNCTION(object->SetElement(index, *value, false), Object);
|
||||
}
|
||||
|
||||
|
||||
Handle<JSObject> Copy(Handle<JSObject> obj) {
|
||||
CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
|
||||
}
|
||||
|
@ -217,7 +217,8 @@ Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
|
||||
Handle<Object> key);
|
||||
|
||||
Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
|
||||
Handle<Object> SetLocalPropertyIgnoreAttributes(
|
||||
Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
@ -231,6 +232,10 @@ Handle<Object> SetElement(Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
Handle<Object> value);
|
||||
|
||||
Handle<Object> SetOwnElement(Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
Handle<Object> value);
|
||||
|
||||
Handle<Object> GetProperty(Handle<JSObject> obj,
|
||||
const char* name);
|
||||
|
||||
|
@ -521,10 +521,6 @@ void Heap::SetLastScriptId(Object* last_script_id) {
|
||||
CALL_AND_RETRY(FUNCTION_CALL, return, return)
|
||||
|
||||
|
||||
#define CALL_HEAP_FUNCTION_INLINE(FUNCTION_CALL) \
|
||||
CALL_AND_RETRY(FUNCTION_CALL, break, break)
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
inline bool Heap::allow_allocation(bool new_state) {
|
||||
|
@ -1823,8 +1823,9 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
|
||||
// We only need to deal with CALLBACKS and INTERCEPTORS
|
||||
MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
|
||||
String* name,
|
||||
Object* value) {
|
||||
if (!result->IsProperty()) {
|
||||
Object* value,
|
||||
bool check_prototype) {
|
||||
if (check_prototype && !result->IsProperty()) {
|
||||
LookupCallbackSetterInPrototypes(name, result);
|
||||
}
|
||||
|
||||
@ -1850,7 +1851,8 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
|
||||
LookupResult r;
|
||||
LookupRealNamedProperty(name, &r);
|
||||
if (r.IsProperty()) {
|
||||
return SetPropertyWithFailedAccessCheck(&r, name, value);
|
||||
return SetPropertyWithFailedAccessCheck(&r, name, value,
|
||||
check_prototype);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1891,7 +1893,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
|
||||
// Check access rights if needed.
|
||||
if (IsAccessCheckNeeded()
|
||||
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
||||
return SetPropertyWithFailedAccessCheck(result, name, value);
|
||||
return SetPropertyWithFailedAccessCheck(result, name, value, true);
|
||||
}
|
||||
|
||||
if (IsJSGlobalProxy()) {
|
||||
@ -1981,7 +1983,7 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
|
||||
// callback setter removed. The two lines looking up the LookupResult
|
||||
// result are also added. If one of the functions is changed, the other
|
||||
// should be.
|
||||
MaybeObject* JSObject::IgnoreAttributesAndSetLocalProperty(
|
||||
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes) {
|
||||
@ -1993,14 +1995,14 @@ MaybeObject* JSObject::IgnoreAttributesAndSetLocalProperty(
|
||||
// Check access rights if needed.
|
||||
if (IsAccessCheckNeeded()
|
||||
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
||||
return SetPropertyWithFailedAccessCheck(&result, name, value);
|
||||
return SetPropertyWithFailedAccessCheck(&result, name, value, false);
|
||||
}
|
||||
|
||||
if (IsJSGlobalProxy()) {
|
||||
Object* proto = GetPrototype();
|
||||
if (proto->IsNull()) return value;
|
||||
ASSERT(proto->IsJSGlobalObject());
|
||||
return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty(
|
||||
return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
|
||||
name,
|
||||
value,
|
||||
attributes);
|
||||
|
@ -1341,7 +1341,8 @@ class JSObject: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck(
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
Object* value);
|
||||
Object* value,
|
||||
bool check_prototype);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithCallback(Object* structure,
|
||||
String* name,
|
||||
Object* value,
|
||||
@ -1356,7 +1357,7 @@ class JSObject: public HeapObject {
|
||||
String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
MUST_USE_RESULT MaybeObject* IgnoreAttributesAndSetLocalProperty(
|
||||
MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
|
||||
String* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
|
@ -3660,11 +3660,9 @@ Handle<Object> JsonParser::ParseJsonObject() {
|
||||
if (value.is_null()) return Handle<Object>::null();
|
||||
uint32_t index;
|
||||
if (key->AsArrayIndex(&index)) {
|
||||
CALL_HEAP_FUNCTION_INLINE(
|
||||
(*json_object)->SetElement(index, *value, true));
|
||||
SetOwnElement(json_object, index, value);
|
||||
} else {
|
||||
CALL_HEAP_FUNCTION_INLINE(
|
||||
(*json_object)->SetPropertyPostInterceptor(*key, *value, NONE));
|
||||
SetLocalPropertyIgnoreAttributes(json_object, key, value, NONE);
|
||||
}
|
||||
} while (scanner_.Next() == Token::COMMA);
|
||||
if (scanner_.current_token() != Token::RBRACE) {
|
||||
|
@ -330,13 +330,18 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
Handle<Object> result;
|
||||
uint32_t element_index = 0;
|
||||
if (key->IsSymbol()) {
|
||||
// If key is a symbol it is not an array element.
|
||||
if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
|
||||
// Array index as string (uint32).
|
||||
result = SetOwnElement(boilerplate, element_index, value);
|
||||
} else {
|
||||
Handle<String> name(String::cast(*key));
|
||||
ASSERT(!name->AsArrayIndex(&element_index));
|
||||
result = SetProperty(boilerplate, name, value, NONE);
|
||||
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
|
||||
value, NONE);
|
||||
}
|
||||
} else if (key->ToArrayIndex(&element_index)) {
|
||||
// Array index (uint32).
|
||||
result = SetElement(boilerplate, element_index, value);
|
||||
result = SetOwnElement(boilerplate, element_index, value);
|
||||
} else {
|
||||
// Non-uint32 number.
|
||||
ASSERT(key->IsNumber());
|
||||
@ -345,7 +350,8 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
|
||||
Vector<char> buffer(arr, ARRAY_SIZE(arr));
|
||||
const char* str = DoubleToCString(num, buffer);
|
||||
Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
|
||||
result = SetProperty(boilerplate, name, value, NONE);
|
||||
result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
|
||||
value, NONE);
|
||||
}
|
||||
// If setting the property on the boilerplate throws an
|
||||
// exception, the exception is converted to an empty handle in
|
||||
@ -984,7 +990,7 @@ static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
|
||||
// of callbacks in the prototype chain (this rules out using
|
||||
// SetProperty). Also, we must use the handle-based version to
|
||||
// avoid GC issues.
|
||||
IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
|
||||
SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1099,7 +1105,7 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
|
||||
// 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 IgnoreAttributesAndSetLocalProperty for
|
||||
// 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.
|
||||
@ -1162,7 +1168,7 @@ static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
|
||||
|
||||
global = Top::context()->global();
|
||||
if (assign) {
|
||||
return global->IgnoreAttributesAndSetLocalProperty(*name,
|
||||
return global->SetLocalPropertyIgnoreAttributes(*name,
|
||||
args[1],
|
||||
attributes);
|
||||
}
|
||||
@ -1190,11 +1196,11 @@ static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
|
||||
// there, we add the property and 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 use IgnoreAttributesAndSetLocalProperty instead
|
||||
// We use SetLocalPropertyIgnoreAttributes instead
|
||||
LookupResult lookup;
|
||||
global->LocalLookup(*name, &lookup);
|
||||
if (!lookup.IsProperty()) {
|
||||
return global->IgnoreAttributesAndSetLocalProperty(*name,
|
||||
return global->SetLocalPropertyIgnoreAttributes(*name,
|
||||
*value,
|
||||
attributes);
|
||||
}
|
||||
@ -1467,25 +1473,25 @@ static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
|
||||
PropertyAttributes writable =
|
||||
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
|
||||
MaybeObject* result;
|
||||
result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
|
||||
result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
|
||||
source,
|
||||
final);
|
||||
ASSERT(!result->IsFailure());
|
||||
result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
|
||||
result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
|
||||
global,
|
||||
final);
|
||||
ASSERT(!result->IsFailure());
|
||||
result =
|
||||
regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
|
||||
regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
|
||||
ignoreCase,
|
||||
final);
|
||||
ASSERT(!result->IsFailure());
|
||||
result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
|
||||
result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
|
||||
multiline,
|
||||
final);
|
||||
ASSERT(!result->IsFailure());
|
||||
result =
|
||||
regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
|
||||
regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
|
||||
Smi::FromInt(0),
|
||||
writable);
|
||||
ASSERT(!result->IsFailure());
|
||||
@ -3571,7 +3577,7 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
|
||||
NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
// Use IgnoreAttributes version since a readonly property may be
|
||||
// overridden and SetProperty does not allow this.
|
||||
return js_object->IgnoreAttributesAndSetLocalProperty(*name,
|
||||
return js_object->SetLocalPropertyIgnoreAttributes(*name,
|
||||
*obj_value,
|
||||
attr);
|
||||
}
|
||||
@ -3674,7 +3680,7 @@ MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
|
||||
} else {
|
||||
Handle<String> key_string = Handle<String>::cast(key);
|
||||
key_string->TryFlatten();
|
||||
return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
|
||||
return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
|
||||
*value,
|
||||
attr);
|
||||
}
|
||||
@ -3689,7 +3695,7 @@ MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
return js_object->SetElement(index, *value);
|
||||
} else {
|
||||
return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
|
||||
return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3771,7 +3777,7 @@ static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
|
||||
}
|
||||
|
||||
return object->
|
||||
IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
|
||||
SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,9 +30,16 @@
|
||||
|
||||
// See http://code.google.com/p/v8/issues/detail?id=192
|
||||
|
||||
// UPDATE: This bug report is no longer valid. In ES5, creating object
|
||||
// literals MUST NOT trigger inherited accessors, but act as if creating
|
||||
// the properties using DefineOwnProperty.
|
||||
|
||||
Object.prototype.__defineGetter__("x", function() {});
|
||||
Object.prototype.__defineSetter__("y",
|
||||
function() { assertUnreachable("setter"); });
|
||||
|
||||
// Creating this object literal will throw an exception because we are
|
||||
// Creating this object literal will *not* throw an exception because we are
|
||||
// assigning to a property that has only a getter.
|
||||
assertThrows("({ x: 42 })");
|
||||
|
||||
var x = ({ x: 42, y: 37 });
|
||||
assertEquals(42, x.x);
|
||||
assertEquals(37, x.y);
|
||||
|
Loading…
Reference in New Issue
Block a user