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 | |
39 | namespace JSC { namespace DFG { |
40 | |
41 | class Graph; |
42 | struct Prefix; |
43 | |
44 | template<typename T> |
45 | struct 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 | |
65 | struct 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 | |
77 | struct 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 | |
89 | struct 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 | |
101 | struct 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 | |
114 | template<typename WatchpointSetType, typename Adaptor = SetPointerAdaptor<WatchpointSetType>> |
115 | class GenericDesiredWatchpoints { |
116 | #if !ASSERT_DISABLED |
117 | typedef HashMap<WatchpointSetType, bool> StateMap; |
118 | #endif |
119 | public: |
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 | |
164 | private: |
165 | HashSet<WatchpointSetType> m_sets; |
166 | bool m_reallyAdded; |
167 | }; |
168 | |
169 | class DesiredWatchpoints { |
170 | public: |
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 | |
216 | private: |
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 | |