Renaming SpecInt32, SpecInt52, MachineInt to SpecInt32Only, SpecInt52Only, AnyInt.
[WebKit-https.git] / Source / JavaScriptCore / bytecode / SpeculatedType.cpp
1 /*
2  * Copyright (C) 2011-2013, 2015-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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "SpeculatedType.h"
31
32 #include "DirectArguments.h"
33 #include "JSArray.h"
34 #include "JSFunction.h"
35 #include "JSCInlines.h"
36 #include "ScopedArguments.h"
37 #include "StringObject.h"
38 #include "ValueProfile.h"
39 #include <wtf/StringPrintStream.h>
40
41 namespace JSC {
42
43 void dumpSpeculation(PrintStream& out, SpeculatedType value)
44 {
45     if (value == SpecNone) {
46         out.print("None");
47         return;
48     }
49     
50     StringPrintStream myOut;
51     
52     bool isTop = true;
53     
54     if ((value & SpecCell) == SpecCell)
55         myOut.print("Cell");
56     else {
57         if ((value & SpecObject) == SpecObject)
58             myOut.print("Object");
59         else {
60             if (value & SpecCellOther)
61                 myOut.print("Othercell");
62             else
63                 isTop = false;
64     
65             if (value & SpecObjectOther)
66                 myOut.print("Otherobj");
67             else
68                 isTop = false;
69     
70             if (value & SpecFinalObject)
71                 myOut.print("Final");
72             else
73                 isTop = false;
74
75             if (value & SpecArray)
76                 myOut.print("Array");
77             else
78                 isTop = false;
79     
80             if (value & SpecInt8Array)
81                 myOut.print("Int8array");
82             else
83                 isTop = false;
84     
85             if (value & SpecInt16Array)
86                 myOut.print("Int16array");
87             else
88                 isTop = false;
89     
90             if (value & SpecInt32Array)
91                 myOut.print("Int32array");
92             else
93                 isTop = false;
94     
95             if (value & SpecUint8Array)
96                 myOut.print("Uint8array");
97             else
98                 isTop = false;
99
100             if (value & SpecUint8ClampedArray)
101                 myOut.print("Uint8clampedarray");
102             else
103                 isTop = false;
104     
105             if (value & SpecUint16Array)
106                 myOut.print("Uint16array");
107             else
108                 isTop = false;
109     
110             if (value & SpecUint32Array)
111                 myOut.print("Uint32array");
112             else
113                 isTop = false;
114     
115             if (value & SpecFloat32Array)
116                 myOut.print("Float32array");
117             else
118                 isTop = false;
119     
120             if (value & SpecFloat64Array)
121                 myOut.print("Float64array");
122             else
123                 isTop = false;
124     
125             if (value & SpecFunction)
126                 myOut.print("Function");
127             else
128                 isTop = false;
129     
130             if (value & SpecDirectArguments)
131                 myOut.print("Directarguments");
132             else
133                 isTop = false;
134     
135             if (value & SpecScopedArguments)
136                 myOut.print("Scopedarguments");
137             else
138                 isTop = false;
139     
140             if (value & SpecStringObject)
141                 myOut.print("Stringobject");
142             else
143                 isTop = false;
144     
145             if (value & SpecRegExpObject)
146                 myOut.print("Regexpobject");
147             else
148                 isTop = false;
149         }
150
151         if ((value & SpecString) == SpecString)
152             myOut.print("String");
153         else {
154             if (value & SpecStringIdent)
155                 myOut.print("Stringident");
156             else
157                 isTop = false;
158             
159             if (value & SpecStringVar)
160                 myOut.print("Stringvar");
161             else
162                 isTop = false;
163         }
164
165         if (value & SpecSymbol)
166             myOut.print("Symbol");
167         else
168             isTop = false;
169     }
170     
171     if (value == SpecInt32Only)
172         myOut.print("Int32");
173     else {
174         if (value & SpecBoolInt32)
175             myOut.print("Boolint32");
176         else
177             isTop = false;
178         
179         if (value & SpecNonBoolInt32)
180             myOut.print("Nonboolint32");
181         else
182             isTop = false;
183     }
184     
185     if (value & SpecInt52Only)
186         myOut.print("Int52");
187         
188     if ((value & SpecBytecodeDouble) == SpecBytecodeDouble)
189         myOut.print("Bytecodedouble");
190     else {
191         if (value & SpecAnyIntAsDouble)
192             myOut.print("AnyIntAsDouble");
193         else
194             isTop = false;
195         
196         if (value & SpecNonIntAsDouble)
197             myOut.print("Nonintasdouble");
198         else
199             isTop = false;
200         
201         if (value & SpecDoublePureNaN)
202             myOut.print("Doublepurenan");
203         else
204             isTop = false;
205     }
206     
207     if (value & SpecDoubleImpureNaN)
208         out.print("Doubleimpurenan");
209     
210     if (value & SpecBoolean)
211         myOut.print("Bool");
212     else
213         isTop = false;
214     
215     if (value & SpecOther)
216         myOut.print("Other");
217     else
218         isTop = false;
219     
220     if (isTop)
221         out.print("Top");
222     else
223         out.print(myOut.toCString());
224     
225     if (value & SpecEmpty)
226         out.print("Empty");
227 }
228
229 // We don't expose this because we don't want anyone relying on the fact that this method currently
230 // just returns string constants.
231 static const char* speculationToAbbreviatedString(SpeculatedType prediction)
232 {
233     if (isFinalObjectSpeculation(prediction))
234         return "<Final>";
235     if (isArraySpeculation(prediction))
236         return "<Array>";
237     if (isStringIdentSpeculation(prediction))
238         return "<StringIdent>";
239     if (isStringSpeculation(prediction))
240         return "<String>";
241     if (isFunctionSpeculation(prediction))
242         return "<Function>";
243     if (isInt8ArraySpeculation(prediction))
244         return "<Int8array>";
245     if (isInt16ArraySpeculation(prediction))
246         return "<Int16array>";
247     if (isInt32ArraySpeculation(prediction))
248         return "<Int32array>";
249     if (isUint8ArraySpeculation(prediction))
250         return "<Uint8array>";
251     if (isUint16ArraySpeculation(prediction))
252         return "<Uint16array>";
253     if (isUint32ArraySpeculation(prediction))
254         return "<Uint32array>";
255     if (isFloat32ArraySpeculation(prediction))
256         return "<Float32array>";
257     if (isFloat64ArraySpeculation(prediction))
258         return "<Float64array>";
259     if (isDirectArgumentsSpeculation(prediction))
260         return "<DirectArguments>";
261     if (isScopedArgumentsSpeculation(prediction))
262         return "<ScopedArguments>";
263     if (isStringObjectSpeculation(prediction))
264         return "<StringObject>";
265     if (isRegExpObjectSpeculation(prediction))
266         return "<RegExpObject>";
267     if (isStringOrStringObjectSpeculation(prediction))
268         return "<StringOrStringObject>";
269     if (isObjectSpeculation(prediction))
270         return "<Object>";
271     if (isCellSpeculation(prediction))
272         return "<Cell>";
273     if (isBoolInt32Speculation(prediction))
274         return "<BoolInt32>";
275     if (isInt32Speculation(prediction))
276         return "<Int32>";
277     if (isAnyIntAsDoubleSpeculation(prediction))
278         return "<AnyIntAsDouble>";
279     if (isInt52Speculation(prediction))
280         return "<Int52>";
281     if (isAnyIntSpeculation(prediction))
282         return "<AnyInt>";
283     if (isDoubleSpeculation(prediction))
284         return "<Double>";
285     if (isFullNumberSpeculation(prediction))
286         return "<Number>";
287     if (isBooleanSpeculation(prediction))
288         return "<Boolean>";
289     if (isOtherSpeculation(prediction))
290         return "<Other>";
291     if (isMiscSpeculation(prediction))
292         return "<Misc>";
293     return "";
294 }
295
296 void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value)
297 {
298     out.print(speculationToAbbreviatedString(value));
299 }
300
301 SpeculatedType speculationFromTypedArrayType(TypedArrayType type)
302 {
303     switch (type) {
304     case TypeInt8:
305         return SpecInt8Array;
306     case TypeInt16:
307         return SpecInt16Array;
308     case TypeInt32:
309         return SpecInt32Array;
310     case TypeUint8:
311         return SpecUint8Array;
312     case TypeUint8Clamped:
313         return SpecUint8ClampedArray;
314     case TypeUint16:
315         return SpecUint16Array;
316     case TypeUint32:
317         return SpecUint32Array;
318     case TypeFloat32:
319         return SpecFloat32Array;
320     case TypeFloat64:
321         return SpecFloat64Array;
322     case NotTypedArray:
323     case TypeDataView:
324         break;
325     }
326     RELEASE_ASSERT_NOT_REACHED();
327     return SpecNone;
328 }
329
330 SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
331 {
332     if (classInfo == JSFinalObject::info())
333         return SpecFinalObject;
334     
335     if (classInfo == JSArray::info())
336         return SpecArray;
337     
338     if (classInfo == DirectArguments::info())
339         return SpecDirectArguments;
340     
341     if (classInfo == ScopedArguments::info())
342         return SpecScopedArguments;
343     
344     if (classInfo == StringObject::info())
345         return SpecStringObject;
346
347     if (classInfo == RegExpObject::info())
348         return SpecRegExpObject;
349     
350     if (classInfo->isSubClassOf(JSFunction::info()))
351         return SpecFunction;
352     
353     if (isTypedView(classInfo->typedArrayStorageType))
354         return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
355     
356     if (classInfo->isSubClassOf(JSObject::info()))
357         return SpecObjectOther;
358     
359     return SpecCellOther;
360 }
361
362 SpeculatedType speculationFromStructure(Structure* structure)
363 {
364     if (structure->typeInfo().type() == StringType)
365         return SpecString;
366     if (structure->typeInfo().type() == SymbolType)
367         return SpecSymbol;
368     return speculationFromClassInfo(structure->classInfo());
369 }
370
371 SpeculatedType speculationFromCell(JSCell* cell)
372 {
373     if (JSString* string = jsDynamicCast<JSString*>(cell)) {
374         if (const StringImpl* impl = string->tryGetValueImpl()) {
375             if (impl->isAtomic())
376                 return SpecStringIdent;
377         }
378         return SpecStringVar;
379     }
380     return speculationFromStructure(cell->structure());
381 }
382
383 SpeculatedType speculationFromValue(JSValue value)
384 {
385     if (value.isEmpty())
386         return SpecEmpty;
387     if (value.isInt32()) {
388         if (value.asInt32() & ~1)
389             return SpecNonBoolInt32;
390         return SpecBoolInt32;
391     }
392     if (value.isDouble()) {
393         double number = value.asNumber();
394         if (number != number)
395             return SpecDoublePureNaN;
396         if (value.isAnyInt())
397             return SpecAnyIntAsDouble;
398         return SpecNonIntAsDouble;
399     }
400     if (value.isCell())
401         return speculationFromCell(value.asCell());
402     if (value.isBoolean())
403         return SpecBoolean;
404     ASSERT(value.isUndefinedOrNull());
405     return SpecOther;
406 }
407
408 TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType type)
409 {
410     if (isInt8ArraySpeculation(type))
411         return TypeInt8;
412         
413     if (isInt16ArraySpeculation(type))
414         return TypeInt16;
415         
416     if (isInt32ArraySpeculation(type))
417         return TypeInt32;
418         
419     if (isUint8ArraySpeculation(type))
420         return TypeUint8;
421         
422     if (isUint8ClampedArraySpeculation(type))
423         return TypeUint8Clamped;
424         
425     if (isUint16ArraySpeculation(type))
426         return TypeUint16;
427         
428     if (isUint32ArraySpeculation(type))
429         return TypeUint32;
430         
431     if (isFloat32ArraySpeculation(type))
432         return TypeFloat32;
433         
434     if (isFloat64ArraySpeculation(type))
435         return TypeFloat64;
436     
437     return NotTypedArray;
438 }
439
440 SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type)
441 {
442     if (type & (SpecAnyInt | SpecAnyIntAsDouble))
443         type |= (SpecAnyInt | SpecAnyIntAsDouble);
444     if (type & SpecString)
445         type |= SpecString;
446     return type;
447 }
448
449 bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b)
450 {
451     a = leastUpperBoundOfStrictlyEquivalentSpeculations(a);
452     b = leastUpperBoundOfStrictlyEquivalentSpeculations(b);
453     
454     // Anything could be equal to a string.
455     if (a & SpecString)
456         return true;
457     if (b & SpecString)
458         return true;
459     
460     // If both sides are definitely only objects, then equality is fairly sane.
461     if (isObjectSpeculation(a) && isObjectSpeculation(b))
462         return !!(a & b);
463     
464     // If either side could be an object or not, then we could call toString or
465     // valueOf, which could return anything.
466     if (a & SpecObject)
467         return true;
468     if (b & SpecObject)
469         return true;
470     
471     // Neither side is an object or string, so the world is relatively sane.
472     return !!(a & b);
473 }
474
475 SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
476 {
477     SpeculatedType result = a | b;
478     // Impure NaN could become pure NaN during addition because addition may clear bits.
479     if (result & SpecDoubleImpureNaN)
480         result |= SpecDoublePureNaN;
481     // Values could overflow, or fractions could become integers.
482     if (result & SpecDoubleReal)
483         result |= SpecDoubleReal;
484     return result;
485 }
486
487 SpeculatedType typeOfDoubleDifference(SpeculatedType a, SpeculatedType b)
488 {
489     return typeOfDoubleSum(a, b);
490 }
491
492 SpeculatedType typeOfDoubleProduct(SpeculatedType a, SpeculatedType b)
493 {
494     return typeOfDoubleSum(a, b);
495 }
496
497 static SpeculatedType polluteDouble(SpeculatedType value)
498 {
499     // Impure NaN could become pure NaN because the operation could clear some bits.
500     if (value & SpecDoubleImpureNaN)
501         value |= SpecDoubleNaN;
502     // Values could overflow, fractions could become integers, or an error could produce
503     // PureNaN.
504     if (value & SpecDoubleReal)
505         value |= SpecDoubleReal | SpecDoublePureNaN;
506     return value;
507 }
508
509 SpeculatedType typeOfDoubleQuotient(SpeculatedType a, SpeculatedType b)
510 {
511     return polluteDouble(a | b);
512 }
513
514 SpeculatedType typeOfDoubleMinMax(SpeculatedType a, SpeculatedType b)
515 {
516     SpeculatedType result = a | b;
517     // Impure NaN could become pure NaN during addition because addition may clear bits.
518     if (result & SpecDoubleImpureNaN)
519         result |= SpecDoublePureNaN;
520     return result;
521 }
522
523 SpeculatedType typeOfDoubleNegation(SpeculatedType value)
524 {
525     // Changing bits can make pure NaN impure and vice versa:
526     // 0xefff000000000000 (pure) - 0xffff000000000000 (impure)
527     if (value & SpecDoubleNaN)
528         value |= SpecDoubleNaN;
529     // We could get negative zero, which mixes SpecAnyIntAsDouble and SpecNotIntAsDouble.
530     // We could also overflow a large negative int into something that is no longer
531     // representable as an int.
532     if (value & SpecDoubleReal)
533         value |= SpecDoubleReal;
534     return value;
535 }
536
537 SpeculatedType typeOfDoubleAbs(SpeculatedType value)
538 {
539     return typeOfDoubleNegation(value);
540 }
541
542 SpeculatedType typeOfDoubleRounding(SpeculatedType value)
543 {
544     // Double Pure NaN can becomes impure when converted back from Float.
545     // and vice versa.
546     if (value & SpecDoubleNaN)
547         value |= SpecDoubleNaN;
548     // We might lose bits, which leads to a value becoming integer-representable.
549     if (value & SpecNonIntAsDouble)
550         value |= SpecAnyIntAsDouble;
551     return value;
552 }
553
554 SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue)
555 {
556     // Math.pow() always return NaN if the exponent is NaN, unlike std::pow().
557     // We always set a pure NaN in that case.
558     if (yValue & SpecDoubleNaN)
559         xValue |= SpecDoublePureNaN;
560     return polluteDouble(xValue);
561 }
562
563 SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b)
564 {
565     return polluteDouble(a | b);
566 }
567
568 SpeculatedType typeOfDoubleUnaryOp(SpeculatedType value)
569 {
570     return polluteDouble(value);
571 }
572
573 } // namespace JSC
574