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);