File indexing completed on 2024-05-12 15:43:24

0001 /*
0002  *  This file is part of the KDE libraries
0003  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
0004  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
0005  *
0006  *  This library is free software; you can redistribute it and/or
0007  *  modify it under the terms of the GNU Library General Public
0008  *  License as published by the Free Software Foundation; either
0009  *  version 2 of the License, or (at your option) any later version.
0010  *
0011  *  This library is distributed in the hope that it will be useful,
0012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  *  Library General Public License for more details.
0015  *
0016  *  You should have received a copy of the GNU Library General Public License
0017  *  along with this library; see the file COPYING.LIB.  If not, write to
0018  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  *  Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #ifndef KJS_JS_IMMEDIATE_H
0024 #define KJS_JS_IMMEDIATE_H
0025 
0026 #include <kjs/global.h>
0027 #include "JSType.h"
0028 #include <wtf/Assertions.h>
0029 #include <wtf/AlwaysInline.h>
0030 #include <wtf/MathExtras.h>
0031 #if HAVE_STDINT_H
0032 #include <stdint.h>
0033 #endif
0034 #include <stdlib.h>
0035 
0036 #if PLATFORM(SOLARIS_OS)
0037 static inline int signbit(double x)
0038 {
0039     return (x < 0.0) ? 1 : 0;
0040 }
0041 #endif
0042 
0043 namespace KJS
0044 {
0045 
0046 class ExecState;
0047 class JSObject;
0048 class JSValue;
0049 class UString;
0050 
0051 KJS_EXPORT extern const double NaN;
0052 KJS_EXPORT extern const double Inf;
0053 
0054 /*
0055  * A JSValue*  is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
0056  * signed int masquerading as a pointer). The low two bits in a JSValue* are available
0057  * for type tagging because allocator alignment guarantees they will be 00 in cell pointers.
0058  *
0059  * For example, on a 32 bit system:
0060  *
0061  * JSCell*:       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                 00
0062  *               [ high 30 bits: pointer address ]  [ low 2 bits -- always 0 ]
0063  *
0064  * JSImmediate:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                 TT
0065  *               [ high 30 bits: signed int ]       [ low 2 bits -- type tag ]
0066  *
0067  * The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
0068  * and undefined/null.
0069  *
0070  * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits
0071  * available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has
0072  * to sort them out.
0073  */
0074 
0075 class KJS_EXPORT JSImmediate
0076 {
0077 public:
0078     static ALWAYS_INLINE bool isImmediate(const JSValue *v)
0079     {
0080         return getTag(v) != 0;
0081     }
0082 
0083     static ALWAYS_INLINE bool isNumber(const JSValue *v)
0084     {
0085         return (getTag(v) == NumberType);
0086     }
0087 
0088     static ALWAYS_INLINE bool isBoolean(const JSValue *v)
0089     {
0090         return (getTag(v) == BooleanType);
0091     }
0092 
0093     // Since we have room for only 3 unique tags, null and undefined have to share.
0094     static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue *v)
0095     {
0096         return (getTag(v) == UndefinedType);
0097     }
0098 
0099     static JSValue *from(char);
0100     static JSValue *from(signed char);
0101     static JSValue *from(unsigned char);
0102     static JSValue *from(short);
0103     static JSValue *from(unsigned short);
0104     static JSValue *from(int);
0105     static JSValue *from(unsigned);
0106     static JSValue *from(long);
0107     static JSValue *from(unsigned long);
0108     static JSValue *from(long long);
0109     static JSValue *from(unsigned long long);
0110     static JSValue *from(double);
0111 
0112     static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue *v1, const JSValue *v2)
0113     {
0114         return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagMask) == NumberType;
0115     }
0116 
0117     static ALWAYS_INLINE JSValue *andImmediateNumbers(const JSValue *v1, const JSValue *v2)
0118     {
0119         ASSERT(areBothImmediateNumbers(v1, v2));
0120         return reinterpret_cast<JSValue *>(reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2));
0121     }
0122 
0123     static double toDouble(const JSValue *);
0124 
0125     // Non-converting getters for Number's
0126     static double getNumber(const JSValue *);    // This returns NaN if the value is not a Number.
0127     static bool   getNumber(const JSValue *, double &valOut);
0128 
0129     static bool toBoolean(const JSValue *);
0130     static JSObject *toObject(const JSValue *, ExecState *);
0131     static UString toString(const JSValue *);
0132     static JSType type(const JSValue *);
0133 
0134     static bool getUInt32(const JSValue *, uint32_t &);
0135     static bool getTruncatedInt32(const JSValue *, int32_t &);
0136     static bool getTruncatedUInt32(const JSValue *, uint32_t &);
0137 
0138     static int32_t getTruncatedInt32(const JSValue *);
0139 
0140     static JSValue *trueImmediate();
0141     static JSValue *falseImmediate();
0142     static JSValue *undefinedImmediate();
0143     static JSValue *nullImmediate();
0144 
0145 private:
0146     static const uintptr_t TagMask = 3; // type tags are 2 bits long
0147 
0148     // Immediate values are restricted to a 30 bit signed value.
0149     static const int minImmediateInt = -(1 << 29);
0150     static const int maxImmediateInt = (1 << 29) - 1;
0151     static const unsigned maxImmediateUInt = maxImmediateInt;
0152 
0153     static ALWAYS_INLINE JSValue *tag(uintptr_t bits, uintptr_t tag)
0154     {
0155         return reinterpret_cast<JSValue *>(bits | tag);
0156     }
0157 
0158     static ALWAYS_INLINE uintptr_t unTag(const JSValue *v)
0159     {
0160         return reinterpret_cast<uintptr_t>(v) & ~TagMask;
0161     }
0162 
0163     static ALWAYS_INLINE uintptr_t getTag(const JSValue *v)
0164     {
0165         return reinterpret_cast<uintptr_t>(v) & TagMask;
0166     }
0167 };
0168 
0169 ALWAYS_INLINE JSValue *JSImmediate::trueImmediate()
0170 {
0171     return tag(1 << 2, BooleanType);
0172 }
0173 ALWAYS_INLINE JSValue *JSImmediate::falseImmediate()
0174 {
0175     return tag(0, BooleanType);
0176 }
0177 ALWAYS_INLINE JSValue *JSImmediate::undefinedImmediate()
0178 {
0179     return tag(1 << 2, UndefinedType);
0180 }
0181 ALWAYS_INLINE JSValue *JSImmediate::nullImmediate()
0182 {
0183     return tag(0, UndefinedType);
0184 }
0185 
0186 ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue *v)
0187 {
0188     ASSERT(isImmediate(v));
0189     uintptr_t bits = unTag(v);
0190     return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
0191 }
0192 
0193 ALWAYS_INLINE JSValue *JSImmediate::from(char i)
0194 {
0195     return tag(i << 2, NumberType);
0196 }
0197 
0198 ALWAYS_INLINE JSValue *JSImmediate::from(signed char i)
0199 {
0200     return tag(i << 2, NumberType);
0201 }
0202 
0203 ALWAYS_INLINE JSValue *JSImmediate::from(unsigned char i)
0204 {
0205     return tag(i << 2, NumberType);
0206 }
0207 
0208 ALWAYS_INLINE JSValue *JSImmediate::from(short i)
0209 {
0210     return tag(i << 2, NumberType);
0211 }
0212 
0213 ALWAYS_INLINE JSValue *JSImmediate::from(unsigned short i)
0214 {
0215     return tag(i << 2, NumberType);
0216 }
0217 
0218 ALWAYS_INLINE JSValue *JSImmediate::from(int i)
0219 {
0220     if ((i < minImmediateInt) || (i > maxImmediateInt)) {
0221         return nullptr;
0222     }
0223     return tag(i << 2, NumberType);
0224 }
0225 
0226 ALWAYS_INLINE JSValue *JSImmediate::from(unsigned i)
0227 {
0228     if (i > maxImmediateUInt) {
0229         return nullptr;
0230     }
0231     return tag(i << 2, NumberType);
0232 }
0233 
0234 ALWAYS_INLINE JSValue *JSImmediate::from(long i)
0235 {
0236     if ((i < minImmediateInt) || (i > maxImmediateInt)) {
0237         return nullptr;
0238     }
0239     return tag(i << 2, NumberType);
0240 }
0241 
0242 ALWAYS_INLINE JSValue *JSImmediate::from(unsigned long i)
0243 {
0244     if (i > maxImmediateUInt) {
0245         return nullptr;
0246     }
0247     return tag(i << 2, NumberType);
0248 }
0249 
0250 ALWAYS_INLINE JSValue *JSImmediate::from(long long i)
0251 {
0252     if ((i < minImmediateInt) || (i > maxImmediateInt)) {
0253         return nullptr;
0254     }
0255     return tag(static_cast<uintptr_t>(i) << 2, NumberType);
0256 }
0257 
0258 ALWAYS_INLINE JSValue *JSImmediate::from(unsigned long long i)
0259 {
0260     if (i > maxImmediateUInt) {
0261         return nullptr;
0262     }
0263     return tag(static_cast<uintptr_t>(i) << 2, NumberType);
0264 }
0265 
0266 ALWAYS_INLINE JSValue *JSImmediate::from(double d)
0267 {
0268     using namespace std;
0269     const int intVal = static_cast<int>(d);
0270 
0271     if ((intVal < minImmediateInt) || (intVal > maxImmediateInt)) {
0272         return nullptr;
0273     }
0274 
0275     // Check for data loss from conversion to int.
0276     if ((intVal != d) || (!intVal && signbit(d))) {
0277         return nullptr;
0278     }
0279 
0280     return tag(intVal << 2, NumberType);
0281 }
0282 
0283 ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(const JSValue *v)
0284 {
0285     ASSERT(isNumber(v));
0286     return static_cast<int32_t>(unTag(v)) >> 2;
0287 }
0288 
0289 ALWAYS_INLINE double JSImmediate::toDouble(const JSValue *v)
0290 {
0291     ASSERT(isImmediate(v));
0292     const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
0293     if (JSImmediate::getTag(v) == UndefinedType && i) {
0294         return NaN;
0295     }
0296     return i;
0297 }
0298 
0299 ALWAYS_INLINE double JSImmediate::getNumber(const JSValue *v)
0300 {
0301     ASSERT(isImmediate(v));
0302     const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
0303     if (JSImmediate::getTag(v) != NumberType) {
0304         return NaN;
0305     }
0306     return i;
0307 }
0308 
0309 ALWAYS_INLINE bool JSImmediate::getNumber(const JSValue *v, double &numberOut)
0310 {
0311     ASSERT(isImmediate(v));
0312     numberOut = static_cast<int32_t>(unTag(v)) >> 2;
0313     return (JSImmediate::getTag(v) == NumberType);
0314 }
0315 
0316 ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue *v, uint32_t &i)
0317 {
0318     const int32_t si = static_cast<int32_t>(unTag(v)) >> 2;
0319     i = si;
0320     return isNumber(v) & (si >= 0);
0321 }
0322 
0323 ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue *v, int32_t &i)
0324 {
0325     i = static_cast<int32_t>(unTag(v)) >> 2;
0326     return isNumber(v);
0327 }
0328 
0329 ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue *v, uint32_t &i)
0330 {
0331     return getUInt32(v, i);
0332 }
0333 
0334 } // namespace KJS
0335 
0336 #endif