1/*
2 * Copyright (C) 2013-2019 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#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGCommonData.h"
31#include "FunctionExecutable.h"
32#include "JSArrayBufferView.h"
33#include "ObjectPropertyCondition.h"
34#include "SymbolTable.h"
35#include "Watchpoint.h"
36#include <wtf/CommaPrinter.h>
37#include <wtf/HashSet.h>
38
39namespace JSC { namespace DFG {
40
41class Graph;
42struct Prefix;
43
44template<typename T>
45struct SetPointerAdaptor {
46 static void add(CodeBlock* codeBlock, T set, CommonData& common)
47 {
48 CodeBlockJettisoningWatchpoint* watchpoint = nullptr;
49 {
50 ConcurrentJSLocker locker(codeBlock->m_lock);
51 watchpoint = common.watchpoints.add(codeBlock);
52 }
53 return set->add(WTFMove(watchpoint));
54 }
55 static bool hasBeenInvalidated(T set)
56 {
57 return set->hasBeenInvalidated();
58 }
59 static void dumpInContext(PrintStream& out, T set, DumpContext*)
60 {
61 out.print(RawPointer(set));
62 }
63};
64
65struct SymbolTableAdaptor {
66 static void add(CodeBlock*, SymbolTable*, CommonData&);
67 static bool hasBeenInvalidated(SymbolTable* symbolTable)
68 {
69 return symbolTable->singleton().hasBeenInvalidated();
70 }
71 static void dumpInContext(PrintStream& out, SymbolTable* symbolTable, DumpContext*)
72 {
73 out.print(RawPointer(symbolTable));
74 }
75};
76
77struct FunctionExecutableAdaptor {
78 static void add(CodeBlock*, FunctionExecutable*, CommonData&);
79 static bool hasBeenInvalidated(FunctionExecutable* executable)
80 {
81 return executable->singleton().hasBeenInvalidated();
82 }
83 static void dumpInContext(PrintStream& out, FunctionExecutable* executable, DumpContext*)
84 {
85 out.print(RawPointer(executable));
86 }
87};
88
89struct ArrayBufferViewWatchpointAdaptor {
90 static void add(CodeBlock*, JSArrayBufferView*, CommonData&);
91 static bool hasBeenInvalidated(JSArrayBufferView* view)
92 {
93 return !view->length();
94 }
95 static void dumpInContext(PrintStream& out, JSArrayBufferView* view, DumpContext* context)
96 {
97 out.print(inContext(JSValue(view), context));
98 }
99};
100
101struct AdaptiveStructureWatchpointAdaptor {
102 static void add(CodeBlock*, const ObjectPropertyCondition&, CommonData&);
103 static bool hasBeenInvalidated(const ObjectPropertyCondition& key)
104 {
105 return !key.isWatchable();
106 }
107 static void dumpInContext(
108 PrintStream& out, const ObjectPropertyCondition& key, DumpContext* context)
109 {
110 out.print(inContext(key, context));
111 }
112};
113
114template<typename WatchpointSetType, typename Adaptor = SetPointerAdaptor<WatchpointSetType>>
115class GenericDesiredWatchpoints {
116#if !ASSERT_DISABLED
117 typedef HashMap<WatchpointSetType, bool> StateMap;
118#endif
119public:
120 GenericDesiredWatchpoints()
121 : m_reallyAdded(false)
122 {
123 }
124
125 void addLazily(const WatchpointSetType& set)
126 {
127 m_sets.add(set);
128 }
129
130 void reallyAdd(CodeBlock* codeBlock, CommonData& common)
131 {
132 RELEASE_ASSERT(!m_reallyAdded);
133
134 for (auto& set : m_sets)
135 Adaptor::add(codeBlock, set, common);
136
137 m_reallyAdded = true;
138 }
139
140 bool areStillValid() const
141 {
142 for (auto& set : m_sets) {
143 if (Adaptor::hasBeenInvalidated(set))
144 return false;
145 }
146
147 return true;
148 }
149
150 bool isWatched(const WatchpointSetType& set) const
151 {
152 return m_sets.contains(set);
153 }
154
155 void dumpInContext(PrintStream& out, DumpContext* context) const
156 {
157 CommaPrinter comma;
158 for (const WatchpointSetType& entry : m_sets) {
159 out.print(comma);
160 Adaptor::dumpInContext(out, entry, context);
161 }
162 }
163
164private:
165 HashSet<WatchpointSetType> m_sets;
166 bool m_reallyAdded;
167};
168
169class DesiredWatchpoints {
170public:
171 DesiredWatchpoints();
172 ~DesiredWatchpoints();
173
174 void addLazily(WatchpointSet*);
175 void addLazily(InlineWatchpointSet&);
176 void addLazily(SymbolTable*);
177 void addLazily(FunctionExecutable*);
178 void addLazily(JSArrayBufferView*);
179
180 // It's recommended that you don't call this directly. Use Graph::watchCondition(), which does
181 // the required GC magic as well as some other bookkeeping.
182 void addLazily(const ObjectPropertyCondition&);
183
184 bool consider(Structure*);
185
186 void reallyAdd(CodeBlock*, CommonData&);
187
188 bool areStillValid() const;
189
190 bool isWatched(WatchpointSet* set)
191 {
192 return m_sets.isWatched(set);
193 }
194 bool isWatched(InlineWatchpointSet& set)
195 {
196 return m_inlineSets.isWatched(&set);
197 }
198 bool isWatched(SymbolTable* symbolTable)
199 {
200 return m_symbolTables.isWatched(symbolTable);
201 }
202 bool isWatched(FunctionExecutable* executable)
203 {
204 return m_functionExecutables.isWatched(executable);
205 }
206 bool isWatched(JSArrayBufferView* view)
207 {
208 return m_bufferViews.isWatched(view);
209 }
210 bool isWatched(const ObjectPropertyCondition& key)
211 {
212 return m_adaptiveStructureSets.isWatched(key);
213 }
214 void dumpInContext(PrintStream&, DumpContext*) const;
215
216private:
217 GenericDesiredWatchpoints<WatchpointSet*> m_sets;
218 GenericDesiredWatchpoints<InlineWatchpointSet*> m_inlineSets;
219 GenericDesiredWatchpoints<SymbolTable*, SymbolTableAdaptor> m_symbolTables;
220 GenericDesiredWatchpoints<FunctionExecutable*, FunctionExecutableAdaptor> m_functionExecutables;
221 GenericDesiredWatchpoints<JSArrayBufferView*, ArrayBufferViewWatchpointAdaptor> m_bufferViews;
222 GenericDesiredWatchpoints<ObjectPropertyCondition, AdaptiveStructureWatchpointAdaptor> m_adaptiveStructureSets;
223};
224
225} } // namespace JSC::DFG
226
227#endif // ENABLE(DFG_JIT)
228