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