Changeset 104836 in webkit


Ignore:
Timestamp:
Jan 12, 2012 10:38:24 AM (12 years ago)
Author:
barraclough@apple.com
Message:

Allow accessor get/set property to be set to undefined
https://bugs.webkit.org/show_bug.cgi?id=76148

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

AccessorDescriptor properties may have their get & set properties defined to reference a function
(Callable object) or be set to undefined. Valid PropertyDescriptors created by toPropertyDescriptor
(defined from JS code via Object.defineProperty, etc) have get and set properties that are in one of
three states (1) nonexistent, (2) set to undefined, or (3) a function (any Callable object).

On the PropertyDescriptor object these three states are represneted by JSValue(), jsUndefined(), and
any JSObject* (with a constraint that this must be callable).

Logically the get/set property of an accessor descriptor on an object might be in any of the three
states above, but in practice there is no way to distinguish between the first two states. As such
we stor the get/set values in property storage in a JSObject* field, with 0 indicating absent or
undefined. When unboxing to a PropertyDescriptor, map this back to a JS undefined value.

  • runtime/GetterSetter.h:

(JSC::GetterSetter::setGetter):
(JSC::GetterSetter::setSetter):

  • Allow the getter/setter to be cleared.
  • runtime/JSArray.cpp:

(JSC::JSArray::putDescriptor):

  • Changed to call getterObject/setterObject.

(JSC::JSArray::defineOwnNumericProperty):

  • Added ASSERT.
  • runtime/JSObject.cpp:

(JSC::putDescriptor):
(JSC::JSObject::defineOwnProperty):

  • Changed to call getterObject/setterObject.
  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetOwnPropertyDescriptor):

  • getter/setter values read from properties on object are never missing, they will now be set as undefined by 'setDescriptor'.

(JSC::toPropertyDescriptor):

  • Do not translate undefined->empty, this loses an important distinction between a get/set property being absent, or being explicitly set to undefined.
  • runtime/PropertyDescriptor.cpp:

(JSC::PropertyDescriptor::getterObject):
(JSC::PropertyDescriptor::setterObject):

  • Accessors to convert the get/set property to an object pointer, converting undefined to 0.

(JSC::PropertyDescriptor::setDescriptor):
(JSC::PropertyDescriptor::setAccessorDescriptor):

  • Translate a getter/setter internally represented at 0 to undefined, indicating that it is present.
  • runtime/PropertyDescriptor.h:
    • Declare getterObject/setterObject.

LayoutTests:

  • fast/js/Object-defineProperty-expected.txt:
  • fast/js/script-tests/Object-defineProperty.js:
    • Update a couple of inaccurate tests (it is invalid for a property to have both a get: and value: field; AccessorDescritor properties do not have a writable property). Add more test cases.
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r104831 r104836  
     12012-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
    1142012-01-12  Pavel Podivilov  <podivilov@chromium.org>
    215
  • trunk/LayoutTests/fast/js/Object-defineProperty-expected.txt

    r75884 r104836  
    66PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1}), 'foo')) is JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false})
    77PASS 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})
     8PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {get:undefined}), 'foo')) is JSON.stringify({enumerable: false, configurable: false})
    99PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: false}), 'foo')) is JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false})
    1010PASS JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: true}), 'foo')) is JSON.stringify({value: 1, writable: true, enumerable: false, configurable: false})
     
    2323PASS Object.defineProperty({}) threw exception TypeError: Property description must be an object..
    2424PASS Object.defineProperty({}, 'foo') threw exception TypeError: Property description must be an object..
    25 PASS Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo is true
     25PASS Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo threw exception TypeError: Invalid property.  'value' present on property with getter or setter..
    2626PASS Object.defineProperty({get foo() { return true; } }, 'foo', {configurable:false}).foo is true
    2727PASS Object.defineProperty(createUnconfigurableProperty({}, 'foo'), 'foo', {configurable: true}) threw exception TypeError: Attempting to configurable attribute of unconfigurable property..
     
    5959PASS Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {get: getter1}).foo threw exception called getter1.
    6060PASS Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {set: setter1}).foo='test' threw exception called setter1.
     61PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo is 42
     62PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42
     63PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo is undefined
     64PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42
     65PASS var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo is undefined
     66PASS var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo = 42; o.result; is 42
     67PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo is 42
     68PASS 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.
     69PASS var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo is 42
     70PASS 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.
     71PASS var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo is undefined
     72PASS 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.
     73PASS 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
     74PASS 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
     75PASS 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
     76PASS 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
     77PASS 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
     78PASS 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
     79PASS 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
     80PASS 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.
    6181PASS successfullyParsed is true
    6282
  • trunk/LayoutTests/fast/js/script-tests/Object-defineProperty.js

    r98407 r104836  
    66         "JSON.stringify({writable: false, enumerable: false, configurable: false})");
    77shouldBe("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})");
    99shouldBe("JSON.stringify(Object.getOwnPropertyDescriptor(Object.defineProperty({}, 'foo', {value:1, writable: false}), 'foo'))",
    1010         "JSON.stringify({value: 1, writable: false, enumerable: false, configurable: false})");
     
    3131shouldThrow("Object.defineProperty({})");
    3232shouldThrow("Object.defineProperty({}, 'foo')");
    33 shouldBeTrue("Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo");
     33shouldThrow("Object.defineProperty({}, 'foo', {get:undefined, value:true}).foo");
    3434shouldBeTrue("Object.defineProperty({get foo() { return true; } }, 'foo', {configurable:false}).foo");
    3535
     
    8181shouldThrow("Object.defineProperty(Object.defineProperty({}, 'foo', {value: 1, configurable: true}), 'foo', {get: getter1}).foo", "'called getter1'");
    8282shouldThrow("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.
     86shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo", '42')
     87shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42');
     88shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo", 'undefined')
     89shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42');
     90shouldBe("var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo", 'undefined')
     91shouldBe("var o = Object.defineProperty({}, 'foo', {set:function(x){this.result = x;}}); o.foo = 42; o.result;", '42');
     92shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo", '42')
     93shouldThrow("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}, set:undefined}); o.foo = 42; o.result;");
     94shouldBe("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo", '42')
     95shouldThrow("var o = Object.defineProperty({}, 'foo', {get:function(){return 42;}}); o.foo = 42; o.result;");
     96shouldBe("var o = Object.defineProperty({}, 'foo', {get:undefined, set:undefined}); o.foo", 'undefined')
     97shouldThrow("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.
     99shouldBe("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')
     100shouldBe("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')
     101shouldBe("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')
     102shouldBe("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')
     103shouldBe("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')
     104shouldBe("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')
     105shouldBe("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')
     106shouldThrow("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  
     12012-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
    1492012-01-12  Zeno Albisser  <zeno@webkit.org>
    250
  • trunk/Source/JavaScriptCore/runtime/GetterSetter.h

    r103243 r104836  
    5757
    5858        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); }
    6060        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); }
    6262        static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
    6363        {
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r104784 r104836  
    355355    if (descriptor.isAccessorDescriptor()) {
    356356        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();
    363361        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();
    370366
    371367        GetterSetter* accessor = GetterSetter::create(exec);
     
    492488            // 10.b. else, the [[Configurable]] field of current is true, so any change is acceptable.
    493489        } else {
     490            ASSERT(current.isAccessorDescriptor() && current.getterPresent() && current.setterPresent());
    494491            // 11. Else, IsAccessorDescriptor(current) and IsAccessorDescriptor(Desc) are both true so, if the [[Configurable]] field of current is false, then
    495492            if (!current.configurable()) {
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r104784 r104836  
    692692        if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
    693693            GetterSetter* accessor = GetterSetter::create(exec);
    694             if (oldDescriptor.getter()) {
     694            if (oldDescriptor.getterPresent()) {
    695695                attributes |= Accessor;
    696                 accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter()));
     696                accessor->setGetter(exec->globalData(), oldDescriptor.getterObject());
    697697            }
    698             if (oldDescriptor.setter()) {
     698            if (oldDescriptor.setterPresent()) {
    699699                attributes |= Accessor;
    700                 accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter()));
     700                accessor->setSetter(exec->globalData(), oldDescriptor.setterObject());
    701701            }
    702702            target->methodTable()->putWithAttributes(target, exec, propertyName, accessor, attributes);
     
    712712    }
    713713    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);
    716716    if (exec->hadException())
    717717        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);
    720720    return !exec->hadException();
    721721}
     
    824824    GetterSetter* getterSetter = asGetterSetter(accessor);
    825825    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());
    830830        return true;
    831831    }
    832832    object->methodTable()->deleteProperty(object, exec, propertyName);
    833833    unsigned attrs = current.attributesWithOverride(descriptor);
    834     if (descriptor.setter() || descriptor.getter())
     834    if (descriptor.setterPresent() || descriptor.getterPresent())
    835835        attrs |= Accessor;
    836836    object->putDirect(exec->globalData(), propertyName, getterSetter, attrs);
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r104784 r104836  
    165165        description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
    166166    } 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);
    169171    }
    170172   
     
    252254                return false;
    253255            }
    254         } else
    255             get = JSValue();
     256        }
    256257        desc.setGetter(get);
    257258    }
     
    268269                return false;
    269270            }
    270         } else
    271             set = JSValue();
    272 
     271        }
    273272        desc.setSetter(set);
    274273    }
  • trunk/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp

    r104784 r104836  
    8585}
    8686
     87JSObject* PropertyDescriptor::getterObject() const
     88{
     89    ASSERT(isAccessorDescriptor() && getterPresent());
     90    return m_getter.isObject() ? asObject(m_getter) : 0;
     91}
     92
     93JSObject* PropertyDescriptor::setterObject() const
     94{
     95    ASSERT(isAccessorDescriptor() && setterPresent());
     96    return m_setter.isObject() ? asObject(m_setter) : 0;
     97}
     98
    8799void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
    88100{
     
    92104    m_attributes = attributes;
    93105    if (value.isGetterSetter()) {
     106        m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
     107
    94108        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();
    100111        m_seenAttributes = EnumerablePresent | ConfigurablePresent;
    101         m_attributes &= ~ReadOnly;
    102112    } else {
    103113        m_value = value;
     
    109119{
    110120    ASSERT(attributes & Accessor);
    111     ASSERT(accessor->getter() || accessor->setter());
     121    attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
     122
    112123    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();
    116126    m_seenAttributes = EnumerablePresent | ConfigurablePresent;
    117127}
     
    213223unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
    214224{
     225    unsigned currentAttributes = current.m_attributes;
    215226    unsigned overrideMask = 0;
    216227    if (writablePresent())
     
    222233    if (isAccessorDescriptor())
    223234        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  
    5252        JSValue getter() const;
    5353        JSValue setter() const;
     54        JSObject* getterObject() const;
     55        JSObject* setterObject() const;
    5456        void setUndefined();
    5557        void setDescriptor(JSValue value, unsigned attributes);
Note: See TracChangeset for help on using the changeset viewer.