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:
lrn@chromium.org 2011-01-06 14:00:50 +00:00
parent dde853a4ad
commit a50e69bda5
10 changed files with 89 additions and 65 deletions

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);