#ifndef KJS_JS_IMMEDIATE_H
#define KJS_JS_IMMEDIATE_H
#include "JSType.h"
#include <wtf/Assertions.h>
#include <stdint.h>
#include <stdlib.h>
namespace KJS {
class ExecState;
class JSObject;
class JSValue;
class UString;
class JSImmediate {
public:
static bool isImmediate(const JSValue* v)
{
return getTag(v) != 0;
}
static bool isNumber(const JSValue* v)
{
return (getTag(v) == NumberType);
}
static bool isBoolean(const JSValue* v)
{
return (getTag(v) == BooleanType);
}
static bool isUndefinedOrNull(const JSValue* v)
{
return (getTag(v) == UndefinedType);
}
static JSValue* fromDouble(double d);
static double toDouble(const JSValue* v);
static bool toBoolean(const JSValue* v);
static JSObject* toObject(const JSValue*, ExecState*);
static UString toString(const JSValue*);
static JSType type(const JSValue*);
static JSValue* trueImmediate();
static JSValue* falseImmediate();
static JSValue* NaNImmediate();
static JSValue* undefinedImmediate();
static JSValue* nullImmediate();
private:
static const uintptr_t TagMask = 3;
static JSValue* tag(uintptr_t bits, uintptr_t tag)
{
return reinterpret_cast<JSValue*>(bits | tag);
}
static uintptr_t unTag(const JSValue* v)
{
return reinterpret_cast<uintptr_t>(v) & ~TagMask;
}
static uintptr_t getTag(const JSValue* v)
{
return reinterpret_cast<uintptr_t>(v) & TagMask;
}
union FloatUnion {
uint32_t asBits;
float asFloat;
};
union DoubleUnion {
uint64_t asBits;
double asDouble;
};
static const bool is32bit =
sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint32_t);
static const bool is64bit =
sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint64_t);
template<bool for32bit, bool for64bit> struct FPBitValues {};
};
template<> struct JSImmediate::FPBitValues<true, false> {
static const uint32_t nanAsBits = 0x7fc00000;
static const uint32_t oneAsBits = 0x3f800000;
static const uint32_t zeroAsBits = 0x0;
static JSValue* fromDouble(double d)
{
FloatUnion floatUnion;
floatUnion.asFloat = static_cast<float>(d);
if ((floatUnion.asBits & TagMask) != 0)
return 0;
DoubleUnion doubleUnion1, doubleUnion2;
doubleUnion1.asDouble = floatUnion.asFloat;
doubleUnion2.asDouble = d;
if (doubleUnion1.asBits != doubleUnion2.asBits)
return 0;
return tag(floatUnion.asBits, NumberType);
}
static double toDouble(const JSValue* v)
{
ASSERT(isImmediate(v));
FloatUnion floatUnion;
floatUnion.asBits = static_cast<uint32_t>(unTag(v));
return floatUnion.asFloat;
}
};
template<> struct JSImmediate::FPBitValues<false, true> {
static const uint64_t nanAsBits = 0x7ff80000ULL << 32;
static const uint64_t oneAsBits = 0x3ff00000ULL << 32;
static const uint64_t zeroAsBits = 0x0;
static JSValue* fromDouble(double d)
{
DoubleUnion doubleUnion;
doubleUnion.asDouble = d;
if ((doubleUnion.asBits & TagMask) != 0)
return 0;
return tag(static_cast<uintptr_t>(doubleUnion.asBits), NumberType);
}
static double toDouble(const JSValue* v)
{
ASSERT(isImmediate(v));
DoubleUnion doubleUnion;
doubleUnion.asBits = unTag(v);
return doubleUnion.asDouble;
}
};
inline JSValue* JSImmediate::trueImmediate() { return tag(FPBitValues<is32bit, is64bit>::oneAsBits, BooleanType); }
inline JSValue* JSImmediate::falseImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, BooleanType); }
inline JSValue* JSImmediate::NaNImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, NumberType); }
inline JSValue* JSImmediate::undefinedImmediate() { return tag(FPBitValues<is32bit, is64bit>::nanAsBits, UndefinedType); }
inline JSValue* JSImmediate::nullImmediate() { return tag(FPBitValues<is32bit, is64bit>::zeroAsBits, UndefinedType); }
inline bool JSImmediate::toBoolean(const JSValue* v)
{
ASSERT(isImmediate(v));
uintptr_t bits = unTag(v);
if ((bits << 1) == 0) return false;
return bits != FPBitValues<is32bit, is64bit>::nanAsBits;
}
inline JSValue* JSImmediate::fromDouble(double d)
{
return FPBitValues<is32bit, is64bit>::fromDouble(d);
}
inline double JSImmediate::toDouble(const JSValue* v)
{
return FPBitValues<is32bit, is64bit>::toDouble(v);
}
}
#endif