Title: [295608] trunk
Revision
295608
Author
shvaikal...@gmail.com
Date
2022-06-16 13:11:51 -0700 (Thu, 16 Jun 2022)

Log Message

CommonSlowPaths::putDirectWithReify() is incorrect for DontDelete properties
https://bugs.webkit.org/show_bug.cgi?id=241651
<rdar://94016559>

Reviewed by Saam Barati.

Provided the base object has no read-only / accessor / custom properties,
putDirectWithReify() is incorrect for an object with non-configurable property,
whether it's on the structure or a non-reified static none.

In that case, putDirectWithReify() ignores existing non-configurable / non-reified
descriptor and produces an incorrect property descriptor instead of throwing TypeError.
One it's observed in the wild is via an instance field [1].

The issue was due to incorrect ReadOnly-focused check for putDirect() fast path,
which would be correct for [[Set]] but not for [[DefineOwnProperty]].

Apart from introducing tighter fast patch check, this change extracts
JSFunction::mayHaveNonReifiedPrototype() helper, cleaning up JSFunction's overrides,
and removes now unused PutModeDefineOwnPropertyIgnoringExtensibility, which apart from
ignoring extensibility, also ignored read-only / accessor / custom properties,
which felt a bit counter-intuitive.

This change carefully preserves the fast path introduced in webkit.org/b/232479.

[1]: https://tc39.es/ecma262/#sec-definefield

* Source/_javascript_Core/runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::originalStructureBeforePut):
(JSC::CommonSlowPaths::canPutDirectFast):
(JSC::CommonSlowPaths::putDirectWithReify):
(JSC::CommonSlowPaths::putDirectAccessorWithReify):
* Source/_javascript_Core/runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::put):
(JSC::JSFunction::deleteProperty):
(JSC::JSFunction::defineOwnProperty):
(JSC::JSFunction::reifyLazyPropertyIfNeeded):
(JSC::JSFunction::reifyLazyPrototypeIfNeeded):
* Source/_javascript_Core/runtime/JSFunction.h:
* Source/_javascript_Core/runtime/JSFunctionInlines.h:
(JSC::JSFunction::mayHaveNonReifiedPrototype):
* Source/_javascript_Core/runtime/JSObject.cpp:
(JSC::JSObject::putDirectCustomAccessor):
(JSC::JSObject::putDirectNonIndexAccessor):
* Source/_javascript_Core/runtime/JSObject.h:
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectRespectingExtensibility): Deleted.
* Source/_javascript_Core/runtime/JSObjectInlines.h:
(JSC::JSObject::putDirectInternal):
* Source/_javascript_Core/tools/JSDollarVM.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::JSDollarVM::finishCreation):

Canonical link: https://commits.webkit.org/251613@main

Modified Paths

Added Paths

Diff

Added: trunk/JSTests/stress/putDirectWithReify-JSFinalObject.js (0 => 295608)


--- trunk/JSTests/stress/putDirectWithReify-JSFinalObject.js	                        (rev 0)
+++ trunk/JSTests/stress/putDirectWithReify-JSFinalObject.js	2022-06-16 20:11:51 UTC (rev 295608)
@@ -0,0 +1,107 @@
+"use strict";
+
+const runs = 1e5;
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`Bad value: ${actual}!`);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    try {
+        func();
+    } catch (error) {
+        errorThrown = true;
+        if (String(error) !== errorMessage)
+            throw new Error(`Bad error: ${error}!`);
+    }
+    if (!errorThrown)
+        throw new Error(`Didn't throw!`);
+}
+
+(function testFinalObject() {
+    class TestFinalObjectDontDeleteBase {
+        constructor() {
+            Object.defineProperty(this, "foo", { value: 1, writable: true, enumerable: true, configurable: false });
+        }
+    }
+
+    class TestFinalObjectDontDelete extends TestFinalObjectDontDeleteBase {
+        foo = 1;
+    }
+
+    for (var i = 0; i < runs; i++) {
+        shouldThrow(() => { new TestFinalObjectDontDelete(); }, "TypeError: Attempting to change configurable attribute of unconfigurable property.");
+    }
+
+    ///
+
+    class TestFinalObjectReadOnlyBase {
+        constructor() {
+            Object.defineProperty(this, "foo", { value: 1, writable: false, enumerable: false, configurable: true });
+        }
+    }
+
+    class TestFinalObjectReadOnly extends TestFinalObjectReadOnlyBase {
+        foo = 42;
+    }
+
+    for (var i = 0; i < runs; i++) {
+        var object = new TestFinalObjectReadOnly();
+        shouldBe(object.foo, 42);
+
+        var fooDesc = Object.getOwnPropertyDescriptor(object, "foo");
+        shouldBe(fooDesc.value, 42);
+        shouldBe(fooDesc.writable, true);
+        shouldBe(fooDesc.enumerable, true);
+        shouldBe(fooDesc.configurable, true);
+    }
+
+    ///
+
+    class TestFinalObjectNonExtendableBase {
+        constructor() {
+            Object.preventExtensions(this);
+        }
+    }
+
+    class TestFinalObjectNonExtendable extends TestFinalObjectNonExtendableBase {
+        foo = 42;
+    }
+
+    for (var i = 0; i < runs; i++) {
+        shouldThrow(() => { new TestFinalObjectNonExtendable(); }, "TypeError: Attempting to define property on object that is not extensible.");
+    }
+})();
+
+(function testNonReifiedStatic() {
+    class TestNonReifiedStaticBase {
+        constructor() {
+            return $vm.createStaticDontDeleteDontEnum();
+        }
+    }
+
+    class TestNonReifiedStaticDontEnum extends TestNonReifiedStaticBase {
+        dontEnum = 42;
+    }
+
+    for (var i = 0; i < runs; i++) {
+        var object = new TestNonReifiedStaticDontEnum();
+        shouldBe(object.dontEnum, 42);
+
+        var dontEnumDesc = Object.getOwnPropertyDescriptor(object, "dontEnum");
+        shouldBe(dontEnumDesc.value, 42);
+        shouldBe(dontEnumDesc.writable, true);
+        shouldBe(dontEnumDesc.enumerable, true);
+        shouldBe(dontEnumDesc.configurable, true);
+    }
+
+    class TestNonReifiedStaticDontDelete extends TestNonReifiedStaticBase {
+        dontDelete = "foo";
+    }
+
+    for (var i = 0; i < runs; i++) {
+        shouldThrow(() => { new TestNonReifiedStaticDontDelete(); }, "TypeError: Attempting to change configurable attribute of unconfigurable property.");
+    }
+})();

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2022-06-16 20:11:51 UTC (rev 295608)
@@ -178,15 +178,40 @@
     return false;
 }
 
+ALWAYS_INLINE Structure* originalStructureBeforePut(JSCell* cell)
+{
+    if (cell->type() == PureForwardingProxyType)
+        return jsCast<JSProxy*>(cell)->target()->structure();
+    return cell->structure();
+}
+
 ALWAYS_INLINE Structure* originalStructureBeforePut(JSValue value)
 {
     if (!value.isCell())
         return nullptr;
-    if (value.asCell()->type() == PureForwardingProxyType)
-        return jsCast<JSProxy*>(value)->target()->structure();
-    return value.asCell()->structure();
+    return originalStructureBeforePut(value.asCell());
 }
 
+static ALWAYS_INLINE bool canPutDirectFast(VM& vm, Structure* structure, PropertyName propertyName, bool isJSFunction)
+{
+    if (!structure->isStructureExtensible())
+        return false;
+
+    unsigned currentAttributes = 0;
+    structure->get(vm, propertyName, currentAttributes);
+    if (currentAttributes & PropertyAttribute::DontDelete)
+        return false;
+
+    if (!isJSFunction) {
+        if (structure->hasNonReifiedStaticProperties())
+            return false;
+        if (structure->classInfoForCells()->methodTable.defineOwnProperty != &JSObject::defineOwnProperty)
+            return false;
+    }
+
+    return true;
+}
+
 static ALWAYS_INLINE void putDirectWithReify(VM& vm, JSGlobalObject* globalObject, JSObject* baseObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot, Structure** result = nullptr)
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -195,14 +220,14 @@
         jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, void());
     }
+
+    Structure* structure = originalStructureBeforePut(baseObject);
     if (result)
-        *result = originalStructureBeforePut(baseObject);
+        *result = structure;
 
-    Structure* structure = baseObject->structure();
-    if (LIKELY(propertyName != vm.propertyNames->underscoreProto && !structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && (isJSFunction || structure->classInfoForCells()->methodTable.defineOwnProperty == &JSObject::defineOwnProperty))) {
-        auto error = baseObject->putDirectRespectingExtensibility(vm, propertyName, value, 0, slot);
-        if (!error.isNull())
-            typeError(globalObject, scope, slot.isStrictMode(), error);
+    if (LIKELY(canPutDirectFast(vm, structure, propertyName, isJSFunction))) {
+        bool success = baseObject->putDirect(vm, propertyName, value, 0, slot);
+        ASSERT_UNUSED(success, success);
     } else {
         slot.disableCaching();
         scope.release();
@@ -214,10 +239,16 @@
 static ALWAYS_INLINE void putDirectAccessorWithReify(VM& vm, JSGlobalObject* globalObject, JSObject* baseObject, PropertyName propertyName, GetterSetter* accessor, unsigned attribute)
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
-    if (baseObject->inherits<JSFunction>()) {
+    bool isJSFunction = baseObject->inherits<JSFunction>();
+    if (isJSFunction) {
         jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, void());
     }
+
+    // baseObject is either JSFinalObject during object literal construction, or a userland JSFunction class
+    // constructor, both of which are guaranteed to be extensible and without non-configurable |propertyName|.
+    // Please also note that static "prototype" accessor in a `class` literal is a syntax error.
+    ASSERT(canPutDirectFast(vm, originalStructureBeforePut(baseObject), propertyName, isJSFunction));
     scope.release();
     baseObject->putDirectAccessor(globalObject, propertyName, accessor, attribute);
 }

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2022-06-16 20:11:51 UTC (rev 295608)
@@ -330,13 +330,8 @@
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     JSFunction* thisObject = jsCast<JSFunction*>(object);
-    if (thisObject->isHostOrBuiltinFunction()) {
-        thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
-        RELEASE_AND_RETURN(scope, Base::getOwnPropertySlot(thisObject, globalObject, propertyName, slot));
-    }
 
-    if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty()) {
+    if (propertyName == vm.propertyNames->prototype && thisObject->mayHaveNonReifiedPrototype()) {
         unsigned attributes;
         PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
         if (!isValidOffset(offset)) {
@@ -386,15 +381,7 @@
             rareData->setHasModifiedNameForNonHostFunction();
     }
 
-    if (thisObject->isHostOrBuiltinFunction()) {
-        PropertyStatus propertyType = thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
-        if (isLazy(propertyType))
-            slot.disableCaching();
-        RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
-    }
-
-    if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty()) {
+    if (propertyName == vm.propertyNames->prototype && thisObject->mayHaveNonReifiedPrototype()) {
         slot.disableCaching();
         if (FunctionRareData* rareData = thisObject->rareData())
             rareData->clear("Store to prototype property of a function");
@@ -429,17 +416,8 @@
             rareData->setHasModifiedNameForNonHostFunction();
     }
 
-    if (thisObject->isHostOrBuiltinFunction()) {
-        thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
-    } else if (vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
-        // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
-        if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty())
-            return false;
-
-        thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
-    }
+    thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
+    RETURN_IF_EXCEPTION(scope, false);
     
     RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, propertyName, slot));
 }
@@ -459,13 +437,7 @@
             rareData->setHasModifiedNameForNonHostFunction();
     }
 
-    if (thisObject->isHostOrBuiltinFunction()) {
-        thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
-        RETURN_IF_EXCEPTION(scope, false);
-        RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
-    }
-
-    if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty()) {
+    if (propertyName == vm.propertyNames->prototype && thisObject->mayHaveNonReifiedPrototype()) {
         if (FunctionRareData* rareData = thisObject->rareData())
             rareData->clear("Store to prototype property of a function");
         if (!isValidOffset(thisObject->getDirectOffset(vm, propertyName))) {
@@ -634,8 +606,12 @@
 
 JSFunction::PropertyStatus JSFunction::reifyLazyPropertyIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
 {
-    if (isHostOrBuiltinFunction() && !this->inherits<JSBoundFunction>() && !this->inherits<JSRemoteFunction>())
-        return PropertyStatus::Eager;
+    if (isHostOrBuiltinFunction())
+        return reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
+
+    PropertyStatus lazyPrototype = reifyLazyPrototypeIfNeeded(vm, globalObject, propertyName);
+    if (isLazy(lazyPrototype))
+        return lazyPrototype;
     PropertyStatus lazyLength = reifyLazyLengthIfNeeded(vm, globalObject, propertyName);
     if (isLazy(lazyLength))
         return lazyLength;
@@ -656,6 +632,20 @@
     return reifyLazyBoundNameIfNeeded(vm, globalObject, propertyName);
 }
 
+JSFunction::PropertyStatus JSFunction::reifyLazyPrototypeIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
+{
+    if (propertyName == vm.propertyNames->prototype && mayHaveNonReifiedPrototype()) {
+        if (!getDirect(vm, propertyName)) {
+            // For class constructors, prototype object is initialized from bytecode via defineOwnProperty().
+            ASSERT(!jsExecutable()->isClassConstructorFunction());
+            putDirect(vm, propertyName, constructPrototypeObject(globalObject, this), prototypeAttributesForNonClass);
+            return PropertyStatus::Reified;
+        }
+        return PropertyStatus::Lazy;
+    }
+    return PropertyStatus::Eager;
+}
+
 JSFunction::PropertyStatus JSFunction::reifyLazyLengthIfNeeded(VM& vm, JSGlobalObject*, PropertyName propertyName)
 {
     if (propertyName == vm.propertyNames->length) {

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSFunction.h	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h	2022-06-16 20:11:51 UTC (rev 295608)
@@ -168,6 +168,7 @@
     PropertyStatus reifyLazyPropertyIfNeeded(VM&, JSGlobalObject*, PropertyName);
 
     bool canAssumeNameAndLengthAreOriginal(VM&);
+    bool mayHaveNonReifiedPrototype();
 
 protected:
     JS_EXPORT_PRIVATE JSFunction(VM&, NativeExecutable*, JSGlobalObject*, Structure*);
@@ -209,6 +210,7 @@
     static bool isReified(PropertyStatus property) { return property == PropertyStatus::Reified; }
 
     PropertyStatus reifyLazyPropertyForHostOrBuiltinIfNeeded(VM&, JSGlobalObject*, PropertyName);
+    PropertyStatus reifyLazyPrototypeIfNeeded(VM&, JSGlobalObject*, PropertyName);
     PropertyStatus reifyLazyLengthIfNeeded(VM&, JSGlobalObject*, PropertyName);
     PropertyStatus reifyLazyNameIfNeeded(VM&, JSGlobalObject*, PropertyName);
     PropertyStatus reifyLazyBoundNameIfNeeded(VM&, JSGlobalObject*, PropertyName);

Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h	2022-06-16 20:11:51 UTC (rev 295608)
@@ -139,6 +139,11 @@
     return true;
 }
 
+inline bool JSFunction::mayHaveNonReifiedPrototype()
+{
+    return !isHostOrBuiltinFunction() && jsExecutable()->hasPrototypeProperty();
+}
+
 inline bool JSFunction::canUseAllocationProfile()
 {
     if (isHostOrBuiltinFunction()) {

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2022-06-16 20:11:51 UTC (rev 295608)
@@ -2015,7 +2015,7 @@
         attributes |= PropertyAttribute::CustomValue;
 
     PutPropertySlot slot(this);
-    bool result = putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
+    bool result = putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot).isNull();
 
     ASSERT(slot.type() == PutPropertySlot::NewProperty);
 
@@ -2046,7 +2046,7 @@
 {
     ASSERT(attributes & PropertyAttribute::Accessor);
     PutPropertySlot slot(this);
-    bool result = putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, accessor, attributes, slot).isNull();
+    bool result = putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, accessor, attributes, slot).isNull();
 
     Structure* structure = this->structure();
     if (attributes & PropertyAttribute::ReadOnly)

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2022-06-16 20:11:51 UTC (rev 295608)
@@ -104,7 +104,6 @@
     enum PutMode : uint8_t {
         PutModePut,
         PutModeDefineOwnProperty,
-        PutModeDefineOwnPropertyIgnoringExtensibility,
     };
 
 public:
@@ -687,7 +686,6 @@
     bool putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0);
     bool putDirect(VM&, PropertyName, JSValue, unsigned attributes, PutPropertySlot&);
     bool putDirect(VM&, PropertyName, JSValue, PutPropertySlot&);
-    ASCIILiteral putDirectRespectingExtensibility(VM&, PropertyName, JSValue, unsigned attributes, PutPropertySlot&);
     void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
     bool putDirectNonIndexAccessor(VM&, PropertyName, GetterSetter*, unsigned attributes);
     void putDirectNonIndexAccessorWithoutTransition(VM&, PropertyName, GetterSetter*, unsigned attributes);
@@ -1586,7 +1584,7 @@
     ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor));
     ASSERT(!value.isCustomGetterSetter() && !(attributes & PropertyAttribute::CustomAccessorOrValue));
     PutPropertySlot slot(this);
-    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
+    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot).isNull();
 }
 
 inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
@@ -1593,7 +1591,7 @@
 {
     ASSERT(!value.isGetterSetter());
     ASSERT(!value.isCustomGetterSetter());
-    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, attributes, slot).isNull();
+    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot).isNull();
 }
 
 inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
@@ -1600,16 +1598,9 @@
 {
     ASSERT(!value.isGetterSetter());
     ASSERT(!value.isCustomGetterSetter());
-    return putDirectInternal<PutModeDefineOwnPropertyIgnoringExtensibility>(vm, propertyName, value, 0, slot).isNull();
+    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot).isNull();
 }
 
-inline ASCIILiteral JSObject::putDirectRespectingExtensibility(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
-{
-    ASSERT(!value.isGetterSetter());
-    ASSERT(!value.isCustomGetterSetter());
-    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
-}
-
 constexpr inline intptr_t offsetInButterfly(PropertyOffset offset)
 {
     return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();

Modified: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (295607 => 295608)


--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h	2022-06-16 20:11:51 UTC (rev 295608)
@@ -331,7 +331,7 @@
         unsigned currentAttributes;
         PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
         if (offset != invalidOffset) {
-            if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
+            if (mode == PutModePut && (currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor))
                 return ReadonlyPropertyChangeError;
 
             putDirectOffset(vm, offset, value);
@@ -339,7 +339,7 @@
 
             // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition.
             // https://bugs.webkit.org/show_bug.cgi?id=214342
-            if ((mode == PutModeDefineOwnProperty || mode == PutModeDefineOwnPropertyIgnoringExtensibility) && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue)))
+            if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue)))
                 setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
             else {
                 ASSERT(!(currentAttributes & PropertyAttribute::AccessorOrCustomAccessorOrValue));
@@ -349,7 +349,7 @@
             return { };
         }
 
-        if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && !isStructureExtensible())
+        if (mode == PutModePut && !isStructureExtensible())
             return NonExtensibleObjectPropertyDefineError;
 
         offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure);
@@ -388,7 +388,7 @@
     unsigned currentAttributes;
     offset = structure->get(vm, propertyName, currentAttributes);
     if (offset != invalidOffset) {
-        if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
+        if (mode == PutModePut && (currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor))
             return ReadonlyPropertyChangeError;
 
         structure->didReplaceProperty(offset);
@@ -396,7 +396,7 @@
 
         // FIXME: Check attributes against PropertyAttribute::CustomAccessorOrValue. Changing GetterSetter should work w/o transition.
         // https://bugs.webkit.org/show_bug.cgi?id=214342
-        if ((mode == PutModeDefineOwnProperty || mode == PutModeDefineOwnPropertyIgnoringExtensibility) && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) {
+        if (mode == PutModeDefineOwnProperty && (attributes != currentAttributes || (attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue))) {
             // We want the structure transition watchpoint to fire after this object has switched structure.
             // This allows adaptive watchpoints to observe if the new structure is the one we want.
             DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure);
@@ -409,7 +409,7 @@
         return { };
     }
 
-    if ((mode == PutModePut || mode == PutModeDefineOwnProperty) && !isStructureExtensible())
+    if (mode == PutModePut && !isStructureExtensible())
         return NonExtensibleObjectPropertyDefineError;
     
     // We want the structure transition watchpoint to fire after this object has switched structure.

Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (295607 => 295608)


--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2022-06-16 20:00:12 UTC (rev 295607)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2022-06-16 20:11:51 UTC (rev 295608)
@@ -887,6 +887,68 @@
     }
 };
 
+static JSC_DECLARE_HOST_FUNCTION(staticDontDeleteDontEnumMethod);
+
+class StaticDontDeleteDontEnum : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    StaticDontDeleteDontEnum(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+        DollarVMAssertScope assertScope;
+    }
+
+    DECLARE_INFO;
+
+    template<typename CellType, SubspaceAccess>
+    static CompleteSubspace* subspaceFor(VM& vm)
+    {
+        return &vm.cellSpace();
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        DollarVMAssertScope assertScope;
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    static StaticDontDeleteDontEnum* create(VM& vm, Structure* structure)
+    {
+        DollarVMAssertScope assertScope;
+        StaticDontDeleteDontEnum* result = new (NotNull, allocateCell<StaticDontDeleteDontEnum>(vm)) StaticDontDeleteDontEnum(vm, structure);
+        result->finishCreation(vm);
+        return result;
+    }
+};
+
+JSC_DEFINE_HOST_FUNCTION(staticDontDeleteDontEnumMethod, (JSGlobalObject*, CallFrame*))
+{
+    DollarVMAssertScope assertScope;
+    return encodedJSUndefined();
+}
+
+static const struct CompactHashIndex staticDontDeleteDontEnumTableIndex[8] = {
+    { 0, -1 },
+    { 1, -1 },
+    { -1, -1 },
+    { -1, -1 },
+    { -1, -1 },
+    { 2, -1 },
+    { -1, -1 },
+    { -1, -1 },
+};
+
+static const struct HashTableValue staticDontDeleteDontEnumTableValues[3] = {
+   { "dontEnum"_s, static_cast<unsigned>(PropertyAttribute::Function|PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(staticDontDeleteDontEnumMethod), (intptr_t)(0) } },
+   { "dontDelete"_s, static_cast<unsigned>(PropertyAttribute::Function|PropertyAttribute::DontDelete), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(staticDontDeleteDontEnumMethod), (intptr_t)(0) } },
+   { "dontDeleteDontEnum"_s, static_cast<unsigned>(PropertyAttribute::Function|PropertyAttribute::DontDelete|PropertyAttribute::DontEnum), NoIntrinsic, { (intptr_t)static_cast<RawNativeFunction>(staticDontDeleteDontEnumMethod), (intptr_t)(0) } },
+};
+
+static const struct HashTable staticDontDeleteDontEnumTable =
+    { 3, 7, false, nullptr, staticDontDeleteDontEnumTableValues, staticDontDeleteDontEnumTableIndex };
+
 class ObjectDoingSideEffectPutWithoutCorrectSlotStatus : public JSNonFinalObject {
     using Base = JSNonFinalObject;
     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesPut;
@@ -1803,6 +1865,7 @@
 
 const ClassInfo StaticCustomAccessor::s_info = { "StaticCustomAccessor"_s, &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(StaticCustomAccessor) };
 const ClassInfo StaticCustomValue::s_info = { "StaticCustomValue"_s, &Base::s_info, &staticCustomValueTable, nullptr, CREATE_METHOD_TABLE(StaticCustomValue) };
+const ClassInfo StaticDontDeleteDontEnum::s_info = { "StaticDontDeleteDontEnum"_s, &Base::s_info, &staticDontDeleteDontEnumTable, nullptr, CREATE_METHOD_TABLE(StaticDontDeleteDontEnum) };
 const ClassInfo ObjectDoingSideEffectPutWithoutCorrectSlotStatus::s_info = { "ObjectDoingSideEffectPutWithoutCorrectSlotStatus"_s, &Base::s_info, &staticCustomAccessorTable, nullptr, CREATE_METHOD_TABLE(ObjectDoingSideEffectPutWithoutCorrectSlotStatus) };
 
 ElementHandleOwner* Element::handleOwner()
@@ -2079,6 +2142,7 @@
 #endif
 static JSC_DECLARE_HOST_FUNCTION(functionCreateStaticCustomAccessor);
 static JSC_DECLARE_HOST_FUNCTION(functionCreateStaticCustomValue);
+static JSC_DECLARE_HOST_FUNCTION(functionCreateStaticDontDeleteDontEnum);
 static JSC_DECLARE_HOST_FUNCTION(functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus);
 static JSC_DECLARE_HOST_FUNCTION(functionCreateEmptyFunctionWithName);
 static JSC_DECLARE_HOST_FUNCTION(functionSetImpureGetterDelegate);
@@ -3081,6 +3145,16 @@
     return JSValue::encode(result);
 }
 
+JSC_DEFINE_HOST_FUNCTION(functionCreateStaticDontDeleteDontEnum, (JSGlobalObject* globalObject, CallFrame*))
+{
+    DollarVMAssertScope assertScope;
+    VM& vm = globalObject->vm();
+    JSLockHolder lock(vm);
+    Structure* structure = StaticDontDeleteDontEnum::createStructure(vm, globalObject, jsNull());
+    auto* result = StaticDontDeleteDontEnum::create(vm, structure);
+    return JSValue::encode(result);
+}
+
 JSC_DEFINE_HOST_FUNCTION(functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus, (JSGlobalObject* globalObject, CallFrame* callFrame))
 {
     DollarVMAssertScope assertScope;
@@ -3927,6 +4001,7 @@
 #endif
     addFunction(vm, "createStaticCustomAccessor"_s, functionCreateStaticCustomAccessor, 0);
     addFunction(vm, "createStaticCustomValue"_s, functionCreateStaticCustomValue, 0);
+    addFunction(vm, "createStaticDontDeleteDontEnum"_s, functionCreateStaticDontDeleteDontEnum, 0);
     addFunction(vm, "createObjectDoingSideEffectPutWithoutCorrectSlotStatus"_s, functionCreateObjectDoingSideEffectPutWithoutCorrectSlotStatus, 0);
     addFunction(vm, "createEmptyFunctionWithName"_s, functionCreateEmptyFunctionWithName, 1);
     addFunction(vm, "getPrivateProperty"_s, functionGetPrivateProperty, 2);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to