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