DFG should be able to set watchpoints on structure transitions in the
method check prototype chain
https://bugs.webkit.org/show_bug.cgi?id=89058

Source/JavaScriptCore: 

Reviewed by Gavin Barraclough.
        
This adds the ability to set watchpoints on Structures, and then does
the most modest thing we can do with this ability: the DFG now sets
watchpoints on structure transitions in the prototype chain of method
checks.
        
This appears to be a >1% speed-up on V8.

* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
* bytecode/StructureSet.h:
(JSC::StructureSet::containsOnly):
(StructureSet):
* bytecode/Watchpoint.cpp:
(JSC::WatchpointSet::WatchpointSet):
(JSC::InlineWatchpointSet::add):
(JSC):
(JSC::InlineWatchpointSet::inflateSlow):
(JSC::InlineWatchpointSet::freeFat):
* bytecode/Watchpoint.h:
(WatchpointSet):
(JSC):
(InlineWatchpointSet):
(JSC::InlineWatchpointSet::InlineWatchpointSet):
(JSC::InlineWatchpointSet::~InlineWatchpointSet):
(JSC::InlineWatchpointSet::hasBeenInvalidated):
(JSC::InlineWatchpointSet::isStillValid):
(JSC::InlineWatchpointSet::startWatching):
(JSC::InlineWatchpointSet::notifyWrite):
(JSC::InlineWatchpointSet::isFat):
(JSC::InlineWatchpointSet::fat):
(JSC::InlineWatchpointSet::inflate):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addStructureTransitionCheck):
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(CSEPhase):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCommon.h:
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::isCellConstant):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addWeakReferences):
(JITCompiler):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasStructure):
(Node):
(JSC::DFG::Node::structure):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGRepatch.cpp:
(JSC::DFG::emitPutTransitionStub):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITStubs.cpp:
(JSC::JITThunks::tryCachePutByID):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
* runtime/Structure.h:
(JSC::Structure::transitionWatchpointSetHasBeenInvalidated):
(Structure):
(JSC::Structure::transitionWatchpointSetIsStillValid):
(JSC::Structure::addTransitionWatchpoint):
(JSC::Structure::notifyTransitionFromThisStructure):
(JSC::JSCell::setStructure):
* runtime/SymbolTable.cpp:
(JSC::SymbolTableEntry::attemptToWatch):

LayoutTests: 

Rubber stamped by Gavin Barraclough.

* fast/js/dfg-call-method-hit-watchpoint-expected.txt: Added.
* fast/js/dfg-call-method-hit-watchpoint.html: Added.
* fast/js/script-tests/dfg-call-method-hit-watchpoint.js: Added.
(Thingy):
(Thingy.prototype.foo):
(callFoo):
(.Thingy.prototype.foo):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@120499 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index dc42397..56912614 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -155,6 +155,7 @@
     , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
     , m_prototype(globalData, this, prototype)
     , m_classInfo(classInfo)
+    , m_transitionWatchpointSet(InitializedWatching)
     , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
     , m_offset(noOffset)
     , m_dictionaryKind(NoneDictionaryKind)
@@ -177,6 +178,7 @@
     , m_typeInfo(CompoundType, OverridesVisitChildren)
     , m_prototype(globalData, this, jsNull())
     , m_classInfo(&s_info)
+    , m_transitionWatchpointSet(InitializedWatching)
     , m_propertyStorageCapacity(0)
     , m_offset(noOffset)
     , m_dictionaryKind(NoneDictionaryKind)
@@ -197,6 +199,7 @@
     , m_typeInfo(previous->typeInfo())
     , m_prototype(globalData, this, previous->storedPrototype())
     , m_classInfo(previous->m_classInfo)
+    , m_transitionWatchpointSet(InitializedWatching)
     , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
     , m_offset(noOffset)
     , m_dictionaryKind(previous->m_dictionaryKind)
@@ -210,6 +213,7 @@
     , m_didTransition(true)
     , m_staticFunctionReified(previous->m_staticFunctionReified)
 {
+    previous->notifyTransitionFromThisStructure();
     if (previous->m_globalObject)
         m_globalObject.set(globalData, this, previous->m_globalObject.get());
 }
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index c1d4c96..448a81c 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -37,6 +37,7 @@
 #include "StructureTransitionTable.h"
 #include "JSTypeInfo.h"
 #include "UString.h"
+#include "Watchpoint.h"
 #include "Weak.h"
 #include <wtf/PassOwnPtr.h>
 #include <wtf/PassRefPtr.h>
@@ -210,6 +211,27 @@
             return structure;
         }
         
+        bool transitionWatchpointSetHasBeenInvalidated() const
+        {
+            return m_transitionWatchpointSet.hasBeenInvalidated();
+        }
+        
+        bool transitionWatchpointSetIsStillValid() const
+        {
+            return m_transitionWatchpointSet.isStillValid();
+        }
+        
+        void addTransitionWatchpoint(Watchpoint* watchpoint) const
+        {
+            ASSERT(transitionWatchpointSetIsStillValid());
+            m_transitionWatchpointSet.add(watchpoint);
+        }
+        
+        void notifyTransitionFromThisStructure() const
+        {
+            m_transitionWatchpointSet.notifyWrite();
+        }
+        
         static JS_EXPORTDATA const ClassInfo s_info;
 
     private:
@@ -293,9 +315,11 @@
 
         OwnPtr<PropertyTable> m_propertyTable;
 
-        uint32_t m_propertyStorageCapacity;
-
         WriteBarrier<JSString> m_objectToStringValue;
+        
+        mutable InlineWatchpointSet m_transitionWatchpointSet;
+
+        uint32_t m_propertyStorageCapacity;
 
         // m_offset does not account for anonymous slots
         int m_offset;
@@ -365,6 +389,9 @@
     {
         ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
         ASSERT(structure->classInfo() == m_structure->classInfo());
+        ASSERT(!m_structure
+               || m_structure->transitionWatchpointSetHasBeenInvalidated()
+               || m_structure.get() == structure);
         m_structure.set(globalData, this, structure);
     }
 
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp
index 99e2f23..2a9d716 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.cpp
+++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp
@@ -59,10 +59,8 @@
 void SymbolTableEntry::attemptToWatch()
 {
     FatEntry* entry = inflate();
-    if (!entry->m_watchpoints) {
-        entry->m_watchpoints = adoptRef(new WatchpointSet());
-        entry->m_watchpoints->startWatching();
-    }
+    if (!entry->m_watchpoints)
+        entry->m_watchpoints = adoptRef(new WatchpointSet(InitializedWatching));
 }
 
 bool* SymbolTableEntry::addressOfIsWatched()