1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef DFGDesiredWatchpoints_h 27#define DFGDesiredWatchpoints_h 28 29#if ENABLE(DFG_JIT) 30 31#include "CodeOrigin.h" 32#include "DFGCommonData.h" 33#include "JSArrayBufferView.h" 34#include "Watchpoint.h" 35#include <wtf/HashMap.h> 36#include <wtf/HashSet.h> 37#include <wtf/Noncopyable.h> 38#include <wtf/Vector.h> 39 40namespace JSC { namespace DFG { 41 42template<typename WatchpointSetType> 43struct WatchpointForGenericWatchpointSet { 44 WatchpointForGenericWatchpointSet() 45 : m_exitKind(ExitKindUnset) 46 , m_set(0) 47 { 48 } 49 50 WatchpointForGenericWatchpointSet( 51 CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set) 52 : m_codeOrigin(codeOrigin) 53 , m_exitKind(exitKind) 54 , m_set(set) 55 { 56 } 57 58 CodeOrigin m_codeOrigin; 59 ExitKind m_exitKind; 60 WatchpointSetType* m_set; 61}; 62 63template<typename T> 64struct GenericSetAdaptor { 65 static void add(CodeBlock*, T* set, Watchpoint* watchpoint) 66 { 67 return set->add(watchpoint); 68 } 69 static bool hasBeenInvalidated(T* set) { return set->hasBeenInvalidated(); } 70}; 71 72struct ArrayBufferViewWatchpointAdaptor { 73 static void add(CodeBlock*, JSArrayBufferView*, Watchpoint*); 74 static bool hasBeenInvalidated(JSArrayBufferView* view) 75 { 76 bool result = !view->length(); 77 WTF::loadLoadFence(); 78 return result; 79 } 80}; 81 82template<typename WatchpointSetType, typename Adaptor = GenericSetAdaptor<WatchpointSetType>> 83class GenericDesiredWatchpoints { 84#if !ASSERT_DISABLED 85 typedef HashMap<WatchpointSetType*, bool> StateMap; 86#endif 87public: 88 GenericDesiredWatchpoints() 89 : m_reallyAdded(false) 90 { 91 } 92 93 void addLazily(WatchpointSetType* set) 94 { 95 m_sets.add(set); 96 } 97 98 void addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set) 99 { 100 m_profiledWatchpoints.append( 101 WatchpointForGenericWatchpointSet<WatchpointSetType>(codeOrigin, exitKind, set)); 102 } 103 104 void reallyAdd(CodeBlock* codeBlock, CommonData& common) 105 { 106 RELEASE_ASSERT(!m_reallyAdded); 107 108 typename HashSet<WatchpointSetType*>::iterator iter = m_sets.begin(); 109 typename HashSet<WatchpointSetType*>::iterator end = m_sets.end(); 110 for (; iter != end; ++iter) { 111 common.watchpoints.append(CodeBlockJettisoningWatchpoint(codeBlock)); 112 Adaptor::add(codeBlock, *iter, &common.watchpoints.last()); 113 } 114 115 for (unsigned i = m_profiledWatchpoints.size(); i--;) { 116 WatchpointForGenericWatchpointSet<WatchpointSetType> watchpoint = 117 m_profiledWatchpoints[i]; 118 common.profiledWatchpoints.append( 119 ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock)); 120 Adaptor::add(codeBlock, watchpoint.m_set, &common.profiledWatchpoints.last()); 121 } 122 123 m_reallyAdded = true; 124 } 125 126 bool areStillValid() const 127 { 128 typename HashSet<WatchpointSetType*>::iterator iter = m_sets.begin(); 129 typename HashSet<WatchpointSetType*>::iterator end = m_sets.end(); 130 for (; iter != end; ++iter) { 131 if (Adaptor::hasBeenInvalidated(*iter)) 132 return false; 133 } 134 135 for (unsigned i = m_profiledWatchpoints.size(); i--;) { 136 if (Adaptor::hasBeenInvalidated(m_profiledWatchpoints[i].m_set)) 137 return false; 138 } 139 140 return true; 141 } 142 143#if ASSERT_DISABLED 144 bool isStillValid(WatchpointSetType* set) 145 { 146 return !Adaptor::hasBeenInvalidated(set); 147 } 148 149 bool shouldAssumeMixedState(WatchpointSetType*) 150 { 151 return true; 152 } 153#else 154 bool isStillValid(WatchpointSetType* set) 155 { 156 bool result = !Adaptor::hasBeenInvalidated(set); 157 m_firstKnownState.add(set, result); 158 return result; 159 } 160 161 bool shouldAssumeMixedState(WatchpointSetType* set) 162 { 163 typename StateMap::iterator iter = m_firstKnownState.find(set); 164 if (iter == m_firstKnownState.end()) 165 return false; 166 167 return iter->value != !Adaptor::hasBeenInvalidated(set); 168 } 169#endif 170 171 bool isValidOrMixed(WatchpointSetType* set) 172 { 173 return isStillValid(set) || shouldAssumeMixedState(set); 174 } 175 176private: 177 Vector<WatchpointForGenericWatchpointSet<WatchpointSetType>> m_profiledWatchpoints; 178 HashSet<WatchpointSetType*> m_sets; 179#if !ASSERT_DISABLED 180 StateMap m_firstKnownState; 181#endif 182 bool m_reallyAdded; 183}; 184 185class DesiredWatchpoints { 186public: 187 DesiredWatchpoints(); 188 ~DesiredWatchpoints(); 189 190 void addLazily(WatchpointSet*); 191 void addLazily(InlineWatchpointSet&); 192 void addLazily(JSArrayBufferView*); 193 void addLazily(CodeOrigin, ExitKind, WatchpointSet*); 194 void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&); 195 196 void reallyAdd(CodeBlock*, CommonData&); 197 198 bool areStillValid() const; 199 200 bool isStillValid(WatchpointSet* set) 201 { 202 return m_sets.isStillValid(set); 203 } 204 bool isStillValid(InlineWatchpointSet& set) 205 { 206 return m_inlineSets.isStillValid(&set); 207 } 208 bool isStillValid(JSArrayBufferView* view) 209 { 210 return m_bufferViews.isStillValid(view); 211 } 212 bool shouldAssumeMixedState(WatchpointSet* set) 213 { 214 return m_sets.shouldAssumeMixedState(set); 215 } 216 bool shouldAssumeMixedState(InlineWatchpointSet& set) 217 { 218 return m_inlineSets.shouldAssumeMixedState(&set); 219 } 220 bool shouldAssumeMixedState(JSArrayBufferView* view) 221 { 222 return m_bufferViews.shouldAssumeMixedState(view); 223 } 224 bool isValidOrMixed(WatchpointSet* set) 225 { 226 return m_sets.isValidOrMixed(set); 227 } 228 bool isValidOrMixed(InlineWatchpointSet& set) 229 { 230 return m_inlineSets.isValidOrMixed(&set); 231 } 232 bool isValidOrMixed(JSArrayBufferView* view) 233 { 234 return m_bufferViews.isValidOrMixed(view); 235 } 236 237private: 238 GenericDesiredWatchpoints<WatchpointSet> m_sets; 239 GenericDesiredWatchpoints<InlineWatchpointSet> m_inlineSets; 240 GenericDesiredWatchpoints<JSArrayBufferView, ArrayBufferViewWatchpointAdaptor> m_bufferViews; 241}; 242 243} } // namespace JSC::DFG 244 245#endif // ENABLE(DFG_JIT) 246 247#endif // DFGDesiredWatchpoints_h 248 249