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
35namespace JSC { namespace DFG {
36
37void 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
51void 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
80void AbstractValue::set(Graph& graph, Structure* structure)
81{
82 set(graph, graph.registerStructure(structure));
83}
84
85void 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
98void 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
109void 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
129void 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
178void AbstractValue::fixTypeForRepresentation(Graph& graph, Node* node)
179{
180 fixTypeForRepresentation(graph, node->result(), node);
181}
182
183bool 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
230FiltrationResult 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
258FiltrationResult 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
269FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
270{
271 ASSERT(arrayModes);
272
273 if (isClear())
274 return FiltrationOK;
275
276 m_type &= SpecCell;
277 m_arrayModes &= arrayModes;
278 return normalizeClarity();
279}
280
281FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
282{
283 // FIXME: AI should track ClassInfo to leverage hierarchical class information.
284 // https://bugs.webkit.org/show_bug.cgi?id=162989
285 if (isClear())
286 return FiltrationOK;
287
288 m_type &= speculationFromClassInfo(classInfo);
289 m_structure.filterClassInfo(classInfo);
290
291 m_structure.filter(m_type);
292
293 filterArrayModesByType();
294 filterValueByType();
295 return normalizeClarity(graph);
296}
297
298FiltrationResult AbstractValue::filterSlow(SpeculatedType type)
299{
300 m_type &= type;
301
302 // It's possible that prior to this filter() call we had, say, (Final, TOP), and
303 // the passed type is Array. At this point we'll have (None, TOP). The best way
304 // to ensure that the structure filtering does the right thing is to filter on
305 // the new type (None) rather than the one passed (Array).
306 m_structure.filter(m_type);
307 filterArrayModesByType();
308 filterValueByType();
309 return normalizeClarity();
310}
311
312FiltrationResult AbstractValue::fastForwardToAndFilterSlow(AbstractValueClobberEpoch newEpoch, SpeculatedType type)
313{
314 if (newEpoch != m_effectEpoch)
315 fastForwardToSlow(newEpoch);
316
317 return filterSlow(type);
318}
319
320FiltrationResult AbstractValue::filterByValue(const FrozenValue& value)
321{
322 FiltrationResult result = filter(speculationFromValue(value.value()));
323 if (m_type)
324 m_value = value.value();
325 return result;
326}
327
328bool AbstractValue::contains(RegisteredStructure structure) const
329{
330 return couldBeType(speculationFromStructure(structure.get()))
331 && (m_arrayModes & arrayModesFromStructure(structure.get()))
332 && m_structure.contains(structure);
333}
334
335FiltrationResult AbstractValue::filter(const AbstractValue& other)
336{
337 m_type &= other.m_type;
338 m_structure.filter(other.m_structure);
339 m_arrayModes &= other.m_arrayModes;
340
341 m_structure.filter(m_type);
342 filterArrayModesByType();
343 filterValueByType();
344
345 if (normalizeClarity() == Contradiction)
346 return Contradiction;
347
348 if (m_value == other.m_value)
349 return FiltrationOK;
350
351 // Neither of us are BOTTOM, so an empty value means TOP.
352 if (!m_value) {
353 // We previously didn't prove a value but now we have done so.
354 m_value = other.m_value;
355 return FiltrationOK;
356 }
357
358 if (!other.m_value) {
359 // We had proved a value but the other guy hadn't, so keep our proof.
360 return FiltrationOK;
361 }
362
363 // We both proved there to be a specific value but they are different.
364 clear();
365 return Contradiction;
366}
367
368void AbstractValue::filterValueByType()
369{
370 // We could go further, and ensure that if the futurePossibleStructure contravenes
371 // the value, then we could clear both of those things. But that's unlikely to help
372 // in any realistic scenario, so we don't do it. Simpler is better.
373
374 if (!m_value)
375 return;
376
377 if (validateTypeAcceptingBoxedInt52(m_value))
378 return;
379
380 // We assume that the constant value can produce a narrower type at
381 // some point. For example, rope JSString produces SpecString, but
382 // it produces SpecStringIdent once it is resolved to AtomStringImpl.
383 // We do not make this AbstractValue cleared, but clear the constant
384 // value if validation fails currently.
385 m_value = JSValue();
386}
387
388void AbstractValue::filterArrayModesByType()
389{
390 if (!(m_type & SpecCell))
391 m_arrayModes = 0;
392 else if (!(m_type & ~SpecArray))
393 m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
394
395 // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
396 // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
397 // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
398 // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
399 // type system they are arrays (since they expose the magical length
400 // property and are otherwise allocated using array allocation). Hence the
401 // following would be wrong:
402 //
403 // if (!(m_type & SpecArray))
404 // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
405}
406
407bool AbstractValue::shouldBeClear() const
408{
409 if (m_type == SpecNone)
410 return true;
411
412 if (!(m_type & ~SpecCell)
413 && (!m_arrayModes || m_structure.isClear()))
414 return true;
415
416 return false;
417}
418
419FiltrationResult AbstractValue::normalizeClarity()
420{
421 // It's useful to be able to quickly check if an abstract value is clear.
422 // This normalizes everything to make that easy.
423
424 FiltrationResult result;
425
426 if (shouldBeClear()) {
427 clear();
428 result = Contradiction;
429 } else
430 result = FiltrationOK;
431
432 checkConsistency();
433
434 return result;
435}
436
437FiltrationResult AbstractValue::normalizeClarity(Graph& graph)
438{
439 FiltrationResult result = normalizeClarity();
440 assertIsRegistered(graph);
441 return result;
442}
443
444#if !ASSERT_DISABLED
445void AbstractValue::checkConsistency() const
446{
447 if (!(m_type & SpecCell)) {
448 RELEASE_ASSERT(m_structure.isClear());
449 RELEASE_ASSERT(!m_arrayModes);
450 }
451
452 if (isClear())
453 RELEASE_ASSERT(!m_value);
454
455 if (!!m_value)
456 RELEASE_ASSERT(validateTypeAcceptingBoxedInt52(m_value));
457
458 // Note that it's possible for a prediction like (Final, []). This really means that
459 // the value is bottom and that any code that uses the value is unreachable. But
460 // we don't want to get pedantic about this as it would only increase the computational
461 // complexity of the code.
462}
463
464void AbstractValue::assertIsRegistered(Graph& graph) const
465{
466 m_structure.assertIsRegistered(graph);
467}
468#endif // !ASSERT_DISABLED
469
470ResultType AbstractValue::resultType() const
471{
472 ASSERT(isType(SpecBytecodeTop));
473 if (isType(SpecBoolean))
474 return ResultType::booleanType();
475 if (isType(SpecInt32Only))
476 return ResultType::numberTypeIsInt32();
477 if (isType(SpecBytecodeNumber))
478 return ResultType::numberType();
479 if (isType(SpecString))
480 return ResultType::stringType();
481 if (isType(SpecString | SpecBytecodeNumber))
482 return ResultType::stringOrNumberType();
483 return ResultType::unknownType();
484}
485
486void AbstractValue::dump(PrintStream& out) const
487{
488 dumpInContext(out, 0);
489}
490
491void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const
492{
493 out.print("(", SpeculationDump(m_type));
494 if (m_type & SpecCell) {
495 out.print(
496 ", ", ArrayModesDump(m_arrayModes), ", ",
497 inContext(m_structure, context));
498 }
499 if (!!m_value)
500 out.print(", ", inContext(m_value, context));
501 out.print(", ", m_effectEpoch);
502 out.print(")");
503}
504
505void AbstractValue::validateReferences(const TrackedReferences& trackedReferences)
506{
507 trackedReferences.check(m_value);
508 m_structure.validateReferences(trackedReferences);
509}
510
511#if USE(JSVALUE64) && !defined(NDEBUG)
512void AbstractValue::ensureCanInitializeWithZeros()
513{
514 std::aligned_storage<sizeof(AbstractValue), alignof(AbstractValue)>::type zeroFilledStorage;
515 memset(static_cast<void*>(&zeroFilledStorage), 0, sizeof(AbstractValue));
516 ASSERT(*this == *static_cast<AbstractValue*>(static_cast<void*>(&zeroFilledStorage)));
517}
518#endif
519
520void AbstractValue::fastForwardToSlow(AbstractValueClobberEpoch newEpoch)
521{
522 ASSERT(newEpoch != m_effectEpoch);
523
524 if (newEpoch.clobberEpoch() != m_effectEpoch.clobberEpoch())
525 clobberStructures();
526 if (newEpoch.structureClobberState() == StructuresAreWatched)
527 m_structure.observeInvalidationPoint();
528
529 m_effectEpoch = newEpoch;
530
531 checkConsistency();
532}
533
534} } // namespace JSC::DFG
535
536#endif // ENABLE(DFG_JIT)
537
538