From: peterhal@chromium.org Date: Thu, 3 Feb 2011 19:29:10 +0000 (+0000) Subject: Fix bugs 992, 1083 and 1092 X-Git-Tag: upstream/4.7.83~20341 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c894b1f317b6c748db9d8a1e151bf2c375b2b6b7;p=platform%2Fupstream%2Fv8.git Fix bugs 992, 1083 and 1092 My previous patch added an assert which uncovered 1092 in the sputnik tests. This patch adds the fix for 1092, which is to ensure that NormalizeProperties does not get called for a JSGlobalProxy along all code paths. Add sputnik tests to .gitignore. BUG= TEST= Review URL: http://codereview.chromium.org/6286060 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6627 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/.gitignore b/.gitignore index d85ef64..c68dadb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ d8_g shell shell_g /obj/ +/test/sputnik/sputniktests/ /tools/oom_dump/oom_dump /tools/oom_dump/oom_dump.o /tools/visual_studio/Debug diff --git a/src/handles.cc b/src/handles.cc index 461c3f5..274c34d 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -873,7 +873,7 @@ OptimizedObjectForAddingMultipleProperties(Handle object, int expected_additional_properties, bool condition) { object_ = object; - if (condition && object_->HasFastProperties()) { + if (condition && object_->HasFastProperties() && !object->IsJSGlobalProxy()) { // Normalize the properties of object to avoid n^2 behavior // when extending the object multiple properties. Indicate the number of // properties to be added. diff --git a/src/objects.cc b/src/objects.cc index 69727d2..524c024 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1213,6 +1213,8 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, MaybeObject* JSObject::AddFastProperty(String* name, Object* value, PropertyAttributes attributes) { + ASSERT(!IsJSGlobalProxy()); + // Normalize the object if the name is an actual string (not the // hidden symbols) and is not a real identifier. StringInputBuffer buffer(name); @@ -2288,6 +2290,9 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode, // The global object is always normalized. ASSERT(!IsGlobalObject()); + // JSGlobalProxy must never be normalized + ASSERT(!IsJSGlobalProxy()); + // Allocate new content. int property_count = map()->NumberOfDescribedProperties(); if (expected_additional_properties > 0) { diff --git a/src/runtime.cc b/src/runtime.cc index 239ba08..0c4237f 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -3602,7 +3602,12 @@ static MaybeObject* Runtime_KeyedGetProperty(Arguments args) { args.at(1)); } - +// Implements part of 8.12.9 DefineOwnProperty. +// There are 3 cases that lead here: +// Step 4b - define a new accessor property. +// Steps 9c & 12 - replace an existing data property with an accessor property. +// Step 12 - update an existing accessor property with an accessor or generic +// descriptor. static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) { ASSERT(args.length() == 5); HandleScope scope; @@ -3634,6 +3639,12 @@ static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) { return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr); } +// Implements part of 8.12.9 DefineOwnProperty. +// There are 3 cases that lead here: +// Step 4a - define a new data property. +// Steps 9b & 12 - replace an existing accessor property with a data property. +// Step 12 - update an existing data property with a data or generic +// descriptor. static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) { ASSERT(args.length() == 4); HandleScope scope; @@ -3657,7 +3668,9 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) { if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) && is_element) { // Normalize the elements to enable attributes on the property. - NormalizeElements(js_object); + if (!js_object->IsJSGlobalProxy()) { + NormalizeElements(js_object); + } Handle dictionary(js_object->element_dictionary()); // Make sure that we never go back to fast case. dictionary->set_requires_slow_elements(); @@ -3677,7 +3690,9 @@ static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) { if (result.IsProperty() && (attr != result.GetAttributes() || result.type() == CALLBACKS)) { // New attributes - normalize to avoid writing to instance descriptor - NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); + if (!js_object->IsJSGlobalProxy()) { + 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->SetLocalPropertyIgnoreAttributes(*name, @@ -4273,7 +4288,7 @@ static MaybeObject* Runtime_ToSlowProperties(Arguments args) { ASSERT(args.length() == 1); Handle object = args.at(0); - if (object->IsJSObject()) { + if (object->IsJSObject() && !object->IsJSGlobalProxy()) { Handle js_object = Handle::cast(object); NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); } diff --git a/src/v8natives.js b/src/v8natives.js index 233f8b4..0444469 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -545,10 +545,12 @@ function DefineOwnProperty(obj, p, desc, should_throw) { if (IS_UNDEFINED(current) && !extensible) throw MakeTypeError("define_disallowed", ["defineProperty"]); - if (!IS_UNDEFINED(current) && !current.isConfigurable()) { + if (!IS_UNDEFINED(current)) { // Step 5 and 6 - if ((!desc.hasEnumerable() || - SameValue(desc.isEnumerable() && current.isEnumerable())) && + if ((IsGenericDescriptor(desc) || + IsDataDescriptor(desc) == IsDataDescriptor(current)) && + (!desc.hasEnumerable() || + SameValue(desc.isEnumerable(), current.isEnumerable())) && (!desc.hasConfigurable() || SameValue(desc.isConfigurable(), current.isConfigurable())) && (!desc.hasWritable() || @@ -561,29 +563,35 @@ function DefineOwnProperty(obj, p, desc, should_throw) { SameValue(desc.getSet(), current.getSet()))) { return true; } - - // Step 7 - if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable()) - throw MakeTypeError("redefine_disallowed", ["defineProperty"]); - // Step 9 - if (IsDataDescriptor(current) != IsDataDescriptor(desc)) - throw MakeTypeError("redefine_disallowed", ["defineProperty"]); - // Step 10 - if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { - if (!current.isWritable() && desc.isWritable()) - throw MakeTypeError("redefine_disallowed", ["defineProperty"]); - if (!current.isWritable() && desc.hasValue() && - !SameValue(desc.getValue(), current.getValue())) { - throw MakeTypeError("redefine_disallowed", ["defineProperty"]); - } - } - // Step 11 - if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { - if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){ + if (!current.isConfigurable()) { + // Step 7 + if (desc.isConfigurable() || + (desc.hasEnumerable() && + desc.isEnumerable() != current.isEnumerable())) throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + // Step 8 + if (!IsGenericDescriptor(desc)) { + // Step 9a + if (IsDataDescriptor(current) != IsDataDescriptor(desc)) + throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + // Step 10a + if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { + if (!current.isWritable() && desc.isWritable()) + throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + if (!current.isWritable() && desc.hasValue() && + !SameValue(desc.getValue(), current.getValue())) { + throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + } + } + // Step 11 + if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { + if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){ + throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + } + if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) + throw MakeTypeError("redefine_disallowed", ["defineProperty"]); + } } - if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) - throw MakeTypeError("redefine_disallowed", ["defineProperty"]); } } @@ -607,7 +615,16 @@ function DefineOwnProperty(obj, p, desc, should_throw) { } else flag |= DONT_DELETE; - if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) { + if (IsDataDescriptor(desc) || + (IsGenericDescriptor(desc) && + (IS_UNDEFINED(current) || IsDataDescriptor(current)))) { + // There are 3 cases that lead here: + // Step 4a - defining a new data property. + // Steps 9b & 12 - replacing an existing accessor property with a data + // property. + // Step 12 - updating an existing data property with a data or generic + // descriptor. + if (desc.hasWritable()) { flag |= desc.isWritable() ? 0 : READ_ONLY; } else if (!IS_UNDEFINED(current)) { @@ -615,20 +632,30 @@ function DefineOwnProperty(obj, p, desc, should_throw) { } else { flag |= READ_ONLY; } + var value = void 0; // Default value is undefined. if (desc.hasValue()) { value = desc.getValue(); - } else if (!IS_UNDEFINED(current)) { + } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) { value = current.getValue(); } + %DefineOrRedefineDataProperty(obj, p, value, flag); + } else if (IsGenericDescriptor(desc)) { + // Step 12 - updating an existing accessor property with generic + // descriptor. Changing flags only. + %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag); } else { - if (desc.hasGetter() && - (IS_FUNCTION(desc.getGet()) || IS_UNDEFINED(desc.getGet()))) { - %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); + // There are 3 cases that lead here: + // Step 4b - defining a new accessor property. + // Steps 9c & 12 - replacing an existing data property with an accessor + // property. + // Step 12 - updating an existing accessor property with an accessor + // descriptor. + if (desc.hasGetter()) { + %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); } - if (desc.hasSetter() && - (IS_FUNCTION(desc.getSet()) || IS_UNDEFINED(desc.getSet()))) { + if (desc.hasSetter()) { %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag); } } diff --git a/test/mjsunit/object-define-property.js b/test/mjsunit/object-define-property.js index d24a4e5..a8a3213 100644 --- a/test/mjsunit/object-define-property.js +++ b/test/mjsunit/object-define-property.js @@ -749,14 +749,33 @@ assertTrue(desc.writable); assertTrue(desc.enumerable); assertFalse(desc.configurable); -// Ensure that we can't overwrite the non configurable element. +// Can use defineProperty to change the value of a non +// configurable property. try { Object.defineProperty(obj6, '2', descElement); + desc = Object.getOwnPropertyDescriptor(obj6, '2'); + assertEquals(desc.value, 'foobar'); +} catch (e) { + assertUnreachable(); +} + +// Ensure that we can't change the descriptor of a +// non configurable property. +try { + var descAccessor = { get: function() { return 0; } }; + Object.defineProperty(obj6, '2', descAccessor); assertUnreachable(); } catch (e) { assertTrue(/Cannot redefine property/.test(e)); } +Object.defineProperty(obj6, '2', descElementNonWritable); +desc = Object.getOwnPropertyDescriptor(obj6, '2'); +assertEquals(desc.value, 'foofoo'); +assertFalse(desc.writable); +assertTrue(desc.enumerable); +assertFalse(desc.configurable); + Object.defineProperty(obj6, '3', descElementNonWritable); desc = Object.getOwnPropertyDescriptor(obj6, '3'); assertEquals(desc.value, 'foofoo'); @@ -827,14 +846,33 @@ assertTrue(desc.writable); assertTrue(desc.enumerable); assertFalse(desc.configurable); -// Ensure that we can't overwrite the non configurable element. +// Can use defineProperty to change the value of a non +// configurable property of an array. try { Object.defineProperty(arr, '2', descElement); + desc = Object.getOwnPropertyDescriptor(arr, '2'); + assertEquals(desc.value, 'foobar'); +} catch (e) { + assertUnreachable(); +} + +// Ensure that we can't change the descriptor of a +// non configurable property. +try { + var descAccessor = { get: function() { return 0; } }; + Object.defineProperty(arr, '2', descAccessor); assertUnreachable(); } catch (e) { assertTrue(/Cannot redefine property/.test(e)); } +Object.defineProperty(arr, '2', descElementNonWritable); +desc = Object.getOwnPropertyDescriptor(arr, '2'); +assertEquals(desc.value, 'foofoo'); +assertFalse(desc.writable); +assertTrue(desc.enumerable); +assertFalse(desc.configurable); + Object.defineProperty(arr, '3', descElementNonWritable); desc = Object.getOwnPropertyDescriptor(arr, '3'); assertEquals(desc.value, 'foofoo'); @@ -898,3 +936,98 @@ Object.defineProperty(o, "x", { writable: false }); assertEquals(undefined, o.x); o.x = 37; assertEquals(undefined, o.x); + +function testDefineProperty(obj, propertyName, desc, resultDesc) { + Object.defineProperty(obj, propertyName, desc); + var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName); + assertEquals(resultDesc.enumerable, actualDesc.enumerable); + assertEquals(resultDesc.configurable, actualDesc.configurable); + if (resultDesc.hasOwnProperty('value')) { + assertEquals(resultDesc.value, actualDesc.value); + assertEquals(resultDesc.writable, actualDesc.writable); + assertFalse(resultDesc.hasOwnProperty('get')); + assertFalse(resultDesc.hasOwnProperty('set')); + } else { + assertEquals(resultDesc.get, actualDesc.get); + assertEquals(resultDesc.set, actualDesc.set); + assertFalse(resultDesc.hasOwnProperty('value')); + assertFalse(resultDesc.hasOwnProperty('writable')); + } +} + +// tests redefining existing property with a generic descriptor +o = { p : 42 }; +testDefineProperty(o, 'p', + { }, + { value : 42, writable : true, enumerable : true, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : true }, + { value : 42, writable : true, enumerable : true, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { configurable : true }, + { value : 42, writable : true, enumerable : true, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : false }, + { value : 42, writable : true, enumerable : false, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { configurable : false }, + { value : 42, writable : true, enumerable : true, configurable : false }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : true, configurable : true }, + { value : 42, writable : true, enumerable : true, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : false, configurable : true }, + { value : 42, writable : true, enumerable : false, configurable : true }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : true, configurable : false }, + { value : 42, writable : true, enumerable : true, configurable : false }); + +o = { p : 42 }; +testDefineProperty(o, 'p', + { enumerable : false, configurable : false }, + { value : 42, writable : true, enumerable : false, configurable : false }); + +// can make a writable, non-configurable field non-writable +o = { p : 42 }; +Object.defineProperty(o, 'p', { configurable: false }); +testDefineProperty(o, 'p', + { writable: false }, + { value : 42, writable : false, enumerable : true, configurable : false }); + +// redefine of get only property with generic descriptor +o = {}; +Object.defineProperty(o, 'p', + { get : getter1, enumerable: true, configurable: true }); +testDefineProperty(o, 'p', + { enumerable : false, configurable : false }, + { get: getter1, set: undefined, enumerable : false, configurable : false }); + +// redefine of get/set only property with generic descriptor +o = {}; +Object.defineProperty(o, 'p', + { get: getter1, set: setter1, enumerable: true, configurable: true }); +testDefineProperty(o, 'p', + { enumerable : false, configurable : false }, + { get: getter1, set: setter1, enumerable : false, configurable : false }); + +// redefine of set only property with generic descriptor +o = {}; +Object.defineProperty(o, 'p', + { set : setter1, enumerable: true, configurable: true }); +testDefineProperty(o, 'p', + { enumerable : false, configurable : false }, + { get: undefined, set: setter1, enumerable : false, configurable : false }); diff --git a/test/mjsunit/regress/regress-1083.js b/test/mjsunit/regress/regress-1083.js new file mode 100644 index 0000000..d231899 --- /dev/null +++ b/test/mjsunit/regress/regress-1083.js @@ -0,0 +1,38 @@ +// Copyright 2011 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. + +// Test that changing the generic descriptor flags on a property +// on the global object doesn't break invariants. +Object.defineProperty(this, 'Object', {enumerable:true}); + +var desc = Object.getOwnPropertyDescriptor(this, 'Object'); +assertTrue(desc.enumerable); +assertTrue(desc.configurable); +assertFalse(desc.hasOwnProperty('get')); +assertFalse(desc.hasOwnProperty('set')); +assertTrue(desc.hasOwnProperty('value')); +assertTrue(desc.writable); diff --git a/test/mjsunit/regress/regress-1092.js b/test/mjsunit/regress/regress-1092.js new file mode 100644 index 0000000..0b29231 --- /dev/null +++ b/test/mjsunit/regress/regress-1092.js @@ -0,0 +1,35 @@ +// Copyright 2011 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. + +// Test that CodeGenerator::EmitKeyedPropertyAssignment for the start +// of an initialization block doesn't normalize the properties of the +// JSGlobalProxy. +this.w = 0; +this.x = 1; +this.y = 2; +this.z = 3; + diff --git a/test/mjsunit/regress/regress-992.js b/test/mjsunit/regress/regress-992.js new file mode 100644 index 0000000..dbe25a5 --- /dev/null +++ b/test/mjsunit/regress/regress-992.js @@ -0,0 +1,43 @@ +// Copyright 2011 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. + +// Object.defineProperty with generic desc on existing property +// should just update enumerable/configurable flags. + +var obj = { get p() { return 42; } }; +var desc = Object.getOwnPropertyDescriptor(obj, 'p'); +var getter = desc.get; + +Object.defineProperty(obj, 'p', {enumerable: false }); +assertEquals(obj.p, 42); +desc = Object.getOwnPropertyDescriptor(obj, 'p'); +assertFalse(desc.enumerable); +assertTrue(desc.configurable); +assertEquals(desc.get, getter); +assertEquals(desc.set, undefined); +assertFalse(desc.hasOwnProperty('value')); +assertFalse(desc.hasOwnProperty('writable'));