SpeculatedType.cpp [plain text]
#include "config.h"
#include "SpeculatedType.h"
#include "DirectArguments.h"
#include "JSArray.h"
#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSMap.h"
#include "JSSet.h"
#include "ProxyObject.h"
#include "RegExpObject.h"
#include "ScopedArguments.h"
#include "StringObject.h"
#include "ValueProfile.h"
#include <wtf/CommaPrinter.h>
#include <wtf/StringPrintStream.h>
namespace JSC {
struct PrettyPrinter {
PrettyPrinter(PrintStream& out)
: out(out)
, separator("|")
{ }
template<typename T>
void print(const T& value)
{
out.print(separator, value);
}
PrintStream& out;
CommaPrinter separator;
};
void dumpSpeculation(PrintStream& outStream, SpeculatedType value)
{
StringPrintStream strStream;
PrettyPrinter out(outStream);
PrettyPrinter strOut(strStream);
if (value == SpecNone) {
out.print("None");
return;
}
bool isTop = true;
if ((value & SpecCell) == SpecCell)
strOut.print("Cell");
else {
if ((value & SpecObject) == SpecObject)
strOut.print("Object");
else {
if (value & SpecCellOther)
strOut.print("OtherCell");
else
isTop = false;
if (value & SpecObjectOther)
strOut.print("OtherObj");
else
isTop = false;
if (value & SpecFinalObject)
strOut.print("Final");
else
isTop = false;
if (value & SpecArray)
strOut.print("Array");
else
isTop = false;
if (value & SpecInt8Array)
strOut.print("Int8Array");
else
isTop = false;
if (value & SpecInt16Array)
strOut.print("Int16Array");
else
isTop = false;
if (value & SpecInt32Array)
strOut.print("Int32Array");
else
isTop = false;
if (value & SpecUint8Array)
strOut.print("Uint8Array");
else
isTop = false;
if (value & SpecUint8ClampedArray)
strOut.print("Uint8ClampedArray");
else
isTop = false;
if (value & SpecUint16Array)
strOut.print("Uint16Array");
else
isTop = false;
if (value & SpecUint32Array)
strOut.print("Uint32Array");
else
isTop = false;
if (value & SpecFloat32Array)
strOut.print("Float32array");
else
isTop = false;
if (value & SpecFloat64Array)
strOut.print("Float64Array");
else
isTop = false;
if (value & SpecFunction)
strOut.print("Function");
else
isTop = false;
if (value & SpecDirectArguments)
strOut.print("DirectArguments");
else
isTop = false;
if (value & SpecScopedArguments)
strOut.print("ScopedArguments");
else
isTop = false;
if (value & SpecStringObject)
strOut.print("StringObject");
else
isTop = false;
if (value & SpecRegExpObject)
strOut.print("RegExpObject");
else
isTop = false;
if (value & SpecMapObject)
strOut.print("MapObject");
else
isTop = false;
if (value & SpecSetObject)
strOut.print("SetObject");
else
isTop = false;
if (value & SpecProxyObject)
strOut.print("ProxyObject");
else
isTop = false;
if (value & SpecDerivedArray)
strOut.print("DerivedArray");
else
isTop = false;
}
if ((value & SpecString) == SpecString)
strOut.print("String");
else {
if (value & SpecStringIdent)
strOut.print("StringIdent");
else
isTop = false;
if (value & SpecStringVar)
strOut.print("StringVar");
else
isTop = false;
}
if (value & SpecSymbol)
strOut.print("Symbol");
else
isTop = false;
}
if (value == SpecInt32Only)
strOut.print("Int32");
else {
if (value & SpecBoolInt32)
strOut.print("BoolInt32");
else
isTop = false;
if (value & SpecNonBoolInt32)
strOut.print("NonBoolInt32");
else
isTop = false;
}
if (value & SpecInt52Only)
strOut.print("Int52");
if ((value & SpecBytecodeDouble) == SpecBytecodeDouble)
strOut.print("BytecodeDouble");
else {
if (value & SpecAnyIntAsDouble)
strOut.print("AnyIntAsDouble");
else
isTop = false;
if (value & SpecNonIntAsDouble)
strOut.print("NonIntAsdouble");
else
isTop = false;
if (value & SpecDoublePureNaN)
strOut.print("DoublePureNan");
else
isTop = false;
}
if (value & SpecDoubleImpureNaN)
out.print("DoubleImpureNan");
if (value & SpecBoolean)
strOut.print("Bool");
else
isTop = false;
if (value & SpecOther)
strOut.print("Other");
else
isTop = false;
if (isTop)
out.print("Top");
else
out.print(strStream.toCString());
if (value & SpecEmpty)
out.print("Empty");
}
static const char* speculationToAbbreviatedString(SpeculatedType prediction)
{
if (isFinalObjectSpeculation(prediction))
return "<Final>";
if (isArraySpeculation(prediction))
return "<Array>";
if (isStringIdentSpeculation(prediction))
return "<StringIdent>";
if (isStringSpeculation(prediction))
return "<String>";
if (isFunctionSpeculation(prediction))
return "<Function>";
if (isInt8ArraySpeculation(prediction))
return "<Int8array>";
if (isInt16ArraySpeculation(prediction))
return "<Int16array>";
if (isInt32ArraySpeculation(prediction))
return "<Int32array>";
if (isUint8ArraySpeculation(prediction))
return "<Uint8array>";
if (isUint16ArraySpeculation(prediction))
return "<Uint16array>";
if (isUint32ArraySpeculation(prediction))
return "<Uint32array>";
if (isFloat32ArraySpeculation(prediction))
return "<Float32array>";
if (isFloat64ArraySpeculation(prediction))
return "<Float64array>";
if (isDirectArgumentsSpeculation(prediction))
return "<DirectArguments>";
if (isScopedArgumentsSpeculation(prediction))
return "<ScopedArguments>";
if (isStringObjectSpeculation(prediction))
return "<StringObject>";
if (isRegExpObjectSpeculation(prediction))
return "<RegExpObject>";
if (isStringOrStringObjectSpeculation(prediction))
return "<StringOrStringObject>";
if (isObjectSpeculation(prediction))
return "<Object>";
if (isCellSpeculation(prediction))
return "<Cell>";
if (isBoolInt32Speculation(prediction))
return "<BoolInt32>";
if (isInt32Speculation(prediction))
return "<Int32>";
if (isAnyIntAsDoubleSpeculation(prediction))
return "<AnyIntAsDouble>";
if (isInt52Speculation(prediction))
return "<Int52>";
if (isAnyIntSpeculation(prediction))
return "<AnyInt>";
if (isDoubleSpeculation(prediction))
return "<Double>";
if (isFullNumberSpeculation(prediction))
return "<Number>";
if (isBooleanSpeculation(prediction))
return "<Boolean>";
if (isOtherSpeculation(prediction))
return "<Other>";
if (isMiscSpeculation(prediction))
return "<Misc>";
return "";
}
void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value)
{
out.print(speculationToAbbreviatedString(value));
}
SpeculatedType speculationFromTypedArrayType(TypedArrayType type)
{
switch (type) {
case TypeInt8:
return SpecInt8Array;
case TypeInt16:
return SpecInt16Array;
case TypeInt32:
return SpecInt32Array;
case TypeUint8:
return SpecUint8Array;
case TypeUint8Clamped:
return SpecUint8ClampedArray;
case TypeUint16:
return SpecUint16Array;
case TypeUint32:
return SpecUint32Array;
case TypeFloat32:
return SpecFloat32Array;
case TypeFloat64:
return SpecFloat64Array;
case NotTypedArray:
case TypeDataView:
break;
}
RELEASE_ASSERT_NOT_REACHED();
return SpecNone;
}
SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
{
if (classInfo == JSString::info())
return SpecString;
if (classInfo == Symbol::info())
return SpecSymbol;
if (classInfo == JSFinalObject::info())
return SpecFinalObject;
if (classInfo == JSArray::info())
return SpecArray;
if (classInfo == DirectArguments::info())
return SpecDirectArguments;
if (classInfo == ScopedArguments::info())
return SpecScopedArguments;
if (classInfo == StringObject::info())
return SpecStringObject;
if (classInfo == RegExpObject::info())
return SpecRegExpObject;
if (classInfo == JSMap::info())
return SpecMapObject;
if (classInfo == JSSet::info())
return SpecSetObject;
if (classInfo == ProxyObject::info())
return SpecProxyObject;
if (classInfo->isSubClassOf(JSFunction::info()))
return SpecFunction;
if (isTypedView(classInfo->typedArrayStorageType))
return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
if (classInfo->isSubClassOf(JSArray::info()))
return SpecDerivedArray;
if (classInfo->isSubClassOf(JSObject::info()))
return SpecObjectOther;
return SpecCellOther;
}
SpeculatedType speculationFromStructure(Structure* structure)
{
if (structure->typeInfo().type() == StringType)
return SpecString;
if (structure->typeInfo().type() == SymbolType)
return SpecSymbol;
if (structure->typeInfo().type() == DerivedArrayType)
return SpecDerivedArray;
return speculationFromClassInfo(structure->classInfo());
}
SpeculatedType speculationFromCell(JSCell* cell)
{
if (cell->isString()) {
JSString* string = jsCast<JSString*>(cell);
if (const StringImpl* impl = string->tryGetValueImpl()) {
if (impl->isAtomic())
return SpecStringIdent;
}
return SpecStringVar;
}
return speculationFromStructure(cell->structure());
}
SpeculatedType speculationFromValue(JSValue value)
{
if (value.isEmpty())
return SpecEmpty;
if (value.isInt32()) {
if (value.asInt32() & ~1)
return SpecNonBoolInt32;
return SpecBoolInt32;
}
if (value.isDouble()) {
double number = value.asNumber();
if (number != number)
return SpecDoublePureNaN;
if (value.isAnyInt())
return SpecAnyIntAsDouble;
return SpecNonIntAsDouble;
}
if (value.isCell())
return speculationFromCell(value.asCell());
if (value.isBoolean())
return SpecBoolean;
ASSERT(value.isUndefinedOrNull());
return SpecOther;
}
TypedArrayType typedArrayTypeFromSpeculation(SpeculatedType type)
{
if (isInt8ArraySpeculation(type))
return TypeInt8;
if (isInt16ArraySpeculation(type))
return TypeInt16;
if (isInt32ArraySpeculation(type))
return TypeInt32;
if (isUint8ArraySpeculation(type))
return TypeUint8;
if (isUint8ClampedArraySpeculation(type))
return TypeUint8Clamped;
if (isUint16ArraySpeculation(type))
return TypeUint16;
if (isUint32ArraySpeculation(type))
return TypeUint32;
if (isFloat32ArraySpeculation(type))
return TypeFloat32;
if (isFloat64ArraySpeculation(type))
return TypeFloat64;
return NotTypedArray;
}
SpeculatedType speculationFromJSType(JSType type)
{
switch (type) {
case StringType:
return SpecString;
case SymbolType:
return SpecSymbol;
case ArrayType:
return SpecArray;
case DerivedArrayType:
return SpecDerivedArray;
case RegExpObjectType:
return SpecRegExpObject;
case ProxyObjectType:
return SpecProxyObject;
case JSMapType:
return SpecMapObject;
case JSSetType:
return SpecSetObject;
default:
ASSERT_NOT_REACHED();
}
return SpecNone;
}
SpeculatedType leastUpperBoundOfStrictlyEquivalentSpeculations(SpeculatedType type)
{
if (type & (SpecAnyInt | SpecAnyIntAsDouble))
type |= (SpecAnyInt | SpecAnyIntAsDouble);
if (type & SpecString)
type |= SpecString;
return type;
}
bool valuesCouldBeEqual(SpeculatedType a, SpeculatedType b)
{
a = leastUpperBoundOfStrictlyEquivalentSpeculations(a);
b = leastUpperBoundOfStrictlyEquivalentSpeculations(b);
if (a & SpecString)
return true;
if (b & SpecString)
return true;
if (isObjectSpeculation(a) && isObjectSpeculation(b))
return !!(a & b);
if (a & SpecObject)
return true;
if (b & SpecObject)
return true;
return !!(a & b);
}
SpeculatedType typeOfDoubleSum(SpeculatedType a, SpeculatedType b)
{
SpeculatedType result = a | b;
if (result & SpecDoubleImpureNaN)
result |= SpecDoublePureNaN;
if (result & SpecDoubleReal)
result |= SpecDoubleReal;
return result;
}
SpeculatedType typeOfDoubleDifference(SpeculatedType a, SpeculatedType b)
{
return typeOfDoubleSum(a, b);
}
SpeculatedType typeOfDoubleProduct(SpeculatedType a, SpeculatedType b)
{
return typeOfDoubleSum(a, b);
}
static SpeculatedType polluteDouble(SpeculatedType value)
{
if (value & SpecDoubleImpureNaN)
value |= SpecDoubleNaN;
if (value & SpecDoubleReal)
value |= SpecDoubleReal | SpecDoublePureNaN;
return value;
}
SpeculatedType typeOfDoubleQuotient(SpeculatedType a, SpeculatedType b)
{
return polluteDouble(a | b);
}
SpeculatedType typeOfDoubleMinMax(SpeculatedType a, SpeculatedType b)
{
SpeculatedType result = a | b;
if (result & SpecDoubleImpureNaN)
result |= SpecDoublePureNaN;
return result;
}
SpeculatedType typeOfDoubleNegation(SpeculatedType value)
{
if (value & SpecDoubleNaN)
value |= SpecDoubleNaN;
if (value & SpecDoubleReal)
value |= SpecDoubleReal;
return value;
}
SpeculatedType typeOfDoubleAbs(SpeculatedType value)
{
return typeOfDoubleNegation(value);
}
SpeculatedType typeOfDoubleRounding(SpeculatedType value)
{
if (value & SpecDoubleNaN)
value |= SpecDoubleNaN;
if (value & SpecNonIntAsDouble)
value |= SpecAnyIntAsDouble;
return value;
}
SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue)
{
if (yValue & SpecDoubleNaN)
xValue |= SpecDoublePureNaN;
return polluteDouble(xValue);
}
SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b)
{
return polluteDouble(a | b);
}
SpeculatedType typeOfDoubleUnaryOp(SpeculatedType value)
{
return polluteDouble(value);
}
}