Ignore:
Timestamp:
Mar 1, 2016, 1:45:16 PM (9 years ago)
Author:
[email protected]
Message:

IsExtensible should be a virtual method in the method table
https://bugs.webkit.org/show_bug.cgi?id=154799

Reviewed by Mark Lam.

This patch makes us more consistent with how the ES6 specification models the
IsExtensible trap. Moving this method into ClassInfo::methodTable
is a prerequisite for implementing Proxy.IsExtensible.

  • runtime/ClassInfo.h:
  • runtime/JSCell.cpp:

(JSC::JSCell::preventExtensions):
(JSC::JSCell::isExtensible):

  • runtime/JSCell.h:
  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncProtoSetter):

  • runtime/JSObject.cpp:

(JSC::JSObject::preventExtensions):
(JSC::JSObject::isExtensible):
(JSC::JSObject::reifyAllStaticProperties):
(JSC::JSObject::defineOwnIndexedProperty):
(JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::defineOwnNonIndexProperty):
(JSC::JSObject::defineOwnProperty):

  • runtime/JSObject.h:

(JSC::JSObject::isSealed):
(JSC::JSObject::isFrozen):
(JSC::JSObject::isExtensibleImpl):
(JSC::JSObject::isStructureExtensible):
(JSC::JSObject::isExtensibleInline):
(JSC::JSObject::indexingShouldBeSparse):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::isExtensible): Deleted.

  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorSetPrototypeOf):
(JSC::objectConstructorIsSealed):
(JSC::objectConstructorIsFrozen):
(JSC::objectConstructorIsExtensible):
(JSC::objectConstructorIs):

  • runtime/ProxyObject.cpp:

(JSC::ProxyObject::performInternalMethodGetOwnProperty):
(JSC::ProxyObject::performHasProperty):

  • runtime/ReflectObject.cpp:

(JSC::reflectObjectIsExtensible):
(JSC::reflectObjectSetPrototypeOf):

  • runtime/SparseArrayValueMap.cpp:

(JSC::SparseArrayValueMap::putEntry):
(JSC::SparseArrayValueMap::putDirect):

  • runtime/StringObject.cpp:

(JSC::StringObject::defineOwnProperty):

  • runtime/Structure.cpp:

(JSC::Structure::isSealed):
(JSC::Structure::isFrozen):

  • runtime/Structure.h:
Location:
trunk/Source/JavaScriptCore/runtime
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/ClassInfo.h

    r197391 r197412  
    106106    typedef bool (*PreventExtensionsFunctionPtr)(JSObject*, ExecState*);
    107107    PreventExtensionsFunctionPtr preventExtensions;
     108
     109    typedef bool (*IsExtensibleFunctionPtr)(JSObject*, ExecState*);
     110    IsExtensibleFunctionPtr isExtensible;
    108111
    109112    typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&);
     
    159162        &ClassName::getTypedArrayImpl, \
    160163        &ClassName::preventExtensions, \
     164        &ClassName::isExtensible, \
    161165        &ClassName::dumpToStream, \
    162166        &ClassName::estimatedSize \
  • trunk/Source/JavaScriptCore/runtime/JSCell.cpp

    r197391 r197412  
    276276}
    277277
     278bool JSCell::isExtensible(JSObject*, ExecState*)
     279{
     280    RELEASE_ASSERT_NOT_REACHED();
     281}
     282
    278283} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r197391 r197412  
    208208    static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    209209    static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*);
     210    static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*);
    210211
    211212    static String className(const JSObject*);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r196745 r197412  
    886886        return JSValue::encode(jsUndefined());
    887887
    888     if (!thisObject->isExtensible())
     888    bool isExtensible = thisObject->isExtensibleInline(exec);
     889    if (exec->hadException())
     890        return JSValue::encode(jsUndefined());
     891    if (!isExtensible)
    889892        return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
    890893
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r197391 r197412  
    16781678bool JSObject::preventExtensions(JSObject* object, ExecState* exec)
    16791679{
    1680     if (!object->isExtensible())
     1680    if (!object->isStructureExtensible()) {
     1681        // We've already set the internal [[PreventExtensions]] field to false.
     1682        // We don't call the methodTable isExtensible here because it's not defined
     1683        // that way in the specification. We are just doing an optimization here.
    16811684        return true;
     1685    }
    16821686
    16831687    VM& vm = exec->vm();
     
    16851689    object->setStructure(vm, Structure::preventExtensionsTransition(vm, object->structure(vm)));
    16861690    return true;
     1691}
     1692
     1693bool JSObject::isExtensible(JSObject* obj, ExecState*)
     1694{
     1695    return obj->isExtensibleImpl();
    16871696}
    16881697
     
    18221831    // 4. If current is undefined and extensible is true, then
    18231832    if (result.isNewEntry) {
    1824         if (!isExtensible()) {
     1833        if (!isStructureExtensible()) {
    18251834            map->remove(result.iterator);
    18261835            return reject(exec, throwException, "Attempting to define property on object that is not extensible.");
     
    20382047    if (LIKELY(!map)) {
    20392048        // If the array is not extensible, we should have entered dictionary mode, and created the sparse map.
    2040         ASSERT(isExtensible());
     2049        ASSERT(isStructureExtensible());
    20412050   
    20422051        // Update m_length if necessary.
     
    20642073    if (i >= length) {
    20652074        // Prohibit growing the array if length is not writable.
    2066         if (map->lengthIsReadOnly() || !isExtensible()) {
     2075        if (map->lengthIsReadOnly() || !isStructureExtensible()) {
    20672076            if (shouldThrow)
    20682077                throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     
    21842193    if (LIKELY(!map)) {
    21852194        // If the array is not extensible, we should have entered dictionary mode, and created the spare map.
    2186         ASSERT(isExtensible());
     2195        ASSERT(isStructureExtensible());
    21872196   
    21882197        // Update m_length if necessary.
     
    22142223            if (map->lengthIsReadOnly())
    22152224                return reject(exec, mode == PutDirectIndexShouldThrow, StrictModeReadonlyPropertyWriteError);
    2216             if (!isExtensible())
     2225            if (!isStructureExtensible())
    22172226                return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
    22182227        }
     
    28492858    PropertyDescriptor current;
    28502859    bool isCurrentDefined = getOwnPropertyDescriptor(exec, propertyName, current);
    2851     return validateAndApplyPropertyDescriptor(exec, this, propertyName, isExtensible(), descriptor, isCurrentDefined, current, throwException);
     2860    bool isExtensible = isExtensibleInline(exec);
     2861    if (UNLIKELY(exec->hadException()))
     2862        return false;
     2863    return validateAndApplyPropertyDescriptor(exec, this, propertyName, isExtensible, descriptor, isCurrentDefined, current, throwException);
    28522864}
    28532865
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r197391 r197412  
    616616    JS_EXPORT_PRIVATE void freeze(VM&);
    617617    JS_EXPORT_PRIVATE static bool preventExtensions(JSObject*, ExecState*);
     618    JS_EXPORT_PRIVATE static bool isExtensible(JSObject*, ExecState*);
    618619    bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
    619620    bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
    620     bool isExtensible() { return structure()->isExtensible(); }
     621private:
     622    ALWAYS_INLINE bool isExtensibleImpl() { return isStructureExtensible(); }
     623public:
     624    // You should only call isStructureExtensible() when:
     625    // - Performing this check in a way that isn't described in the specification
     626    //   as calling the virtual [[IsExtensible]] trap.
     627    // - When you're guaranteed that object->methodTable()->isExtensible isn't
     628    //   overridden.
     629    ALWAYS_INLINE bool isStructureExtensible() { return structure()->isStructureExtensible(); }
     630    // You should call this when performing [[IsExtensible]] trap in a place
     631    // that is described in the specification. This performs the fully virtual
     632    // [[IsExtensible]] trap.
     633    ALWAYS_INLINE bool isExtensibleInline(ExecState* exec)
     634    {
     635        VM& vm = exec->vm();
     636        auto isExtensibleMethod = methodTable(vm)->isExtensible;
     637        if (LIKELY(isExtensibleMethod == JSObject::isExtensible))
     638            return isExtensibleImpl();
     639
     640        return isExtensibleMethod(this, exec);
     641    }
    621642    bool indexingShouldBeSparse()
    622643    {
    623         return !isExtensible()
     644        return !isStructureExtensible()
    624645            || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
    625646    }
     
    12731294        }
    12741295
    1275         if ((mode == PutModePut) && !isExtensible())
     1296        if ((mode == PutModePut) && !isStructureExtensible())
    12761297            return false;
    12771298
     
    13381359    }
    13391360
    1340     if ((mode == PutModePut) && !isExtensible())
     1361    if ((mode == PutModePut) && !isStructureExtensible())
    13411362        return false;
    13421363
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r197391 r197412  
    213213        return JSValue::encode(objectValue);
    214214
    215     if (!object->isExtensible())
     215    bool isExtensible = object->isExtensibleInline(exec);
     216    if (exec->hadException())
     217        return JSValue::encode(JSValue());
     218    if (!isExtensible)
    216219        return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
    217220
     
    617620    // 3. If the [[Extensible]] internal property of O is false, then return true.
    618621    // 4. Otherwise, return false.
    619     return JSValue::encode(jsBoolean(!object->isExtensible()));
     622    bool isExtensible = object->isExtensibleInline(exec);
     623    if (exec->hadException())
     624        return JSValue::encode(JSValue());
     625    return JSValue::encode(jsBoolean(!isExtensible));
    620626}
    621627
     
    651657    // 3. If the [[Extensible]] internal property of O is false, then return true.
    652658    // 4. Otherwise, return false.
    653     return JSValue::encode(jsBoolean(!object->isExtensible()));
     659    bool isExtensible = object->isExtensibleInline(exec);
     660    if (exec->hadException())
     661        return JSValue::encode(JSValue());
     662    return JSValue::encode(jsBoolean(!isExtensible));
    654663}
    655664
     
    659668    if (!obj.isObject())
    660669        return JSValue::encode(jsBoolean(false));
    661     return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));
     670    JSObject* object = asObject(obj);
     671    bool isExtensible = object->isExtensibleInline(exec);
     672    if (exec->hadException())
     673        return JSValue::encode(JSValue());
     674    return JSValue::encode(jsBoolean(isExtensible));
    662675}
    663676
  • trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp

    r197383 r197412  
    197197        // FIXME: this doesn't work if 'target' is another Proxy. We don't have isExtensible implemented in a way that fits w/ Proxys.
    198198        // https://bugs.webkit.org/show_bug.cgi?id=154375
    199         if (!target->isExtensible()) {
     199        bool isExtensible = target->isExtensibleInline(exec);
     200        if (exec->hadException())
     201            return false;
     202        if (!isExtensible) {
    200203            // FIXME: Come up with a test for this error. I'm not sure how to because
    201204            // Object.seal(o) will make all fields [[Configurable]] false.
     
    208211    }
    209212
     213    bool isExtensible = target->isExtensibleInline(exec);
     214    if (exec->hadException())
     215        return false;
    210216    PropertyDescriptor trapResultAsDescriptor;
    211217    toPropertyDescriptor(exec, trapResult, trapResultAsDescriptor);
     
    213219        return false;
    214220    bool throwException = false;
    215     bool valid = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, target->isExtensible(),
     221    bool valid = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, isExtensible,
    216222        trapResultAsDescriptor, isTargetPropertyDescriptorDefined, targetPropertyDescriptor, throwException);
    217223    if (!valid) {
     
    289295                return false;
    290296            }
    291             if (!target->isExtensible()) {
     297            bool isExtensible = target->isExtensibleInline(exec);
     298            if (exec->hadException())
     299                return false;
     300            if (!isExtensible) {
    292301                throwVMTypeError(exec, ASCIILiteral("Proxy 'has' must return 'true' for a non-extensible 'target' object with a configurable property."));
    293302                return false;
  • trunk/Source/JavaScriptCore/runtime/ReflectObject.cpp

    r197391 r197412  
    169169    if (!target.isObject())
    170170        return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.isExtensible requires the first argument be an object")));
    171     return JSValue::encode(jsBoolean(asObject(target)->isExtensible()));
     171
     172    bool isExtensible = asObject(target)->isExtensibleInline(exec);
     173    if (exec->hadException())
     174        return JSValue::encode(JSValue());
     175    return JSValue::encode(jsBoolean(isExtensible));
    172176}
    173177
     
    212216        return JSValue::encode(jsBoolean(true));
    213217
    214     if (!object->isExtensible())
     218    bool isExtensible = object->isExtensibleInline(exec);
     219    if (exec->hadException())
     220        return JSValue::encode(JSValue());
     221    if (!isExtensible)
    215222        return JSValue::encode(jsBoolean(false));
    216223
  • trunk/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp

    r196490 r197412  
    9999    // In the uncommon case that this is a new property, and the array is not
    100100    // extensible, this is not the right thing to have done - so remove again.
    101     if (result.isNewEntry && !array->isExtensible()) {
     101    if (result.isNewEntry && !array->isStructureExtensible()) {
    102102        remove(result.iterator);
    103103        if (shouldThrow)
     
    119119    // In the uncommon case that this is a new property, and the array is not
    120120    // extensible, this is not the right thing to have done - so remove again.
    121     if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isExtensible()) {
     121    if (mode != PutDirectIndexLikePutDirect && result.isNewEntry && !array->isStructureExtensible()) {
    122122        remove(result.iterator);
    123123        return reject(exec, mode == PutDirectIndexShouldThrow, "Attempting to define property on object that is not extensible.");
  • trunk/Source/JavaScriptCore/runtime/StringObject.cpp

    r187355 r197412  
    8787
    8888    if (propertyName == exec->propertyNames().length) {
    89         if (!object->isExtensible()) {
     89        bool isExtensible = object->isExtensibleInline(exec);
     90        if (exec->hadException())
     91            return false;
     92        if (!isExtensible) {
    9093            if (throwException)
    9194                exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r197391 r197412  
    692692bool Structure::isSealed(VM& vm)
    693693{
    694     if (isExtensible())
     694    if (isStructureExtensible())
    695695        return false;
    696696
     
    711711bool Structure::isFrozen(VM& vm)
    712712{
    713     if (isExtensible())
     713    if (isStructureExtensible())
    714714        return false;
    715715
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r197391 r197412  
    184184    JS_EXPORT_PRIVATE bool isSealed(VM&);
    185185    JS_EXPORT_PRIVATE bool isFrozen(VM&);
    186     bool isExtensible() const { return !didPreventExtensions(); }
     186    bool isStructureExtensible() const { return !didPreventExtensions(); }
    187187    bool putWillGrowOutOfLineStorage();
    188188    size_t suggestedNewOutOfLineStorageCapacity();
Note: See TracChangeset for help on using the changeset viewer.