Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (284575 => 284576)
--- trunk/Source/_javascript_Core/ChangeLog 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-10-20 22:08:45 UTC (rev 284576)
@@ -1,3 +1,24 @@
+2021-10-20 Justin Michaud <[email protected]>
+
+ We should watch isHavingABadTime if we read from the structureCache
+ https://bugs.webkit.org/show_bug.cgi?id=232019
+
+ Reviewed by Yusuke Suzuki.
+
+ We should lock the structure cache when we clear it, and the compiler thread should
+ watch isHavingABadTime in the case that the cache might get cleared.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::haveABadTime):
+ * runtime/StructureCache.cpp:
+ (JSC::StructureCache::clear):
+ * runtime/StructureCache.h:
+ (JSC::StructureCache::clear): Deleted.
+
2021-10-20 Michael Saboff <[email protected]>
Add missing overflow checks to DFGIntegerRangeOptimizationPhase::isEquivalentTo()
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (284575 => 284576)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2021-10-20 22:08:45 UTC (rev 284576)
@@ -3126,8 +3126,19 @@
Structure* structure = nullptr;
if (base.isNull())
structure = globalObject->nullPrototypeObjectStructure();
- else if (base.isObject())
- structure = m_vm.structureCache.emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity());
+ else if (base.isObject()) {
+ // Having a bad time clears the structureCache, and so it should invalidate this structure.
+ bool isHavingABadTime = globalObject->isHavingABadTime();
+ WTF::loadLoadFence();
+ if (!isHavingABadTime)
+ m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+ // Normally, we would always install a watchpoint. In this case, however, if we haveABadTime, we
+ // still want to optimize. There is no watchpoint for that case though, so we need to make sure this load
+ // does not get hoisted above the check.
+ WTF::loadLoadFence();
+ structure = m_vm.structureCache
+ .emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity());
+ }
if (structure) {
m_state.setShouldTryConstantFolding(true);
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (284575 => 284576)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2021-10-20 22:08:45 UTC (rev 284576)
@@ -841,8 +841,19 @@
Structure* structure = nullptr;
if (base.isNull())
structure = globalObject->nullPrototypeObjectStructure();
- else if (base.isObject())
- structure = globalObject->vm().structureCache.emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity());
+ else if (base.isObject()) {
+ // Having a bad time clears the structureCache, and so it should invalidate this structure.
+ bool isHavingABadTime = globalObject->isHavingABadTime();
+ WTF::loadLoadFence();
+ if (!isHavingABadTime)
+ m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
+ // Normally, we would always install a watchpoint. In this case, however, if we haveABadTime, we
+ // still want to optimize. There is no watchpoint for that case though, so we need to make sure this load
+ // does not get hoisted above the check.
+ WTF::loadLoadFence();
+ structure = globalObject->vm().structureCache
+ .emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity());
+ }
if (structure) {
node->convertToNewObject(m_graph.registerStructure(structure));
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (284575 => 284576)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-10-20 22:08:45 UTC (rev 284576)
@@ -1984,6 +1984,15 @@
if (isHavingABadTime())
return;
+ // This must happen first, because the compiler thread may race with haveABadTime.
+ // Let R_BT, W_BT <- Read/Fire the watchpoint, R_SC, W_SC <- Read/clear the structure cache.
+ // The possible interleavings are:
+ // R_BT, R_SC, W_SC, W_BT: Compiler thread installs a watchpoint, and the code is discarded.
+ // R_BT, W_SC, R_SC, W_BT: ^ Same
+ // R_BT, W_SC, W_BT, W_SC: ^ Same
+ // W_SC, R_BT, R_SC, W_BT: ^ Same
+ // W_SC, R_BT, W_BT, R_SC: ^ Same
+ // W_SC, W_BT, R_BT, R_SC: No watchpoint is installed, but we could not see old structures from the cache.
vm.structureCache.clear(); // We may be caching array structures in here.
DeferGC deferGC(vm.heap);
Modified: trunk/Source/_javascript_Core/runtime/StructureCache.cpp (284575 => 284576)
--- trunk/Source/_javascript_Core/runtime/StructureCache.cpp 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/runtime/StructureCache.cpp 2021-10-20 22:08:45 UTC (rev 284576)
@@ -31,6 +31,12 @@
namespace JSC {
+void StructureCache::clear()
+{
+ Locker locker { m_lock };
+ m_structures.clear();
+}
+
inline Structure* StructureCache::createEmptyStructure(JSGlobalObject* globalObject, JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity, bool makePolyProtoStructure, FunctionExecutable* executable)
{
RELEASE_ASSERT(!!prototype); // We use nullptr inside the HashMap for prototype to mean poly proto, so user's of this API must provide non-null prototypes.
Modified: trunk/Source/_javascript_Core/runtime/StructureCache.h (284575 => 284576)
--- trunk/Source/_javascript_Core/runtime/StructureCache.h 2021-10-20 21:50:18 UTC (rev 284575)
+++ trunk/Source/_javascript_Core/runtime/StructureCache.h 2021-10-20 22:08:45 UTC (rev 284576)
@@ -48,7 +48,7 @@
{
}
- void clear() { m_structures.clear(); }
+ JS_EXPORT_PRIVATE void clear();
JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSGlobalObject*, JSObject*, unsigned inlineCapacity, bool makePolyProtoStructure = false, FunctionExecutable* = nullptr);
JS_EXPORT_PRIVATE Structure* emptyStructureForPrototypeFromBaseStructure(JSGlobalObject*, JSObject*, Structure*);