Added: trunk/JSTests/stress/immutable-butterfly-to-string-cache-should-not-happen-for-generic-join.js (0 => 272406)
--- trunk/JSTests/stress/immutable-butterfly-to-string-cache-should-not-happen-for-generic-join.js (rev 0)
+++ trunk/JSTests/stress/immutable-butterfly-to-string-cache-should-not-happen-for-generic-join.js 2021-02-05 08:45:38 UTC (rev 272406)
@@ -0,0 +1,10 @@
+let x = {
+ __proto__: Object,
+};
+function foo() {
+ Object.defineProperty(Object, 0, {});
+}
+let o = {
+ toString: foo
+};
+delete {}[[...[o]]];
Modified: trunk/Source/_javascript_Core/ChangeLog (272405 => 272406)
--- trunk/Source/_javascript_Core/ChangeLog 2021-02-05 08:45:09 UTC (rev 272405)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-02-05 08:45:38 UTC (rev 272406)
@@ -1,5 +1,21 @@
2021-02-05 Yusuke Suzuki <[email protected]>
+ [JSC] JSImmutableButterfly's toString cache should not happen for generic join
+ https://bugs.webkit.org/show_bug.cgi?id=221444
+ <rdar://problem/73972862>
+
+ Reviewed by Mark Lam.
+
+ We should not cache Array#toString results with JSImmutableButterfly if
+ its join operation becomes generic join: including objects in array, since
+ this can invoke object.toString(), and it isn't side-effect free.
+
+ * runtime/ArrayPrototype.cpp:
+ (JSC::fastJoin):
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+
+2021-02-05 Yusuke Suzuki <[email protected]>
+
[JSC] Atomics.store in DFG / FTL should return ToNumber(input) value
https://bugs.webkit.org/show_bug.cgi?id=221438
<rdar://problem/73973264>
Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (272405 => 272406)
--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2021-02-05 08:45:09 UTC (rev 272405)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp 2021-02-05 08:45:38 UTC (rev 272406)
@@ -449,7 +449,7 @@
return false;
}
-inline JSValue fastJoin(JSGlobalObject* globalObject, JSObject* thisObject, StringView separator, unsigned length, bool* sawHoles = nullptr)
+inline JSValue fastJoin(JSGlobalObject* globalObject, JSObject* thisObject, StringView separator, unsigned length, bool& sawHoles, bool& genericCase)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -468,8 +468,7 @@
if (LIKELY(value))
joiner.appendNumber(vm, value.asInt32());
else {
- if (sawHoles)
- *sawHoles = true;
+ sawHoles = true;
if (!holesKnownToBeOK) {
if (holesMustForwardToPrototype(vm, thisObject))
goto generalCase;
@@ -494,8 +493,7 @@
goto generalCase;
RETURN_IF_EXCEPTION(scope, { });
} else {
- if (sawHoles)
- *sawHoles = true;
+ sawHoles = true;
if (!holesKnownToBeOK) {
if (holesMustForwardToPrototype(vm, thisObject))
goto generalCase;
@@ -519,8 +517,7 @@
if (LIKELY(!isHole(value)))
joiner.appendNumber(vm, value);
else {
- if (sawHoles)
- *sawHoles = true;
+ sawHoles = true;
if (!holesKnownToBeOK) {
if (holesMustForwardToPrototype(vm, thisObject))
goto generalCase;
@@ -568,6 +565,7 @@
}
generalCase:
+ genericCase = true;
JSStringJoiner joiner(globalObject, separator, length);
RETURN_IF_EXCEPTION(scope, { });
for (unsigned i = 0; i < length; ++i) {
@@ -579,6 +577,13 @@
RELEASE_AND_RETURN(scope, joiner.join(globalObject));
}
+ALWAYS_INLINE JSValue fastJoin(JSGlobalObject* globalObject, JSObject* thisObject, StringView separator, unsigned length)
+{
+ bool sawHoles = false;
+ bool genericCase = false;
+ return fastJoin(globalObject, thisObject, separator, length, sawHoles, genericCase);
+}
+
inline bool canUseDefaultArrayJoinForToString(VM& vm, JSObject* thisObject)
{
JSGlobalObject* globalObject = thisObject->globalObject();
@@ -650,10 +655,11 @@
}
bool sawHoles = false;
- JSValue result = fastJoin(globalObject, thisArray, { &comma, 1 }, length, &sawHoles);
+ bool genericCase = false;
+ JSValue result = fastJoin(globalObject, thisArray, { &comma, 1 }, length, sawHoles, genericCase);
RETURN_IF_EXCEPTION(scope, { });
- if (!sawHoles && result && isJSString(result) && isCoW) {
+ if (!sawHoles && !genericCase && result && isJSString(result) && isCoW) {
ASSERT(JSImmutableButterfly::fromButterfly(thisArray->butterfly()) == immutableButterfly);
vm.heap.immutableButterflyToStringCache.add(immutableButterfly, jsCast<JSString*>(result));
}