1 | /* |
2 | * Copyright (C) 2011-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 | * |
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 "JSBigInt.h" |
35 | #include "JSBoundFunction.h" |
36 | #include "JSCInlines.h" |
37 | #include "JSFunction.h" |
38 | #include "JSMap.h" |
39 | #include "JSSet.h" |
40 | #include "JSWeakMap.h" |
41 | #include "JSWeakSet.h" |
42 | #include "ProxyObject.h" |
43 | #include "RegExpObject.h" |
44 | #include "ScopedArguments.h" |
45 | #include "StringObject.h" |
46 | #include "ValueProfile.h" |
47 | #include <wtf/CommaPrinter.h> |
48 | #include <wtf/StringPrintStream.h> |
49 | |
50 | namespace JSC { |
51 | |
52 | struct PrettyPrinter { |
53 | PrettyPrinter(PrintStream& out) |
54 | : out(out) |
55 | , separator("|" ) |
56 | { } |
57 | |
58 | template<typename T> |
59 | void print(const T& value) |
60 | { |
61 | out.print(separator, value); |
62 | } |
63 | |
64 | PrintStream& out; |
65 | CommaPrinter separator; |
66 | }; |
67 | |
68 | void dumpSpeculation(PrintStream& outStream, SpeculatedType value) |
69 | { |
70 | StringPrintStream strStream; |
71 | PrettyPrinter out(outStream); |
72 | PrettyPrinter strOut(strStream); |
73 | |
74 | if (value == SpecNone) { |
75 | out.print("None" ); |
76 | return; |
77 | } |
78 | |
79 | bool isTop = true; |
80 | |
81 | if ((value & SpecCell) == SpecCell) |
82 | strOut.print("Cell" ); |
83 | else { |
84 | if ((value & SpecObject) == SpecObject) |
85 | strOut.print("Object" ); |
86 | else { |
87 | if (value & SpecCellOther) |
88 | strOut.print("OtherCell" ); |
89 | else |
90 | isTop = false; |
91 | |
92 | if (value & SpecObjectOther) |
93 | strOut.print("OtherObj" ); |
94 | else |
95 | isTop = false; |
96 | |
97 | if (value & SpecFinalObject) |
98 | strOut.print("Final" ); |
99 | else |
100 | isTop = false; |
101 | |
102 | if (value & SpecArray) |
103 | strOut.print("Array" ); |
104 | else |
105 | isTop = false; |
106 | |
107 | if (value & SpecInt8Array) |
108 | strOut.print("Int8Array" ); |
109 | else |
110 | isTop = false; |
111 | |
112 | if (value & SpecInt16Array) |
113 | strOut.print("Int16Array" ); |
114 | else |
115 | isTop = false; |
116 | |
117 | if (value & SpecInt32Array) |
118 | strOut.print("Int32Array" ); |
119 | else |
120 | isTop = false; |
121 | |
122 | if (value & SpecUint8Array) |
123 | strOut.print("Uint8Array" ); |
124 | else |
125 | isTop = false; |
126 | |
127 | if (value & SpecUint8ClampedArray) |
128 | strOut.print("Uint8ClampedArray" ); |
129 | else |
130 | isTop = false; |
131 | |
132 | if (value & SpecUint16Array) |
133 | strOut.print("Uint16Array" ); |
134 | else |
135 | isTop = false; |
136 | |
137 | if (value & SpecUint32Array) |
138 | strOut.print("Uint32Array" ); |
139 | else |
140 | isTop = false; |
141 | |
142 | if (value & SpecFloat32Array) |
143 | strOut.print("Float32array" ); |
144 | else |
145 | isTop = false; |
146 | |
147 | if (value & SpecFloat64Array) |
148 | strOut.print("Float64Array" ); |
149 | else |
150 | isTop = false; |
151 | |
152 | if (value & SpecFunction) |
153 | strOut.print("Function" ); |
154 | else |
155 | isTop = false; |
156 | |
157 | if (value & SpecDirectArguments) |
158 | strOut.print("DirectArguments" ); |
159 | else |
160 | isTop = false; |
161 | |
162 | if (value & SpecScopedArguments) |
163 | strOut.print("ScopedArguments" ); |
164 | else |
165 | isTop = false; |
166 | |
167 | if (value & SpecStringObject) |
168 | strOut.print("StringObject" ); |
169 | else |
170 | isTop = false; |
171 | |
172 | if (value & SpecRegExpObject) |
173 | strOut.print("RegExpObject" ); |
174 | else |
175 | isTop = false; |
176 | |
177 | if (value & SpecMapObject) |
178 | strOut.print("MapObject" ); |
179 | else |
180 | isTop = false; |
181 | |
182 | if (value & SpecSetObject) |
183 | strOut.print("SetObject" ); |
184 | else |
185 | isTop = false; |
186 | |
187 | if (value & SpecWeakMapObject) |
188 | strOut.print("WeakMapObject" ); |
189 | else |
190 | isTop = false; |
191 | |
192 | if (value & SpecWeakSetObject) |
193 | strOut.print("WeakSetObject" ); |
194 | else |
195 | isTop = false; |
196 | |
197 | if (value & SpecProxyObject) |
198 | strOut.print("ProxyObject" ); |
199 | else |
200 | isTop = false; |
201 | |
202 | if (value & SpecDerivedArray) |
203 | strOut.print("DerivedArray" ); |
204 | else |
205 | isTop = false; |
206 | |
207 | if (value & SpecDataViewObject) |
208 | strOut.print("DataView" ); |
209 | else |
210 | isTop = false; |
211 | } |
212 | |
213 | if ((value & SpecString) == SpecString) |
214 | strOut.print("String" ); |
215 | else { |
216 | if (value & SpecStringIdent) |
217 | strOut.print("StringIdent" ); |
218 | else |
219 | isTop = false; |
220 | |
221 | if (value & SpecStringVar) |
222 | strOut.print("StringVar" ); |
223 | else |
224 | isTop = false; |
225 | } |
226 | |
227 | if (value & SpecSymbol) |
228 | strOut.print("Symbol" ); |
229 | else |
230 | isTop = false; |
231 | |
232 | if (value & SpecBigInt) |
233 | strOut.print("BigInt" ); |
234 | else |
235 | isTop = false; |
236 | } |
237 | |
238 | if (value == SpecInt32Only) |
239 | strOut.print("Int32" ); |
240 | else { |
241 | if (value & SpecBoolInt32) |
242 | strOut.print("BoolInt32" ); |
243 | else |
244 | isTop = false; |
245 | |
246 | if (value & SpecNonBoolInt32) |
247 | strOut.print("NonBoolInt32" ); |
248 | else |
249 | isTop = false; |
250 | } |
251 | |
252 | if ((value & SpecBytecodeDouble) == SpecBytecodeDouble) |
253 | strOut.print("BytecodeDouble" ); |
254 | else { |
255 | if (value & SpecAnyIntAsDouble) |
256 | strOut.print("AnyIntAsDouble" ); |
257 | else |
258 | isTop = false; |
259 | |
260 | if (value & SpecNonIntAsDouble) |
261 | strOut.print("NonIntAsDouble" ); |
262 | else |
263 | isTop = false; |
264 | |
265 | if (value & SpecDoublePureNaN) |
266 | strOut.print("DoublePureNan" ); |
267 | else |
268 | isTop = false; |
269 | } |
270 | |
271 | if (value & SpecDoubleImpureNaN) |
272 | out.print("DoubleImpureNan" ); |
273 | |
274 | if (value & SpecBoolean) |
275 | strOut.print("Bool" ); |
276 | else |
277 | isTop = false; |
278 | |
279 | if (value & SpecOther) |
280 | strOut.print("Other" ); |
281 | else |
282 | isTop = false; |
283 | |
284 | if (value & SpecEmpty) |
285 | strOut.print("Empty" ); |
286 | else |
287 | isTop = false; |
288 | |
289 | if (value & SpecInt52Any) { |
290 | if ((value & SpecInt52Any) == SpecInt52Any) |
291 | strOut.print("Int52Any" ); |
292 | else if (value & SpecInt32AsInt52) |
293 | strOut.print("Int32AsInt52" ); |
294 | else if (value & SpecNonInt32AsInt52) |
295 | strOut.print("NonInt32AsInt52" ); |
296 | } else |
297 | isTop = false; |
298 | |
299 | if (value == SpecBytecodeTop) |
300 | out.print("BytecodeTop" ); |
301 | else if (value == SpecHeapTop) |
302 | out.print("HeapTop" ); |
303 | else if (value == SpecFullTop) |
304 | out.print("FullTop" ); |
305 | else if (isTop) |
306 | out.print("Top" ); |
307 | else |
308 | out.print(strStream.toCString()); |
309 | } |
310 | |
311 | // We don't expose this because we don't want anyone relying on the fact that this method currently |
312 | // just returns string constants. |
313 | static const char* speculationToAbbreviatedString(SpeculatedType prediction) |
314 | { |
315 | if (isFinalObjectSpeculation(prediction)) |
316 | return "<Final>" ; |
317 | if (isArraySpeculation(prediction)) |
318 | return "<Array>" ; |
319 | if (isStringIdentSpeculation(prediction)) |
320 | return "<StringIdent>" ; |
321 | if (isStringSpeculation(prediction)) |
322 | return "<String>" ; |
323 | if (isFunctionSpeculation(prediction)) |
324 | return "<Function>" ; |
325 | if (isInt8ArraySpeculation(prediction)) |
326 | return "<Int8array>" ; |
327 | if (isInt16ArraySpeculation(prediction)) |
328 | return "<Int16array>" ; |
329 | if (isInt32ArraySpeculation(prediction)) |
330 | return "<Int32array>" ; |
331 | if (isUint8ArraySpeculation(prediction)) |
332 | return "<Uint8array>" ; |
333 | if (isUint16ArraySpeculation(prediction)) |
334 | return "<Uint16array>" ; |
335 | if (isUint32ArraySpeculation(prediction)) |
336 | return "<Uint32array>" ; |
337 | if (isFloat32ArraySpeculation(prediction)) |
338 | return "<Float32array>" ; |
339 | if (isFloat64ArraySpeculation(prediction)) |
340 | return "<Float64array>" ; |
341 | if (isDirectArgumentsSpeculation(prediction)) |
342 | return "<DirectArguments>" ; |
343 | if (isScopedArgumentsSpeculation(prediction)) |
344 | return "<ScopedArguments>" ; |
345 | if (isStringObjectSpeculation(prediction)) |
346 | return "<StringObject>" ; |
347 | if (isRegExpObjectSpeculation(prediction)) |
348 | return "<RegExpObject>" ; |
349 | if (isStringOrStringObjectSpeculation(prediction)) |
350 | return "<StringOrStringObject>" ; |
351 | if (isObjectSpeculation(prediction)) |
352 | return "<Object>" ; |
353 | if (isCellSpeculation(prediction)) |
354 | return "<Cell>" ; |
355 | if (isBoolInt32Speculation(prediction)) |
356 | return "<BoolInt32>" ; |
357 | if (isInt32Speculation(prediction)) |
358 | return "<Int32>" ; |
359 | if (isAnyIntAsDoubleSpeculation(prediction)) |
360 | return "<AnyIntAsDouble>" ; |
361 | if (prediction == SpecNonInt32AsInt52) |
362 | return "<NonInt32AsInt52>" ; |
363 | if (prediction == SpecInt32AsInt52) |
364 | return "<Int32AsInt52>" ; |
365 | if (isAnyInt52Speculation(prediction)) |
366 | return "<Int52Any>" ; |
367 | if (isDoubleSpeculation(prediction)) |
368 | return "<Double>" ; |
369 | if (isFullNumberSpeculation(prediction)) |
370 | return "<Number>" ; |
371 | if (isBooleanSpeculation(prediction)) |
372 | return "<Boolean>" ; |
373 | if (isOtherSpeculation(prediction)) |
374 | return "<Other>" ; |
375 | if (isMiscSpeculation(prediction)) |
376 | return "<Misc>" ; |
377 | return "" ; |
378 | } |
379 | |
380 | void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value) |
381 | { |
382 | out.print(speculationToAbbreviatedString(value)); |
383 | } |
384 | |
385 | SpeculatedType speculationFromTypedArrayType(TypedArrayType type) |
386 | { |
387 | switch (type) { |
388 | case TypeInt8: |
389 | return SpecInt8Array; |
390 | case TypeInt16: |
391 | return SpecInt16Array; |
392 | case TypeInt32: |
393 | return SpecInt32Array; |
394 | case TypeUint8: |
395 | return SpecUint8Array; |
396 | case TypeUint8Clamped: |
397 | return SpecUint8ClampedArray; |
398 | case TypeUint16: |
399 | return SpecUint16Array; |
400 | case TypeUint32: |
401 | return SpecUint32Array; |
402 | case TypeFloat32: |
403 | return SpecFloat32Array; |
404 | case TypeFloat64: |
405 | return SpecFloat64Array; |
406 | case NotTypedArray: |
407 | case TypeDataView: |
408 | break; |
409 | } |
410 | RELEASE_ASSERT_NOT_REACHED(); |
411 | return SpecNone; |
412 | } |
413 | |
414 | SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo) |
415 | { |
416 | if (classInfo == JSString::info()) |
417 | return SpecString; |
418 | |
419 | if (classInfo == Symbol::info()) |
420 | return SpecSymbol; |
421 | |
422 | if (classInfo == JSBigInt::info()) |
423 | return SpecBigInt; |
424 | |
425 | if (classInfo == JSFinalObject::info()) |
426 | return SpecFinalObject; |
427 | |
428 | if (classInfo == JSArray::info()) |
429 | return SpecArray; |
430 | |
431 | if (classInfo == DirectArguments::info()) |
432 | return SpecDirectArguments; |
433 | |
434 | if (classInfo == ScopedArguments::info()) |
435 | return SpecScopedArguments; |
436 | |
437 | if (classInfo == StringObject::info()) |
438 | return SpecStringObject; |
439 | |
440 | if (classInfo == RegExpObject::info()) |
441 | return SpecRegExpObject; |
442 | |
443 | if (classInfo == JSMap::info()) |
444 | return SpecMapObject; |
445 | |
446 | if (classInfo == JSSet::info()) |
447 | return SpecSetObject; |
448 | |
449 | if (classInfo == JSWeakMap::info()) |
450 | return SpecWeakMapObject; |
451 | |
452 | if (classInfo == JSWeakSet::info()) |
453 | return SpecWeakSetObject; |
454 | |
455 | if (classInfo == ProxyObject::info()) |
456 | return SpecProxyObject; |
457 | |
458 | if (classInfo == JSDataView::info()) |
459 | return SpecDataViewObject; |
460 | |
461 | if (classInfo->isSubClassOf(JSFunction::info())) { |
462 | if (classInfo == JSBoundFunction::info()) |
463 | return SpecFunctionWithNonDefaultHasInstance; |
464 | return SpecFunctionWithDefaultHasInstance; |
465 | } |
466 | |
467 | if (isTypedView(classInfo->typedArrayStorageType)) |
468 | return speculationFromTypedArrayType(classInfo->typedArrayStorageType); |
469 | |
470 | if (classInfo->isSubClassOf(JSArray::info())) |
471 | return SpecDerivedArray; |
472 | |
473 | if (classInfo->isSubClassOf(JSObject::info())) |
474 | return SpecObjectOther; |
475 | |
476 | return SpecCellOther; |
477 | } |
478 | |
479 | SpeculatedType speculationFromStructure(Structure* structure) |
480 | { |
481 | if (structure->typeInfo().type() == StringType) |
482 | return SpecString; |
483 | if (structure->typeInfo().type() == SymbolType) |
484 | return SpecSymbol; |
485 | if (structure->typeInfo().type() == BigIntType) |
486 | return SpecBigInt; |
487 | if (structure->typeInfo().type() == DerivedArrayType) |
488 | return SpecDerivedArray; |
489 | return speculationFromClassInfo(structure->classInfo()); |
490 | } |
491 | |
492 | SpeculatedType speculationFromCell(JSCell* cell) |
493 | { |
494 | if (cell->isString()) { |
495 | JSString* string = jsCast<JSString*>(cell); |
496 | if (const StringImpl* impl = string->tryGetValueImpl()) { |
497 | if (impl->isAtomic()) |
498 | return SpecStringIdent; |
499 | } |
500 | return SpecString; |
501 | } |
502 | return speculationFromStructure(cell->structure()); |
503 | } |
504 | |
505 | SpeculatedType speculationFromValue(JSValue value) |
506 | { |
507 | if (value.isEmpty()) |
508 | return SpecEmpty; |
509 | if (value.isInt32()) { |
510 | if (value.asInt32() & ~1) |
511 | return SpecNonBoolInt32; |
512 | return SpecBoolInt32; |
513 | } |
514 | if (value.isDouble()) { |
515 | double number = value.asNumber(); |
516 | if (number != number) |
517 | return SpecDoublePureNaN; |
518 | if (value.isAnyInt()) |
519 | return SpecAnyIntAsDouble; |
520 | return SpecNonIntAsDouble; |
521 | } |
522 | if (value.isCell()) |
523 | return speculationFromCell(value.asCell()); |
524 | if (value.isBoolean()) |
525 | return SpecBoolean; |
526 | ASSERT(value.isUndefinedOrNull()); |
527 | return SpecOther; |
528 | } |
529 | |
530 | SpeculatedType int52AwareSpeculationFromValue(JSValue value) |
531 | { |
532 | if (!value.isAnyInt()) |
533 | return speculationFromValue(value); |
534 | |
535 | int64_t intValue = value.asAnyInt(); |
536 | bool isI32 = static_cast<int64_t>(static_cast<int32_t>(intValue)) == intValue; |
537 | if (isI32) |
538 | return SpecInt32AsInt52; |
539 | return SpecNonInt32AsInt52; |
540 | } |
541 | |
542 | TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType type) |
543 | { |
544 | if (isInt8ArraySpeculation(type)) |
545 | return TypeInt8; |
546 | |
547 | if (isInt16ArraySpeculation(type)) |
548 | return TypeInt16; |
549 | |
550 | if (isInt32ArraySpeculation(type)) |
551 | return TypeInt32; |
552 | |
553 | if (isUint8ArraySpeculation(type)) |
554 | return TypeUint8; |
555 | |
556 | if (isUint8ClampedArraySpeculation(type)) |
557 | return TypeUint8Clamped; |
558 | |
559 | if (isUint16ArraySpeculation(type)) |
560 | return TypeUint16; |
561 | |
562 | if (isUint32ArraySpeculation(type)) |
563 | return TypeUint32; |
564 | |
565 | if (isFloat32ArraySpeculation(type)) |
566 | return TypeFloat32; |
567 | |
568 | if (isFloat64ArraySpeculation(type)) |
569 | return TypeFloat64; |
570 | |
571 | return NotTypedArray; |
572 | } |
573 | |
574 | SpeculatedType speculationFromJSType(JSType type) |
575 | { |
576 | switch (type) { |
577 | case StringType: |
578 | return SpecString; |
579 | case SymbolType: |
580 | return SpecSymbol; |
581 | case BigIntType: |
582 | return SpecBigInt; |
583 | case ArrayType: |
584 | return SpecArray; |
585 | case DerivedArrayType: |
586 | return SpecDerivedArray; |
587 | case RegExpObjectType: |
588 | return SpecRegExpObject; |
589 | case ProxyObjectType: |
590 | return SpecProxyObject; |
591 | case JSMapType: |
592 | return SpecMapObject; |
593 | case JSSetType: |
594 | return SpecSetObject; |
595 | case JSWeakMapType: |
596 | return SpecWeakMapObject; |
597 | case JSWeakSetType: |
598 | return SpecWeakSetObject; |
599 | case DataViewType: |
600 | return SpecDataViewObject; |
601 | default: |
602 | ASSERT_NOT_REACHED(); |
603 | } |
604 | return SpecNone; |
605 | } |
606 | |
607 | SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type) |
608 | { |
609 | // SpecNonIntAsDouble includes negative zero (-0.0), which can be equal to 0 and 0.0 in the context of == and ===. |
610 | if (type & (SpecIntAnyFormat | SpecNonIntAsDouble)) |
611 | type |= (SpecIntAnyFormat | SpecNonIntAsDouble); |
612 | |
613 | if (type & SpecString) |
614 | type |= SpecString; |
615 | return type; |
616 | } |
617 | |
618 | bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b) |
619 | { |
620 | a = leastUpperBoundOfStrictlyEquivalentSpeculations(a); |
621 | b = leastUpperBoundOfStrictlyEquivalentSpeculations(b); |
622 | |
623 | // Anything could be equal to a string. |
624 | if (a & SpecString) |
625 | return true; |
626 | if (b & SpecString) |
627 | return true; |
628 | |
629 | // If both sides are definitely only objects, then equality is fairly sane. |
630 | if (isObjectSpeculation(a) && isObjectSpeculation(b)) |
631 | return !!(a & b); |
632 | |
633 | // If either side could be an object or not, then we could call toString or |
634 | // valueOf, which could return anything. |
635 | if (a & SpecObject) |
636 | return true; |
637 | if (b & SpecObject) |
638 | return true; |
639 | |
640 | // Neither side is an object or string, so the world is relatively sane. |
641 | return !!(a & b); |
642 | } |
643 | |
644 | static SpeculatedType typeOfDoubleSumOrDifferenceOrProduct(SpeculatedType a, SpeculatedType b) |
645 | { |
646 | SpeculatedType result = a | b; |
647 | |
648 | if (result & SpecNonIntAsDouble) { |
649 | // NaN can be produced by: |
650 | // Infinity - Infinity |
651 | // Infinity + (-Infinity) |
652 | // Infinity * 0 |
653 | result |= SpecDoublePureNaN; |
654 | } |
655 | |
656 | // Impure NaN could become pure NaN during addition because addition may clear bits. |
657 | if (result & SpecDoubleImpureNaN) |
658 | result |= SpecDoublePureNaN; |
659 | // Values could overflow, or fractions could become integers. |
660 | if (result & SpecDoubleReal) |
661 | result |= SpecDoubleReal; |
662 | return result; |
663 | } |
664 | |
665 | SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b) |
666 | { |
667 | return typeOfDoubleSumOrDifferenceOrProduct(a, b); |
668 | } |
669 | |
670 | SpeculatedType typeOfDoubleDifference(SpeculatedType a, SpeculatedType b) |
671 | { |
672 | return typeOfDoubleSumOrDifferenceOrProduct(a, b); |
673 | } |
674 | |
675 | SpeculatedType typeOfDoubleProduct(SpeculatedType a, SpeculatedType b) |
676 | { |
677 | return typeOfDoubleSumOrDifferenceOrProduct(a, b); |
678 | } |
679 | |
680 | static SpeculatedType polluteDouble(SpeculatedType value) |
681 | { |
682 | // Impure NaN could become pure NaN because the operation could clear some bits. |
683 | if (value & SpecDoubleImpureNaN) |
684 | value |= SpecDoubleNaN; |
685 | // Values could overflow, fractions could become integers, or an error could produce |
686 | // PureNaN. |
687 | if (value & SpecDoubleReal) |
688 | value |= SpecDoubleReal | SpecDoublePureNaN; |
689 | return value; |
690 | } |
691 | |
692 | SpeculatedType typeOfDoubleQuotient(SpeculatedType a, SpeculatedType b) |
693 | { |
694 | return polluteDouble(a | b); |
695 | } |
696 | |
697 | SpeculatedType typeOfDoubleMinMax(SpeculatedType a, SpeculatedType b) |
698 | { |
699 | SpeculatedType result = a | b; |
700 | // Impure NaN could become pure NaN during addition because addition may clear bits. |
701 | if (result & SpecDoubleImpureNaN) |
702 | result |= SpecDoublePureNaN; |
703 | return result; |
704 | } |
705 | |
706 | SpeculatedType typeOfDoubleNegation(SpeculatedType value) |
707 | { |
708 | // Changing bits can make pure NaN impure and vice versa: |
709 | // 0xefff000000000000 (pure) - 0xffff000000000000 (impure) |
710 | if (value & SpecDoubleNaN) |
711 | value |= SpecDoubleNaN; |
712 | // We could get negative zero, which mixes SpecAnyIntAsDouble and SpecNotIntAsDouble. |
713 | // We could also overflow a large negative int into something that is no longer |
714 | // representable as an int. |
715 | if (value & SpecDoubleReal) |
716 | value |= SpecDoubleReal; |
717 | return value; |
718 | } |
719 | |
720 | SpeculatedType typeOfDoubleAbs(SpeculatedType value) |
721 | { |
722 | return typeOfDoubleNegation(value); |
723 | } |
724 | |
725 | SpeculatedType typeOfDoubleRounding(SpeculatedType value) |
726 | { |
727 | // Double Pure NaN can becomes impure when converted back from Float. |
728 | // and vice versa. |
729 | if (value & SpecDoubleNaN) |
730 | value |= SpecDoubleNaN; |
731 | // We might lose bits, which leads to a value becoming integer-representable. |
732 | if (value & SpecNonIntAsDouble) |
733 | value |= SpecAnyIntAsDouble; |
734 | return value; |
735 | } |
736 | |
737 | SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue) |
738 | { |
739 | // Math.pow() always return NaN if the exponent is NaN, unlike std::pow(). |
740 | // We always set a pure NaN in that case. |
741 | if (yValue & SpecDoubleNaN) |
742 | xValue |= SpecDoublePureNaN; |
743 | // Handle the wierd case of NaN ^ 0, which returns 1. See https://tc39.github.io/ecma262/#sec-applying-the-exp-operator |
744 | if (xValue & SpecDoubleNaN) |
745 | xValue |= SpecFullDouble; |
746 | return polluteDouble(xValue); |
747 | } |
748 | |
749 | SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b) |
750 | { |
751 | return polluteDouble(a | b); |
752 | } |
753 | |
754 | SpeculatedType typeOfDoubleUnaryOp(SpeculatedType value) |
755 | { |
756 | return polluteDouble(value); |
757 | } |
758 | |
759 | SpeculatedType speculationFromString(const char* speculation) |
760 | { |
761 | if (!strncmp(speculation, "SpecNone" , strlen("SpecNone" ))) |
762 | return SpecNone; |
763 | if (!strncmp(speculation, "SpecFinalObject" , strlen("SpecFinalObject" ))) |
764 | return SpecFinalObject; |
765 | if (!strncmp(speculation, "SpecArray" , strlen("SpecArray" ))) |
766 | return SpecArray; |
767 | if (!strncmp(speculation, "SpecFunction" , strlen("SpecFunction" ))) |
768 | return SpecFunction; |
769 | if (!strncmp(speculation, "SpecInt8Array" , strlen("SpecInt8Array" ))) |
770 | return SpecInt8Array; |
771 | if (!strncmp(speculation, "SpecInt16Array" , strlen("SpecInt16Array" ))) |
772 | return SpecInt16Array; |
773 | if (!strncmp(speculation, "SpecInt32Array" , strlen("SpecInt32Array" ))) |
774 | return SpecInt32Array; |
775 | if (!strncmp(speculation, "SpecUint8Array" , strlen("SpecUint8Array" ))) |
776 | return SpecUint8Array; |
777 | if (!strncmp(speculation, "SpecUint8ClampedArray" , strlen("SpecUint8ClampedArray" ))) |
778 | return SpecUint8ClampedArray; |
779 | if (!strncmp(speculation, "SpecUint16Array" , strlen("SpecUint16Array" ))) |
780 | return SpecUint16Array; |
781 | if (!strncmp(speculation, "SpecUint32Array" , strlen("SpecUint32Array" ))) |
782 | return SpecUint32Array; |
783 | if (!strncmp(speculation, "SpecFloat32Array" , strlen("SpecFloat32Array" ))) |
784 | return SpecFloat32Array; |
785 | if (!strncmp(speculation, "SpecFloat64Array" , strlen("SpecFloat64Array" ))) |
786 | return SpecFloat64Array; |
787 | if (!strncmp(speculation, "SpecTypedArrayView" , strlen("SpecTypedArrayView" ))) |
788 | return SpecTypedArrayView; |
789 | if (!strncmp(speculation, "SpecDirectArguments" , strlen("SpecDirectArguments" ))) |
790 | return SpecDirectArguments; |
791 | if (!strncmp(speculation, "SpecScopedArguments" , strlen("SpecScopedArguments" ))) |
792 | return SpecScopedArguments; |
793 | if (!strncmp(speculation, "SpecStringObject" , strlen("SpecStringObject" ))) |
794 | return SpecStringObject; |
795 | if (!strncmp(speculation, "SpecRegExpObject" , strlen("SpecRegExpObject" ))) |
796 | return SpecRegExpObject; |
797 | if (!strncmp(speculation, "SpecMapObject" , strlen("SpecMapObject" ))) |
798 | return SpecMapObject; |
799 | if (!strncmp(speculation, "SpecSetObject" , strlen("SpecSetObject" ))) |
800 | return SpecSetObject; |
801 | if (!strncmp(speculation, "SpecWeakMapObject" , strlen("SpecWeakMapObject" ))) |
802 | return SpecWeakMapObject; |
803 | if (!strncmp(speculation, "SpecWeakSetObject" , strlen("SpecWeakSetObject" ))) |
804 | return SpecWeakSetObject; |
805 | if (!strncmp(speculation, "SpecProxyObject" , strlen("SpecProxyObject" ))) |
806 | return SpecProxyObject; |
807 | if (!strncmp(speculation, "SpecDerivedArray" , strlen("SpecDerivedArray" ))) |
808 | return SpecDerivedArray; |
809 | if (!strncmp(speculation, "SpecDataViewObject" , strlen("SpecDataViewObject" ))) |
810 | return SpecDataViewObject; |
811 | if (!strncmp(speculation, "SpecObjectOther" , strlen("SpecObjectOther" ))) |
812 | return SpecObjectOther; |
813 | if (!strncmp(speculation, "SpecObject" , strlen("SpecObject" ))) |
814 | return SpecObject; |
815 | if (!strncmp(speculation, "SpecStringIdent" , strlen("SpecStringIdent" ))) |
816 | return SpecStringIdent; |
817 | if (!strncmp(speculation, "SpecStringVar" , strlen("SpecStringVar" ))) |
818 | return SpecStringVar; |
819 | if (!strncmp(speculation, "SpecString" , strlen("SpecString" ))) |
820 | return SpecString; |
821 | if (!strncmp(speculation, "SpecSymbol" , strlen("SpecSymbol" ))) |
822 | return SpecSymbol; |
823 | if (!strncmp(speculation, "SpecBigInt" , strlen("SpecBigInt" ))) |
824 | return SpecBigInt; |
825 | if (!strncmp(speculation, "SpecCellOther" , strlen("SpecCellOther" ))) |
826 | return SpecCellOther; |
827 | if (!strncmp(speculation, "SpecCell" , strlen("SpecCell" ))) |
828 | return SpecCell; |
829 | if (!strncmp(speculation, "SpecBoolInt32" , strlen("SpecBoolInt32" ))) |
830 | return SpecBoolInt32; |
831 | if (!strncmp(speculation, "SpecNonBoolInt32" , strlen("SpecNonBoolInt32" ))) |
832 | return SpecNonBoolInt32; |
833 | if (!strncmp(speculation, "SpecInt32Only" , strlen("SpecInt32Only" ))) |
834 | return SpecInt32Only; |
835 | if (!strncmp(speculation, "SpecInt32AsInt52" , strlen("SpecInt32AsInt52" ))) |
836 | return SpecInt32AsInt52; |
837 | if (!strncmp(speculation, "SpecNonInt32AsInt52" , strlen("SpecNonInt32AsInt52" ))) |
838 | return SpecNonInt32AsInt52; |
839 | if (!strncmp(speculation, "SpecInt52Any" , strlen("SpecInt52Any" ))) |
840 | return SpecInt52Any; |
841 | if (!strncmp(speculation, "SpecIntAnyFormat" , strlen("SpecIntAnyFormat" ))) |
842 | return SpecIntAnyFormat; |
843 | if (!strncmp(speculation, "SpecAnyIntAsDouble" , strlen("SpecAnyIntAsDouble" ))) |
844 | return SpecAnyIntAsDouble; |
845 | if (!strncmp(speculation, "SpecNonIntAsDouble" , strlen("SpecNonIntAsDouble" ))) |
846 | return SpecNonIntAsDouble; |
847 | if (!strncmp(speculation, "SpecDoubleReal" , strlen("SpecDoubleReal" ))) |
848 | return SpecDoubleReal; |
849 | if (!strncmp(speculation, "SpecDoublePureNaN" , strlen("SpecDoublePureNaN" ))) |
850 | return SpecDoublePureNaN; |
851 | if (!strncmp(speculation, "SpecDoubleImpureNaN" , strlen("SpecDoubleImpureNaN" ))) |
852 | return SpecDoubleImpureNaN; |
853 | if (!strncmp(speculation, "SpecDoubleNaN" , strlen("SpecDoubleNaN" ))) |
854 | return SpecDoubleNaN; |
855 | if (!strncmp(speculation, "SpecBytecodeDouble" , strlen("SpecBytecodeDouble" ))) |
856 | return SpecBytecodeDouble; |
857 | if (!strncmp(speculation, "SpecFullDouble" , strlen("SpecFullDouble" ))) |
858 | return SpecFullDouble; |
859 | if (!strncmp(speculation, "SpecBytecodeRealNumber" , strlen("SpecBytecodeRealNumber" ))) |
860 | return SpecBytecodeRealNumber; |
861 | if (!strncmp(speculation, "SpecFullRealNumber" , strlen("SpecFullRealNumber" ))) |
862 | return SpecFullRealNumber; |
863 | if (!strncmp(speculation, "SpecBytecodeNumber" , strlen("SpecBytecodeNumber" ))) |
864 | return SpecBytecodeNumber; |
865 | if (!strncmp(speculation, "SpecFullNumber" , strlen("SpecFullNumber" ))) |
866 | return SpecFullNumber; |
867 | if (!strncmp(speculation, "SpecBoolean" , strlen("SpecBoolean" ))) |
868 | return SpecBoolean; |
869 | if (!strncmp(speculation, "SpecOther" , strlen("SpecOther" ))) |
870 | return SpecOther; |
871 | if (!strncmp(speculation, "SpecMisc" , strlen("SpecMisc" ))) |
872 | return SpecMisc; |
873 | if (!strncmp(speculation, "SpecHeapTop" , strlen("SpecHeapTop" ))) |
874 | return SpecHeapTop; |
875 | if (!strncmp(speculation, "SpecPrimitive" , strlen("SpecPrimitive" ))) |
876 | return SpecPrimitive; |
877 | if (!strncmp(speculation, "SpecEmpty" , strlen("SpecEmpty" ))) |
878 | return SpecEmpty; |
879 | if (!strncmp(speculation, "SpecBytecodeTop" , strlen("SpecBytecodeTop" ))) |
880 | return SpecBytecodeTop; |
881 | if (!strncmp(speculation, "SpecFullTop" , strlen("SpecFullTop" ))) |
882 | return SpecFullTop; |
883 | if (!strncmp(speculation, "SpecCellCheck" , strlen("SpecCellCheck" ))) |
884 | return SpecCellCheck; |
885 | RELEASE_ASSERT_NOT_REACHED(); |
886 | } |
887 | |
888 | } // namespace JSC |
889 | |
890 | |