Changeset 215272 in webkit for trunk/Source/JavaScriptCore


Ignore:
Timestamp:
Apr 12, 2017, 10:35:31 AM (8 years ago)
Author:
[email protected]
Message:

Implement Object.isFrozen() and Object.isSealed() per ECMA spec
https://bugs.webkit.org/show_bug.cgi?id=170753

Reviewed by Mark Lam.

JSTests:

Added JSC baseline and enabled defineIndexProperty test.

Note that JSC differs from Chakra in that a JSC doesn't use indexed
properties placed on the Array prototype when sorting the indexed
properties of an Object. This is behavior is considered undefined
in the standard.

  • ChakraCore.yaml:
  • ChakraCore/test/es5/defineIndexProperty.baseline-jsc: Added.

Source/JavaScriptCore:

  • runtime/ObjectConstructor.cpp:

(JSC::testIntegrityLevel): Added local helper as described in the ECMA standard.

(JSC::objectConstructorSeal):
(JSC::objectConstructorFreeze):
Eliminated incomplete special handling of JSFinalObjects.

(JSC::objectConstructorIsSealed):
(JSC::objectConstructorIsFrozen):
Refactored to use the new testIntegrityLevel() helper.

Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r215270 r215272  
     12017-04-12  Michael Saboff  <[email protected]>
     2
     3        Implement Object.isFrozen() and Object.isSealed() per ECMA spec
     4        https://bugs.webkit.org/show_bug.cgi?id=170753
     5
     6        Reviewed by Mark Lam.
     7
     8        * runtime/ObjectConstructor.cpp:
     9        (JSC::testIntegrityLevel): Added local helper as described in the ECMA standard.
     10
     11        (JSC::objectConstructorSeal):
     12        (JSC::objectConstructorFreeze):
     13        Eliminated incomplete special handling of JSFinalObjects.
     14
     15        (JSC::objectConstructorIsSealed):
     16        (JSC::objectConstructorIsFrozen):
     17        Refactored to use the new testIntegrityLevel() helper.
     18
    1192017-04-12  Yusuke Suzuki  <[email protected]>
    220
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r215234 r215272  
    547547    return true;
    548548}
    549    
     549
     550template<IntegrityLevel level>
     551bool testIntegrityLevel(ExecState* exec, VM& vm, JSObject* object)
     552{
     553    auto scope = DECLARE_THROW_SCOPE(vm);
     554
     555    // 1. Assert: Type(O) is Object.
     556    // 2. Assert: level is either "sealed" or "frozen".
     557
     558    // 3. Let status be ?IsExtensible(O).
     559    bool status = object->isExtensible(exec);
     560    RETURN_IF_EXCEPTION(scope, { });
     561
     562    // 4. If status is true, return false.
     563    if (status)
     564        return false;
     565
     566    // 6. Let keys be ? O.[[OwnPropertyKeys]]().
     567    PropertyNameArray keys(exec, PropertyNameMode::StringsAndSymbols);
     568    object->methodTable(vm)->getOwnPropertyNames(object, exec, keys, EnumerationMode(DontEnumPropertiesMode::Include));
     569    RETURN_IF_EXCEPTION(scope, { });
     570
     571    // 7. For each element k of keys, do
     572    PropertyNameArray::const_iterator end = keys.end();
     573    for (PropertyNameArray::const_iterator iter = keys.begin(); iter != end; ++iter) {
     574        Identifier propertyName = *iter;
     575        if (vm.propertyNames->isPrivateName(propertyName))
     576            continue;
     577
     578        // a. Let currentDesc be ? O.[[GetOwnProperty]](k)
     579        PropertyDescriptor desc;
     580        bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, desc);
     581        RETURN_IF_EXCEPTION(scope, { });
     582
     583        // b. If currentDesc is not undefined, then
     584        if (!didGetDescriptor)
     585            continue;
     586
     587        // i. If currentDesc.[[Configurable]] is true, return false.
     588        if (desc.configurable())
     589            return false;
     590
     591        // ii. If level is "frozen" and IsDataDescriptor(currentDesc) is true, then
     592        // 1. If currentDesc.[[Writable]] is true, return false.
     593        if (level == IntegrityLevel::Frozen && desc.isDataDescriptor() && desc.writable())
     594            return false;
     595    }
     596
     597    return true;
     598}
     599
    550600EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
    551601{
     
    559609    JSObject* object = asObject(obj);
    560610
    561     if (isJSFinalObject(object)) {
    562         object->seal(vm);
    563         return JSValue::encode(obj);
    564     }
    565 
    566611    bool success = setIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object);
    567612    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     
    578623    VM& vm = exec->vm();
    579624    auto scope = DECLARE_THROW_SCOPE(vm);
    580 
    581     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
    582         object->freeze(vm);
    583         return object;
    584     }
    585625
    586626    bool success = setIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object);
     
    618658{
    619659    VM& vm = exec->vm();
    620     auto scope = DECLARE_THROW_SCOPE(vm);
    621660
    622661    // 1. If Type(O) is not Object, return true.
     
    626665    JSObject* object = asObject(obj);
    627666
    628     if (isJSFinalObject(object))
    629         return JSValue::encode(jsBoolean(object->isSealed(vm)));
    630 
    631     // 2. For each named own property name P of O,
    632     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
    633     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
    634     RETURN_IF_EXCEPTION(scope, { });
    635     PropertyNameArray::const_iterator end = properties.end();
    636     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
    637         Identifier propertyName = *iter;
    638         if (vm.propertyNames->isPrivateName(propertyName))
    639             continue;
    640         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
    641         PropertyDescriptor desc;
    642         bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, desc);
    643         RETURN_IF_EXCEPTION(scope, { });
    644         if (!didGetDescriptor)
    645             continue;
    646         // b. If desc.[[Configurable]] is true, then return false.
    647         if (desc.configurable())
    648             return JSValue::encode(jsBoolean(false));
    649     }
    650 
    651     // 3. If the [[Extensible]] internal property of O is false, then return true.
    652     // 4. Otherwise, return false.
    653     bool isExtensible = object->isExtensible(exec);
    654     RETURN_IF_EXCEPTION(scope, { });
    655     return JSValue::encode(jsBoolean(!isExtensible));
     667    // 2. Return ? TestIntegrityLevel(O, "sealed").
     668    return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object)));
    656669}
    657670
     
    659672{
    660673    VM& vm = exec->vm();
    661     auto scope = DECLARE_THROW_SCOPE(vm);
    662674
    663675    // 1. If Type(O) is not Object, return true.
     
    667679    JSObject* object = asObject(obj);
    668680
    669     if (isJSFinalObject(object))
    670         return JSValue::encode(jsBoolean(object->isFrozen(vm)));
    671 
    672     // 2. For each named own property name P of O,
    673     PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
    674     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
    675     RETURN_IF_EXCEPTION(scope, { });
    676     PropertyNameArray::const_iterator end = properties.end();
    677     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
    678         Identifier propertyName = *iter;
    679         if (vm.propertyNames->isPrivateName(propertyName))
    680             continue;
    681         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
    682         PropertyDescriptor desc;
    683         bool didGetDescriptor = object->getOwnPropertyDescriptor(exec, propertyName, desc);
    684         RETURN_IF_EXCEPTION(scope, { });
    685         if (!didGetDescriptor)
    686             continue;
    687         // b. If IsDataDescriptor(desc) is true then
    688         // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
    689         if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable())
    690             return JSValue::encode(jsBoolean(false));
    691     }
    692 
    693     // 3. If the [[Extensible]] internal property of O is false, then return true.
    694     // 4. Otherwise, return false.
    695     bool isExtensible = object->isExtensible(exec);
    696     RETURN_IF_EXCEPTION(scope, { });
    697     return JSValue::encode(jsBoolean(!isExtensible));
     681    // 2. Return ? TestIntegrityLevel(O, "frozen").
     682    return JSValue::encode(jsBoolean(testIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object)));
    698683}
    699684
Note: See TracChangeset for help on using the changeset viewer.