2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGStructureAbstractValue.h"
33 namespace JSC
{ namespace DFG
{
35 // Comment out the empty SAMPLE() definition, and uncomment the one that uses SamplingRegion, if
36 // you want extremely fine-grained profiling in this code.
38 //#define SAMPLE(name) SamplingRegion samplingRegion(name)
41 void StructureAbstractValue::assertIsRegistered(Graph
& graph
) const
43 SAMPLE("StructureAbstractValue assertIsRegistered");
48 for (unsigned i
= size(); i
--;)
49 graph
.assertIsRegistered(at(i
));
51 #endif // !ASSERT_DISABLED
53 void StructureAbstractValue::clobber()
55 SAMPLE("StructureAbstractValue clobber");
57 // The premise of this approach to clobbering is that anytime we introduce
58 // a watchable structure into an abstract value, we watchpoint it. You can assert
59 // that this holds by calling assertIsWatched().
67 if (!m_set
.singleEntry())
69 if (!m_set
.singleEntry()->dfgShouldWatch())
74 StructureSet::OutOfLineList
* list
= m_set
.list();
75 for (unsigned i
= list
->m_length
; i
--;) {
76 if (!list
->list()[i
]->dfgShouldWatch()) {
83 void StructureAbstractValue::observeTransition(Structure
* from
, Structure
* to
)
85 SAMPLE("StructureAbstractValue observeTransition");
87 ASSERT(!from
->dfgShouldWatch());
92 if (!m_set
.contains(from
))
98 if (m_set
.size() > polymorphismLimit
)
102 void StructureAbstractValue::observeTransitions(const TransitionVector
& vector
)
104 SAMPLE("StructureAbstractValue observeTransitions");
109 StructureSet newStructures
;
110 for (unsigned i
= vector
.size(); i
--;) {
111 ASSERT(!vector
[i
].previous
->dfgShouldWatch());
113 if (!m_set
.contains(vector
[i
].previous
))
116 newStructures
.add(vector
[i
].next
);
119 if (!m_set
.merge(newStructures
))
122 if (m_set
.size() > polymorphismLimit
)
126 bool StructureAbstractValue::add(Structure
* structure
)
128 SAMPLE("StructureAbstractValue add");
133 if (!m_set
.add(structure
))
136 if (m_set
.size() > polymorphismLimit
)
142 bool StructureAbstractValue::merge(const StructureSet
& other
)
144 SAMPLE("StructureAbstractValue merge set");
149 return mergeNotTop(other
);
152 bool StructureAbstractValue::mergeSlow(const StructureAbstractValue
& other
)
154 SAMPLE("StructureAbstractValue merge value slow");
156 // It isn't immediately obvious that the code below is doing the right thing, so let's go
159 // This not clobbered, other not clobbered: Clearly, we don't want to make anything clobbered
160 // since we just have two sets and we are merging them. mergeNotTop() can handle this just
163 // This clobbered, other clobbered: Clobbered means that we have a set of things, plus we
164 // temporarily have the set of all things but the latter will go away once we hit the next
165 // invalidation point. This allows us to merge two clobbered sets the natural way. For now
166 // the set will still be TOP (and so we keep the clobbered bit set), but we know that after
167 // invalidation, we will have the union of the this and other.
169 // This clobbered, other not clobbered: It's safe to merge in other for both before and after
170 // invalidation, so long as we leave the clobbered bit set. Before invalidation this has no
171 // effect since the set will still appear to have all things in it. The way to think about
172 // what invalidation would do is imagine if we had a set A that was clobbered and a set B
173 // that wasn't and we considered the following two cases. Note that we expect A to be the
174 // same at the end in both cases:
176 // A.merge(B) InvalidationPoint
177 // InvalidationPoint A.merge(B)
179 // The fact that we expect A to be the same in both cases means that we want to merge other
180 // into this but keep the clobbered bit.
182 // This not clobbered, other clobbered: This is just the converse of the previous case. We
183 // want to merge other into this and set the clobbered bit.
185 bool changed
= false;
187 if (!isClobbered() && other
.isClobbered()) {
192 changed
|= mergeNotTop(other
.m_set
);
197 bool StructureAbstractValue::mergeNotTop(const StructureSet
& other
)
199 SAMPLE("StructureAbstractValue merge not top");
201 if (!m_set
.merge(other
))
204 if (m_set
.size() > polymorphismLimit
)
210 void StructureAbstractValue::filter(const StructureSet
& other
)
212 SAMPLE("StructureAbstractValue filter set");
220 // We have two choices here:
222 // Do nothing: It's legal to keep our set intact, which would essentially mean that for
223 // now, our set would behave like TOP but after the next invalidation point it wold be
224 // a finite set again. This may be a good choice if 'other' is much bigger than our
227 // Replace m_set with other and clear the clobber bit: This is also legal, and means that
228 // we're no longer clobbered. This is usually better because it immediately gives us a
231 // This scenario should come up rarely. We usually don't do anything to an abstract value
232 // after it is clobbered. But we apply some heuristics.
234 if (other
.size() > m_set
.size() + clobberedSupremacyThreshold
)
235 return; // Keep the clobbered set.
245 void StructureAbstractValue::filter(const StructureAbstractValue
& other
)
247 SAMPLE("StructureAbstractValue filter value");
252 if (other
.isClobbered()) {
256 if (!isClobbered()) {
257 // See justification in filter(const StructureSet&), above. An unclobbered set is
258 // almost always better.
259 if (m_set
.size() > other
.m_set
.size() + clobberedSupremacyThreshold
)
260 *this = other
; // Keep the clobbered set.
264 m_set
.filter(other
.m_set
);
271 void StructureAbstractValue::filterSlow(SpeculatedType type
)
273 SAMPLE("StructureAbstractValue filter type slow");
275 if (!(type
& SpecCell
)) {
283 [&] (Structure
* structure
) {
284 return !!(speculationFromStructure(structure
) & type
);
288 bool StructureAbstractValue::contains(Structure
* structure
) const
290 SAMPLE("StructureAbstractValue contains");
292 if (isTop() || isClobbered())
295 return m_set
.contains(structure
);
298 bool StructureAbstractValue::isSubsetOf(const StructureSet
& other
) const
300 SAMPLE("StructureAbstractValue isSubsetOf set");
302 if (isTop() || isClobbered())
305 return m_set
.isSubsetOf(other
);
308 bool StructureAbstractValue::isSubsetOf(const StructureAbstractValue
& other
) const
310 SAMPLE("StructureAbstractValue isSubsetOf value");
318 if (isClobbered() == other
.isClobbered())
319 return m_set
.isSubsetOf(other
.m_set
);
321 // Here it gets tricky. If in doubt, return false!
324 return false; // A clobbered set is never a subset of an unclobbered set.
326 // An unclobbered set is currently a subset of a clobbered set, but it may not be so after
328 return m_set
.isSubsetOf(other
.m_set
);
331 bool StructureAbstractValue::isSupersetOf(const StructureSet
& other
) const
333 SAMPLE("StructureAbstractValue isSupersetOf set");
335 if (isTop() || isClobbered())
338 return m_set
.isSupersetOf(other
);
341 bool StructureAbstractValue::overlaps(const StructureSet
& other
) const
343 SAMPLE("StructureAbstractValue overlaps set");
345 if (isTop() || isClobbered())
348 return m_set
.overlaps(other
);
351 bool StructureAbstractValue::overlaps(const StructureAbstractValue
& other
) const
353 SAMPLE("StructureAbstractValue overlaps value");
355 if (other
.isTop() || other
.isClobbered())
358 return overlaps(other
.m_set
);
361 bool StructureAbstractValue::equalsSlow(const StructureAbstractValue
& other
) const
363 SAMPLE("StructureAbstractValue equalsSlow");
365 ASSERT(m_set
.m_pointer
!= other
.m_set
.m_pointer
);
367 ASSERT(!other
.isTop());
369 return m_set
== other
.m_set
370 && isClobbered() == other
.isClobbered();
373 void StructureAbstractValue::dumpInContext(PrintStream
& out
, DumpContext
* context
) const
376 out
.print("Clobbered:");
381 out
.print(inContext(m_set
, context
));
384 void StructureAbstractValue::dump(PrintStream
& out
) const
386 dumpInContext(out
, 0);
389 void StructureAbstractValue::validateReferences(const TrackedReferences
& trackedReferences
) const
393 m_set
.validateReferences(trackedReferences
);
396 } } // namespace JSC::DFG
398 #endif // ENABLE(DFG_JIT)