Harden how the compiler references GC objects
[WebKit.git] / Source / JavaScriptCore / dfg / DFGAbstractValue.cpp
1 /*
2  * Copyright (C) 2013-2016 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 & asArrayModes(vector[i].previous->indexingType()))
44                 newModes |= asArrayModes(vector[i].next->indexingType());
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 = asArrayModes(structure->indexingType());
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 = asArrayModes(structure->indexingType());
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::set(Graph& graph, const InferredType::Descriptor& descriptor)
130 {
131     switch (descriptor.kind()) {
132     case InferredType::Bottom:
133         clear();
134         return;
135     case InferredType::Boolean:
136         setType(SpecBoolean);
137         return;
138     case InferredType::Other:
139         setType(SpecOther);
140         return;
141     case InferredType::Int32:
142         setType(SpecInt32Only);
143         return;
144     case InferredType::Number:
145         setType(SpecBytecodeNumber);
146         return;
147     case InferredType::String:
148         set(graph, graph.m_vm.stringStructure.get());
149         return;
150     case InferredType::Symbol:
151         set(graph, graph.m_vm.symbolStructure.get());
152         return;
153     case InferredType::ObjectWithStructure:
154         set(graph, descriptor.structure());
155         return;
156     case InferredType::ObjectWithStructureOrOther:
157         set(graph, descriptor.structure());
158         merge(SpecOther);
159         return;
160     case InferredType::Object:
161         setType(graph, SpecObject);
162         return;
163     case InferredType::ObjectOrOther:
164         setType(graph, SpecObject | SpecOther);
165         return;
166     case InferredType::Top:
167         makeHeapTop();
168         return;
169     }
170
171     RELEASE_ASSERT_NOT_REACHED();
172 }
173
174 void AbstractValue::set(
175     Graph& graph, const InferredType::Descriptor& descriptor, StructureClobberState clobberState)
176 {
177     set(graph, descriptor);
178     if (clobberState == StructuresAreClobbered)
179         clobberStructures();
180 }
181
182 void AbstractValue::fixTypeForRepresentation(Graph& graph, NodeFlags representation, Node* node)
183 {
184     if (representation == NodeResultDouble) {
185         if (m_value) {
186             ASSERT(m_value.isNumber());
187             if (m_value.isInt32())
188                 m_value = jsDoubleNumber(m_value.asNumber());
189         }
190         if (m_type & SpecAnyInt) {
191             m_type &= ~SpecAnyInt;
192             m_type |= SpecAnyIntAsDouble;
193         }
194         if (m_type & ~SpecFullDouble)
195             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n").data());
196     } else if (representation == NodeResultInt52) {
197         if (m_type & SpecAnyIntAsDouble) {
198             m_type &= ~SpecAnyIntAsDouble;
199             m_type |= SpecInt52Only;
200         }
201         if (m_type & ~SpecAnyInt)
202             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for int52 node has type outside SpecAnyInt.\n").data());
203     } else {
204         if (m_type & SpecInt52Only) {
205             m_type &= ~SpecInt52Only;
206             m_type |= SpecAnyIntAsDouble;
207         }
208         if (m_type & ~SpecBytecodeTop)
209             DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n").data());
210     }
211     
212     checkConsistency();
213 }
214
215 void AbstractValue::fixTypeForRepresentation(Graph& graph, Node* node)
216 {
217     fixTypeForRepresentation(graph, node->result(), node);
218 }
219
220 bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value)
221 {
222     AbstractValue oldMe = *this;
223     
224     if (isClear()) {
225         FrozenValue* frozenValue = graph.freeze(value);
226         if (frozenValue->pointsToHeap()) {
227             m_structure = graph.registerStructure(frozenValue->structure());
228             m_arrayModes = asArrayModes(frozenValue->structure()->indexingType());
229         } else {
230             m_structure.clear();
231             m_arrayModes = 0;
232         }
233         
234         m_type = speculationFromValue(value);
235         m_value = value;
236     } else {
237         mergeSpeculation(m_type, speculationFromValue(value));
238         if (!!value && value.isCell()) {
239             RegisteredStructure structure = graph.registerStructure(value.asCell()->structure());
240             mergeArrayModes(m_arrayModes, asArrayModes(structure->indexingType()));
241             m_structure.merge(RegisteredStructureSet(structure));
242         }
243         if (m_value != value)
244             m_value = JSValue();
245     }
246     
247     checkConsistency();
248     assertIsRegistered(graph);
249     
250     return oldMe != *this;
251 }
252
253 bool AbstractValue::isType(Graph& graph, const InferredType::Descriptor& inferredType) const
254 {
255     AbstractValue typeValue;
256     typeValue.set(graph, inferredType);
257
258     AbstractValue mergedValue = *this;
259     mergedValue.merge(typeValue);
260
261     return mergedValue == typeValue;
262 }
263
264 FiltrationResult AbstractValue::filter(
265     Graph& graph, const RegisteredStructureSet& other, SpeculatedType admittedTypes)
266 {
267     ASSERT(!(admittedTypes & SpecCell));
268     
269     if (isClear())
270         return FiltrationOK;
271     
272     // FIXME: This could be optimized for the common case of m_type not
273     // having structures, array modes, or a specific value.
274     // https://bugs.webkit.org/show_bug.cgi?id=109663
275     
276     m_type &= other.speculationFromStructures() | admittedTypes;
277     m_arrayModes &= other.arrayModesFromStructures();
278     m_structure.filter(other);
279     
280     // It's possible that prior to the above two statements we had (Foo, TOP), where
281     // Foo is a SpeculatedType that is disjoint with the passed RegisteredStructureSet. In that
282     // case, we will now have (None, [someStructure]). In general, we need to make
283     // sure that new information gleaned from the SpeculatedType needs to be fed back
284     // into the information gleaned from the RegisteredStructureSet.
285     m_structure.filter(m_type);
286     
287     filterArrayModesByType();
288     filterValueByType();
289     return normalizeClarity(graph);
290 }
291
292 FiltrationResult AbstractValue::changeStructure(Graph& graph, const RegisteredStructureSet& other)
293 {
294     m_type &= other.speculationFromStructures();
295     m_arrayModes = other.arrayModesFromStructures();
296     m_structure = other;
297     
298     filterValueByType();
299     
300     return normalizeClarity(graph);
301 }
302
303 FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
304 {
305     ASSERT(arrayModes);
306     
307     if (isClear())
308         return FiltrationOK;
309     
310     m_type &= SpecCell;
311     m_arrayModes &= arrayModes;
312     return normalizeClarity();
313 }
314
315 FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
316 {
317     // FIXME: AI should track ClassInfo to leverage hierarchical class information.
318     // https://bugs.webkit.org/show_bug.cgi?id=162989
319     if (isClear())
320         return FiltrationOK;
321
322     m_type &= speculationFromClassInfo(classInfo);
323     m_structure.filterClassInfo(classInfo);
324
325     m_structure.filter(m_type);
326
327     filterArrayModesByType();
328     filterValueByType();
329     return normalizeClarity(graph);
330 }
331
332 FiltrationResult AbstractValue::filter(SpeculatedType type)
333 {
334     if ((m_type & type) == m_type)
335         return FiltrationOK;
336     
337     // Fast path for the case that we don't even have a cell.
338     if (!(m_type & SpecCell)) {
339         m_type &= type;
340         FiltrationResult result;
341         if (m_type == SpecNone) {
342             clear();
343             result = Contradiction;
344         } else
345             result = FiltrationOK;
346         checkConsistency();
347         return result;
348     }
349     
350     m_type &= type;
351     
352     // It's possible that prior to this filter() call we had, say, (Final, TOP), and
353     // the passed type is Array. At this point we'll have (None, TOP). The best way
354     // to ensure that the structure filtering does the right thing is to filter on
355     // the new type (None) rather than the one passed (Array).
356     m_structure.filter(m_type);
357     filterArrayModesByType();
358     filterValueByType();
359     return normalizeClarity();
360 }
361
362 FiltrationResult AbstractValue::filterByValue(const FrozenValue& value)
363 {
364     FiltrationResult result = filter(speculationFromValue(value.value()));
365     if (m_type)
366         m_value = value.value();
367     return result;
368 }
369
370 bool AbstractValue::contains(RegisteredStructure structure) const
371 {
372     return couldBeType(speculationFromStructure(structure.get()))
373         && (m_arrayModes & arrayModeFromStructure(structure.get()))
374         && m_structure.contains(structure);
375 }
376
377 FiltrationResult AbstractValue::filter(const AbstractValue& other)
378 {
379     m_type &= other.m_type;
380     m_structure.filter(other.m_structure);
381     m_arrayModes &= other.m_arrayModes;
382
383     m_structure.filter(m_type);
384     filterArrayModesByType();
385     filterValueByType();
386     
387     if (normalizeClarity() == Contradiction)
388         return Contradiction;
389     
390     if (m_value == other.m_value)
391         return FiltrationOK;
392     
393     // Neither of us are BOTTOM, so an empty value means TOP.
394     if (!m_value) {
395         // We previously didn't prove a value but now we have done so.
396         m_value = other.m_value; 
397         return FiltrationOK;
398     }
399     
400     if (!other.m_value) {
401         // We had proved a value but the other guy hadn't, so keep our proof.
402         return FiltrationOK;
403     }
404     
405     // We both proved there to be a specific value but they are different.
406     clear();
407     return Contradiction;
408 }
409
410 FiltrationResult AbstractValue::filter(Graph& graph, const InferredType::Descriptor& descriptor)
411 {
412     AbstractValue filterValue;
413     filterValue.set(graph, descriptor);
414     return filter(filterValue);
415 }
416
417 void AbstractValue::filterValueByType()
418 {
419     // We could go further, and ensure that if the futurePossibleStructure contravenes
420     // the value, then we could clear both of those things. But that's unlikely to help
421     // in any realistic scenario, so we don't do it. Simpler is better.
422
423     if (!!m_type) {
424         // The type is still non-empty. It may be that the new type renders
425         // the value empty because it contravenes the constant value we had.
426         if (m_value && !validateType(m_value))
427             clear();
428         return;
429     }
430     
431     // The type has been rendered empty. That means that the value must now be invalid,
432     // as well.
433     ASSERT(!m_value || !validateType(m_value));
434     m_value = JSValue();
435 }
436
437 void AbstractValue::filterArrayModesByType()
438 {
439     if (!(m_type & SpecCell))
440         m_arrayModes = 0;
441     else if (!(m_type & ~SpecArray))
442         m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
443     
444     // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
445     // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
446     // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
447     // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
448     // type system they are arrays (since they expose the magical length
449     // property and are otherwise allocated using array allocation). Hence the
450     // following would be wrong:
451     //
452     // if (!(m_type & SpecArray))
453     //    m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
454 }
455
456 bool AbstractValue::shouldBeClear() const
457 {
458     if (m_type == SpecNone)
459         return true;
460     
461     if (!(m_type & ~SpecCell)
462         && (!m_arrayModes || m_structure.isClear()))
463         return true;
464     
465     return false;
466 }
467
468 FiltrationResult AbstractValue::normalizeClarity()
469 {
470     // It's useful to be able to quickly check if an abstract value is clear.
471     // This normalizes everything to make that easy.
472     
473     FiltrationResult result;
474     
475     if (shouldBeClear()) {
476         clear();
477         result = Contradiction;
478     } else
479         result = FiltrationOK;
480
481     checkConsistency();
482     
483     return result;
484 }
485
486 FiltrationResult AbstractValue::normalizeClarity(Graph& graph)
487 {
488     FiltrationResult result = normalizeClarity();
489     assertIsRegistered(graph);
490     return result;
491 }
492
493 #if !ASSERT_DISABLED
494 void AbstractValue::checkConsistency() const
495 {
496     if (!(m_type & SpecCell)) {
497         ASSERT(m_structure.isClear());
498         ASSERT(!m_arrayModes);
499     }
500     
501     if (isClear())
502         ASSERT(!m_value);
503     
504     if (!!m_value) {
505         SpeculatedType type = m_type;
506         // This relaxes the assertion below a bit, since we don't know the representation of the
507         // node.
508         if (type & SpecInt52Only)
509             type |= SpecAnyIntAsDouble;
510         ASSERT(mergeSpeculations(type, speculationFromValue(m_value)) == type);
511     }
512     
513     // Note that it's possible for a prediction like (Final, []). This really means that
514     // the value is bottom and that any code that uses the value is unreachable. But
515     // we don't want to get pedantic about this as it would only increase the computational
516     // complexity of the code.
517 }
518
519 void AbstractValue::assertIsRegistered(Graph& graph) const
520 {
521     m_structure.assertIsRegistered(graph);
522 }
523 #endif
524
525 ResultType AbstractValue::resultType() const
526 {
527     ASSERT(isType(SpecBytecodeTop));
528     if (isType(SpecBoolean))
529         return ResultType::booleanType();
530     if (isType(SpecInt32Only))
531         return ResultType::numberTypeIsInt32();
532     if (isType(SpecBytecodeNumber))
533         return ResultType::numberType();
534     if (isType(SpecString))
535         return ResultType::stringType();
536     if (isType(SpecString | SpecBytecodeNumber))
537         return ResultType::stringOrNumberType();
538     return ResultType::unknownType();
539 }
540
541 void AbstractValue::dump(PrintStream& out) const
542 {
543     dumpInContext(out, 0);
544 }
545
546 void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
547 {
548     out.print("(", SpeculationDump(m_type));
549     if (m_type & SpecCell) {
550         out.print(
551             ", ", ArrayModesDump(m_arrayModes), ", ",
552             inContext(m_structure, context));
553     }
554     if (!!m_value)
555         out.print(", ", inContext(m_value, context));
556     out.print(")");
557 }
558
559 void AbstractValue::validateReferences(const TrackedReferences& trackedReferences)
560 {
561     trackedReferences.check(m_value);
562     m_structure.validateReferences(trackedReferences);
563 }
564
565 #if USE(JSVALUE64) && !defined(NDEBUG)
566 void AbstractValue::ensureCanInitializeWithZeros()
567 {
568     std::aligned_storage<sizeof(AbstractValue), alignof(AbstractValue)>::type zeroFilledStorage;
569     memset(static_cast<void*>(&zeroFilledStorage), 0, sizeof(AbstractValue));
570     ASSERT(*this == *static_cast<AbstractValue*>(static_cast<void*>(&zeroFilledStorage)));
571 }
572 #endif
573
574 } } // namespace JSC::DFG
575
576 #endif // ENABLE(DFG_JIT)
577