/ bytecode / SpeculatedType.cpp
SpeculatedType.cpp
   1  /*
   2   * Copyright (C) 2011-2020 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 "DateInstance.h"
  33  #include "DirectArguments.h"
  34  #include "JSArray.h"
  35  #include "JSBigInt.h"
  36  #include "JSBoundFunction.h"
  37  #include "JSDataView.h"
  38  #include "JSFunction.h"
  39  #include "JSMap.h"
  40  #include "JSSet.h"
  41  #include "JSWeakMap.h"
  42  #include "JSWeakSet.h"
  43  #include "ProxyObject.h"
  44  #include "RegExpObject.h"
  45  #include "ScopedArguments.h"
  46  #include "StringObject.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 & SpecDateObject)
 178                  strOut.print("DateObject");
 179              else
 180                  isTop = false;
 181  
 182              if (value & SpecPromiseObject)
 183                  strOut.print("PromiseObject");
 184              else
 185                  isTop = false;
 186  
 187              if (value & SpecMapObject)
 188                  strOut.print("MapObject");
 189              else
 190                  isTop = false;
 191  
 192              if (value & SpecSetObject)
 193                  strOut.print("SetObject");
 194              else
 195                  isTop = false;
 196  
 197              if (value & SpecWeakMapObject)
 198                  strOut.print("WeakMapObject");
 199              else
 200                  isTop = false;
 201  
 202              if (value & SpecWeakSetObject)
 203                  strOut.print("WeakSetObject");
 204              else
 205                  isTop = false;
 206  
 207              if (value & SpecProxyObject)
 208                  strOut.print("ProxyObject");
 209              else
 210                  isTop = false;
 211  
 212              if (value & SpecDerivedArray)
 213                  strOut.print("DerivedArray");
 214              else
 215                  isTop = false;
 216  
 217              if (value & SpecDataViewObject)
 218                  strOut.print("DataView");
 219              else
 220                  isTop = false;
 221          }
 222  
 223          if ((value & SpecString) == SpecString)
 224              strOut.print("String");
 225          else {
 226              if (value & SpecStringIdent)
 227                  strOut.print("StringIdent");
 228              else
 229                  isTop = false;
 230              
 231              if (value & SpecStringVar)
 232                  strOut.print("StringVar");
 233              else
 234                  isTop = false;
 235          }
 236  
 237          if (value & SpecSymbol)
 238              strOut.print("Symbol");
 239          else
 240              isTop = false;
 241      }
 242      
 243      if (value == SpecInt32Only)
 244          strOut.print("Int32");
 245      else {
 246          if (value & SpecBoolInt32)
 247              strOut.print("BoolInt32");
 248          else
 249              isTop = false;
 250          
 251          if (value & SpecNonBoolInt32)
 252              strOut.print("NonBoolInt32");
 253          else
 254              isTop = false;
 255      }
 256  
 257      if ((value & SpecBytecodeDouble) == SpecBytecodeDouble)
 258          strOut.print("BytecodeDouble");
 259      else {
 260          if (value & SpecAnyIntAsDouble)
 261              strOut.print("AnyIntAsDouble");
 262          else
 263              isTop = false;
 264          
 265          if (value & SpecNonIntAsDouble)
 266              strOut.print("NonIntAsDouble");
 267          else
 268              isTop = false;
 269          
 270          if (value & SpecDoublePureNaN)
 271              strOut.print("DoublePureNaN");
 272          else
 273              isTop = false;
 274      }
 275  
 276      if ((value & SpecBigInt) == SpecBigInt)
 277          strOut.print("BigInt");
 278  #if USE(BIGINT32)
 279      else {
 280          if (value & SpecBigInt32)
 281              strOut.print("BigInt32");
 282          else
 283              isTop = false;
 284  
 285          if (value & SpecHeapBigInt)
 286              strOut.print("HeapBigInt");
 287          else
 288              isTop = false;
 289      }
 290  #endif
 291  
 292      if (value & SpecDoubleImpureNaN)
 293          strOut.print("DoubleImpureNaN");
 294      
 295      if (value & SpecBoolean)
 296          strOut.print("Bool");
 297      else
 298          isTop = false;
 299      
 300      if (value & SpecOther)
 301          strOut.print("Other");
 302      else
 303          isTop = false;
 304      
 305      if (value & SpecEmpty)
 306          strOut.print("Empty");
 307      else
 308          isTop = false;
 309  
 310      if (value & SpecInt52Any) {
 311          if ((value & SpecInt52Any) == SpecInt52Any)
 312              strOut.print("Int52Any");
 313          else if (value & SpecInt32AsInt52)
 314              strOut.print("Int32AsInt52");
 315          else if (value & SpecNonInt32AsInt52)
 316              strOut.print("NonInt32AsInt52");
 317      } else
 318          isTop = false;
 319      
 320      if (value == SpecBytecodeTop)
 321          out.print("BytecodeTop");
 322      else if (value == SpecHeapTop)
 323          out.print("HeapTop");
 324      else if (value == SpecFullTop)
 325          out.print("FullTop");
 326      else if (isTop)
 327          out.print("Top");
 328      else
 329          out.print(strStream.toCString());
 330  }
 331  
 332  // We don't expose this because we don't want anyone relying on the fact that this method currently
 333  // just returns string constants.
 334  static const char* speculationToAbbreviatedString(SpeculatedType prediction)
 335  {
 336      if (isFinalObjectSpeculation(prediction))
 337          return "<Final>";
 338      if (isArraySpeculation(prediction))
 339          return "<Array>";
 340      if (isStringIdentSpeculation(prediction))
 341          return "<StringIdent>";
 342      if (isStringSpeculation(prediction))
 343          return "<String>";
 344      if (isFunctionSpeculation(prediction))
 345          return "<Function>";
 346      if (isInt8ArraySpeculation(prediction))
 347          return "<Int8array>";
 348      if (isInt16ArraySpeculation(prediction))
 349          return "<Int16array>";
 350      if (isInt32ArraySpeculation(prediction))
 351          return "<Int32array>";
 352      if (isUint8ArraySpeculation(prediction))
 353          return "<Uint8array>";
 354      if (isUint16ArraySpeculation(prediction))
 355          return "<Uint16array>";
 356      if (isUint32ArraySpeculation(prediction))
 357          return "<Uint32array>";
 358      if (isFloat32ArraySpeculation(prediction))
 359          return "<Float32array>";
 360      if (isFloat64ArraySpeculation(prediction))
 361          return "<Float64array>";
 362      if (isDirectArgumentsSpeculation(prediction))
 363          return "<DirectArguments>";
 364      if (isScopedArgumentsSpeculation(prediction))
 365          return "<ScopedArguments>";
 366      if (isStringObjectSpeculation(prediction))
 367          return "<StringObject>";
 368      if (isRegExpObjectSpeculation(prediction))
 369          return "<RegExpObject>";
 370      if (isStringOrStringObjectSpeculation(prediction))
 371          return "<StringOrStringObject>";
 372      if (isObjectSpeculation(prediction))
 373          return "<Object>";
 374      if (isCellSpeculation(prediction))
 375          return "<Cell>";
 376      if (isBoolInt32Speculation(prediction))
 377          return "<BoolInt32>";
 378      if (isInt32Speculation(prediction))
 379          return "<Int32>";
 380      if (isAnyIntAsDoubleSpeculation(prediction))
 381          return "<AnyIntAsDouble>";
 382      if (prediction == SpecNonInt32AsInt52)
 383          return "<NonInt32AsInt52>";
 384      if (prediction == SpecInt32AsInt52)
 385          return "<Int32AsInt52>";
 386      if (isAnyInt52Speculation(prediction))
 387          return "<Int52Any>";
 388      if (isDoubleSpeculation(prediction))
 389          return "<Double>";
 390      if (isFullNumberSpeculation(prediction))
 391          return "<Number>";
 392      if (isBooleanSpeculation(prediction))
 393          return "<Boolean>";
 394      if (isOtherSpeculation(prediction))
 395          return "<Other>";
 396      if (isMiscSpeculation(prediction))
 397          return "<Misc>";
 398      return "";
 399  }
 400  
 401  void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value)
 402  {
 403      out.print(speculationToAbbreviatedString(value));
 404  }
 405  
 406  SpeculatedType speculationFromTypedArrayType(TypedArrayType type)
 407  {
 408      switch (type) {
 409      case TypeInt8:
 410          return SpecInt8Array;
 411      case TypeInt16:
 412          return SpecInt16Array;
 413      case TypeInt32:
 414          return SpecInt32Array;
 415      case TypeUint8:
 416          return SpecUint8Array;
 417      case TypeUint8Clamped:
 418          return SpecUint8ClampedArray;
 419      case TypeUint16:
 420          return SpecUint16Array;
 421      case TypeUint32:
 422          return SpecUint32Array;
 423      case TypeFloat32:
 424          return SpecFloat32Array;
 425      case TypeFloat64:
 426          return SpecFloat64Array;
 427      case NotTypedArray:
 428      case TypeDataView:
 429          break;
 430      }
 431      RELEASE_ASSERT_NOT_REACHED();
 432      return SpecNone;
 433  }
 434  
 435  SpeculatedType speculationFromClassInfoInheritance(const ClassInfo* classInfo)
 436  {
 437      if (classInfo == JSString::info())
 438          return SpecString;
 439      ASSERT_WITH_MESSAGE(!classInfo->isSubClassOf(JSString::info()), "Rope strings should still have JSString's ClassInfo");
 440  
 441      static_assert(std::is_final_v<Symbol>);
 442      if (classInfo == Symbol::info())
 443          return SpecSymbol;
 444  
 445      static_assert(std::is_final_v<JSBigInt>);
 446      if (classInfo == JSBigInt::info())
 447          return SpecHeapBigInt;
 448  
 449      static_assert(std::is_final_v<JSFinalObject>);
 450      if (classInfo == JSFinalObject::info())
 451          return SpecFinalObject;
 452      
 453      static_assert(std::is_final_v<DirectArguments>);
 454      if (classInfo == DirectArguments::info())
 455          return SpecDirectArguments;
 456      
 457      static_assert(std::is_final_v<ScopedArguments>);
 458      if (classInfo == ScopedArguments::info())
 459          return SpecScopedArguments;
 460  
 461      static_assert(std::is_final_v<RegExpObject>);
 462      if (classInfo == RegExpObject::info())
 463          return SpecRegExpObject;
 464  
 465      static_assert(std::is_final_v<DateInstance>);
 466      if (classInfo == DateInstance::info())
 467          return SpecDateObject;
 468  
 469      static_assert(std::is_final_v<JSMap>);
 470      if (classInfo == JSMap::info())
 471          return SpecMapObject;
 472  
 473      static_assert(std::is_final_v<JSSet>);
 474      if (classInfo == JSSet::info())
 475          return SpecSetObject;
 476  
 477      static_assert(std::is_final_v<JSWeakMap>);
 478      if (classInfo == JSWeakMap::info())
 479          return SpecWeakMapObject;
 480  
 481      static_assert(std::is_final_v<JSWeakSet>);
 482      if (classInfo == JSWeakSet::info())
 483          return SpecWeakSetObject;
 484  
 485      static_assert(std::is_final_v<ProxyObject>);
 486      if (classInfo == ProxyObject::info())
 487          return SpecProxyObject;
 488  
 489      static_assert(std::is_final_v<JSDataView>);
 490      if (classInfo == JSDataView::info())
 491          return SpecDataViewObject;
 492  
 493      if (classInfo->isSubClassOf(StringObject::info()))
 494          return SpecStringObject | SpecObjectOther;
 495  
 496      if (classInfo->isSubClassOf(JSArray::info()))
 497          return SpecArray | SpecDerivedArray;
 498  
 499      if (classInfo->isSubClassOf(JSFunction::info())) {
 500          if (classInfo == JSBoundFunction::info())
 501              return SpecFunctionWithNonDefaultHasInstance;
 502          return SpecFunctionWithDefaultHasInstance;
 503      }
 504  
 505      if (classInfo->isSubClassOf(JSPromise::info()))
 506          return SpecPromiseObject;
 507      
 508      if (isTypedView(classInfo->typedArrayStorageType))
 509          return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
 510      
 511      if (classInfo->isSubClassOf(JSObject::info()))
 512          return SpecObjectOther;
 513      
 514      return SpecCellOther;
 515  }
 516  
 517  SpeculatedType speculationFromStructure(Structure* structure)
 518  {
 519      SpeculatedType filteredResult = SpecNone;
 520      switch (structure->typeInfo().type()) {
 521      case StringType:
 522          filteredResult = SpecString;
 523          break;
 524      case SymbolType:
 525          filteredResult = SpecSymbol;
 526          break;
 527      case HeapBigIntType:
 528          filteredResult = SpecHeapBigInt;
 529          break;
 530      case DerivedArrayType:
 531          filteredResult = SpecDerivedArray;
 532          break;
 533      case ArrayType:
 534          filteredResult = SpecArray;
 535          break;
 536      case StringObjectType:
 537          filteredResult = SpecStringObject;
 538          break;
 539      // We do not want to accept String.prototype in StringObjectUse, so that we do not include it as SpecStringObject.
 540      case DerivedStringObjectType:
 541          filteredResult = SpecObjectOther;
 542          break;
 543      default:
 544          return speculationFromClassInfoInheritance(structure->classInfo());
 545      }
 546      ASSERT(filteredResult);
 547      ASSERT(isSubtypeSpeculation(filteredResult, speculationFromClassInfoInheritance(structure->classInfo())));
 548      return filteredResult;
 549  }
 550  
 551  ALWAYS_INLINE static bool isSanePointer(const void* pointer)
 552  {
 553      // FIXME: rdar://69036888: remove this when no longer needed.
 554  #if CPU(ADDRESS64)
 555      uintptr_t pointerAsInt = bitwise_cast<uintptr_t>(pointer);
 556      uintptr_t canonicalPointerBits = pointerAsInt << (64 - OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH));
 557      uintptr_t nonCanonicalPointerBits = pointerAsInt >> OS_CONSTANT(EFFECTIVE_ADDRESS_WIDTH);
 558      return !nonCanonicalPointerBits && canonicalPointerBits;
 559  #else
 560      UNUSED_PARAM(pointer);
 561      return true;
 562  #endif
 563  }
 564  
 565  SpeculatedType speculationFromCell(JSCell* cell)
 566  {
 567      if (UNLIKELY(!isSanePointer(cell))) {
 568          ASSERT_NOT_REACHED();
 569          return SpecNone;
 570      }
 571      if (cell->isString()) {
 572          JSString* string = jsCast<JSString*>(cell);
 573          if (const StringImpl* impl = string->tryGetValueImpl()) {
 574              if (UNLIKELY(!isSanePointer(impl))) {
 575                  ASSERT_NOT_REACHED();
 576                  return SpecNone;
 577              }
 578              if (impl->isAtom())
 579                  return SpecStringIdent;
 580          }
 581          return SpecString;
 582      }
 583      // FIXME: rdar://69036888: undo this when no longer needed.
 584      auto* structure = cell->vm().tryGetStructure(cell->structureID());
 585      if (UNLIKELY(!isSanePointer(structure))) {
 586          ASSERT_NOT_REACHED();
 587          return SpecNone;
 588      }
 589      return speculationFromStructure(structure);
 590  }
 591  
 592  SpeculatedType speculationFromValue(JSValue value)
 593  {
 594      if (value.isEmpty())
 595          return SpecEmpty;
 596      if (value.isInt32()) {
 597          if (value.asInt32() & ~1)
 598              return SpecNonBoolInt32;
 599          return SpecBoolInt32;
 600      }
 601      if (value.isDouble()) {
 602          double number = value.asNumber();
 603          if (number != number)
 604              return SpecDoublePureNaN;
 605          if (value.isAnyInt())
 606              return SpecAnyIntAsDouble;
 607          return SpecNonIntAsDouble;
 608      }
 609      if (value.isBigInt32())
 610          return SpecBigInt32;
 611      if (value.isCell())
 612          return speculationFromCell(value.asCell());
 613      if (value.isBoolean())
 614          return SpecBoolean;
 615      ASSERT(value.isUndefinedOrNull());
 616      return SpecOther;
 617  }
 618  
 619  SpeculatedType int52AwareSpeculationFromValue(JSValue value)
 620  {
 621      if (!value.isAnyInt())
 622          return speculationFromValue(value);
 623  
 624      int64_t intValue = value.asAnyInt();
 625      bool isI32 = static_cast<int64_t>(static_cast<int32_t>(intValue)) == intValue;
 626      if (isI32)
 627          return SpecInt32AsInt52;
 628      return SpecNonInt32AsInt52;
 629  }
 630  
 631  TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType type)
 632  {
 633      if (isInt8ArraySpeculation(type))
 634          return TypeInt8;
 635          
 636      if (isInt16ArraySpeculation(type))
 637          return TypeInt16;
 638          
 639      if (isInt32ArraySpeculation(type))
 640          return TypeInt32;
 641          
 642      if (isUint8ArraySpeculation(type))
 643          return TypeUint8;
 644          
 645      if (isUint8ClampedArraySpeculation(type))
 646          return TypeUint8Clamped;
 647          
 648      if (isUint16ArraySpeculation(type))
 649          return TypeUint16;
 650          
 651      if (isUint32ArraySpeculation(type))
 652          return TypeUint32;
 653          
 654      if (isFloat32ArraySpeculation(type))
 655          return TypeFloat32;
 656          
 657      if (isFloat64ArraySpeculation(type))
 658          return TypeFloat64;
 659      
 660      return NotTypedArray;
 661  }
 662  
 663  Optional<SpeculatedType> speculationFromJSType(JSType type)
 664  {
 665      switch (type) {
 666      case StringType:
 667          return SpecString;
 668      case SymbolType:
 669          return SpecSymbol;
 670      case HeapBigIntType:
 671          return SpecHeapBigInt;
 672      case ArrayType:
 673          return SpecArray;
 674      case DerivedArrayType:
 675          return SpecDerivedArray;
 676      case RegExpObjectType:
 677          return SpecRegExpObject;
 678      case JSDateType:
 679          return SpecDateObject;
 680      case ProxyObjectType:
 681          return SpecProxyObject;
 682      case JSPromiseType:
 683          return SpecPromiseObject;
 684      case JSMapType:
 685          return SpecMapObject;
 686      case JSSetType:
 687          return SpecSetObject;
 688      case JSWeakMapType:
 689          return SpecWeakMapObject;
 690      case JSWeakSetType:
 691          return SpecWeakSetObject;
 692      case DataViewType:
 693          return SpecDataViewObject;
 694      default:
 695          return WTF::nullopt;
 696      }
 697  }
 698  
 699  SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type)
 700  {
 701      // SpecNonIntAsDouble includes negative zero (-0.0), which can be equal to 0 and 0.0 in the context of == and ===.
 702      if (type & (SpecIntAnyFormat | SpecNonIntAsDouble))
 703          type |= (SpecIntAnyFormat | SpecNonIntAsDouble);
 704  
 705      if (type & SpecString)
 706          type |= SpecString;
 707  
 708      if (type & SpecBigInt)
 709          type |= SpecBigInt;
 710  
 711      return type;
 712  }
 713  
 714  static inline SpeculatedType leastUpperBoundOfEquivalentSpeculations(SpeculatedType type)
 715  {
 716      type = leastUpperBoundOfStrictlyEquivalentSpeculations(type);
 717  
 718      // Boolean or BigInt can be converted to Number when performing non-strict equal.
 719      if (type & (SpecIntAnyFormat | SpecNonIntAsDouble | SpecBoolean | SpecBigInt))
 720          type |= (SpecIntAnyFormat | SpecNonIntAsDouble | SpecBoolean | SpecBigInt);
 721  
 722      return type;
 723  }
 724  
 725  bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b)
 726  {
 727      a = leastUpperBoundOfEquivalentSpeculations(a);
 728      b = leastUpperBoundOfEquivalentSpeculations(b);
 729      
 730      // Anything could be equal to a string.
 731      if (a & SpecString)
 732          return true;
 733      if (b & SpecString)
 734          return true;
 735      
 736      // If both sides are definitely only objects, then equality is fairly sane.
 737      if (isObjectSpeculation(a) && isObjectSpeculation(b))
 738          return !!(a & b);
 739      
 740      // If either side could be an object or not, then we could call toString or
 741      // valueOf, which could return anything.
 742      if (a & SpecObject)
 743          return true;
 744      if (b & SpecObject)
 745          return true;
 746      
 747      // Neither side is an object or string, so the world is relatively sane.
 748      return !!(a & b);
 749  }
 750  
 751  static SpeculatedType typeOfDoubleSumOrDifferenceOrProduct(SpeculatedType a, SpeculatedType b)
 752  {
 753      SpeculatedType result = a | b;
 754  
 755      if (result & SpecNonIntAsDouble) {
 756          // NaN can be produced by:
 757          // Infinity - Infinity
 758          // Infinity + (-Infinity)
 759          // Infinity * 0
 760          result |= SpecDoublePureNaN;
 761      }
 762  
 763      // Impure NaN could become pure NaN during addition because addition may clear bits.
 764      if (result & SpecDoubleImpureNaN)
 765          result |= SpecDoublePureNaN;
 766      // Values could overflow, or fractions could become integers.
 767      if (result & SpecDoubleReal)
 768          result |= SpecDoubleReal;
 769      return result;
 770  }
 771  
 772  SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
 773  {
 774      return typeOfDoubleSumOrDifferenceOrProduct(a, b);
 775  }
 776  
 777  SpeculatedType typeOfDoubleDifference(SpeculatedType a, SpeculatedType b)
 778  {
 779      return typeOfDoubleSumOrDifferenceOrProduct(a, b);
 780  }
 781  
 782  SpeculatedType typeOfDoubleIncOrDec(SpeculatedType t)
 783  {
 784      // Impure NaN could become pure NaN during addition because addition may clear bits.
 785      if (t & SpecDoubleImpureNaN)
 786          t |= SpecDoublePureNaN;
 787      // Values could overflow, or fractions could become integers.
 788      if (t & SpecDoubleReal)
 789          t |= SpecDoubleReal;
 790      return t;
 791  }
 792  
 793  SpeculatedType typeOfDoubleProduct(SpeculatedType a, SpeculatedType b)
 794  {
 795      return typeOfDoubleSumOrDifferenceOrProduct(a, b);
 796  }
 797  
 798  static SpeculatedType polluteDouble(SpeculatedType value)
 799  {
 800      // Impure NaN could become pure NaN because the operation could clear some bits.
 801      if (value & SpecDoubleImpureNaN)
 802          value |= SpecDoubleNaN;
 803      // Values could overflow, fractions could become integers, or an error could produce
 804      // PureNaN.
 805      if (value & SpecDoubleReal)
 806          value |= SpecDoubleReal | SpecDoublePureNaN;
 807      return value;
 808  }
 809  
 810  SpeculatedType typeOfDoubleQuotient(SpeculatedType a, SpeculatedType b)
 811  {
 812      return polluteDouble(a | b);
 813  }
 814  
 815  SpeculatedType typeOfDoubleMinMax(SpeculatedType a, SpeculatedType b)
 816  {
 817      SpeculatedType result = a | b;
 818      // Impure NaN could become pure NaN during addition because addition may clear bits.
 819      if (result & SpecDoubleImpureNaN)
 820          result |= SpecDoublePureNaN;
 821      return result;
 822  }
 823  
 824  SpeculatedType typeOfDoubleNegation(SpeculatedType value)
 825  {
 826      // Changing bits can make pure NaN impure and vice versa:
 827      // 0xefff000000000000 (pure) - 0xffff000000000000 (impure)
 828      if (value & SpecDoubleNaN)
 829          value |= SpecDoubleNaN;
 830      // We could get negative zero, which mixes SpecAnyIntAsDouble and SpecNotIntAsDouble.
 831      // We could also overflow a large negative int into something that is no longer
 832      // representable as an int.
 833      if (value & SpecDoubleReal)
 834          value |= SpecDoubleReal;
 835      return value;
 836  }
 837  
 838  SpeculatedType typeOfDoubleAbs(SpeculatedType value)
 839  {
 840      return typeOfDoubleNegation(value);
 841  }
 842  
 843  SpeculatedType typeOfDoubleRounding(SpeculatedType value)
 844  {
 845      // Double Pure NaN can becomes impure when converted back from Float.
 846      // and vice versa.
 847      if (value & SpecDoubleNaN)
 848          value |= SpecDoubleNaN;
 849      // We might lose bits, which leads to a value becoming integer-representable.
 850      if (value & SpecNonIntAsDouble)
 851          value |= SpecAnyIntAsDouble;
 852      return value;
 853  }
 854  
 855  SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue)
 856  {
 857      // Math.pow() always return NaN if the exponent is NaN, unlike std::pow().
 858      // We always set a pure NaN in that case.
 859      if (yValue & SpecDoubleNaN)
 860          xValue |= SpecDoublePureNaN;
 861      // Handle the wierd case of NaN ^ 0, which returns 1. See https://tc39.github.io/ecma262/#sec-applying-the-exp-operator
 862      if (xValue & SpecDoubleNaN)
 863          xValue |= SpecFullDouble;
 864      return polluteDouble(xValue);
 865  }
 866  
 867  SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b)
 868  {
 869      return polluteDouble(a | b);
 870  }
 871  
 872  SpeculatedType typeOfDoubleUnaryOp(SpeculatedType value)
 873  {
 874      return polluteDouble(value);
 875  }
 876  
 877  SpeculatedType speculationFromString(const char* speculation)
 878  {
 879      if (!strncmp(speculation, "SpecNone", strlen("SpecNone")))
 880          return SpecNone;
 881      if (!strncmp(speculation, "SpecFinalObject", strlen("SpecFinalObject")))
 882          return SpecFinalObject;
 883      if (!strncmp(speculation, "SpecArray", strlen("SpecArray")))
 884          return SpecArray;
 885      if (!strncmp(speculation, "SpecFunction", strlen("SpecFunction")))
 886          return SpecFunction;
 887      if (!strncmp(speculation, "SpecInt8Array", strlen("SpecInt8Array")))
 888          return SpecInt8Array;
 889      if (!strncmp(speculation, "SpecInt16Array", strlen("SpecInt16Array")))
 890          return SpecInt16Array;
 891      if (!strncmp(speculation, "SpecInt32Array", strlen("SpecInt32Array")))
 892          return SpecInt32Array;
 893      if (!strncmp(speculation, "SpecUint8Array", strlen("SpecUint8Array")))
 894          return SpecUint8Array;
 895      if (!strncmp(speculation, "SpecUint8ClampedArray", strlen("SpecUint8ClampedArray")))
 896          return SpecUint8ClampedArray;
 897      if (!strncmp(speculation, "SpecUint16Array", strlen("SpecUint16Array")))
 898          return SpecUint16Array;
 899      if (!strncmp(speculation, "SpecUint32Array", strlen("SpecUint32Array")))
 900          return SpecUint32Array;
 901      if (!strncmp(speculation, "SpecFloat32Array", strlen("SpecFloat32Array")))
 902          return SpecFloat32Array;
 903      if (!strncmp(speculation, "SpecFloat64Array", strlen("SpecFloat64Array")))
 904          return SpecFloat64Array;
 905      if (!strncmp(speculation, "SpecTypedArrayView", strlen("SpecTypedArrayView")))
 906          return SpecTypedArrayView;
 907      if (!strncmp(speculation, "SpecDirectArguments", strlen("SpecDirectArguments")))
 908          return SpecDirectArguments;
 909      if (!strncmp(speculation, "SpecScopedArguments", strlen("SpecScopedArguments")))
 910          return SpecScopedArguments;
 911      if (!strncmp(speculation, "SpecStringObject", strlen("SpecStringObject")))
 912          return SpecStringObject;
 913      if (!strncmp(speculation, "SpecRegExpObject", strlen("SpecRegExpObject")))
 914          return SpecRegExpObject;
 915      if (!strncmp(speculation, "SpecDateObject", strlen("SpecDateObject")))
 916          return SpecDateObject;
 917      if (!strncmp(speculation, "SpecPromiseObject", strlen("SpecPromiseObject")))
 918          return SpecPromiseObject;
 919      if (!strncmp(speculation, "SpecMapObject", strlen("SpecMapObject")))
 920          return SpecMapObject;
 921      if (!strncmp(speculation, "SpecSetObject", strlen("SpecSetObject")))
 922          return SpecSetObject;
 923      if (!strncmp(speculation, "SpecWeakMapObject", strlen("SpecWeakMapObject")))
 924          return SpecWeakMapObject;
 925      if (!strncmp(speculation, "SpecWeakSetObject", strlen("SpecWeakSetObject")))
 926          return SpecWeakSetObject;
 927      if (!strncmp(speculation, "SpecProxyObject", strlen("SpecProxyObject")))
 928          return SpecProxyObject;
 929      if (!strncmp(speculation, "SpecDerivedArray", strlen("SpecDerivedArray")))
 930          return SpecDerivedArray;
 931      if (!strncmp(speculation, "SpecDataViewObject", strlen("SpecDataViewObject")))
 932          return SpecDataViewObject;
 933      if (!strncmp(speculation, "SpecObjectOther", strlen("SpecObjectOther")))
 934          return SpecObjectOther;
 935      if (!strncmp(speculation, "SpecObject", strlen("SpecObject")))
 936          return SpecObject;
 937      if (!strncmp(speculation, "SpecStringIdent", strlen("SpecStringIdent")))
 938          return SpecStringIdent;
 939      if (!strncmp(speculation, "SpecStringVar", strlen("SpecStringVar")))
 940          return SpecStringVar;
 941      if (!strncmp(speculation, "SpecString", strlen("SpecString")))
 942          return SpecString;
 943      if (!strncmp(speculation, "SpecSymbol", strlen("SpecSymbol")))
 944          return SpecSymbol;
 945      if (!strncmp(speculation, "SpecBigInt", strlen("SpecBigInt")))
 946          return SpecBigInt;
 947      if (!strncmp(speculation, "SpecCellOther", strlen("SpecCellOther")))
 948          return SpecCellOther;
 949      if (!strncmp(speculation, "SpecCell", strlen("SpecCell")))
 950          return SpecCell;
 951      if (!strncmp(speculation, "SpecBoolInt32", strlen("SpecBoolInt32")))
 952          return SpecBoolInt32;
 953      if (!strncmp(speculation, "SpecNonBoolInt32", strlen("SpecNonBoolInt32")))
 954          return SpecNonBoolInt32;
 955      if (!strncmp(speculation, "SpecInt32Only", strlen("SpecInt32Only")))
 956          return SpecInt32Only;
 957      if (!strncmp(speculation, "SpecInt32AsInt52", strlen("SpecInt32AsInt52")))
 958          return SpecInt32AsInt52;
 959      if (!strncmp(speculation, "SpecNonInt32AsInt52", strlen("SpecNonInt32AsInt52")))
 960          return SpecNonInt32AsInt52;
 961      if (!strncmp(speculation, "SpecInt52Any", strlen("SpecInt52Any")))
 962          return SpecInt52Any;
 963      if (!strncmp(speculation, "SpecIntAnyFormat", strlen("SpecIntAnyFormat")))
 964          return SpecIntAnyFormat;
 965      if (!strncmp(speculation, "SpecAnyIntAsDouble", strlen("SpecAnyIntAsDouble")))
 966          return SpecAnyIntAsDouble;
 967      if (!strncmp(speculation, "SpecNonIntAsDouble", strlen("SpecNonIntAsDouble")))
 968          return SpecNonIntAsDouble;
 969      if (!strncmp(speculation, "SpecDoubleReal", strlen("SpecDoubleReal")))
 970          return SpecDoubleReal;
 971      if (!strncmp(speculation, "SpecDoublePureNaN", strlen("SpecDoublePureNaN")))
 972          return SpecDoublePureNaN;
 973      if (!strncmp(speculation, "SpecDoubleImpureNaN", strlen("SpecDoubleImpureNaN")))
 974          return SpecDoubleImpureNaN;
 975      if (!strncmp(speculation, "SpecDoubleNaN", strlen("SpecDoubleNaN")))
 976          return SpecDoubleNaN;
 977      if (!strncmp(speculation, "SpecBytecodeDouble", strlen("SpecBytecodeDouble")))
 978          return SpecBytecodeDouble;
 979      if (!strncmp(speculation, "SpecFullDouble", strlen("SpecFullDouble")))
 980          return SpecFullDouble;
 981      if (!strncmp(speculation, "SpecBytecodeRealNumber", strlen("SpecBytecodeRealNumber")))
 982          return SpecBytecodeRealNumber;
 983      if (!strncmp(speculation, "SpecFullRealNumber", strlen("SpecFullRealNumber")))
 984          return SpecFullRealNumber;
 985      if (!strncmp(speculation, "SpecBytecodeNumber", strlen("SpecBytecodeNumber")))
 986          return SpecBytecodeNumber;
 987      if (!strncmp(speculation, "SpecFullNumber", strlen("SpecFullNumber")))
 988          return SpecFullNumber;
 989      if (!strncmp(speculation, "SpecBoolean", strlen("SpecBoolean")))
 990          return SpecBoolean;
 991      if (!strncmp(speculation, "SpecOther", strlen("SpecOther")))
 992          return SpecOther;
 993      if (!strncmp(speculation, "SpecMisc", strlen("SpecMisc")))
 994          return SpecMisc;
 995      if (!strncmp(speculation, "SpecHeapTop", strlen("SpecHeapTop")))
 996          return SpecHeapTop;
 997      if (!strncmp(speculation, "SpecPrimitive", strlen("SpecPrimitive")))
 998          return SpecPrimitive;
 999      if (!strncmp(speculation, "SpecEmpty", strlen("SpecEmpty")))
1000          return SpecEmpty;
1001      if (!strncmp(speculation, "SpecBytecodeTop", strlen("SpecBytecodeTop")))
1002          return SpecBytecodeTop;
1003      if (!strncmp(speculation, "SpecFullTop", strlen("SpecFullTop")))
1004          return SpecFullTop;
1005      if (!strncmp(speculation, "SpecCellCheck", strlen("SpecCellCheck")))
1006          return SpecCellCheck;
1007      RELEASE_ASSERT_NOT_REACHED();
1008  }
1009  
1010  } // namespace JSC
1011