Title: [266715] trunk
Revision
266715
Author
[email protected]
Date
2020-09-08 00:21:07 -0700 (Tue, 08 Sep 2020)

Log Message

[JSC] Special property caching should check Structure's cacheability
https://bugs.webkit.org/show_bug.cgi?id=216222

Reviewed by Saam Barati.

JSTests:

* stress/module-namespace-object-caching.js: Added.
(shouldBe):
(async fn):
* stress/not-cache-over-uncacheable-dictionary.js: Added.
(shouldBe):
* stress/resources/to-string-module.js: Added.
(export.toString):
* stress/resources/value-of-module.js: Added.
(export.valueOf):

Source/_javascript_Core:

While StructureRareData::cacheSpecialPropertySlow caches properties, the way it takes is incomplete.
It is not checking Structure's cacheability. We were caching miss condition even if structure is !propertyAccessesAreCacheableForAbsence.
We should perform the same check done in IC case. Strictly speaking, we can cache value for uncacheable-dictionary because we are setting
property change watchpoint (which will fire). But it sounds not so profitable if this structure is uncacheable.

* runtime/JSObject.cpp:
(JSC::JSObject::convertToUncacheableDictionary):
* runtime/JSObject.h:
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::cacheSpecialPropertySlow):
* tools/JSDollarVM.cpp:
(JSC::functionToUncacheableDictionary):
(JSC::JSDollarVM::finishCreation):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (266714 => 266715)


--- trunk/JSTests/ChangeLog	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/JSTests/ChangeLog	2020-09-08 07:21:07 UTC (rev 266715)
@@ -1,3 +1,20 @@
+2020-09-08  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Special property caching should check Structure's cacheability
+        https://bugs.webkit.org/show_bug.cgi?id=216222
+
+        Reviewed by Saam Barati.
+
+        * stress/module-namespace-object-caching.js: Added.
+        (shouldBe):
+        (async fn):
+        * stress/not-cache-over-uncacheable-dictionary.js: Added.
+        (shouldBe):
+        * stress/resources/to-string-module.js: Added.
+        (export.toString):
+        * stress/resources/value-of-module.js: Added.
+        (export.valueOf):
+
 2020-09-04  Yusuke Suzuki  <[email protected]>
 
         [JSC] Align legacy Intl constructor behavior to spec

Added: trunk/JSTests/stress/module-namespace-object-caching.js (0 => 266715)


--- trunk/JSTests/stress/module-namespace-object-caching.js	                        (rev 0)
+++ trunk/JSTests/stress/module-namespace-object-caching.js	2020-09-08 07:21:07 UTC (rev 266715)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+async function fn() {
+    // Both should have same structure.
+    const valueOfModule = await import('./resources/value-of-module.js');
+    const toStringModule = await import('./resources/to-string-module.js');
+
+    // These valueOf / toString should not be cached.
+    shouldBe(String(toStringModule), `2020`);
+    shouldBe(Number(toStringModule), 2020); // valueOf should not be cached since namespace object is impure for absent.
+
+    shouldBe(Number(valueOfModule), 42); // If the above access accidentally cached the value, this will not return 42.
+    shouldBe(String(valueOfModule), `42`);
+}
+fn().catch($vm.abort);

Added: trunk/JSTests/stress/not-cache-over-uncacheable-dictionary.js (0 => 266715)


--- trunk/JSTests/stress/not-cache-over-uncacheable-dictionary.js	                        (rev 0)
+++ trunk/JSTests/stress/not-cache-over-uncacheable-dictionary.js	2020-09-08 07:21:07 UTC (rev 266715)
@@ -0,0 +1,14 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+var object = {};
+$vm.toUncacheableDictionary(object);
+shouldBe(String(object), `[object Object]`);
+shouldBe(String(object), `[object Object]`);
+shouldBe(String(object), `[object Object]`);
+object[Symbol.toStringTag] = "OK";
+shouldBe(String(object), `[object OK]`);
+shouldBe(String(object), `[object OK]`);
+shouldBe(String(object), `[object OK]`);

Added: trunk/JSTests/stress/resources/to-string-module.js (0 => 266715)


--- trunk/JSTests/stress/resources/to-string-module.js	                        (rev 0)
+++ trunk/JSTests/stress/resources/to-string-module.js	2020-09-08 07:21:07 UTC (rev 266715)
@@ -0,0 +1,4 @@
+export function toString()
+{
+    return "2020";
+}

Added: trunk/JSTests/stress/resources/value-of-module.js (0 => 266715)


--- trunk/JSTests/stress/resources/value-of-module.js	                        (rev 0)
+++ trunk/JSTests/stress/resources/value-of-module.js	2020-09-08 07:21:07 UTC (rev 266715)
@@ -0,0 +1,4 @@
+export function valueOf()
+{
+    return 42;
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (266714 => 266715)


--- trunk/Source/_javascript_Core/ChangeLog	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-09-08 07:21:07 UTC (rev 266715)
@@ -1,3 +1,24 @@
+2020-09-08  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Special property caching should check Structure's cacheability
+        https://bugs.webkit.org/show_bug.cgi?id=216222
+
+        Reviewed by Saam Barati.
+
+        While StructureRareData::cacheSpecialPropertySlow caches properties, the way it takes is incomplete.
+        It is not checking Structure's cacheability. We were caching miss condition even if structure is !propertyAccessesAreCacheableForAbsence.
+        We should perform the same check done in IC case. Strictly speaking, we can cache value for uncacheable-dictionary because we are setting
+        property change watchpoint (which will fire). But it sounds not so profitable if this structure is uncacheable.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::convertToUncacheableDictionary):
+        * runtime/JSObject.h:
+        * runtime/StructureRareData.cpp:
+        (JSC::StructureRareData::cacheSpecialPropertySlow):
+        * tools/JSDollarVM.cpp:
+        (JSC::functionToUncacheableDictionary):
+        (JSC::JSDollarVM::finishCreation):
+
 2020-09-07  Joonghun Park  <[email protected]>
 
         Unreviewed. Remove the build warning below since r266567.

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (266714 => 266715)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2020-09-08 07:21:07 UTC (rev 266715)
@@ -3738,6 +3738,16 @@
         vm, Structure::toCacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire));
 }
 
+void JSObject::convertToUncacheableDictionary(VM& vm)
+{
+    if (structure(vm)->isUncacheableDictionary())
+        return;
+    DeferredStructureTransitionWatchpointFire deferredWatchpointFire(vm, structure(vm));
+    setStructure(
+        vm, Structure::toUncacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire));
+}
+
+
 void JSObject::shiftButterflyAfterFlattening(const GCSafeConcurrentJSLocker&, VM& vm, Structure* structure, size_t outOfLineCapacityAfter)
 {
     // This could interleave visitChildren because some old structure could have been a non

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (266714 => 266715)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2020-09-08 07:21:07 UTC (rev 266715)
@@ -851,6 +851,7 @@
     void setStructure(VM&, Structure*);
 
     JS_EXPORT_PRIVATE void convertToDictionary(VM&);
+    JS_EXPORT_PRIVATE void convertToUncacheableDictionary(VM&);
 
     void flattenDictionaryObject(VM& vm)
     {

Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.cpp (266714 => 266715)


--- trunk/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.cpp	2020-09-08 07:21:07 UTC (rev 266715)
@@ -134,6 +134,12 @@
         uid = vm.propertyNames->toPrimitiveSymbol.impl();
         break;
     }
+
+    if (!ownStructure->propertyAccessesAreCacheable() || ownStructure->isProxy()) {
+        giveUpOnSpecialPropertyCache(key);
+        return;
+    }
+
     ObjectPropertyConditionSet conditionSet;
     if (slot.isValue()) {
         // We don't handle the own property case of special properties (toString, valueOf, @@toPrimitive, @@toStringTag) because we would never know if a new
@@ -144,11 +150,24 @@
 
         // This will not create a condition for the current structure but that is good because we know that property
         // is not on the ownStructure so we will transisition if one is added and this cache will no longer be used.
-        prepareChainForCaching(globalObject, ownStructure, slot.slotBase());
+        auto cacheStatus = prepareChainForCaching(globalObject, ownStructure, slot.slotBase());
+        if (!cacheStatus) {
+            giveUpOnSpecialPropertyCache(key);
+            return;
+        }
         conditionSet = generateConditionsForPrototypePropertyHit(vm, this, globalObject, ownStructure, slot.slotBase(), uid);
         ASSERT(!conditionSet.isValid() || conditionSet.hasOneSlotBaseCondition());
     } else if (slot.isUnset()) {
-        prepareChainForCaching(globalObject, ownStructure, nullptr);
+        if (!ownStructure->propertyAccessesAreCacheableForAbsence()) {
+            giveUpOnSpecialPropertyCache(key);
+            return;
+        }
+
+        auto cacheStatus = prepareChainForCaching(globalObject, ownStructure, nullptr);
+        if (!cacheStatus) {
+            giveUpOnSpecialPropertyCache(key);
+            return;
+        }
         conditionSet = generateConditionsForPropertyMiss(vm, this, globalObject, ownStructure, uid);
     } else
         return;

Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (266714 => 266715)


--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2020-09-08 04:30:14 UTC (rev 266714)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp	2020-09-08 07:21:07 UTC (rev 266715)
@@ -3153,6 +3153,19 @@
     return JSValue::encode(jsBoolean(Gigacage::isEnabled()));
 }
 
+static EncodedJSValue JSC_HOST_CALL functionToUncacheableDictionary(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+    DollarVMAssertScope assertScope;
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSObject* object = jsDynamicCast<JSObject*>(vm, callFrame->argument(0));
+    if (!object)
+        return throwVMTypeError(globalObject, scope, "Expected first argument to be an object"_s);
+    object->convertToUncacheableDictionary(vm);
+    return JSValue::encode(object);
+}
+
 constexpr unsigned jsDollarVMPropertyAttributes = PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete;
 
 void JSDollarVM::finishCreation(VM& vm)
@@ -3300,6 +3313,8 @@
     addFunction(vm, "useJIT", functionUseJIT, 0);
     addFunction(vm, "isGigacageEnabled", functionIsGigacageEnabled, 0);
 
+    addFunction(vm, "toUncacheableDictionary", functionToUncacheableDictionary, 1);
+
     m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull()));
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to