From 827276c2d159a3a2cecc137c623a0eb2425a23e8 Mon Sep 17 00:00:00 2001 From: Yusuke Suzuki Date: Fri, 15 Mar 2024 12:01:30 -0700 Subject: [PATCH] PropertyCondition::isValidValueForAttributes should handle custom accessor and custom value https://bugs.webkit.org/show_bug.cgi?id=266695 rdar://119854137 Reviewed by Mark Lam. PropertyCondition::isValidValueForAttributes only handled accessors and values. And it didn't handle custom accessor / custom values. This patch changes it so that we can check custom accessor / custom value cases correctly. * JSTests/stress/attribute-custom-accessor.js: Added. (async asyncSleep): (setHasBeenDictionary): (watchToJSONForReplacements): (async watchLastMatchForReplacements.getLastMatch): (async watchLastMatchForReplacements): (const.target.toJSON): (opt): (async main): * Source/JavaScriptCore/bytecode/PropertyCondition.cpp: (JSC::PropertyCondition::isValidValueForAttributes): Originally-landed-as: 272448.6@safari-7618-branch (24d1c08b9dfa). rdar://124557469 Canonical link: https://commits.webkit.org/276183@main --- JSTests/stress/attribute-custom-accessor.js | 87 +++++++++++++++++++ .../bytecode/PropertyCondition.cpp | 8 +- 2 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 JSTests/stress/attribute-custom-accessor.js diff --git a/JSTests/stress/attribute-custom-accessor.js b/JSTests/stress/attribute-custom-accessor.js new file mode 100644 index 0000000000000..268025cff0943 --- /dev/null +++ b/JSTests/stress/attribute-custom-accessor.js @@ -0,0 +1,87 @@ +async function asyncSleep(ms) { + return new Promise(resolve => { + setTimeout(() => { + resolve(); + }, ms); + }); +} + +function reifyAllStaticProperties(object) { + Object.assign({}, object); +} + +function setHasBeenDictionary(object) { + for (let i = 0; i < 100; i++) { + object.b = 1; + delete object.b; + } + + for (const x in Object.create(object)) { + + } +} + +function watchToJSONForReplacements(object) { + JSON.stringify(Object.create(object)); +} + +async function watchLastMatchForReplacements(object) { + const tmp = Object.create(object); + function getLastMatch() { + return tmp.lastMatch; + } + + for (let i = 0; i < 2000; i++) { + try { + getLastMatch(); + } catch { + + } + } + + await asyncSleep(500); +} + +const target = { + toJSON: (() => { + const object = {}; + for (let i = 0; i < 10; i++) { + object['a' + i] = 1; + } + + object.lastMatch = 0x8888; + + return object; + })() +}; + +function opt() { + return target.toJSON.lastMatch; +} + +async function main() { + setHasBeenDictionary(target); + + reifyAllStaticProperties(RegExp); + await watchLastMatchForReplacements(RegExp); + + for (let i = 0; i < 2000; i++) { + opt(); + } + + await asyncSleep(200); + + target.toJSON = RegExp; + target.b = 1; + + watchToJSONForReplacements(target); + + await asyncSleep(1000); + + const custom_getter_setter = opt(); + describe(custom_getter_setter); + + custom_getter_setter.x = 1; +} + +main(); diff --git a/Source/JavaScriptCore/bytecode/PropertyCondition.cpp b/Source/JavaScriptCore/bytecode/PropertyCondition.cpp index 502e15db389e5..028a54299f323 100644 --- a/Source/JavaScriptCore/bytecode/PropertyCondition.cpp +++ b/Source/JavaScriptCore/bytecode/PropertyCondition.cpp @@ -498,9 +498,11 @@ bool PropertyCondition::isValidValueForAttributes(JSValue value, unsigned attrib { if (!value) return false; - bool attributesClaimAccessor = !!(attributes & PropertyAttribute::Accessor); - bool valueClaimsAccessor = !!jsDynamicCast(value); - return attributesClaimAccessor == valueClaimsAccessor; + if (value.inherits()) + return attributes & PropertyAttribute::Accessor; + if (value.inherits()) + return attributes & PropertyAttribute::CustomAccessorOrValue; + return !(attributes & PropertyAttribute::AccessorOrCustomAccessorOrValue); } bool PropertyCondition::isValidValueForPresence(JSValue value) const