Revision: 6205
Author: [email protected]
Date: Thu Jan 6 06:00:50 2011
Log: Avoid calling inherited setters when creating object literals and
their boilerplates.
Fix issue 1015.
Review URL: http://codereview.chromium.org/6118001
http://code.google.com/p/v8/source/detail?r=6205
Added:
/branches/bleeding_edge/test/mjsunit/regress/regress-1015.js
Deleted:
/branches/bleeding_edge/test/mjsunit/bugs/bug-1015.js
Modified:
/branches/bleeding_edge/src/accessors.cc
/branches/bleeding_edge/src/handles.cc
/branches/bleeding_edge/src/handles.h
/branches/bleeding_edge/src/heap-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/test/mjsunit/regress/regress-192.js
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-1015.js Thu Jan 6
06:00:50 2011
@@ -0,0 +1,66 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See: http://code.google.com/p/v8/issues/detail?id=1015
+
+// Object and array literals should be created using DefineOwnProperty, and
+// therefore not hit setters in the prototype.
+
+function mkFail(message) {
+ return function () { assertUnreachable(message); }
+}
+
+Object.defineProperty(Object.prototype, "foo",
+ {get: mkFail("oget"), set: mkFail("oset")});
+Object.defineProperty(Array.prototype, "2",
+ {get: mkFail("aget"), set: mkFail("aset")});
+
+function inFunction() {
+ for (var i = 0; i < 10; i++) {
+ // in loop.
+ var ja = JSON.parse('[1,2,3,4]');
+ var jo = JSON.parse('{"bar": 10, "foo": 20}')
+ var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}')
+ var a = [1,2,3,4];
+ var o = { bar: 10, foo: 20 };
+ var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } },
+ bar: 10 };
+ }
+}
+
+for (var i = 0; i < 10; i++) {
+ // In global scope.
+ var ja = JSON.parse('[1,2,3,4]');
+ var jo = JSON.parse('{"bar": 10, "foo": 20}')
+ var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}')
+ var a = [1,2,3,4];
+ var o = { bar: 10, foo: 20 };
+ var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } },
+ bar: 10 };
+ // In function scope.
+ inFunction();
+}
=======================================
--- /branches/bleeding_edge/test/mjsunit/bugs/bug-1015.js Tue Jan 4
05:14:39 2011
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// See: http://code.google.com/p/v8/issues/detail?id=1015
-
-// Object and array literals should be created using DefineOwnProperty, and
-// therefore not hit setters in the prototype.
-
-function mkFail(message) {
- return function () { assertUnreachable(message); }
-}
-
-Object.defineProperty(Object.prototype, "foo",
- {get: mkFail("oget"), set: mkFail("oset")});
-Object.defineProperty(Array.prototype, "2",
- {get: mkFail("aget"), set: mkFail("aset")});
-
-function inFunction() {
- for (var i = 0; i < 10; i++) {
- // in loop.
- var ja = JSON.parse('[1,2,3,4]');
- var jo = JSON.parse('{"bar": 10, "foo": 20}')
- var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}')
- var a = [1,2,3,4];
- var o = { bar: 10, foo: 20 };
- var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } },
- bar: 10 };
- }
-}
-
-for (var i = 0; i < 10; i++) {
- // In global scope.
- var ja = JSON.parse('[1,2,3,4]');
- var jo = JSON.parse('{"bar": 10, "foo": 20}')
- var jop = JSON.parse('{"bar": 10, "__proto__": { }, "foo": 20}')
- var a = [1,2,3,4];
- var o = { bar: 10, foo: 20 };
- var op = { __proto__: { set bar(v) { assertUnreachable("bset"); } },
- bar: 10 };
- // In function scope.
- inFunction();
-}
=======================================
--- /branches/bleeding_edge/src/accessors.cc Tue Dec 7 03:31:57 2010
+++ /branches/bleeding_edge/src/accessors.cc Thu Jan 6 06:00:50 2011
@@ -126,8 +126,8 @@
// 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(),
- value, NONE);
+ return
object->SetLocalPropertyIgnoreAttributes(Heap::length_symbol(),
+ value, NONE);
}
}
return Top::Throw(*Factory::NewRangeError("invalid_array_length",
=======================================
--- /branches/bleeding_edge/src/handles.cc Tue Dec 7 03:31:57 2010
+++ /branches/bleeding_edge/src/handles.cc Thu Jan 6 06:00:50 2011
@@ -280,13 +280,13 @@
}
-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);
}
@@ -420,6 +420,15 @@
}
CALL_HEAP_FUNCTION(object->SetElement(index, *value), 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) {
=======================================
--- /branches/bleeding_edge/src/handles.h Tue Dec 7 03:31:57 2010
+++ /branches/bleeding_edge/src/handles.h Thu Jan 6 06:00:50 2011
@@ -217,9 +217,10 @@
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
Handle<Object> key);
-Handle<Object> IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,
- Handle<String> key,
- Handle<Object> value,
+Handle<Object> SetLocalPropertyIgnoreAttributes(
+ Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
PropertyAttributes attributes);
Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
@@ -231,6 +232,10 @@
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);
=======================================
--- /branches/bleeding_edge/src/heap-inl.h Tue Jan 4 04:19:55 2011
+++ /branches/bleeding_edge/src/heap-inl.h Thu Jan 6 06:00:50 2011
@@ -521,10 +521,6 @@
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) {
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Jan 4 05:59:34 2011
+++ /branches/bleeding_edge/src/objects.cc Thu Jan 6 06:00:50 2011
@@ -1823,8 +1823,9 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Jan 4 04:19:55 2011
+++ /branches/bleeding_edge/src/objects.h Thu Jan 6 06:00:50 2011
@@ -1341,7 +1341,8 @@
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 @@
String* name,
Object* value,
PropertyAttributes attributes);
- MUST_USE_RESULT MaybeObject* IgnoreAttributesAndSetLocalProperty(
+ MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
String* key,
Object* value,
PropertyAttributes attributes);
=======================================
--- /branches/bleeding_edge/src/parser.cc Wed Jan 5 03:25:42 2011
+++ /branches/bleeding_edge/src/parser.cc Thu Jan 6 06:00:50 2011
@@ -3660,11 +3660,9 @@
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) {
=======================================
--- /branches/bleeding_edge/src/runtime.cc Thu Jan 6 05:14:32 2011
+++ /branches/bleeding_edge/src/runtime.cc Thu Jan 6 06:00:50 2011
@@ -330,13 +330,18 @@
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
- // If key is a symbol it is not an array element.
- Handle<String> name(String::cast(*key));
- ASSERT(!name->AsArrayIndex(&element_index));
- result = SetProperty(boilerplate, name, value, NONE);
+ 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 = 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 @@
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 @@
// 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 @@
// 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,9 +1168,9 @@
global = Top::context()->global();
if (assign) {
- return global->IgnoreAttributesAndSetLocalProperty(*name,
- args[1],
- attributes);
+ return global->SetLocalPropertyIgnoreAttributes(*name,
+ args[1],
+ attributes);
}
return Heap::undefined_value();
}
@@ -1190,13 +1196,13 @@
// 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,
- *value,
- attributes);
+ return global->SetLocalPropertyIgnoreAttributes(*name,
+ *value,
+ attributes);
}
// Determine if this is a redeclaration of something not
@@ -1467,27 +1473,27 @@
PropertyAttributes writable =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
MaybeObject* result;
- result =
regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
- source,
- final);
+ result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
+ source,
+ final);
ASSERT(!result->IsFailure());
- result =
regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
- global,
- final);
+ result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
+ global,
+ final);
ASSERT(!result->IsFailure());
result =
-
regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
- ignoreCase,
- final);
+ regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
+ ignoreCase,
+ final);
ASSERT(!result->IsFailure());
- result =
regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
- multiline,
- final);
+ result =
regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
+ multiline,
+ final);
ASSERT(!result->IsFailure());
result =
-
regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
- Smi::FromInt(0),
- writable);
+ regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
+ Smi::FromInt(0),
+ writable);
ASSERT(!result->IsFailure());
USE(result);
return regexp;
@@ -3571,9 +3577,9 @@
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,
- *obj_value,
- attr);
+ return js_object->SetLocalPropertyIgnoreAttributes(*name,
+ *obj_value,
+ attr);
}
return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
@@ -3674,9 +3680,9 @@
} else {
Handle<String> key_string = Handle<String>::cast(key);
key_string->TryFlatten();
- return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
- *value,
- attr);
+ return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
+ *value,
+ attr);
}
}
@@ -3689,7 +3695,7 @@
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 @@
}
return object->
- IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
+ SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/regress/regress-192.js Tue Dec 7
03:01:02 2010
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-192.js Thu Jan 6
06:00:50 2011
@@ -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() {});
-
-// Creating this object literal will throw an exception because we are
+Object.prototype.__defineSetter__("y",
+ function() {
assertUnreachable("setter"); });
+
+// 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);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev