[JSC] Owner of watchpoints should validate at GC finalizing phase
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Mar 2019 20:29:29 +0000 (20:29 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Mar 2019 20:29:29 +0000 (20:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195827

Reviewed by Filip Pizlo.

JSTests:

* stress/gc-should-reap-dead-watchpoints.js: Added.
(foo):
(A.prototype.y):
(A):

Source/JavaScriptCore:

This patch fixes JSC's watchpoint liveness issue by the following two policies.

1. Watchpoint should have owner cell, and "fire" operation should be gaurded with owner cell's isLive check.

Watchpoints should hold its owner cell, and fire procedure should be guarded by `owner->isLive()`.
When the owner cell is destroyed, these watchpoints are destroyed too. But this destruction can
be delayed due to incremental sweeper. So the following condition can happen.

When we have a watchpoint like the following.

    class XXXWatchpoint {
        ObjectPropertyCondition m_key;
        JSCell* m_owner;
    };

Both m_key's cell and m_owner is now unreachable from the root. So eventually, m_owner cell's destructor
is called and this watchpoint will be destroyed. But before that, m_key's cell can be destroyed. And this
watchpoint's fire procedure can be called since m_owner's destructor is not called yet. In this situation,
we encounter the destroyed cell held in m_key. This problem can be avoided if we guard fire procedure with
`m_owner->isLive()`. Until the owner cell is destroyed, this guard avoids "fire" procedure execution. And
once the destructor of m_owner is called, this watchpoint will be destroyed too.

2. Watchpoint liveness should be maintained by owner cell's unconditional finalizer

Watchpoints often hold weak references to the other cell (like, m_key in the above example). If we do not
delete watchpoints with dead cells when these weak cells become dead, these watchpoints continue holding dead cells,
and watchpoint's fire operation can use these dead cells accidentally. isLive / isStillLive check for these weak cells
in fire operation is not useful. Because these dead cells can be reused to the other live cells eventually, and this
isLive / isStillLive checks fail to see these cells are live if they are reused. Appropriate way is deleting watchpoints
with dead cells when finalizing GC. In this patch, we do this in unconditional finalizers in owner cells of watchpoints.
We already did this in CodeBlock etc. We add the same thing to StructureRareData which owns watchpoints for toString operations.

* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecode/AdaptiveInferredPropertyValueWatchpointBase.h:
(JSC::AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint::StructureWatchpoint): Deleted.
(JSC::AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint::PropertyWatchpoint): Deleted.
* bytecode/CodeBlockJettisoningWatchpoint.h:
(JSC::CodeBlockJettisoningWatchpoint::CodeBlockJettisoningWatchpoint): Deleted.
* bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp:
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):
* bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h:
(JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::key const): Deleted.
* bytecode/StructureStubClearingWatchpoint.cpp:
(JSC::StructureStubClearingWatchpoint::fireInternal):
(JSC::WatchpointsOnStructureStubInfo::isValid const):
* bytecode/StructureStubClearingWatchpoint.h:
(JSC::StructureStubClearingWatchpoint::StructureStubClearingWatchpoint): Deleted.
* dfg/DFGAdaptiveInferredPropertyValueWatchpoint.cpp:
(JSC::DFG::AdaptiveInferredPropertyValueWatchpoint::isValid const):
* dfg/DFGAdaptiveInferredPropertyValueWatchpoint.h:
* dfg/DFGAdaptiveStructureWatchpoint.cpp:
(JSC::DFG::AdaptiveStructureWatchpoint::fireInternal):
* dfg/DFGAdaptiveStructureWatchpoint.h:
(JSC::DFG::AdaptiveStructureWatchpoint::key const): Deleted.
* dfg/DFGDesiredWatchpoints.cpp:
(JSC::DFG::ArrayBufferViewWatchpointAdaptor::add):
* heap/Heap.cpp:
(JSC::Heap::finalizeUnconditionalFinalizers):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::setupGetByIdPrototypeCache):
* runtime/ArrayBuffer.cpp:
(JSC::ArrayBuffer::notifyIncommingReferencesOfTransfer):
* runtime/ArrayBufferNeuteringWatchpointSet.cpp: Renamed from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp.
(JSC::ArrayBufferNeuteringWatchpointSet::ArrayBufferNeuteringWatchpointSet):
(JSC::ArrayBufferNeuteringWatchpointSet::destroy):
(JSC::ArrayBufferNeuteringWatchpointSet::create):
(JSC::ArrayBufferNeuteringWatchpointSet::createStructure):
(JSC::ArrayBufferNeuteringWatchpointSet::fireAll):
* runtime/ArrayBufferNeuteringWatchpointSet.h: Renamed from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h.
* runtime/FunctionRareData.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::tryInstallArraySpeciesWatchpoint):
* runtime/ObjectPropertyChangeAdaptiveWatchpoint.h:
(JSC::ObjectPropertyChangeAdaptiveWatchpoint::ObjectPropertyChangeAdaptiveWatchpoint): Deleted.
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::finalizeUnconditionally):
* runtime/StructureRareData.h:
* runtime/VM.cpp:
(JSC::VM::VM):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243560 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
JSTests/ChangeLog
JSTests/stress/gc-should-reap-dead-watchpoints.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/bytecode/AdaptiveInferredPropertyValueWatchpointBase.h
Source/JavaScriptCore/bytecode/CodeBlockJettisoningWatchpoint.h
Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp
Source/JavaScriptCore/bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h
Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.cpp
Source/JavaScriptCore/bytecode/StructureStubClearingWatchpoint.h
Source/JavaScriptCore/dfg/DFGAdaptiveInferredPropertyValueWatchpoint.cpp
Source/JavaScriptCore/dfg/DFGAdaptiveInferredPropertyValueWatchpoint.h
Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.cpp
Source/JavaScriptCore/dfg/DFGAdaptiveStructureWatchpoint.h
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/ArrayBuffer.cpp
Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpointSet.cpp [moved from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp with 66% similarity]
Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpointSet.h [moved from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h with 91% similarity]
Source/JavaScriptCore/runtime/FunctionRareData.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/ObjectPropertyChangeAdaptiveWatchpoint.h
Source/JavaScriptCore/runtime/StructureRareData.cpp
Source/JavaScriptCore/runtime/StructureRareData.h
Source/JavaScriptCore/runtime/VM.cpp

index fad3b8c..19cd93d 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-27  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Owner of watchpoints should validate at GC finalizing phase
+        https://bugs.webkit.org/show_bug.cgi?id=195827
+
+        Reviewed by Filip Pizlo.
+
+        * stress/gc-should-reap-dead-watchpoints.js: Added.
+        (foo):
+        (A.prototype.y):
+        (A):
+
 2019-03-26  Dominik Infuehr  <dinfuehr@igalia.com>
 
         Skip WebAssembly test on 32-bit systems
diff --git a/JSTests/stress/gc-should-reap-dead-watchpoints.js b/JSTests/stress/gc-should-reap-dead-watchpoints.js
new file mode 100644 (file)
index 0000000..e06c754
--- /dev/null
@@ -0,0 +1,25 @@
+//@ requireOptions("--forceEagerCompilation=true")
+
+// This test should not crash.
+
+let a;
+
+function foo(s) {
+    try {
+        eval(s);
+    } catch (e) {
+        gc();
+        a / 1;
+        a = null;
+    }
+}
+
+foo('zz');
+foo('class A { y() {} }; a=new A; zz');
+foo('class C { y() {} }; gc();');
+
+class A {
+    y() {}
+}
+
+A.prototype.z = 0
index 32f6042..270d044 100644 (file)
@@ -1,3 +1,93 @@
+2019-03-27  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [JSC] Owner of watchpoints should validate at GC finalizing phase
+        https://bugs.webkit.org/show_bug.cgi?id=195827
+
+        Reviewed by Filip Pizlo.
+
+        This patch fixes JSC's watchpoint liveness issue by the following two policies.
+
+        1. Watchpoint should have owner cell, and "fire" operation should be gaurded with owner cell's isLive check.
+
+        Watchpoints should hold its owner cell, and fire procedure should be guarded by `owner->isLive()`.
+        When the owner cell is destroyed, these watchpoints are destroyed too. But this destruction can
+        be delayed due to incremental sweeper. So the following condition can happen.
+
+        When we have a watchpoint like the following.
+
+            class XXXWatchpoint {
+                ObjectPropertyCondition m_key;
+                JSCell* m_owner;
+            };
+
+        Both m_key's cell and m_owner is now unreachable from the root. So eventually, m_owner cell's destructor
+        is called and this watchpoint will be destroyed. But before that, m_key's cell can be destroyed. And this
+        watchpoint's fire procedure can be called since m_owner's destructor is not called yet. In this situation,
+        we encounter the destroyed cell held in m_key. This problem can be avoided if we guard fire procedure with
+        `m_owner->isLive()`. Until the owner cell is destroyed, this guard avoids "fire" procedure execution. And
+        once the destructor of m_owner is called, this watchpoint will be destroyed too.
+
+        2. Watchpoint liveness should be maintained by owner cell's unconditional finalizer
+
+        Watchpoints often hold weak references to the other cell (like, m_key in the above example). If we do not
+        delete watchpoints with dead cells when these weak cells become dead, these watchpoints continue holding dead cells,
+        and watchpoint's fire operation can use these dead cells accidentally. isLive / isStillLive check for these weak cells
+        in fire operation is not useful. Because these dead cells can be reused to the other live cells eventually, and this
+        isLive / isStillLive checks fail to see these cells are live if they are reused. Appropriate way is deleting watchpoints
+        with dead cells when finalizing GC. In this patch, we do this in unconditional finalizers in owner cells of watchpoints.
+        We already did this in CodeBlock etc. We add the same thing to StructureRareData which owns watchpoints for toString operations.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecode/AdaptiveInferredPropertyValueWatchpointBase.h:
+        (JSC::AdaptiveInferredPropertyValueWatchpointBase::StructureWatchpoint::StructureWatchpoint): Deleted.
+        (JSC::AdaptiveInferredPropertyValueWatchpointBase::PropertyWatchpoint::PropertyWatchpoint): Deleted.
+        * bytecode/CodeBlockJettisoningWatchpoint.h:
+        (JSC::CodeBlockJettisoningWatchpoint::CodeBlockJettisoningWatchpoint): Deleted.
+        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.cpp:
+        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint):
+        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal):
+        * bytecode/LLIntPrototypeLoadAdaptiveStructureWatchpoint.h:
+        (JSC::LLIntPrototypeLoadAdaptiveStructureWatchpoint::key const): Deleted.
+        * bytecode/StructureStubClearingWatchpoint.cpp:
+        (JSC::StructureStubClearingWatchpoint::fireInternal):
+        (JSC::WatchpointsOnStructureStubInfo::isValid const):
+        * bytecode/StructureStubClearingWatchpoint.h:
+        (JSC::StructureStubClearingWatchpoint::StructureStubClearingWatchpoint): Deleted.
+        * dfg/DFGAdaptiveInferredPropertyValueWatchpoint.cpp:
+        (JSC::DFG::AdaptiveInferredPropertyValueWatchpoint::isValid const):
+        * dfg/DFGAdaptiveInferredPropertyValueWatchpoint.h:
+        * dfg/DFGAdaptiveStructureWatchpoint.cpp:
+        (JSC::DFG::AdaptiveStructureWatchpoint::fireInternal):
+        * dfg/DFGAdaptiveStructureWatchpoint.h:
+        (JSC::DFG::AdaptiveStructureWatchpoint::key const): Deleted.
+        * dfg/DFGDesiredWatchpoints.cpp:
+        (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add):
+        * heap/Heap.cpp:
+        (JSC::Heap::finalizeUnconditionalFinalizers):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::setupGetByIdPrototypeCache):
+        * runtime/ArrayBuffer.cpp:
+        (JSC::ArrayBuffer::notifyIncommingReferencesOfTransfer):
+        * runtime/ArrayBufferNeuteringWatchpointSet.cpp: Renamed from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp.
+        (JSC::ArrayBufferNeuteringWatchpointSet::ArrayBufferNeuteringWatchpointSet):
+        (JSC::ArrayBufferNeuteringWatchpointSet::destroy):
+        (JSC::ArrayBufferNeuteringWatchpointSet::create):
+        (JSC::ArrayBufferNeuteringWatchpointSet::createStructure):
+        (JSC::ArrayBufferNeuteringWatchpointSet::fireAll):
+        * runtime/ArrayBufferNeuteringWatchpointSet.h: Renamed from Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h.
+        * runtime/FunctionRareData.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::tryInstallArraySpeciesWatchpoint):
+        * runtime/ObjectPropertyChangeAdaptiveWatchpoint.h:
+        (JSC::ObjectPropertyChangeAdaptiveWatchpoint::ObjectPropertyChangeAdaptiveWatchpoint): Deleted.
+        * runtime/StructureRareData.cpp:
+        (JSC::StructureRareData::finalizeUnconditionally):
+        * runtime/StructureRareData.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+
 2019-03-26  Saam Barati  <sbarati@apple.com>
 
         FTL: Emit code to validate AI's state when running the compiled code
index db25b72..7574587 100644 (file)
                0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */ = {isa = PBXBuildFile; fileRef = 930DAD030FB1EB1A0082D205 /* NodeConstructors.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FFC92161B94FB3E0071DD66 /* DFGPropertyTypeKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC92151B94FB3E0071DD66 /* DFGPropertyTypeKey.h */; };
                0FFC99D1184EC8AD009C10AB /* ConstantMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; };
                0FFFC95A14EF90A900C72532 /* DFGCSEPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94E14EF909500C72532 /* DFGCSEPhase.h */; };
                0FFFC95C14EF90AF00C72532 /* DFGPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95014EF909500C72532 /* DFGPhase.h */; };
                0FFB80BB20A794700006AAF6 /* JITCodeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCodeInlines.h; sourceTree = "<group>"; };
                0FFC92151B94FB3E0071DD66 /* DFGPropertyTypeKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPropertyTypeKey.h; path = dfg/DFGPropertyTypeKey.h; sourceTree = "<group>"; };
                0FFC99D0184EC8AD009C10AB /* ConstantMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantMode.h; sourceTree = "<group>"; };
-               0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBufferNeuteringWatchpoint.cpp; sourceTree = "<group>"; };
-               0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferNeuteringWatchpoint.h; sourceTree = "<group>"; };
+               0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBufferNeuteringWatchpointSet.cpp; sourceTree = "<group>"; };
+               0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferNeuteringWatchpointSet.h; sourceTree = "<group>"; };
                0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; };
                0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; };
                0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCSEPhase.cpp; path = dfg/DFGCSEPhase.cpp; sourceTree = "<group>"; };
                                0F6B1CB71861244C00845D97 /* ArityCheckMode.h */,
                                A7A8AF2517ADB5F2005AB174 /* ArrayBuffer.cpp */,
                                A7A8AF2617ADB5F3005AB174 /* ArrayBuffer.h */,
-                               0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */,
-                               0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */,
+                               0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.cpp */,
+                               0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.h */,
                                0F30FB601DC2DE96003124F2 /* ArrayBufferSharingMode.h */,
                                A7A8AF2717ADB5F3005AB174 /* ArrayBufferView.cpp */,
                                A7A8AF2817ADB5F3005AB174 /* ArrayBufferView.h */,
                                86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
                                0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */,
                                A7A8AF3517ADB5F3005AB174 /* ArrayBuffer.h in Headers */,
-                               0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h in Headers */,
+                               0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpointSet.h in Headers */,
                                0F30FB611DC2DE99003124F2 /* ArrayBufferSharingMode.h in Headers */,
                                A7A8AF3717ADB5F3005AB174 /* ArrayBufferView.h in Headers */,
                                BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
index f05a3fe..59a35b2 100644 (file)
@@ -692,7 +692,7 @@ profiler/ProfilerUID.cpp
 runtime/AbstractModuleRecord.cpp
 runtime/ArgList.cpp
 runtime/ArrayBuffer.cpp
-runtime/ArrayBufferNeuteringWatchpoint.cpp
+runtime/ArrayBufferNeuteringWatchpointSet.cpp
 runtime/ArrayBufferView.cpp
 runtime/ArrayConstructor.cpp
 runtime/ArrayConventions.cpp
index 50d84ba..5d4e02a 100644 (file)
@@ -50,13 +50,13 @@ protected:
     virtual void handleFire(VM&, const FireDetail&) = 0;
 
 private:
-    class StructureWatchpoint : public Watchpoint {
+    class StructureWatchpoint final : public Watchpoint {
     public:
         StructureWatchpoint() { }
     protected:
         void fireInternal(VM&, const FireDetail&) override;
     };
-    class PropertyWatchpoint : public Watchpoint {
+    class PropertyWatchpoint final : public Watchpoint {
     public:
         PropertyWatchpoint() { }
     protected:
index 610261f..af24ea3 100644 (file)
@@ -31,7 +31,7 @@ namespace JSC {
 
 class CodeBlock;
 
-class CodeBlockJettisoningWatchpoint : public Watchpoint {
+class CodeBlockJettisoningWatchpoint final : public Watchpoint {
 public:
     CodeBlockJettisoningWatchpoint(CodeBlock* codeBlock)
         : m_codeBlock(codeBlock)
index 6beddf9..1bebc48 100644 (file)
@@ -32,8 +32,9 @@
 
 namespace JSC {
 
-LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, OpGetById::Metadata& getByIdMetadata)
-    : m_key(key)
+LLIntPrototypeLoadAdaptiveStructureWatchpoint::LLIntPrototypeLoadAdaptiveStructureWatchpoint(CodeBlock* owner, const ObjectPropertyCondition& key, OpGetById::Metadata& getByIdMetadata)
+    : m_owner(owner)
+    , m_key(key)
     , m_getByIdMetadata(getByIdMetadata)
 {
     RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
@@ -49,6 +50,9 @@ void LLIntPrototypeLoadAdaptiveStructureWatchpoint::install(VM& vm)
 
 void LLIntPrototypeLoadAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&)
 {
+    if (!m_owner->isLive())
+        return;
+
     if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
         install(vm);
         return;
index 0a1730a..9e11808 100644 (file)
@@ -31,9 +31,9 @@
 
 namespace JSC {
 
-class LLIntPrototypeLoadAdaptiveStructureWatchpoint : public Watchpoint {
+class LLIntPrototypeLoadAdaptiveStructureWatchpoint final : public Watchpoint {
 public:
-    LLIntPrototypeLoadAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, OpGetById::Metadata&);
+    LLIntPrototypeLoadAdaptiveStructureWatchpoint(CodeBlock*, const ObjectPropertyCondition&, OpGetById::Metadata&);
 
     void install(VM&);
 
@@ -45,6 +45,7 @@ protected:
     void fireInternal(VM&, const FireDetail&) override;
 
 private:
+    CodeBlock* m_owner;
     ObjectPropertyCondition m_key;
     OpGetById::Metadata& m_getByIdMetadata;
 };
index 648b1e8..9416d30 100644 (file)
@@ -36,6 +36,9 @@ namespace JSC {
 
 void StructureStubClearingWatchpoint::fireInternal(VM& vm, const FireDetail&)
 {
+    if (!m_holder.isValid())
+        return;
+
     if (!m_key || !m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
         // This will implicitly cause my own demise: stub reset removes all watchpoints.
         // That works, because deleting a watchpoint removes it from the set's list, and
@@ -54,6 +57,11 @@ void StructureStubClearingWatchpoint::fireInternal(VM& vm, const FireDetail&)
     m_key.object()->structure(vm)->addTransitionWatchpoint(this);
 }
 
+inline bool WatchpointsOnStructureStubInfo::isValid() const
+{
+    return m_codeBlock->isLive();
+}
+
 StructureStubClearingWatchpoint* WatchpointsOnStructureStubInfo::addWatchpoint(const ObjectPropertyCondition& key)
 {
     return m_watchpoints.add(key, *this);
index 07e1f74..70b697f 100644 (file)
@@ -40,7 +40,7 @@ class CodeBlock;
 class StructureStubInfo;
 class WatchpointsOnStructureStubInfo;
 
-class StructureStubClearingWatchpoint : public Watchpoint {
+class StructureStubClearingWatchpoint final : public Watchpoint {
     WTF_MAKE_NONCOPYABLE(StructureStubClearingWatchpoint);
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -78,6 +78,8 @@ public:
     
     CodeBlock* codeBlock() const { return m_codeBlock; }
     StructureStubInfo* stubInfo() const { return m_stubInfo; }
+
+    bool isValid() const;
     
 private:
     CodeBlock* m_codeBlock;
index 5b4a237..6a06eb0 100644 (file)
@@ -51,6 +51,11 @@ void AdaptiveInferredPropertyValueWatchpoint::handleFire(VM&, const FireDetail&
     m_codeBlock->jettison(Profiler::JettisonDueToUnprofiledWatchpoint, CountReoptimization, &lazyDetail);
 }
 
+bool AdaptiveInferredPropertyValueWatchpoint::isValid() const
+{
+    return m_codeBlock->isLive();
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index 6199a70..d17e198 100644 (file)
 
 namespace JSC { namespace DFG {
 
-class AdaptiveInferredPropertyValueWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+class AdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
 public:
     typedef AdaptiveInferredPropertyValueWatchpointBase Base;
     AdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, CodeBlock*);
 
 private:
+    bool isValid() const override;
+
     void handleFire(VM&, const FireDetail&) override;
 
     CodeBlock* m_codeBlock;
index d4a8b9a..5b9dda6 100644 (file)
@@ -52,6 +52,9 @@ void AdaptiveStructureWatchpoint::install(VM& vm)
 
 void AdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail& detail)
 {
+    if (!m_codeBlock->isLive())
+        return;
+
     if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
         install(vm);
         return;
index c1f574f..94013dc 100644 (file)
@@ -32,7 +32,7 @@
 
 namespace JSC { namespace DFG {
 
-class AdaptiveStructureWatchpoint : public Watchpoint {
+class AdaptiveStructureWatchpoint final : public Watchpoint {
 public:
     AdaptiveStructureWatchpoint(const ObjectPropertyCondition&, CodeBlock*);
     
index a4cb00f..1ac86ac 100644 (file)
@@ -28,7 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
-#include "ArrayBufferNeuteringWatchpoint.h"
+#include "ArrayBufferNeuteringWatchpointSet.h"
 #include "CodeBlock.h"
 #include "JSCInlines.h"
 
@@ -39,8 +39,8 @@ void ArrayBufferViewWatchpointAdaptor::add(
 {
     VM& vm = *codeBlock->vm();
     Watchpoint* watchpoint = common.watchpoints.add(codeBlock);
-    ArrayBufferNeuteringWatchpoint* neuteringWatchpoint =
-        ArrayBufferNeuteringWatchpoint::create(vm);
+    ArrayBufferNeuteringWatchpointSet* neuteringWatchpoint =
+        ArrayBufferNeuteringWatchpointSet::create(vm);
     neuteringWatchpoint->set().add(watchpoint);
     codeBlock->addConstant(neuteringWatchpoint);
     // FIXME: We don't need to set this watchpoint at all for shared buffers.
index 9ddd137..4953ac2 100644 (file)
@@ -595,6 +595,7 @@ void Heap::finalizeUnconditionalFinalizers()
             this->finalizeMarkedUnconditionalFinalizers<CodeBlock>(space.set);
         });
     finalizeMarkedUnconditionalFinalizers<ExecutableToCodeBlockEdge>(vm()->executableToCodeBlockEdgesWithFinalizers);
+    finalizeMarkedUnconditionalFinalizers<StructureRareData>(vm()->structureRareDataSpace);
     if (vm()->m_weakSetSpace)
         finalizeMarkedUnconditionalFinalizers<JSWeakSet>(*vm()->m_weakSetSpace);
     if (vm()->m_weakMapSpace)
index 7fc3730..9d1d819 100644 (file)
@@ -727,7 +727,7 @@ static void setupGetByIdPrototypeCache(ExecState* exec, VM& vm, const Instructio
             return;
         if (condition.condition().kind() == PropertyCondition::Presence)
             offset = condition.condition().offset();
-        watchpoints.add(condition, metadata)->install(vm);
+        watchpoints.add(codeBlock, condition, metadata)->install(vm);
     }
 
     ASSERT((offset == invalidOffset) == slot.isUnset());
index 6c56d59..8f8556b 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 #include "ArrayBuffer.h"
 
-#include "ArrayBufferNeuteringWatchpoint.h"
+#include "ArrayBufferNeuteringWatchpointSet.h"
 #include "JSArrayBufferView.h"
 #include "JSCInlines.h"
 #include <wtf/Gigacage.h>
@@ -382,7 +382,7 @@ void ArrayBuffer::notifyIncommingReferencesOfTransfer(VM& vm)
         JSCell* cell = incomingReferenceAt(i);
         if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(vm, cell))
             view->neuter();
-        else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast<ArrayBufferNeuteringWatchpoint*>(vm, cell))
+        else if (ArrayBufferNeuteringWatchpointSet* watchpoint = jsDynamicCast<ArrayBufferNeuteringWatchpointSet*>(vm, cell))
             watchpoint->fireAll();
     }
 }
  */
 
 #include "config.h"
-#include "ArrayBufferNeuteringWatchpoint.h"
+#include "ArrayBufferNeuteringWatchpointSet.h"
 
 #include "JSCInlines.h"
 
 namespace JSC {
 
-const ClassInfo ArrayBufferNeuteringWatchpoint::s_info = {
-    "ArrayBufferNeuteringWatchpoint", nullptr, nullptr, nullptr,
-    CREATE_METHOD_TABLE(ArrayBufferNeuteringWatchpoint)
+const ClassInfo ArrayBufferNeuteringWatchpointSet::s_info = {
+    "ArrayBufferNeuteringWatchpointSet", nullptr, nullptr, nullptr,
+    CREATE_METHOD_TABLE(ArrayBufferNeuteringWatchpointSet)
 };
 
-ArrayBufferNeuteringWatchpoint::ArrayBufferNeuteringWatchpoint(VM& vm)
+ArrayBufferNeuteringWatchpointSet::ArrayBufferNeuteringWatchpointSet(VM& vm)
     : Base(vm, vm.arrayBufferNeuteringWatchpointStructure.get())
     , m_set(adoptRef(*new WatchpointSet(IsWatched)))
 {
 }
 
-void ArrayBufferNeuteringWatchpoint::destroy(JSCell* cell)
+void ArrayBufferNeuteringWatchpointSet::destroy(JSCell* cell)
 {
-    static_cast<ArrayBufferNeuteringWatchpoint*>(cell)->ArrayBufferNeuteringWatchpoint::~ArrayBufferNeuteringWatchpoint();
+    static_cast<ArrayBufferNeuteringWatchpointSet*>(cell)->ArrayBufferNeuteringWatchpointSet::~ArrayBufferNeuteringWatchpointSet();
 }
 
-ArrayBufferNeuteringWatchpoint* ArrayBufferNeuteringWatchpoint::create(VM& vm)
+ArrayBufferNeuteringWatchpointSet* ArrayBufferNeuteringWatchpointSet::create(VM& vm)
 {
-    ArrayBufferNeuteringWatchpoint* result = new
-        (NotNull, allocateCell<ArrayBufferNeuteringWatchpoint>(vm.heap))
-        ArrayBufferNeuteringWatchpoint(vm);
+    ArrayBufferNeuteringWatchpointSet* result = new
+        (NotNull, allocateCell<ArrayBufferNeuteringWatchpointSet>(vm.heap))
+        ArrayBufferNeuteringWatchpointSet(vm);
     result->finishCreation(vm);
     return result;
 }
 
-Structure* ArrayBufferNeuteringWatchpoint::createStructure(VM& vm)
+Structure* ArrayBufferNeuteringWatchpointSet::createStructure(VM& vm)
 {
     return Structure::create(vm, 0, jsNull(), TypeInfo(CellType, StructureFlags), info());
 }
 
-void ArrayBufferNeuteringWatchpoint::fireAll()
+void ArrayBufferNeuteringWatchpointSet::fireAll()
 {
     m_set->fireAll(*vm(), "Array buffer was neutered");
 }
 
 namespace JSC {
 
-class ArrayBufferNeuteringWatchpoint final : public JSCell {
+class ArrayBufferNeuteringWatchpointSet final : public JSCell {
 public:
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
     DECLARE_INFO;
     
-    static ArrayBufferNeuteringWatchpoint* create(VM&);
+    static ArrayBufferNeuteringWatchpointSet* create(VM&);
 
     static const bool needsDestruction = true;
     static void destroy(JSCell*);
@@ -49,7 +49,7 @@ public:
     void fireAll();
 
 private:
-    explicit ArrayBufferNeuteringWatchpoint(VM&);
+    explicit ArrayBufferNeuteringWatchpointSet(VM&);
     
     Ref<WatchpointSet> m_set;
 };
index bf73031..132c279 100644 (file)
@@ -116,7 +116,7 @@ protected:
 
 private:
 
-    class AllocationProfileClearingWatchpoint : public Watchpoint {
+    class AllocationProfileClearingWatchpoint final : public Watchpoint {
     public:
         AllocationProfileClearingWatchpoint(FunctionRareData* rareData)
             : m_rareData(rareData)
index 7afe703..adef69b 100644 (file)
@@ -1103,57 +1103,57 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(arrayIteratorPrototype, m_vm.propertyNames->next);
-        m_arrayIteratorPrototypeNext = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_arrayIteratorProtocolWatchpoint);
+        m_arrayIteratorPrototypeNext = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_arrayIteratorProtocolWatchpoint);
         m_arrayIteratorPrototypeNext->install(vm);
     }
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(this->arrayPrototype(), m_vm.propertyNames->iteratorSymbol);
-        m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_arrayIteratorProtocolWatchpoint);
+        m_arrayPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_arrayIteratorProtocolWatchpoint);
         m_arrayPrototypeSymbolIteratorWatchpoint->install(vm);
     }
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(mapIteratorPrototype, m_vm.propertyNames->next);
-        m_mapIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_mapIteratorProtocolWatchpoint);
+        m_mapIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_mapIteratorProtocolWatchpoint);
         m_mapIteratorPrototypeNextWatchpoint->install(vm);
     }
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_mapPrototype.get(), m_vm.propertyNames->iteratorSymbol);
-        m_mapPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_mapIteratorProtocolWatchpoint);
+        m_mapPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_mapIteratorProtocolWatchpoint);
         m_mapPrototypeSymbolIteratorWatchpoint->install(vm);
     }
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(setIteratorPrototype, m_vm.propertyNames->next);
-        m_setIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_setIteratorProtocolWatchpoint);
+        m_setIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_setIteratorProtocolWatchpoint);
         m_setIteratorPrototypeNextWatchpoint->install(vm);
     }
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_setPrototype.get(), m_vm.propertyNames->iteratorSymbol);
-        m_setPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_setIteratorProtocolWatchpoint);
+        m_setPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_setIteratorProtocolWatchpoint);
         m_setPrototypeSymbolIteratorWatchpoint->install(vm);
     }
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_stringIteratorPrototype.get(), m_vm.propertyNames->next);
-        m_stringIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_stringIteratorProtocolWatchpoint);
+        m_stringIteratorPrototypeNextWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_stringIteratorProtocolWatchpoint);
         m_stringIteratorPrototypeNextWatchpoint->install(vm);
     }
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_stringPrototype.get(), m_vm.propertyNames->iteratorSymbol);
-        m_stringPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_stringIteratorProtocolWatchpoint);
+        m_stringPrototypeSymbolIteratorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_stringIteratorProtocolWatchpoint);
         m_stringPrototypeSymbolIteratorWatchpoint->install(vm);
     }
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_mapPrototype.get(), m_vm.propertyNames->set);
-        m_mapPrototypeSetWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_mapSetWatchpoint);
+        m_mapPrototypeSetWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_mapSetWatchpoint);
         m_mapPrototypeSetWatchpoint->install(vm);
     }
 
     {
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(m_setPrototype.get(), m_vm.propertyNames->add);
-        m_setPrototypeAddWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_setAddWatchpoint);
+        m_setPrototypeAddWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_setAddWatchpoint);
         m_setPrototypeAddWatchpoint->install(vm);
     }
 
@@ -1164,7 +1164,7 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
         this->symbolPrototype();
 
         ObjectPropertyCondition condition = setupAdaptiveWatchpoint(numberPrototype, m_vm.propertyNames->toString);
-        m_numberPrototypeToStringWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(condition, m_numberToStringWatchpoint);
+        m_numberPrototypeToStringWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, condition, m_numberToStringWatchpoint);
         m_numberPrototypeToStringWatchpoint->install(vm);
         m_numberProtoToStringFunction.set(vm, this, jsCast<JSFunction*>(numberPrototype->getDirect(vm, vm.propertyNames->toString)));
     }
@@ -1892,10 +1892,10 @@ void JSGlobalObject::tryInstallArraySpeciesWatchpoint(ExecState* exec)
     RELEASE_ASSERT(!m_arraySpeciesWatchpoint.isBeingWatched());
     m_arraySpeciesWatchpoint.touch(vm, "Set up array species watchpoint.");
 
-    m_arrayPrototypeConstructorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(constructorCondition, m_arraySpeciesWatchpoint);
+    m_arrayPrototypeConstructorWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, constructorCondition, m_arraySpeciesWatchpoint);
     m_arrayPrototypeConstructorWatchpoint->install(vm);
 
-    m_arrayConstructorSpeciesWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(speciesCondition, m_arraySpeciesWatchpoint);
+    m_arrayConstructorSpeciesWatchpoint = std::make_unique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, speciesCondition, m_arraySpeciesWatchpoint);
     m_arrayConstructorSpeciesWatchpoint->install(vm);
 }
 
index 4e0c209..541f345 100644 (file)
 namespace JSC {
 
 template<typename Watchpoint>
-class ObjectPropertyChangeAdaptiveWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+class ObjectPropertyChangeAdaptiveWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
 public:
     using Base = AdaptiveInferredPropertyValueWatchpointBase;
-    ObjectPropertyChangeAdaptiveWatchpoint(const ObjectPropertyCondition& condition, Watchpoint& watchpoint)
+    ObjectPropertyChangeAdaptiveWatchpoint(JSCell* owner, const ObjectPropertyCondition& condition, Watchpoint& watchpoint)
         : Base(condition)
+        , m_owner(owner)
         , m_watchpoint(watchpoint)
     {
         RELEASE_ASSERT(watchpoint.stateOnJSThread() == IsWatched);
     }
 
 private:
+    bool isValid() const override
+    {
+        return m_owner->isLive();
+    }
+
     void handleFire(VM& vm, const FireDetail&) override
     {
         m_watchpoint.fireAll(vm, StringFireDetail("Object Property is changed."));
     }
 
+    JSCell* m_owner;
     Watchpoint& m_watchpoint;
 };
 
index d5606cd..5c1c5f7 100644 (file)
@@ -78,7 +78,7 @@ void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
 // ----------- Object.prototype.toString() helper watchpoint classes -----------
 
-class ObjectToStringAdaptiveInferredPropertyValueWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+class ObjectToStringAdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
 public:
     typedef AdaptiveInferredPropertyValueWatchpointBase Base;
     ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
@@ -90,12 +90,14 @@ private:
     StructureRareData* m_structureRareData;
 };
 
-class ObjectToStringAdaptiveStructureWatchpoint : public Watchpoint {
+class ObjectToStringAdaptiveStructureWatchpoint final : public Watchpoint {
 public:
     ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
 
     void install(VM&);
 
+    const ObjectPropertyCondition& key() const { return m_key; }
+
 protected:
     void fireInternal(VM&, const FireDetail&) override;
     
@@ -169,6 +171,22 @@ inline void StructureRareData::clearObjectToStringValue()
     m_objectToStringValue.clear();
 }
 
+void StructureRareData::finalizeUnconditionally(VM& vm)
+{
+    if (m_objectToStringAdaptiveInferredValueWatchpoint) {
+        if (!m_objectToStringAdaptiveInferredValueWatchpoint->key().isStillLive(vm)) {
+            clearObjectToStringValue();
+            return;
+        }
+    }
+    for (auto* watchpoint : m_objectToStringAdaptiveWatchpointSet) {
+        if (!watchpoint->key().isStillLive(vm)) {
+            clearObjectToStringValue();
+            return;
+        }
+    }
+}
+
 // ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
 
 ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
index c4be714..e03b23f 100644 (file)
@@ -90,6 +90,8 @@ public:
 
     DECLARE_EXPORT_INFO;
 
+    void finalizeUnconditionally(VM&);
+
 private:
     friend class Structure;
     friend class ObjectToStringAdaptiveStructureWatchpoint;
index 43753da..3ed6de9 100644 (file)
@@ -30,7 +30,7 @@
 #include "VM.h"
 
 #include "ArgList.h"
-#include "ArrayBufferNeuteringWatchpoint.h"
+#include "ArrayBufferNeuteringWatchpointSet.h"
 #include "BuiltinExecutables.h"
 #include "BytecodeIntrinsicRegistry.h"
 #include "CodeBlock.h"
@@ -381,7 +381,7 @@ VM::VM(VMType vmType, HeapType heapType)
     structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
     sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
     templateObjectDescriptorStructure.set(*this, JSTemplateObjectDescriptor::createStructure(*this, 0, jsNull()));
-    arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this));
+    arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpointSet::createStructure(*this));
     unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull()));
     unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));