[ iOS wk2 Release ] perf/clone-with-focus.html is flaky failing.
[WebKit.git] / Source / JavaScriptCore / dfg / DFGAbstractValue.cpp
1 /*
2  * Copyright (C) 2013-2018 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 #include "config.h"
27 #include "DFGAbstractValue.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "JSCInlines.h"
33 #include "TrackedReferences.h"
34
35 namespace JSC { namespace DFG {
36
37 void AbstractValue::observeTransitions(const TransitionVector& vector)
38 {
39     if (m_type & SpecCell) {
40         m_structure.observeTransitions(vector);
41         ArrayModes newModes = 0;
42         for (unsigned i = vector.size(); i--;) {
43             if (m_arrayModes & arrayModesFromStructure(vector[i].previous.get()))
44                 newModes |= arrayModesFromStructure(vector[i].next.get());
45         }
46         m_arrayModes |= newModes;
47     }
48     checkConsistency();
49 }
50
51 void AbstractValue::set(Graph& graph, const FrozenValue& value, StructureClobberState clobberState)
52 {
53     if (!!value && value.value().isCell()) {
54         Structure* structure = value.structure();
55         StructureRegistrationResult result;
56         RegisteredStructure registeredStructure = graph.registerStructure(structure, result);
57         if (result == StructureRegisteredAndWatched) {
58             m_structure = registeredStructure;
59             if (clobberState == StructuresAreClobbered) {
60                 m_arrayModes = ALL_ARRAY_MODES;
61                 m_structure.clobber();
62             } else
63                 m_arrayModes = arrayModesFromStructure(structure);
64         } else {
65             m_structure.makeTop();
66             m_arrayModes = ALL_ARRAY_MODES;
67         }
68     } else {
69         m_structure.clear();
70         m_arrayModes = 0;
71     }
72     
73     m_type = speculationFromValue(value.value());
74     m_value = value.value();
75     
76     checkConsistency();
77     assertIsRegistered(graph);
78 }
79
80 void AbstractValue::set(Graph& graph, Structure* structure)
81 {
82     set(graph, graph.registerStructure(structure));
83 }
84
85 void AbstractValue::set(Graph& graph, RegisteredStructure structure)
86 {
87     RELEASE_ASSERT(structure);
88     
89     m_structure = structure;
90     m_arrayModes = arrayModesFromStructure(structure.get());
91     m_type = speculationFromStructure(structure.get());
92     m_value = JSValue();
93     
94     checkConsistency();
95     assertIsRegistered(graph);
96 }
97
98 void AbstractValue::set(Graph& graph, const RegisteredStructureSet& set)
99 {
100     m_structure = set;
101     m_arrayModes = set.arrayModesFromStructures();
102     m_type = set.speculationFromStructures();
103     m_value = JSValue();
104     
105     checkConsistency();
106     assertIsRegistered(graph);
107 }
108
109 void AbstractValue::setType(Graph& graph, SpeculatedType type)
110 {
111     SpeculatedType cellType = type & SpecCell;
112     if (cellType) {
113         if (!(cellType & ~SpecString))
114             m_structure = graph.stringStructure;
115         else if (isSymbolSpeculation(cellType))
116             m_structure = graph.symbolStructure;
117         else
118             m_structure.makeTop();
119         m_arrayModes = ALL_ARRAY_MODES;
120     } else {
121         m_structure.clear();
122         m_arrayModes = 0;
123     }
124     m_type = type;
125     m_value = JSValue();
126     checkConsistency();
127 }
128
129 void AbstractValue::fixTypeForRepresentation(Graph& graph, NodeFlags representation, Node* node)
130 {
131     if (representation == NodeResultDouble) {
132         if (m_value) {
133             DFG_ASSERT(graph, node, m_value.isNumber());
134             if (m_value.isInt32())
135                 m_value = jsDoubleNumber(m_value.asNumber());
136         }
137         if (m_type & SpecIntAnyFormat) {
138             m_type &= ~SpecIntAnyFormat;
139             m_type |= SpecAnyIntAsDouble;
140         }
141         if (m_type & ~SpecFullDouble)
142             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n").data());
143     } else if (representation == NodeResultInt52) {
144         if (m_type & SpecAnyIntAsDouble) {
145             // AnyIntAsDouble can produce i32 or i52. SpecAnyIntAsDouble doesn't bound the magnitude of the value.
146             m_type &= ~SpecAnyIntAsDouble;
147             m_type |= SpecInt52Any;
148         }
149
150         if (m_type & SpecInt32Only) {
151             m_type &= ~SpecInt32Only;
152             m_type |= SpecInt32AsInt52;
153         }
154
155         if (m_type & ~SpecInt52Any)
156             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for int52 node has type outside SpecInt52Any.\n").data());
157
158         if (m_value) {
159             DFG_ASSERT(graph, node, m_value.isAnyInt());
160             m_type = int52AwareSpeculationFromValue(m_value);
161         }
162     } else {
163         if (m_type & SpecInt32AsInt52) {
164             m_type &= ~SpecInt32AsInt52;
165             m_type |= SpecInt32Only;
166         }
167         if (m_type & SpecNonInt32AsInt52) {
168             m_type &= ~SpecNonInt32AsInt52;
169             m_type |= SpecAnyIntAsDouble;
170         }
171         if (m_type & ~SpecBytecodeTop)
172             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n").data());
173     }
174     
175     checkConsistency();
176 }
177
178 void AbstractValue::fixTypeForRepresentation(Graph& graph, Node* node)
179 {
180     fixTypeForRepresentation(graph, node->result(), node);
181 }
182
183 bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value, VariableAccessData* variable, Node* node)
184 {
185     FlushFormat flushFormat = variable->flushFormat();
186
187     {
188         if (flushFormat == FlushedDouble && value.isNumber())
189             value = jsDoubleNumber(value.asNumber());
190         SpeculatedType incomingType = resultFor(flushFormat) == NodeResultInt52 ? int52AwareSpeculationFromValue(value) : speculationFromValue(value);
191         SpeculatedType requiredType = typeFilterFor(flushFormat);
192         if (incomingType & ~requiredType)
193             return false;
194     }
195
196     AbstractValue oldMe = *this;
197     
198     if (isClear()) {
199         FrozenValue* frozenValue = graph.freeze(value);
200         if (frozenValue->pointsToHeap()) {
201             m_structure = graph.registerStructure(frozenValue->structure());
202             m_arrayModes = arrayModesFromStructure(frozenValue->structure());
203         } else {
204             m_structure.clear();
205             m_arrayModes = 0;
206         }
207         
208         m_type = speculationFromValue(value);
209         m_value = value;
210     } else {
211         mergeSpeculation(m_type, speculationFromValue(value));
212         if (!!value && value.isCell()) {
213             RegisteredStructure structure = graph.registerStructure(value.asCell()->structure(graph.m_vm));
214             mergeArrayModes(m_arrayModes, arrayModesFromStructure(structure.get()));
215             m_structure.merge(RegisteredStructureSet(structure));
216         }
217         if (m_value != value)
218             m_value = JSValue();
219     }
220     
221     assertIsRegistered(graph);
222
223     fixTypeForRepresentation(graph, resultFor(flushFormat), node);
224
225     checkConsistency();
226     
227     return oldMe != *this;
228 }
229
230 FiltrationResult AbstractValue::filter(
231     Graph& graph, const RegisteredStructureSet& other, SpeculatedType admittedTypes)
232 {
233     ASSERT(!(admittedTypes & SpecCell));
234     
235     if (isClear())
236         return FiltrationOK;
237     
238     // FIXME: This could be optimized for the common case of m_type not
239     // having structures, array modes, or a specific value.
240     // https://bugs.webkit.org/show_bug.cgi?id=109663
241     
242     m_type &= other.speculationFromStructures() | admittedTypes;
243     m_arrayModes &= other.arrayModesFromStructures();
244     m_structure.filter(other);
245     
246     // It's possible that prior to the above two statements we had (Foo, TOP), where
247     // Foo is a SpeculatedType that is disjoint with the passed RegisteredStructureSet. In that
248     // case, we will now have (None, [someStructure]). In general, we need to make
249     // sure that new information gleaned from the SpeculatedType needs to be fed back
250     // into the information gleaned from the RegisteredStructureSet.
251     m_structure.filter(m_type);
252     
253     filterArrayModesByType();
254     filterValueByType();
255     return normalizeClarity(graph);
256 }
257
258 FiltrationResult AbstractValue::changeStructure(Graph& graph, const RegisteredStructureSet& other)
259 {
260     m_type &= other.speculationFromStructures();
261     m_arrayModes = other.arrayModesFromStructures();
262     m_structure = other;
263     
264     filterValueByType();
265     
266     return normalizeClarity(graph);
267 }
268
269 FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes, SpeculatedType admittedTypes)
270 {
271     ASSERT(arrayModes);
272     ASSERT(!(admittedTypes & SpecCell));
273     
274     if (isClear())
275         return FiltrationOK;
276     
277     m_type &= SpecCell | admittedTypes;
278     m_arrayModes &= arrayModes;
279     return normalizeClarity();
280 }
281
282 FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
283 {
284     // FIXME: AI should track ClassInfo to leverage hierarchical class information.
285     // https://bugs.webkit.org/show_bug.cgi?id=162989
286     if (isClear())
287         return FiltrationOK;
288
289     m_type &= speculationFromClassInfo(classInfo);
290     m_structure.filterClassInfo(classInfo);
291
292     m_structure.filter(m_type);
293
294     filterArrayModesByType();
295     filterValueByType();
296     return normalizeClarity(graph);
297 }
298
299 FiltrationResult AbstractValue::filterSlow(SpeculatedType type)
300 {
301     m_type &= type;
302     
303     // It's possible that prior to this filter() call we had, say, (Final, TOP), and
304     // the passed type is Array. At this point we'll have (None, TOP). The best way
305     // to ensure that the structure filtering does the right thing is to filter on
306     // the new type (None) rather than the one passed (Array).
307     m_structure.filter(m_type);
308     filterArrayModesByType();
309     filterValueByType();
310     return normalizeClarity();
311 }
312
313 FiltrationResult AbstractValue::fastForwardToAndFilterSlow(AbstractValueClobberEpoch newEpoch, SpeculatedType type)
314 {
315     if (newEpoch != m_effectEpoch)
316         fastForwardToSlow(newEpoch);
317     
318     return filterSlow(type);
319 }
320
321 FiltrationResult AbstractValue::filterByValue(const FrozenValue& value)
322 {
323     FiltrationResult result = filter(speculationFromValue(value.value()));
324     if (m_type)
325         m_value = value.value();
326     return result;
327 }
328
329 bool AbstractValue::contains(RegisteredStructure structure) const
330 {
331     return couldBeType(speculationFromStructure(structure.get()))
332         && (m_arrayModes & arrayModesFromStructure(structure.get()))
333         && m_structure.contains(structure);
334 }
335
336 FiltrationResult AbstractValue::filter(const AbstractValue& other)
337 {
338     m_type &= other.m_type;
339     m_structure.filter(other.m_structure);
340     m_arrayModes &= other.m_arrayModes;
341
342     m_structure.filter(m_type);
343     filterArrayModesByType();
344     filterValueByType();
345     
346     if (normalizeClarity() == Contradiction)
347         return Contradiction;
348     
349     if (m_value == other.m_value)
350         return FiltrationOK;
351     
352     // Neither of us are BOTTOM, so an empty value means TOP.
353     if (!m_value) {
354         // We previously didn't prove a value but now we have done so.
355         m_value = other.m_value; 
356         return FiltrationOK;
357     }
358     
359     if (!other.m_value) {
360         // We had proved a value but the other guy hadn't, so keep our proof.
361         return FiltrationOK;
362     }
363     
364     // We both proved there to be a specific value but they are different.
365     clear();
366     return Contradiction;
367 }
368
369 void AbstractValue::filterValueByType()
370 {
371     // We could go further, and ensure that if the futurePossibleStructure contravenes
372     // the value, then we could clear both of those things. But that's unlikely to help
373     // in any realistic scenario, so we don't do it. Simpler is better.
374
375     if (!m_value)
376         return;
377
378     if (validateTypeAcceptingBoxedInt52(m_value))
379         return;
380
381     // We assume that the constant value can produce a narrower type at
382     // some point. For example, rope JSString produces SpecString, but
383     // it produces SpecStringIdent once it is resolved to AtomStringImpl.
384     // We do not make this AbstractValue cleared, but clear the constant
385     // value if validation fails currently.
386     m_value = JSValue();
387 }
388
389 void AbstractValue::filterArrayModesByType()
390 {
391     if (!(m_type & SpecCell))
392         m_arrayModes = 0;
393     else if (!(m_type & ~SpecArray))
394         m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
395     
396     // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
397     // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
398     // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
399     // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
400     // type system they are arrays (since they expose the magical length
401     // property and are otherwise allocated using array allocation). Hence the
402     // following would be wrong:
403     //
404     // if (!(m_type & SpecArray))
405     //    m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
406 }
407
408 bool AbstractValue::shouldBeClear() const
409 {
410     if (m_type == SpecNone)
411         return true;
412     
413     if (!(m_type & ~SpecCell)
414         && (!m_arrayModes || m_structure.isClear()))
415         return true;
416     
417     return false;
418 }
419
420 FiltrationResult AbstractValue::normalizeClarity()
421 {
422     // It's useful to be able to quickly check if an abstract value is clear.
423     // This normalizes everything to make that easy.
424     
425     FiltrationResult result;
426     
427     if (shouldBeClear()) {
428         clear();
429         result = Contradiction;
430     } else
431         result = FiltrationOK;
432
433     checkConsistency();
434     
435     return result;
436 }
437
438 FiltrationResult AbstractValue::normalizeClarity(Graph& graph)
439 {
440     FiltrationResult result = normalizeClarity();
441     assertIsRegistered(graph);
442     return result;
443 }
444
445 #if ASSERT_ENABLED
446 void AbstractValue::checkConsistency() const
447 {
448     if (!(m_type & SpecCell)) {
449         RELEASE_ASSERT(m_structure.isClear());
450         RELEASE_ASSERT(!m_arrayModes);
451     }
452     
453     if (isClear())
454         RELEASE_ASSERT(!m_value);
455     
456     if (!!m_value)
457         RELEASE_ASSERT(validateTypeAcceptingBoxedInt52(m_value));
458
459     // Note that it's possible for a prediction like (Final, []). This really means that
460     // the value is bottom and that any code that uses the value is unreachable. But
461     // we don't want to get pedantic about this as it would only increase the computational
462     // complexity of the code.
463 }
464
465 void AbstractValue::assertIsRegistered(Graph& graph) const
466 {
467     m_structure.assertIsRegistered(graph);
468 }
469 #endif // ASSERT_ENABLED
470
471 ResultType AbstractValue::resultType() const
472 {
473     ASSERT(isType(SpecBytecodeTop));
474     if (isType(SpecBoolean))
475         return ResultType::booleanType();
476     if (isType(SpecInt32Only))
477         return ResultType::numberTypeIsInt32();
478     if (isType(SpecBytecodeNumber))
479         return ResultType::numberType();
480     if (isType(SpecString))
481         return ResultType::stringType();
482     if (isType(SpecString | SpecBytecodeNumber))
483         return ResultType::stringOrNumberType();
484     return ResultType::unknownType();
485 }
486
487 void AbstractValue::dump(PrintStream& out) const
488 {
489     dumpInContext(out, 0);
490 }
491
492 void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
493 {
494     out.print("(", SpeculationDump(m_type));
495     if (m_type & SpecCell) {
496         out.print(
497             ", ", ArrayModesDump(m_arrayModes), ", ",
498             inContext(m_structure, context));
499     }
500     if (!!m_value)
501         out.print(", ", inContext(m_value, context));
502     out.print(", ", m_effectEpoch);
503     out.print(")");
504 }
505
506 void AbstractValue::validateReferences(const TrackedReferences& trackedReferences)
507 {
508     trackedReferences.check(m_value);
509     m_structure.validateReferences(trackedReferences);
510 }
511
512 #if USE(JSVALUE64) && !defined(NDEBUG)
513 void AbstractValue::ensureCanInitializeWithZeros()
514 {
515     std::aligned_storage<sizeof(AbstractValue), alignof(AbstractValue)>::type zeroFilledStorage;
516     memset(static_cast<void*>(&zeroFilledStorage), 0, sizeof(AbstractValue));
517     ASSERT(*this == *static_cast<AbstractValue*>(static_cast<void*>(&zeroFilledStorage)));
518 }
519 #endif
520
521 void AbstractValue::fastForwardToSlow(AbstractValueClobberEpoch newEpoch)
522 {
523     ASSERT(newEpoch != m_effectEpoch);
524     
525     if (newEpoch.clobberEpoch() != m_effectEpoch.clobberEpoch())
526         clobberStructures();
527     if (newEpoch.structureClobberState() == StructuresAreWatched)
528         m_structure.observeInvalidationPoint();
529     
530     m_effectEpoch = newEpoch;
531     
532     checkConsistency();
533 }
534
535 } } // namespace JSC::DFG
536
537 #endif // ENABLE(DFG_JIT)
538