fourthTier: It should be possible to query WatchpointSets, and add Watchpoints, even...
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 03:58:49 +0000 (03:58 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2013 03:58:49 +0000 (03:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=114909

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

The idea here is that a concurrent compiler will use watchpoint sets as follows:

During concurrent compilation: It will create Watchpoints, and query WatchpointSets only
for the purpose of profiling. That is, it will use decide whether it is profitable to
compile the code "as if" the watchpoint sets are valid.

During synchronous linking: By "linking" I don't necessarily mean the LinkBuffer stuff,
but just the very bitter end of compilation where we make the JIT code callable. This
can happen after LinkBuffer stuff. Anyway, this will have to happen synchronously, and
at that point we can (a) check that all WatchpointSets that we assumed were valid are
still valid and (b) if they are then we add the watchpoints to those sets. If any of the
sets are invalid, we give up on this compilation and try again later.

The querying of WatchpointSets is engineered to say that the set is still valid if it
is so *right now*, but this is done in a racy way and so it may say so spuriously: we
may, with hopefully low probability, have a set that says it is valid even though it was
just invalidated. The goal is only to ensure that (i) a set never claims to be invalid
if it is actually valid, (ii) a set doesn't claim to be valid if it was invalidated
before compilation even began, and (iii) querying the validity of a set doesn't cause us
to crash.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Watchpoint.cpp:
(JSC::InlineWatchpointSet::inflateSlow):
* bytecode/Watchpoint.h:
(WatchpointSet):
(InlineWatchpointSet):
(JSC::InlineWatchpointSet::hasBeenInvalidated):
(JSC::InlineWatchpointSet::isThin):
(JSC::InlineWatchpointSet::isFat):
(JSC::InlineWatchpointSet::fat):
* dfg/DFGDesiredWatchpoints.cpp: Added.
(DFG):
(JSC::DFG::DesiredWatchpoints::DesiredWatchpoints):
(JSC::DFG::DesiredWatchpoints::~DesiredWatchpoints):
(JSC::DFG::DesiredWatchpoints::addLazily):
(JSC::DFG::DesiredWatchpoints::reallyAdd):
(JSC::DFG::DesiredWatchpoints::areStillValid):
* dfg/DFGDesiredWatchpoints.h: Added.
(DFG):
(JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet):
(WatchpointForGenericWatchpointSet):
(GenericDesiredWatchpoints):
(JSC::DFG::GenericDesiredWatchpoints::GenericDesiredWatchpoints):
(JSC::DFG::GenericDesiredWatchpoints::addLazily):
(JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
(JSC::DFG::GenericDesiredWatchpoints::areStillValid):
(DesiredWatchpoints):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addLazily):
(JITCompiler):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCompile.cpp:
(JSC::FTL::compile):
* ftl/FTLCompile.h:
(FTL):
* ftl/FTLState.h:
(State):
* runtime/JSFunction.h:
(JSFunction):
(JSC::JSFunction::allocationProfileWatchpointSet):
* runtime/Structure.h:
(Structure):
(JSC::Structure::transitionWatchpointSet):

Source/WTF:

Reviewed by Oliver Hunt.

Harden our notions of memory fences, now that we're doing racy algorithms.

* wtf/Atomics.h:
(WTF):
(WTF::compilerFence):
(WTF::armV7_dmb):
(WTF::armV7_dmb_st):
(WTF::loadLoadFence):
(WTF::loadStoreFence):
(WTF::storeLoadFence):
(WTF::storeStoreFence):
(WTF::memoryBarrierAfterLock):
(WTF::memoryBarrierBeforeUnlock):
(WTF::x86_mfence):

Conflicts:
Source/WTF/wtf/Atomics.h

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

18 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/Watchpoint.cpp
Source/JavaScriptCore/bytecode/Watchpoint.h
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGDriver.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCompile.cpp
Source/JavaScriptCore/ftl/FTLCompile.h
Source/JavaScriptCore/ftl/FTLState.h
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/Structure.h
Source/WTF/ChangeLog

index d4c1838..4f87ce7 100644 (file)
@@ -1,4 +1,109 @@
-2013-04-20  Filip Pizlo  <fpizlo@apple.com>
+2013-07-16  Oliver Hunt <oliver@apple.com>
+
+        Merge dfgFourthTier r148836
+
+    2013-04-21  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: It should be possible to query WatchpointSets, and add Watchpoints, even if the compiler is running in another thread
+        https://bugs.webkit.org/show_bug.cgi?id=114909
+
+        Reviewed by Oliver Hunt.
+        
+        The idea here is that a concurrent compiler will use watchpoint sets as follows:
+        
+        During concurrent compilation: It will create Watchpoints, and query WatchpointSets only
+        for the purpose of profiling. That is, it will use decide whether it is profitable to
+        compile the code "as if" the watchpoint sets are valid.
+        
+        During synchronous linking: By "linking" I don't necessarily mean the LinkBuffer stuff,
+        but just the very bitter end of compilation where we make the JIT code callable. This
+        can happen after LinkBuffer stuff. Anyway, this will have to happen synchronously, and
+        at that point we can (a) check that all WatchpointSets that we assumed were valid are
+        still valid and (b) if they are then we add the watchpoints to those sets. If any of the
+        sets are invalid, we give up on this compilation and try again later.
+        
+        The querying of WatchpointSets is engineered to say that the set is still valid if it
+        is so *right now*, but this is done in a racy way and so it may say so spuriously: we
+        may, with hopefully low probability, have a set that says it is valid even though it was
+        just invalidated. The goal is only to ensure that (i) a set never claims to be invalid
+        if it is actually valid, (ii) a set doesn't claim to be valid if it was invalidated
+        before compilation even began, and (iii) querying the validity of a set doesn't cause us
+        to crash.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/Watchpoint.cpp:
+        (JSC::InlineWatchpointSet::inflateSlow):
+        * bytecode/Watchpoint.h:
+        (WatchpointSet):
+        (InlineWatchpointSet):
+        (JSC::InlineWatchpointSet::hasBeenInvalidated):
+        (JSC::InlineWatchpointSet::isThin):
+        (JSC::InlineWatchpointSet::isFat):
+        (JSC::InlineWatchpointSet::fat):
+        * dfg/DFGDesiredWatchpoints.cpp: Added.
+        (DFG):
+        (JSC::DFG::DesiredWatchpoints::DesiredWatchpoints):
+        (JSC::DFG::DesiredWatchpoints::~DesiredWatchpoints):
+        (JSC::DFG::DesiredWatchpoints::addLazily):
+        (JSC::DFG::DesiredWatchpoints::reallyAdd):
+        (JSC::DFG::DesiredWatchpoints::areStillValid):
+        * dfg/DFGDesiredWatchpoints.h: Added.
+        (DFG):
+        (JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet):
+        (WatchpointForGenericWatchpointSet):
+        (GenericDesiredWatchpoints):
+        (JSC::DFG::GenericDesiredWatchpoints::GenericDesiredWatchpoints):
+        (JSC::DFG::GenericDesiredWatchpoints::addLazily):
+        (JSC::DFG::GenericDesiredWatchpoints::reallyAdd):
+        (JSC::DFG::GenericDesiredWatchpoints::areStillValid):
+        (DesiredWatchpoints):
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compile):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::link):
+        (JSC::DFG::JITCompiler::compile):
+        (JSC::DFG::JITCompiler::compileFunction):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::addLazily):
+        (JITCompiler):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+        (JSC::DFG::SpeculativeJIT::compileObjectEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+        (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+        (JSC::DFG::SpeculativeJIT::compileObjectEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+        (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::compile):
+        * ftl/FTLCompile.h:
+        (FTL):
+        * ftl/FTLState.h:
+        (State):
+        * runtime/JSFunction.h:
+        (JSFunction):
+        (JSC::JSFunction::allocationProfileWatchpointSet):
+        * runtime/Structure.h:
+        (Structure):
+        (JSC::Structure::transitionWatchpointSet):
+
+2013-07-16  Oliver Hunt <oliver@apple.com>
+
+        Merge dfgFourthTier r148804
+
+    2013-04-20  Filip Pizlo  <fpizlo@apple.com>
 
         fourthTier: value profiles and array profiles should be thread-safe enough to be accessible in a concurrent compilation thread
         https://bugs.webkit.org/show_bug.cgi?id=114906
index 75e845e..e29d0dd 100644 (file)
                0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
+               0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */; };
+               0FE8534C1723CDA500B618F5 /* DFGDesiredWatchpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FEA0A08170513DB00BB722C /* FTLAbbreviations.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEA09FD170513DB00BB722C /* FTLAbbreviations.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FEA0A09170513DB00BB722C /* FTLCapabilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA09FE170513DB00BB722C /* FTLCapabilities.cpp */; };
                0FEA0A0A170513DB00BB722C /* FTLCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEA09FF170513DB00BB722C /* FTLCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
+               0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredWatchpoints.cpp; path = dfg/DFGDesiredWatchpoints.cpp; sourceTree = "<group>"; };
+               0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredWatchpoints.h; path = dfg/DFGDesiredWatchpoints.h; sourceTree = "<group>"; };
                0FEA09FD170513DB00BB722C /* FTLAbbreviations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLAbbreviations.h; path = ftl/FTLAbbreviations.h; sourceTree = "<group>"; };
                0FEA09FE170513DB00BB722C /* FTLCapabilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLCapabilities.cpp; path = ftl/FTLCapabilities.cpp; sourceTree = "<group>"; };
                0FEA09FF170513DB00BB722C /* FTLCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLCapabilities.h; path = ftl/FTLCapabilities.h; sourceTree = "<group>"; };
                                0FFFC94E14EF909500C72532 /* DFGCSEPhase.h */,
                                0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */,
                                0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */,
+                               0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */,
+                               0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */,
                                0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */,
                                0FF427621591A1C9004CB9FF /* DFGDisassembler.h */,
                                0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */,
                                FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
                                0F4680CA14BBB16C00BFE272 /* LLIntCommon.h in Headers */,
                                0F4680D314BBD16700BFE272 /* LLIntData.h in Headers */,
+                               0FE8534C1723CDA500B618F5 /* DFGDesiredWatchpoints.h in Headers */,
                                0F0B839B14BCF46000885B4F /* LLIntEntrypoints.h in Headers */,
                                0F4680A314BA7F8D00BFE272 /* LLIntExceptions.h in Headers */,
                                0F4680CB14BBB17200BFE272 /* LLIntOfflineAsmConfig.h in Headers */,
                                0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */,
                                147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */,
                                C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */,
+                               0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */,
                                0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */,
                                C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */,
                                C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */,
index 75dfe8a..d0c17ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -87,6 +87,7 @@ WatchpointSet* InlineWatchpointSet::inflateSlow()
         fat->m_isInvalidated = true;
     if (m_data & IsWatchedFlag)
         fat->m_isWatched = true;
+    WTF::storeStoreFence();
     m_data = bitwise_cast<uintptr_t>(fat);
     return fat;
 }
index e6fba93..2054bf7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -54,7 +54,11 @@ public:
     WatchpointSet(InitialWatchpointSetMode);
     ~WatchpointSet();
     
+    // It is safe to call this from another thread.  It may return true
+    // even if the set actually had been invalidated, but that ought to happen
+    // only in the case of races, and should be rare.
     bool isStillValid() const { return !m_isInvalidated; }
+    // Like isStillValid(), may be called from another thread.
     bool hasBeenInvalidated() const { return m_isInvalidated; }
     
     // As a convenience, this will ignore 0. That's because code paths in the DFG
@@ -124,13 +128,20 @@ public:
         freeFat();
     }
     
+    // It is safe to call this from another thread.  It may return false
+    // even if the set actually had been invalidated, but that ought to happen
+    // only in the case of races, and should be rare.
     bool hasBeenInvalidated() const
     {
-        if (isFat())
-            return fat()->hasBeenInvalidated();
-        return m_data & IsInvalidatedFlag;
+        uintptr_t data = m_data;
+        if (isFat(data)) {
+            WTF::loadLoadFence();
+            return fat(data)->hasBeenInvalidated();
+        }
+        return data & IsInvalidatedFlag;
     }
     
+    // Like hasBeenInvalidated(), may be called from another thread.
     bool isStillValid() const
     {
         return !hasBeenInvalidated();
@@ -163,19 +174,27 @@ private:
     static const uintptr_t IsInvalidatedFlag = 2;
     static const uintptr_t IsWatchedFlag     = 4;
     
-    bool isThin() const { return m_data & IsThinFlag; }
-    bool isFat() const { return !isThin(); };
+    static bool isThin(uintptr_t data) { return data & IsThinFlag; }
+    static bool isFat(uintptr_t data) { return !isThin(data); }
+    
+    bool isThin() const { return isThin(m_data); }
+    bool isFat() const { return isFat(m_data); };
+    
+    static WatchpointSet* fat(uintptr_t data)
+    {
+        return bitwise_cast<WatchpointSet*>(data);
+    }
     
     WatchpointSet* fat()
     {
         ASSERT(isFat());
-        return bitwise_cast<WatchpointSet*>(m_data);
+        return fat(m_data);
     }
     
     const WatchpointSet* fat() const
     {
         ASSERT(isFat());
-        return bitwise_cast<WatchpointSet*>(m_data);
+        return fat(m_data);
     }
     
     WatchpointSet* inflate()
diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
new file mode 100644 (file)
index 0000000..b5da4c2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "DFGDesiredWatchpoints.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+DesiredWatchpoints::DesiredWatchpoints() { }
+DesiredWatchpoints::~DesiredWatchpoints() { }
+
+void DesiredWatchpoints::addLazily(Watchpoint* watchpoint, WatchpointSet* set)
+{
+    m_sets.addLazily(WatchpointForWatchpointSet(watchpoint, set));
+}
+
+void DesiredWatchpoints::addLazily(Watchpoint* watchpoint, InlineWatchpointSet& set)
+{
+    m_inlineSets.addLazily(WatchpointForInlineWatchpointSet(watchpoint, &set));
+}
+
+void DesiredWatchpoints::reallyAdd()
+{
+    m_sets.reallyAdd();
+    m_inlineSets.reallyAdd();
+}
+
+bool DesiredWatchpoints::areStillValid() const
+{
+    return m_sets.areStillValid() && m_inlineSets.areStillValid();
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h
new file mode 100644 (file)
index 0000000..a43c90a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGDesiredWatchpoints_h
+#define DFGDesiredWatchpoints_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "Watchpoint.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+template<typename WatchpointSetType>
+struct WatchpointForGenericWatchpointSet {
+    WatchpointForGenericWatchpointSet()
+        : m_watchpoint(0)
+        , m_set(0)
+    {
+    }
+    
+    WatchpointForGenericWatchpointSet(Watchpoint* watchpoint, WatchpointSetType* set)
+        : m_watchpoint(watchpoint)
+        , m_set(set)
+    {
+    }
+    
+    Watchpoint* m_watchpoint;
+    WatchpointSetType* m_set;
+};
+
+typedef WatchpointForGenericWatchpointSet<WatchpointSet> WatchpointForWatchpointSet;
+typedef WatchpointForGenericWatchpointSet<InlineWatchpointSet> WatchpointForInlineWatchpointSet;
+
+template<typename WatchpointSetType>
+class GenericDesiredWatchpoints {
+    WTF_MAKE_NONCOPYABLE(GenericDesiredWatchpoints);
+public:
+    GenericDesiredWatchpoints()
+        : m_reallyAdded(false)
+    {
+    }
+    
+    void addLazily(const WatchpointForGenericWatchpointSet<WatchpointSetType>& watchpoint)
+    {
+        m_watchpoints.append(watchpoint);
+    }
+    
+    void reallyAdd()
+    {
+        RELEASE_ASSERT(!m_reallyAdded);
+        for (unsigned i = m_watchpoints.size(); i--;)
+            m_watchpoints[i].m_set->add(m_watchpoints[i].m_watchpoint);
+        m_reallyAdded = true;
+    }
+    
+    bool areStillValid() const
+    {
+        for (unsigned i = m_watchpoints.size(); i--;) {
+            if (m_watchpoints[i].m_set->hasBeenInvalidated())
+                return false;
+        }
+        return true;
+    }
+
+private:
+    Vector<WatchpointForGenericWatchpointSet<WatchpointSetType> > m_watchpoints;
+    bool m_reallyAdded;
+};
+
+class DesiredWatchpoints {
+public:
+    DesiredWatchpoints();
+    ~DesiredWatchpoints();
+    
+    void addLazily(Watchpoint*, WatchpointSet*);
+    void addLazily(Watchpoint*, InlineWatchpointSet&);
+    
+    void reallyAdd();
+    
+    bool areStillValid() const;
+    
+private:
+    GenericDesiredWatchpoints<WatchpointSet> m_sets;
+    GenericDesiredWatchpoints<InlineWatchpointSet> m_inlineSets;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGDesiredWatchpoints_h
+
index 2302064..27c39ef 100644 (file)
@@ -174,12 +174,7 @@ static bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
         
         FTL::State state(dfg);
         FTL::lowerDFGToLLVM(state);
-        FTL::compile(state, jitCode, *jitCodeWithArityCheck);
-        
-        // FIXME: Need to add support for the case where JIT memory allocation failed.
-        // https://bugs.webkit.org/show_bug.cgi?id=113620
-        
-        return true;
+        return FTL::compile(state, jitCode, *jitCodeWithArityCheck);
     }
 #endif // ENABLE(FTL_JIT)
     
index 4318558..40e2a1d 100644 (file)
@@ -238,6 +238,8 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
         ASSERT(!m_exitSiteLabels.size());
     
     m_jitCode->common.compilation = m_graph.m_compilation;
+    
+    m_watchpoints.reallyAdd();
 }
 
 bool JITCompiler::compile(RefPtr<JSC::JITCode>& entry)
@@ -260,6 +262,9 @@ bool JITCompiler::compile(RefPtr<JSC::JITCode>& entry)
     speculative.createOSREntries();
     setEndOfCode();
 
+    if (!m_watchpoints.areStillValid())
+        return false;
+    
     LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail);
     if (linkBuffer.didFailToAllocate())
         return false;
@@ -349,6 +354,9 @@ bool JITCompiler::compileFunction(RefPtr<JSC::JITCode>& entry, MacroAssemblerCod
     // Create OSR entry trampolines if necessary.
     speculative.createOSREntries();
     setEndOfCode();
+    
+    if (!m_watchpoints.areStillValid())
+        return false;
 
     // === Link ===
     LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail);
index af44e63..9b0a6f8 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "CodeBlock.h"
 #include "DFGCCallHelpers.h"
+#include "DFGDesiredWatchpoints.h"
 #include "DFGDisassembler.h"
 #include "DFGFPRInfo.h"
 #include "DFGGPRInfo.h"
@@ -252,6 +253,15 @@ public:
     // Accessors for properties.
     Graph& graph() { return m_graph; }
     
+    void addLazily(Watchpoint* watchpoint, WatchpointSet* set)
+    {
+        m_watchpoints.addLazily(watchpoint, set);
+    }
+    void addLazily(Watchpoint* watchpoint, InlineWatchpointSet& set)
+    {
+        m_watchpoints.addLazily(watchpoint, set);
+    }
+    
     // Methods to set labels for the disassembler.
     void setStartOfCode()
     {
@@ -469,6 +479,8 @@ private:
     Vector<OSRExitCompilationInfo> m_exitCompilationInfo;
     Vector<Vector<Label> > m_exitSiteLabels;
     unsigned m_currentCodeOriginIndex;
+    
+    DesiredWatchpoints m_watchpoints;
 };
 
 } } // namespace JSC::DFG
index 3bf3044..d0f7229 100644 (file)
@@ -1351,7 +1351,9 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode)
     GPRReg op2GPR = op2.gpr();
     
     if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-        m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
             speculationCheck(
                 BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), 
index f1c942d..77c2ee5 100644 (file)
@@ -391,7 +391,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
 
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
         notMasqueradesAsUndefined = m_jit.jump();
     } else {
@@ -458,7 +460,9 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
 
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         jump(invert ? taken : notTaken, ForceJump);
     } else {
         GPRTemporary localGlobalObject(this);
@@ -1284,7 +1288,9 @@ void SpeculativeJIT::compileObjectEquality(Node* node)
     GPRReg op2GPR = op2.gpr();
     
     if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-        m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1361,7 +1367,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1389,7 +1397,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     
     // We know that within this branch, rightChild must be a cell.
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -1469,7 +1479,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1496,7 +1508,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     
     // We know that within this branch, rightChild must be a cell.
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
             m_jit.branchPtr(
@@ -1614,7 +1628,9 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
 
     MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
 
         DFG_TYPE_CHECK(
             JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
@@ -1744,7 +1760,9 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, Blo
     
     MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
     if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
 
         DFG_TYPE_CHECK(
             JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
@@ -2566,8 +2584,12 @@ void SpeculativeJIT::compile(Node* node)
                 if (node->arrayMode().isSaneChain()) {
                     JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
                     ASSERT(globalObject->arrayPrototypeChainIsSane());
-                    globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
-                    globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                    m_jit.addLazily(
+                        speculationWatchpoint(),
+                        globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
+                    m_jit.addLazily(
+                        speculationWatchpoint(),
+                        globalObject->objectPrototype()->structure()->transitionWatchpointSet());
                 }
                 
                 SpeculateStrictInt32Operand property(this, node->child2());
@@ -3380,7 +3402,9 @@ void SpeculativeJIT::compile(Node* node)
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
             ASSERT(structure->indexingType() == node->indexingType());
@@ -3550,7 +3574,9 @@ void SpeculativeJIT::compile(Node* node)
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             SpeculateStrictInt32Operand size(this, node->child1());
             GPRTemporary result(this);
@@ -3626,7 +3652,9 @@ void SpeculativeJIT::compile(Node* node)
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         IndexingType indexingType = node->indexingType();
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             unsigned numElements = node->numConstants();
             
@@ -3732,7 +3760,9 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case AllocationProfileWatchpoint: {
-        jsCast<JSFunction*>(node->function())->addAllocationProfileWatchpoint(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            jsCast<JSFunction*>(node->function())->allocationProfileWatchpointSet());
         noResult(node);
         break;
     }
@@ -4025,9 +4055,10 @@ void SpeculativeJIT::compile(Node* node)
         // quite a hint already.
         
         m_jit.addWeakReference(node->structure());
-        node->structure()->addTransitionWatchpoint(
+        m_jit.addLazily(
             speculationWatchpoint(
-                node->child1()->op() == WeakJSConstant ? BadWeakConstantCache : BadCache));
+                node->child1()->op() == WeakJSConstant ? BadWeakConstantCache : BadCache),
+            node->structure()->transitionWatchpointSet());
         
 #if !ASSERT_DISABLED
         SpeculateCellOperand op1(this, node->child1());
@@ -4236,9 +4267,9 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case GlobalVarWatchpoint: {
-        m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
-            identifier(node->identifierNumberForCheck())->impl()).addWatchpoint(
-                speculationWatchpoint());
+        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
+            identifier(node->identifierNumberForCheck())->impl()).watchpointSet();
+        m_jit.addLazily(speculationWatchpoint(), set);
         
 #if DFG_ENABLE(JIT_ASSERT)
         GPRTemporary scratch(this);
@@ -4291,7 +4322,9 @@ void SpeculativeJIT::compile(Node* node)
         isCell.link(&m_jit);
         JITCompiler::Jump notMasqueradesAsUndefined;
         if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-            m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
             m_jit.move(TrustedImm32(0), result.gpr());
             notMasqueradesAsUndefined = m_jit.jump();
         } else {
index ec5ee53..3bf7f7c 100644 (file)
@@ -339,7 +339,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
 
-        m_jit.graph().globalObjectFor(operand->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(operand->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR);
         notMasqueradesAsUndefined = m_jit.jump();
     } else {
@@ -405,7 +407,9 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch
         if (!isKnownCell(operand.node()))
             notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
 
-        m_jit.graph().globalObjectFor(operand->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(operand->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         jump(invert ? taken : notTaken, ForceJump);
     } else {
         GPRTemporary localGlobalObject(this);
@@ -1310,7 +1314,9 @@ void SpeculativeJIT::compileObjectEquality(Node* node)
     GPRReg resultGPR = result.gpr();
    
     if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-        m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1383,7 +1389,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1410,7 +1418,9 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r
     
     // We know that within this branch, rightChild must be a cell. 
     if (masqueradesAsUndefinedWatchpointValid) { 
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1487,7 +1497,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     }
 
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1514,7 +1526,9 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild
     
     // We know that within this branch, rightChild must be a cell. 
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal, 
@@ -1626,7 +1640,9 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
 
     MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     if (masqueradesAsUndefinedWatchpointValid) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
         DFG_TYPE_CHECK(
             JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
                 MacroAssembler::Equal,
@@ -1768,7 +1784,9 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, Blo
     
     MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
     if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-        m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint());
 
         DFG_TYPE_CHECK(
             JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
@@ -2475,8 +2493,12 @@ void SpeculativeJIT::compile(Node* node)
                 if (node->arrayMode().isSaneChain()) {
                     JSGlobalObject* globalObject = m_jit.globalObjectFor(node->codeOrigin);
                     ASSERT(globalObject->arrayPrototypeChainIsSane());
-                    globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
-                    globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                    m_jit.addLazily(
+                        speculationWatchpoint(),
+                        globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
+                    m_jit.addLazily(
+                        speculationWatchpoint(),
+                        globalObject->objectPrototype()->structure()->transitionWatchpointSet());
                 }
                 
                 SpeculateStrictInt32Operand property(this, node->child2());
@@ -3294,7 +3316,9 @@ void SpeculativeJIT::compile(Node* node)
     case NewArray: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType());
             RELEASE_ASSERT(structure->indexingType() == node->indexingType());
@@ -3467,7 +3491,9 @@ void SpeculativeJIT::compile(Node* node)
     case NewArrayWithSize: {
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(node->indexingType())) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             SpeculateStrictInt32Operand size(this, node->child1());
             GPRTemporary result(this);
@@ -3540,7 +3566,9 @@ void SpeculativeJIT::compile(Node* node)
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->codeOrigin);
         IndexingType indexingType = node->indexingType();
         if (!globalObject->isHavingABadTime() && !hasArrayStorage(indexingType)) {
-            globalObject->havingABadTimeWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                globalObject->havingABadTimeWatchpoint());
             
             unsigned numElements = node->numConstants();
             
@@ -3639,7 +3667,9 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case AllocationProfileWatchpoint: {
-        jsCast<JSFunction*>(node->function())->addAllocationProfileWatchpoint(speculationWatchpoint());
+        m_jit.addLazily(
+            speculationWatchpoint(),
+            jsCast<JSFunction*>(node->function())->allocationProfileWatchpointSet());
         noResult(node);
         break;
     }
@@ -3931,9 +3961,10 @@ void SpeculativeJIT::compile(Node* node)
         // quite a hint already.
         
         m_jit.addWeakReference(node->structure());
-        node->structure()->addTransitionWatchpoint(
+        m_jit.addLazily(
             speculationWatchpoint(
-                node->child1()->op() == WeakJSConstant ? BadWeakConstantCache : BadCache));
+                node->child1()->op() == WeakJSConstant ? BadWeakConstantCache : BadCache),
+            node->structure()->transitionWatchpointSet());
 
 #if !ASSERT_DISABLED
         SpeculateCellOperand op1(this, node->child1());
@@ -4124,9 +4155,9 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case GlobalVarWatchpoint: {
-        m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
-            identifier(node->identifierNumberForCheck())->impl()).addWatchpoint(
-                speculationWatchpoint());
+        WatchpointSet* set = m_jit.globalObjectFor(node->codeOrigin)->symbolTable()->get(
+            identifier(node->identifierNumberForCheck())->impl()).watchpointSet();
+        m_jit.addLazily(speculationWatchpoint(), set);
         
 #if DFG_ENABLE(JIT_ASSERT)
         GPRTemporary scratch(this);
@@ -4174,7 +4205,9 @@ void SpeculativeJIT::compile(Node* node)
         isCell.link(&m_jit);
         JITCompiler::Jump notMasqueradesAsUndefined;
         if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
-            m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+            m_jit.addLazily(
+                speculationWatchpoint(),
+                m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint());
             m_jit.move(TrustedImm32(0), result.gpr());
             notMasqueradesAsUndefined = m_jit.jump();
         } else {
index 5207c54..28df925 100644 (file)
@@ -49,7 +49,7 @@ static void compileEntry(CCallHelpers& jit)
     jit.emitPutImmediateToCallFrameHeader(jit.codeBlock(), JSStack::CodeBlock);
 }
 
-void compile(State& state, RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
+bool compile(State& state, RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
 {
     LLVMExecutionEngineRef engine;
     char* error = 0;
@@ -80,9 +80,18 @@ void compile(State& state, RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr&
     // FIXME: LLVM should use our own JIT memory allocator, and we shouldn't have to
     // keep around an LLVMExecutionEngineRef to keep code alive.
     // https://bugs.webkit.org/show_bug.cgi?id=113619
+    // FIXME: Need to add support for the case where JIT memory allocation failed.
+    // https://bugs.webkit.org/show_bug.cgi?id=113620
     GeneratedFunction function = reinterpret_cast<GeneratedFunction>(LLVMGetPointerToGlobal(engine, state.function));
     LLVMDisposePassManager(pass);
     
+    if (!state.watchpoints.areStillValid()) {
+        LLVMDisposeExecutionEngine(engine);
+        return false;
+    }
+    
+    state.watchpoints.reallyAdd();
+    
     // Create the entrypoint.
     // FIXME: This is a total kludge - LLVM should just use our calling convention.
     // https://bugs.webkit.org/show_bug.cgi?id=113621
@@ -162,6 +171,8 @@ void compile(State& state, RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr&
             linkBuffer,
             ("FTL entrypoint thunk for %s with LLVM generated code at %p", toCString(CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT)).data(), function)));
     jitCode = state.jitCode;
+    
+    return true;
 }
 
 } } // namespace JSC::FTL
index dd74a3d..1215d52 100644 (file)
@@ -34,7 +34,7 @@
 
 namespace JSC { namespace FTL {
 
-void compile(State&, RefPtr<JSC::JITCode>&, MacroAssemblerCodePtr& jitCodeWithArityCheck);
+bool compile(State&, RefPtr<JSC::JITCode>&, MacroAssemblerCodePtr& jitCodeWithArityCheck);
 
 } } // namespace JSC::FTL
 
index 8922d07..e38ae95 100644 (file)
@@ -30,6 +30,7 @@
 
 #if ENABLE(FTL_JIT)
 
+#include "DFGDesiredWatchpoints.h"
 #include "DFGGraph.h"
 #include "FTLAbbreviations.h"
 #include "FTLJITCode.h"
@@ -51,6 +52,7 @@ public:
     LValue function;
     RefPtr<JITCode> jitCode;
     Vector<OSRExitCompilationInfo> osrExit;
+    DFG::DesiredWatchpoints watchpoints;
     
     void dumpState(const char* when);
 };
index da50f95..e8f2539 100644 (file)
@@ -153,6 +153,11 @@ namespace JSC {
             ASSERT(tryGetAllocationProfile());
             m_allocationProfileWatchpoint.add(watchpoint);
         }
+        
+        InlineWatchpointSet& allocationProfileWatchpointSet()
+        {
+            return m_allocationProfileWatchpoint;
+        }
 
     protected:
         const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
index adcad2a..3d5ea4b 100644 (file)
@@ -344,6 +344,11 @@ public:
     {
         m_transitionWatchpointSet.notifyWrite();
     }
+    
+    InlineWatchpointSet& transitionWatchpointSet() const
+    {
+        return m_transitionWatchpointSet;
+    }
         
     static JS_EXPORTDATA const ClassInfo s_info;
 
index 5c464e8..d48b8a0 100644 (file)
@@ -1,5 +1,31 @@
 2013-07-16  Oliver Hunt <oliver@apple.com>
 
+        Merge dfgFourthTier r148836
+
+    2013-04-21  Filip Pizlo  <fpizlo@apple.com>
+
+        fourthTier: It should be possible to query WatchpointSets, and add Watchpoints, even if the compiler is running in another thread
+        https://bugs.webkit.org/show_bug.cgi?id=114909
+
+        Reviewed by Oliver Hunt.
+        
+        Harden our notions of memory fences, now that we're doing racy algorithms.
+
+        * wtf/Atomics.h:
+        (WTF):
+        (WTF::compilerFence):
+        (WTF::armV7_dmb):
+        (WTF::armV7_dmb_st):
+        (WTF::loadLoadFence):
+        (WTF::loadStoreFence):
+        (WTF::storeLoadFence):
+        (WTF::storeStoreFence):
+        (WTF::memoryBarrierAfterLock):
+        (WTF::memoryBarrierBeforeUnlock):
+        (WTF::x86_mfence):
+
+2013-07-16  Oliver Hunt <oliver@apple.com>
+
         Merge dfgFourthTier r148804
 
     2013-04-20  Filip Pizlo  <fpizlo@apple.com>