Changeset 104836 in webkit
- Timestamp:
- Jan 12, 2012 10:38:24 AM (12 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r104831 r104836 1 2012-01-11 Gavin Barraclough <barraclough@apple.com> 2 3 Allow accessor get/set property to be set to undefined 4 https://bugs.webkit.org/show_bug.cgi?id=76148 5 6 Reviewed by Oliver Hunt. 7 8 * fast/js/Object-defineProperty-expected.txt: 9 * fast/js/script-tests/Object-defineProperty.js: 10 - Update a couple of inaccurate tests (it is invalid for a property to have 11 both a get: and value: field; AccessorDescritor properties do not have a 12 writable property). Add more test cases. 13 1 14 2012-01-12 Pavel Podivilov <podivilov@chromium.org> 2 15 -
trunk/LayoutTests/fast/js/Object-defineProperty-expected.txt
r75884 r104836 6 6 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1}), 'foo')) is JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false}) 7 7 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {}), 'foo')) is JSON.stringify({writable: false, enumerable: false, configurable: false}) 8 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {get:undefined}), 'foo')) is JSON.stringify({ writable: true,enumerable: false, configurable: false})8 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {get:undefined}), 'foo')) is JSON.stringify({enumerable: false, configurable: false}) 9 9 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: false}), 'foo')) is JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false}) 10 10 PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: true}), 'foo')) is JSON.stringify({value: 1, writable: true, enumerable: false, configurable: false}) … … 23 23 PASS Object.defineProperty({}) threw exception TypeError: Property description must be an object.. 24 24 PASS Object.defineProperty({}, 'foo') threw exception TypeError: Property description must be an object.. 25 PASS Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo is true25 PASS Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo threw exception TypeError: Invalid property. 'value' present on property with getter or setter.. 26 26 PASS Object.defineProperty({get foo() { return true; } }, 'foo', {configurable:false}).foo is true 27 27 PASS Object.defineProperty(createUnconfigurableProperty({}, 'foo'), 'foo', {configurable: true}) threw exception TypeError: Attempting to configurable attribute of unconfigurable property.. … … 59 59 PASS Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {get: getter1}).foo threw exception called getter1. 60 60 PASS Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {set: setter1}).foo='test' threw exception called setter1. 61 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo is 42 62 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42 63 PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo is undefined 64 PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42 65 PASS var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo is undefined 66 PASS var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42 67 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo is 42 68 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo = 42; o.result; threw exception TypeError: setting a property that has only a getter. 69 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo is 42 70 PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo = 42; o.result; threw exception TypeError: setting a property that has only a getter. 71 PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo is undefined 72 PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo = 42; o.result; threw exception TypeError: setting a property that has only a getter. 73 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:function(){return 13;}}); o.foo is 13 74 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:function(){return 13;}}); o.foo = 42; o.result; is 42 75 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:undefined}); o.foo is undefined 76 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:undefined}); o.foo = 42; o.result; is 42 77 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:function(){this.result = 13;}}); o.foo is 42 78 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:function(){this.result = 13;}}); o.foo = 42; o.result; is 13 79 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:undefined}); o.foo is 42 80 PASS var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:undefined}); o.foo = 42; o.result; threw exception TypeError: setting a property that has only a getter. 61 81 PASS successfullyParsed is true 62 82 -
trunk/LayoutTests/fast/js/script-tests/Object-defineProperty.js
r98407 r104836 6 6 "JSON.stringify({writable: false, enumerable: false, configurable: false})"); 7 7 shouldBe("JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {get:undefined}), 'foo'))", 8 "JSON.stringify({ writable: true,enumerable: false, configurable: false})");8 "JSON.stringify({enumerable: false, configurable: false})"); 9 9 shouldBe("JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: false}), 'foo'))", 10 10 "JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false})"); … … 31 31 shouldThrow("Object.defineProperty({})"); 32 32 shouldThrow("Object.defineProperty({}, 'foo')"); 33 should BeTrue("Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo");33 shouldThrow("Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo"); 34 34 shouldBeTrue("Object.defineProperty({get foo() { return true; } }, 'foo', {configurable:false}).foo"); 35 35 … … 81 81 shouldThrow("Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {get: getter1}).foo", "'called getter1'"); 82 82 shouldThrow("Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {set: setter1}).foo='test'", "'called setter1'"); 83 84 // Test an object with a getter setter. 85 // Either accessor may be omitted or replaced with undefined, or both may be replaced with undefined. 86 shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo", '42') 87 shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42'); 88 shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo", 'undefined') 89 shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42'); 90 shouldBe("var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo", 'undefined') 91 shouldBe("var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42'); 92 shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo", '42') 93 shouldThrow("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo = 42; o.result;"); 94 shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo", '42') 95 shouldThrow("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo = 42; o.result;"); 96 shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo", 'undefined') 97 shouldThrow("var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo = 42; o.result;"); 98 // Test replacing or removing either the getter or setter individually. 99 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:function(){return 13;}}); o.foo", '13') 100 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:function(){return 13;}}); o.foo = 42; o.result;", '42') 101 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:undefined}); o.foo", 'undefined') 102 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {get:undefined}); o.foo = 42; o.result;", '42') 103 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:function(){this.result = 13;}}); o.foo", '42') 104 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:function(){this.result = 13;}}); o.foo = 42; o.result;", '13') 105 shouldBe("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:undefined}); o.foo", '42') 106 shouldThrow("var o = Object.defineProperty(Object.defineProperty({foo:1}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}), 'foo', {set:undefined}); o.foo = 42; o.result;") -
trunk/Source/JavaScriptCore/ChangeLog
r104826 r104836 1 2012-01-11 Gavin Barraclough <barraclough@apple.com> 2 3 Allow accessor get/set property to be set to undefined 4 https://bugs.webkit.org/show_bug.cgi?id=76148 5 6 Reviewed by Oliver Hunt. 7 8 AccessorDescriptor properties may have their get & set properties defined to reference a function 9 (Callable object) or be set to undefined. Valid PropertyDescriptors created by toPropertyDescriptor 10 (defined from JS code via Object.defineProperty, etc) have get and set properties that are in one of 11 three states (1) nonexistent, (2) set to undefined, or (3) a function (any Callable object). 12 13 On the PropertyDescriptor object these three states are represneted by JSValue(), jsUndefined(), and 14 any JSObject* (with a constraint that this must be callable). 15 16 Logically the get/set property of an accessor descriptor on an object might be in any of the three 17 states above, but in practice there is no way to distinguish between the first two states. As such 18 we stor the get/set values in property storage in a JSObject* field, with 0 indicating absent or 19 undefined. When unboxing to a PropertyDescriptor, map this back to a JS undefined value. 20 21 * runtime/GetterSetter.h: 22 (JSC::GetterSetter::setGetter): 23 (JSC::GetterSetter::setSetter): 24 - Allow the getter/setter to be cleared. 25 * runtime/JSArray.cpp: 26 (JSC::JSArray::putDescriptor): 27 - Changed to call getterObject/setterObject. 28 (JSC::JSArray::defineOwnNumericProperty): 29 - Added ASSERT. 30 * runtime/JSObject.cpp: 31 (JSC::putDescriptor): 32 (JSC::JSObject::defineOwnProperty): 33 - Changed to call getterObject/setterObject. 34 * runtime/ObjectConstructor.cpp: 35 (JSC::objectConstructorGetOwnPropertyDescriptor): 36 - getter/setter values read from properties on object are never missing, they will now be set as undefined by 'setDescriptor'. 37 (JSC::toPropertyDescriptor): 38 - Do not translate undefined->empty, this loses an important distinction between a get/set property being absent, or being explicitly set to undefined. 39 * runtime/PropertyDescriptor.cpp: 40 (JSC::PropertyDescriptor::getterObject): 41 (JSC::PropertyDescriptor::setterObject): 42 - Accessors to convert the get/set property to an object pointer, converting undefined to 0. 43 (JSC::PropertyDescriptor::setDescriptor): 44 (JSC::PropertyDescriptor::setAccessorDescriptor): 45 - Translate a getter/setter internally represented at 0 to undefined, indicating that it is present. 46 * runtime/PropertyDescriptor.h: 47 - Declare getterObject/setterObject. 48 1 49 2012-01-12 Zeno Albisser <zeno@webkit.org> 2 50 -
trunk/Source/JavaScriptCore/runtime/GetterSetter.h
r103243 r104836 57 57 58 58 JSObject* getter() const { return m_getter.get(); } 59 void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.set (globalData, this, getter); }59 void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.setMayBeNull(globalData, this, getter); } 60 60 JSObject* setter() const { return m_setter.get(); } 61 void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set (globalData, this, setter); }61 void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.setMayBeNull(globalData, this, setter); } 62 62 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) 63 63 { -
trunk/Source/JavaScriptCore/runtime/JSArray.cpp
r104784 r104836 355 355 if (descriptor.isAccessorDescriptor()) { 356 356 JSObject* getter = 0; 357 if (descriptor.getter() && descriptor.getter().isObject()) 358 getter = asObject(descriptor.getter()); 359 if (!getter && oldDescriptor.isAccessorDescriptor()) { 360 if (oldDescriptor.getter() && oldDescriptor.getter().isObject()) 361 getter = asObject(oldDescriptor.getter()); 362 } 357 if (descriptor.getterPresent()) 358 getter = descriptor.getterObject(); 359 else if (oldDescriptor.isAccessorDescriptor()) 360 getter = oldDescriptor.getterObject(); 363 361 JSObject* setter = 0; 364 if (descriptor.setter() && descriptor.setter().isObject()) 365 setter = asObject(descriptor.setter()); 366 if (!setter && oldDescriptor.isAccessorDescriptor()) { 367 if (oldDescriptor.setter() && oldDescriptor.setter().isObject()) 368 setter = asObject(oldDescriptor.setter()); 369 } 362 if (descriptor.setterPresent()) 363 setter = descriptor.setterObject(); 364 else if (oldDescriptor.isAccessorDescriptor()) 365 setter = oldDescriptor.setterObject(); 370 366 371 367 GetterSetter* accessor = GetterSetter::create(exec); … … 492 488 // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable. 493 489 } else { 490 ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent()); 494 491 // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then 495 492 if (!current.configurable()) { -
trunk/Source/JavaScriptCore/runtime/JSObject.cpp
r104784 r104836 692 692 if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) { 693 693 GetterSetter* accessor = GetterSetter::create(exec); 694 if (oldDescriptor.getter ()) {694 if (oldDescriptor.getterPresent()) { 695 695 attributes |= Accessor; 696 accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter()));696 accessor->setGetter(exec->globalData(), oldDescriptor.getterObject()); 697 697 } 698 if (oldDescriptor.setter ()) {698 if (oldDescriptor.setterPresent()) { 699 699 attributes |= Accessor; 700 accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter()));700 accessor->setSetter(exec->globalData(), oldDescriptor.setterObject()); 701 701 } 702 702 target->methodTable()->putWithAttributes(target, exec, propertyName, accessor, attributes); … … 712 712 } 713 713 attributes &= ~ReadOnly; 714 if (descriptor.getter () && descriptor.getter().isObject())715 target->methodTable()->defineGetter(target, exec, propertyName, asObject(descriptor.getter()), attributes);714 if (descriptor.getterPresent()) 715 target->methodTable()->defineGetter(target, exec, propertyName, descriptor.getterObject(), attributes); 716 716 if (exec->hadException()) 717 717 return false; 718 if (descriptor.setter () && descriptor.setter().isObject())719 target->methodTable()->defineSetter(target, exec, propertyName, asObject(descriptor.setter()), attributes);718 if (descriptor.setterPresent()) 719 target->methodTable()->defineSetter(target, exec, propertyName, descriptor.setterObject(), attributes); 720 720 return !exec->hadException(); 721 721 } … … 824 824 GetterSetter* getterSetter = asGetterSetter(accessor); 825 825 if (current.attributesEqual(descriptor)) { 826 if (descriptor.setter ())827 getterSetter->setSetter(exec->globalData(), asObject(descriptor.setter()));828 if (descriptor.getter ())829 getterSetter->setGetter(exec->globalData(), asObject(descriptor.getter()));826 if (descriptor.setterPresent()) 827 getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); 828 if (descriptor.getterPresent()) 829 getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); 830 830 return true; 831 831 } 832 832 object->methodTable()->deleteProperty(object, exec, propertyName); 833 833 unsigned attrs = current.attributesWithOverride(descriptor); 834 if (descriptor.setter () || descriptor.getter())834 if (descriptor.setterPresent() || descriptor.getterPresent()) 835 835 attrs |= Accessor; 836 836 object->putDirect(exec->globalData(), propertyName, getterSetter, attrs); -
trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
r104784 r104836 165 165 description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); 166 166 } else { 167 description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0); 168 description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0); 167 ASSERT(descriptor.getter()); 168 ASSERT(descriptor.setter()); 169 description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter(), 0); 170 description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter(), 0); 169 171 } 170 172 … … 252 254 return false; 253 255 } 254 } else 255 get = JSValue(); 256 } 256 257 desc.setGetter(get); 257 258 } … … 268 269 return false; 269 270 } 270 } else 271 set = JSValue(); 272 271 } 273 272 desc.setSetter(set); 274 273 } -
trunk/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
r104784 r104836 85 85 } 86 86 87 JSObject* PropertyDescriptor::getterObject() const 88 { 89 ASSERT(isAccessorDescriptor() && getterPresent()); 90 return m_getter.isObject() ? asObject(m_getter) : 0; 91 } 92 93 JSObject* PropertyDescriptor::setterObject() const 94 { 95 ASSERT(isAccessorDescriptor() && setterPresent()); 96 return m_setter.isObject() ? asObject(m_setter) : 0; 97 } 98 87 99 void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) 88 100 { … … 92 104 m_attributes = attributes; 93 105 if (value.isGetterSetter()) { 106 m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! 107 94 108 GetterSetter* accessor = asGetterSetter(value); 95 96 m_getter = accessor->getter(); 97 m_setter = accessor->setter(); 98 ASSERT(m_getter || m_setter); 99 109 m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); 110 m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); 100 111 m_seenAttributes = EnumerablePresent | ConfigurablePresent; 101 m_attributes &= ~ReadOnly;102 112 } else { 103 113 m_value = value; … … 109 119 { 110 120 ASSERT(attributes & Accessor); 111 ASSERT(accessor->getter() || accessor->setter()); 121 attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! 122 112 123 m_attributes = attributes; 113 m_getter = accessor->getter(); 114 m_setter = accessor->setter(); 115 m_attributes &= ~ReadOnly; 124 m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); 125 m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); 116 126 m_seenAttributes = EnumerablePresent | ConfigurablePresent; 117 127 } … … 213 223 unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const 214 224 { 225 unsigned currentAttributes = current.m_attributes; 215 226 unsigned overrideMask = 0; 216 227 if (writablePresent()) … … 222 233 if (isAccessorDescriptor()) 223 234 overrideMask |= Accessor; 224 return (m_attributes & overrideMask) | (current .m_attributes & ~overrideMask);225 } 226 227 } 235 return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask); 236 } 237 238 } -
trunk/Source/JavaScriptCore/runtime/PropertyDescriptor.h
r104602 r104836 52 52 JSValue getter() const; 53 53 JSValue setter() const; 54 JSObject* getterObject() const; 55 JSObject* setterObject() const; 54 56 void setUndefined(); 55 57 void setDescriptor(JSValue value, unsigned attributes);
Note: See TracChangeset
for help on using the changeset viewer.