| 1 | /* | 
| 2 |  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. | 
| 3 |  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) | 
| 4 |  * | 
| 5 |  *  This library is free software; you can redistribute it and/or | 
| 6 |  *  modify it under the terms of the GNU Library General Public | 
| 7 |  *  License as published by the Free Software Foundation; either | 
| 8 |  *  version 2 of the License, or (at your option) any later version. | 
| 9 |  * | 
| 10 |  *  This library is distributed in the hope that it will be useful, | 
| 11 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 12 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
| 13 |  *  Library General Public License for more details. | 
| 14 |  * | 
| 15 |  *  You should have received a copy of the GNU Library General Public License | 
| 16 |  *  along with this library; see the file COPYING.LIB.  If not, write to | 
| 17 |  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
| 18 |  *  Boston, MA 02110-1301, USA. | 
| 19 |  * | 
| 20 |  */ | 
| 21 |  | 
| 22 | #ifndef JSImmediate_h | 
| 23 | #define JSImmediate_h | 
| 24 |  | 
| 25 | #include <wtf/Platform.h> | 
| 26 |  | 
| 27 | #if !USE(JSVALUE32_64) | 
| 28 |  | 
| 29 | #include "JSValue.h" | 
| 30 |  | 
| 31 | #include <wtf/Assertions.h> | 
| 32 | #include <wtf/AlwaysInline.h> | 
| 33 | #include <wtf/MathExtras.h> | 
| 34 | #include <wtf/StdLibExtras.h> | 
| 35 |  | 
| 36 | #include <limits> | 
| 37 | #include <limits.h> | 
| 38 | #include <stdarg.h> | 
| 39 | #include <stdint.h> | 
| 40 | #include <stdlib.h> | 
| 41 |  | 
| 42 | namespace JSC { | 
| 43 |  | 
| 44 |     class ExecState; | 
| 45 |     class JSCell; | 
| 46 |     class JSFastMath; | 
| 47 |     class JSGlobalData; | 
| 48 |     class JSObject; | 
| 49 |     class UString; | 
| 50 |  | 
| 51 | #if USE(JSVALUE64) | 
| 52 |     inline intptr_t reinterpretDoubleToIntptr(double value) | 
| 53 |     { | 
| 54 |         return WTF::bitwise_cast<intptr_t>(from: value); | 
| 55 |     } | 
| 56 |  | 
| 57 |     inline double reinterpretIntptrToDouble(intptr_t value) | 
| 58 |     { | 
| 59 |         return WTF::bitwise_cast<double>(from: value); | 
| 60 |     } | 
| 61 | #endif | 
| 62 |  | 
| 63 |     /* | 
| 64 |      * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged  | 
| 65 |      * value masquerading as a pointer). The low two bits in a JSValue* are available for type tagging | 
| 66 |      * because allocator alignment guarantees they will be 00 in cell pointers. | 
| 67 |      * | 
| 68 |      * For example, on a 32 bit system: | 
| 69 |      * | 
| 70 |      * JSCell*:             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     00 | 
| 71 |      *                      [ high 30 bits: pointer address ]  [ low 2 bits -- always 0 ] | 
| 72 |      * JSImmediate:         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     TT | 
| 73 |      *                      [ high 30 bits: 'payload' ]             [ low 2 bits -- tag ] | 
| 74 |      * | 
| 75 |      * Where the bottom two bits are non-zero they either indicate that the immediate is a 31 bit signed | 
| 76 |      * integer, or they mark the value as being an immediate of a type other than integer, with a secondary | 
| 77 |      * tag used to indicate the exact type. | 
| 78 |      * | 
| 79 |      * Where the lowest bit is set (TT is equal to 01 or 11) the high 31 bits form a 31 bit signed int value. | 
| 80 |      * Where TT is equal to 10 this indicates this is a type of immediate other than an integer, and the next | 
| 81 |      * two bits will form an extended tag. | 
| 82 |      * | 
| 83 |      * 31 bit signed int:   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     X1 | 
| 84 |      *                      [ high 30 bits of the value ]      [ high bit part of value ] | 
| 85 |      * Other:               YYYYYYYYYYYYYYYYYYYYYYYYYYYY      ZZ               10 | 
| 86 |      *                      [ extended 'payload' ]  [  extended tag  ]  [  tag 'other'  ] | 
| 87 |      * | 
| 88 |      * Where the first bit of the extended tag is set this flags the value as being a boolean, and the following | 
| 89 |      * bit would flag the value as undefined.  If neither bits are set, the value is null. | 
| 90 |      * | 
| 91 |      * Other:               YYYYYYYYYYYYYYYYYYYYYYYYYYYY      UB               10 | 
| 92 |      *                      [ extended 'payload' ]  [ undefined | bool ]  [ tag 'other' ] | 
| 93 |      * | 
| 94 |      * For boolean value the lowest bit in the payload holds the value of the bool, all remaining bits are zero. | 
| 95 |      * For undefined or null immediates the payload is zero. | 
| 96 |      * | 
| 97 |      * Boolean:             000000000000000000000000000V      01               10 | 
| 98 |      *                      [ boolean value ]              [ bool ]       [ tag 'other' ] | 
| 99 |      * Undefined:           0000000000000000000000000000      10               10 | 
| 100 |      *                      [ zero ]                    [ undefined ]     [ tag 'other' ] | 
| 101 |      * Null:                0000000000000000000000000000      00               10 | 
| 102 |      *                      [ zero ]                       [ zero ]       [ tag 'other' ] | 
| 103 |      */ | 
| 104 |  | 
| 105 |     /* | 
| 106 |      * On 64-bit platforms, we support an alternative encoding form for immediates, if | 
| 107 |      * USE(JSVALUE64) is defined.  When this format is used, double precision | 
| 108 |      * floating point values may also be encoded as JSImmediates. | 
| 109 |      * | 
| 110 |      * The encoding makes use of unused NaN space in the IEEE754 representation.  Any value | 
| 111 |      * with the top 13 bits set represents a QNaN (with the sign bit set).  QNaN values | 
| 112 |      * can encode a 51-bit payload.  Hardware produced and C-library payloads typically | 
| 113 |      * have a payload of zero.  We assume that non-zero payloads are available to encode | 
| 114 |      * pointer and integer values.  Since any 64-bit bit pattern where the top 15 bits are | 
| 115 |      * all set represents a NaN with a non-zero payload, we can use this space in the NaN | 
| 116 |      * ranges to encode other values (however there are also other ranges of NaN space that | 
| 117 |      * could have been selected).  This range of NaN space is represented by 64-bit numbers | 
| 118 |      * begining with the 16-bit hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no | 
| 119 |      * valid double-precision numbers will begin fall in these ranges. | 
| 120 |      * | 
| 121 |      * The scheme we have implemented encodes double precision values by adding 2^48 to the | 
| 122 |      * 64-bit integer representation of the number.  After this manipulation, no encoded | 
| 123 |      * double-precision value will begin with the pattern 0x0000 or 0xFFFF. | 
| 124 |      * | 
| 125 |      * The top 16-bits denote the type of the encoded JSImmediate: | 
| 126 |      * | 
| 127 |      * Pointer: 0000:PPPP:PPPP:PPPP | 
| 128 |      *          0001:****:****:**** | 
| 129 |      * Double:{         ... | 
| 130 |      *          FFFE:****:****:**** | 
| 131 |      * Integer: FFFF:0000:IIII:IIII | 
| 132 |      * | 
| 133 |      * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.  The tag 0x0000 | 
| 134 |      * denotes a pointer, or another form of tagged immediate.  Boolean, null and undefined | 
| 135 |      * values are encoded in the same manner as the default format. | 
| 136 |      */ | 
| 137 |  | 
| 138 |     class JSImmediate { | 
| 139 | #ifdef QT_BUILD_SCRIPT_LIB | 
| 140 |     public: // Qt Script needs isImmediate() and from() functions | 
| 141 | #else | 
| 142 |     private: | 
| 143 | #endif | 
| 144 |         friend class JIT; | 
| 145 |         friend class JSValue; | 
| 146 |         friend class JSFastMath; | 
| 147 |         friend JSValue jsNumber(ExecState* exec, double d); | 
| 148 |         friend JSValue jsNumber(ExecState*, char i); | 
| 149 |         friend JSValue jsNumber(ExecState*, unsigned char i); | 
| 150 |         friend JSValue jsNumber(ExecState*, short i); | 
| 151 |         friend JSValue jsNumber(ExecState*, unsigned short i); | 
| 152 |         friend JSValue jsNumber(ExecState* exec, int i); | 
| 153 |         friend JSValue jsNumber(ExecState* exec, unsigned i); | 
| 154 |         friend JSValue jsNumber(ExecState* exec, long i); | 
| 155 |         friend JSValue jsNumber(ExecState* exec, unsigned long i); | 
| 156 |         friend JSValue jsNumber(ExecState* exec, long long i); | 
| 157 |         friend JSValue jsNumber(ExecState* exec, unsigned long long i); | 
| 158 |         friend JSValue jsNumber(JSGlobalData* globalData, double d); | 
| 159 |         friend JSValue jsNumber(JSGlobalData* globalData, short i); | 
| 160 |         friend JSValue jsNumber(JSGlobalData* globalData, unsigned short i); | 
| 161 |         friend JSValue jsNumber(JSGlobalData* globalData, int i); | 
| 162 |         friend JSValue jsNumber(JSGlobalData* globalData, unsigned i); | 
| 163 |         friend JSValue jsNumber(JSGlobalData* globalData, long i); | 
| 164 |         friend JSValue jsNumber(JSGlobalData* globalData, unsigned long i); | 
| 165 |         friend JSValue jsNumber(JSGlobalData* globalData, long long i); | 
| 166 |         friend JSValue jsNumber(JSGlobalData* globalData, unsigned long long i); | 
| 167 |  | 
| 168 | #if USE(JSVALUE64) | 
| 169 |         // If all bits in the mask are set, this indicates an integer number, | 
| 170 |         // if any but not all are set this value is a double precision number. | 
| 171 |         static const intptr_t TagTypeNumber = 0xffff000000000000ll; | 
| 172 |         // This value is 2^48, used to encode doubles such that the encoded value will begin | 
| 173 |         // with a 16-bit pattern within the range 0x0001..0xFFFE. | 
| 174 |         static const intptr_t DoubleEncodeOffset = 0x1000000000000ll; | 
| 175 | #else | 
| 176 |         static const intptr_t TagTypeNumber = 0x1; // bottom bit set indicates integer, this dominates the following bit | 
| 177 | #endif | 
| 178 |         static const intptr_t TagBitTypeOther   = 0x2; // second bit set indicates immediate other than an integer | 
| 179 |         static const intptr_t TagMask           = TagTypeNumber | TagBitTypeOther; | 
| 180 |  | 
| 181 |         static const intptr_t ExtendedTagMask         = 0xC; // extended tag holds a further two bits | 
| 182 |         static const intptr_t ExtendedTagBitBool      = 0x4; | 
| 183 |         static const intptr_t ExtendedTagBitUndefined = 0x8; | 
| 184 |  | 
| 185 |         static const intptr_t FullTagTypeMask      = TagMask | ExtendedTagMask; | 
| 186 |         static const intptr_t FullTagTypeBool      = TagBitTypeOther | ExtendedTagBitBool; | 
| 187 |         static const intptr_t FullTagTypeUndefined = TagBitTypeOther | ExtendedTagBitUndefined; | 
| 188 |         static const intptr_t FullTagTypeNull      = TagBitTypeOther; | 
| 189 |  | 
| 190 | #if USE(JSVALUE64) | 
| 191 |         static const int32_t IntegerPayloadShift  = 0; | 
| 192 | #else | 
| 193 |         static const int32_t IntegerPayloadShift  = 1; | 
| 194 | #endif | 
| 195 |         static const int32_t ExtendedPayloadShift = 4; | 
| 196 |  | 
| 197 |         static const intptr_t ExtendedPayloadBitBoolValue = 1 << ExtendedPayloadShift; | 
| 198 |  | 
| 199 |         static const int32_t signBit = 0x80000000; | 
| 200 |   | 
| 201 |         static ALWAYS_INLINE bool isImmediate(JSValue v) | 
| 202 |         { | 
| 203 |             return rawValue(v) & TagMask; | 
| 204 |         } | 
| 205 |          | 
| 206 |         static ALWAYS_INLINE bool isNumber(JSValue v) | 
| 207 |         { | 
| 208 |             return rawValue(v) & TagTypeNumber; | 
| 209 |         } | 
| 210 |  | 
| 211 |         static ALWAYS_INLINE bool isIntegerNumber(JSValue v) | 
| 212 |         { | 
| 213 | #if USE(JSVALUE64) | 
| 214 |             return (rawValue(v) & TagTypeNumber) == TagTypeNumber; | 
| 215 | #else | 
| 216 |             return isNumber(v); | 
| 217 | #endif | 
| 218 |         } | 
| 219 |  | 
| 220 | #if USE(JSVALUE64) | 
| 221 |         static ALWAYS_INLINE bool isDouble(JSValue v) | 
| 222 |         { | 
| 223 |             return isNumber(v) && !isIntegerNumber(v); | 
| 224 |         } | 
| 225 | #endif | 
| 226 |  | 
| 227 |         static ALWAYS_INLINE bool isPositiveIntegerNumber(JSValue v) | 
| 228 |         { | 
| 229 |             // A single mask to check for the sign bit and the number tag all at once. | 
| 230 |             return (rawValue(v) & (signBit | TagTypeNumber)) == TagTypeNumber; | 
| 231 |         } | 
| 232 |          | 
| 233 |         static ALWAYS_INLINE bool isBoolean(JSValue v) | 
| 234 |         { | 
| 235 |             return (rawValue(v) & FullTagTypeMask) == FullTagTypeBool; | 
| 236 |         } | 
| 237 |          | 
| 238 |         static ALWAYS_INLINE bool isUndefinedOrNull(JSValue v) | 
| 239 |         { | 
| 240 |             // Undefined and null share the same value, bar the 'undefined' bit in the extended tag. | 
| 241 |             return (rawValue(v) & ~ExtendedTagBitUndefined) == FullTagTypeNull; | 
| 242 |         } | 
| 243 |  | 
| 244 |         static JSValue from(char); | 
| 245 |         static JSValue from(signed char); | 
| 246 |         static JSValue from(unsigned char); | 
| 247 |         static JSValue from(short); | 
| 248 |         static JSValue from(unsigned short); | 
| 249 |         static JSValue from(int); | 
| 250 |         static JSValue from(unsigned); | 
| 251 |         static JSValue from(long); | 
| 252 |         static JSValue from(unsigned long); | 
| 253 |         static JSValue from(long long); | 
| 254 |         static JSValue from(unsigned long long); | 
| 255 |         static JSValue from(double); | 
| 256 |  | 
| 257 |         static ALWAYS_INLINE bool isEitherImmediate(JSValue v1, JSValue v2) | 
| 258 |         { | 
| 259 |             return (rawValue(v: v1) | rawValue(v: v2)) & TagMask; | 
| 260 |         } | 
| 261 |  | 
| 262 |         static ALWAYS_INLINE bool areBothImmediate(JSValue v1, JSValue v2) | 
| 263 |         { | 
| 264 |             return isImmediate(v: v1) & isImmediate(v: v2); | 
| 265 |         } | 
| 266 |  | 
| 267 |         static ALWAYS_INLINE bool areBothImmediateIntegerNumbers(JSValue v1, JSValue v2) | 
| 268 |         { | 
| 269 | #if USE(JSVALUE64) | 
| 270 |             return (rawValue(v: v1) & rawValue(v: v2) & TagTypeNumber) == TagTypeNumber; | 
| 271 | #else | 
| 272 |             return rawValue(v1) & rawValue(v2) & TagTypeNumber; | 
| 273 | #endif | 
| 274 |         } | 
| 275 |  | 
| 276 |         static double toDouble(JSValue); | 
| 277 |         static bool toBoolean(JSValue); | 
| 278 |  | 
| 279 |         static bool getUInt32(JSValue, uint32_t&); | 
| 280 |         static bool getTruncatedInt32(JSValue, int32_t&); | 
| 281 |         static bool getTruncatedUInt32(JSValue, uint32_t&); | 
| 282 |  | 
| 283 |         static int32_t getTruncatedInt32(JSValue); | 
| 284 |         static uint32_t getTruncatedUInt32(JSValue); | 
| 285 |  | 
| 286 |         static JSValue trueImmediate(); | 
| 287 |         static JSValue falseImmediate(); | 
| 288 |         static JSValue undefinedImmediate(); | 
| 289 |         static JSValue nullImmediate(); | 
| 290 |         static JSValue zeroImmediate(); | 
| 291 |         static JSValue oneImmediate(); | 
| 292 |  | 
| 293 |     private: | 
| 294 | #if USE(JSVALUE64) | 
| 295 |         static const int minImmediateInt = ((-INT_MAX) - 1); | 
| 296 |         static const int maxImmediateInt = INT_MAX; | 
| 297 | #else | 
| 298 |         static const int minImmediateInt = ((-INT_MAX) - 1) >> IntegerPayloadShift; | 
| 299 |         static const int maxImmediateInt = INT_MAX >> IntegerPayloadShift; | 
| 300 | #endif | 
| 301 |         static const unsigned maxImmediateUInt = maxImmediateInt; | 
| 302 |  | 
| 303 |         static ALWAYS_INLINE JSValue makeValue(intptr_t integer) | 
| 304 |         { | 
| 305 |             return JSValue::makeImmediate(value: integer); | 
| 306 |         } | 
| 307 |  | 
| 308 |         // With USE(JSVALUE64) we want the argument to be zero extended, so the | 
| 309 |         // integer doesn't interfere with the tag bits in the upper word.  In the default encoding, | 
| 310 |         // if intptr_t id larger then int32_t we sign extend the value through the upper word. | 
| 311 | #if USE(JSVALUE64) | 
| 312 |         static ALWAYS_INLINE JSValue makeInt(uint32_t value) | 
| 313 | #else | 
| 314 |         static ALWAYS_INLINE JSValue makeInt(int32_t value) | 
| 315 | #endif | 
| 316 |         { | 
| 317 |             return makeValue(integer: (static_cast<intptr_t>(value) << IntegerPayloadShift) | TagTypeNumber); | 
| 318 |         } | 
| 319 |          | 
| 320 | #if USE(JSVALUE64) | 
| 321 |         static ALWAYS_INLINE JSValue makeDouble(double value) | 
| 322 |         { | 
| 323 |             return makeValue(integer: reinterpretDoubleToIntptr(value) + DoubleEncodeOffset); | 
| 324 |         } | 
| 325 | #endif | 
| 326 |          | 
| 327 |         static ALWAYS_INLINE JSValue makeBool(bool b) | 
| 328 |         { | 
| 329 |             return makeValue(integer: (static_cast<intptr_t>(b) << ExtendedPayloadShift) | FullTagTypeBool); | 
| 330 |         } | 
| 331 |          | 
| 332 |         static ALWAYS_INLINE JSValue makeUndefined() | 
| 333 |         { | 
| 334 |             return makeValue(integer: FullTagTypeUndefined); | 
| 335 |         } | 
| 336 |          | 
| 337 |         static ALWAYS_INLINE JSValue makeNull() | 
| 338 |         { | 
| 339 |             return makeValue(integer: FullTagTypeNull); | 
| 340 |         } | 
| 341 |  | 
| 342 |         template<typename T> | 
| 343 |         static JSValue fromNumberOutsideIntegerRange(T); | 
| 344 |  | 
| 345 | #if USE(JSVALUE64) | 
| 346 |         static ALWAYS_INLINE double doubleValue(JSValue v) | 
| 347 |         { | 
| 348 |             return reinterpretIntptrToDouble(value: rawValue(v) - DoubleEncodeOffset); | 
| 349 |         } | 
| 350 | #endif | 
| 351 |  | 
| 352 |         static ALWAYS_INLINE int32_t intValue(JSValue v) | 
| 353 |         { | 
| 354 |             return static_cast<int32_t>(rawValue(v) >> IntegerPayloadShift); | 
| 355 |         } | 
| 356 |          | 
| 357 |         static ALWAYS_INLINE uint32_t uintValue(JSValue v) | 
| 358 |         { | 
| 359 |             return static_cast<uint32_t>(rawValue(v) >> IntegerPayloadShift); | 
| 360 |         } | 
| 361 |          | 
| 362 |         static ALWAYS_INLINE bool boolValue(JSValue v) | 
| 363 |         { | 
| 364 |             return rawValue(v) & ExtendedPayloadBitBoolValue; | 
| 365 |         } | 
| 366 |          | 
| 367 |         static ALWAYS_INLINE intptr_t rawValue(JSValue v) | 
| 368 |         { | 
| 369 |             return v.immediateValue(); | 
| 370 |         } | 
| 371 |     }; | 
| 372 |  | 
| 373 |     ALWAYS_INLINE JSValue JSImmediate::trueImmediate() { return makeBool(b: true); } | 
| 374 |     ALWAYS_INLINE JSValue JSImmediate::falseImmediate() { return makeBool(b: false); } | 
| 375 |     ALWAYS_INLINE JSValue JSImmediate::undefinedImmediate() { return makeUndefined(); } | 
| 376 |     ALWAYS_INLINE JSValue JSImmediate::nullImmediate() { return makeNull(); } | 
| 377 |     ALWAYS_INLINE JSValue JSImmediate::zeroImmediate() { return makeInt(value: 0); } | 
| 378 |     ALWAYS_INLINE JSValue JSImmediate::oneImmediate() { return makeInt(value: 1); } | 
| 379 |  | 
| 380 | #if USE(JSVALUE64) | 
| 381 |     inline bool doubleToBoolean(double value) | 
| 382 |     { | 
| 383 |         return value < 0.0 || value > 0.0; | 
| 384 |     } | 
| 385 |  | 
| 386 |     ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) | 
| 387 |     { | 
| 388 |         ASSERT(isImmediate(v)); | 
| 389 |         return isNumber(v) ? isIntegerNumber(v) ? v != zeroImmediate() | 
| 390 |             : doubleToBoolean(value: doubleValue(v)) : v == trueImmediate(); | 
| 391 |     } | 
| 392 | #else | 
| 393 |     ALWAYS_INLINE bool JSImmediate::toBoolean(JSValue v) | 
| 394 |     { | 
| 395 |         ASSERT(isImmediate(v)); | 
| 396 |         return isIntegerNumber(v) ? v != zeroImmediate() : v == trueImmediate(); | 
| 397 |     } | 
| 398 | #endif | 
| 399 |  | 
| 400 |     ALWAYS_INLINE uint32_t JSImmediate::getTruncatedUInt32(JSValue v) | 
| 401 |     { | 
| 402 |         // FIXME: should probably be asserting isPositiveIntegerNumber here. | 
| 403 |         ASSERT(isIntegerNumber(v)); | 
| 404 |         return intValue(v); | 
| 405 |     } | 
| 406 |  | 
| 407 | #if USE(JSVALUE64) | 
| 408 |     template<typename T> | 
| 409 |     inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T value) | 
| 410 |     { | 
| 411 |         return makeDouble(value: static_cast<double>(value)); | 
| 412 |     } | 
| 413 | #else | 
| 414 |     template<typename T> | 
| 415 |     inline JSValue JSImmediate::fromNumberOutsideIntegerRange(T) | 
| 416 |     { | 
| 417 |         return JSValue(); | 
| 418 |     } | 
| 419 | #endif | 
| 420 |  | 
| 421 |     ALWAYS_INLINE JSValue JSImmediate::from(char i) | 
| 422 |     { | 
| 423 |         return makeInt(value: i); | 
| 424 |     } | 
| 425 |  | 
| 426 |     ALWAYS_INLINE JSValue JSImmediate::from(signed char i) | 
| 427 |     { | 
| 428 |         return makeInt(value: i); | 
| 429 |     } | 
| 430 |  | 
| 431 |     ALWAYS_INLINE JSValue JSImmediate::from(unsigned char i) | 
| 432 |     { | 
| 433 |         return makeInt(value: i); | 
| 434 |     } | 
| 435 |  | 
| 436 |     ALWAYS_INLINE JSValue JSImmediate::from(short i) | 
| 437 |     { | 
| 438 |         return makeInt(value: i); | 
| 439 |     } | 
| 440 |  | 
| 441 |     ALWAYS_INLINE JSValue JSImmediate::from(unsigned short i) | 
| 442 |     { | 
| 443 |         return makeInt(value: i); | 
| 444 |     } | 
| 445 |  | 
| 446 |     ALWAYS_INLINE JSValue JSImmediate::from(int i) | 
| 447 |     { | 
| 448 | #if !USE(JSVALUE64) | 
| 449 |         if ((i < minImmediateInt) | (i > maxImmediateInt)) | 
| 450 |             return fromNumberOutsideIntegerRange(i); | 
| 451 | #endif | 
| 452 |         return makeInt(value: i); | 
| 453 |     } | 
| 454 |  | 
| 455 |     ALWAYS_INLINE JSValue JSImmediate::from(unsigned i) | 
| 456 |     { | 
| 457 |         if (i > maxImmediateUInt) | 
| 458 |             return fromNumberOutsideIntegerRange(value: i); | 
| 459 |         return makeInt(value: i); | 
| 460 |     } | 
| 461 |  | 
| 462 |     ALWAYS_INLINE JSValue JSImmediate::from(long i) | 
| 463 |     { | 
| 464 |         if ((i < minImmediateInt) | (i > maxImmediateInt)) | 
| 465 |             return fromNumberOutsideIntegerRange(value: i); | 
| 466 |         return makeInt(value: i); | 
| 467 |     } | 
| 468 |  | 
| 469 |     ALWAYS_INLINE JSValue JSImmediate::from(unsigned long i) | 
| 470 |     { | 
| 471 |         if (i > maxImmediateUInt) | 
| 472 |             return fromNumberOutsideIntegerRange(value: i); | 
| 473 |         return makeInt(value: i); | 
| 474 |     } | 
| 475 |  | 
| 476 |     ALWAYS_INLINE JSValue JSImmediate::from(long long i) | 
| 477 |     { | 
| 478 |         if ((i < minImmediateInt) | (i > maxImmediateInt)) | 
| 479 |             return JSValue(); | 
| 480 |         return makeInt(value: static_cast<intptr_t>(i)); | 
| 481 |     } | 
| 482 |  | 
| 483 |     ALWAYS_INLINE JSValue JSImmediate::from(unsigned long long i) | 
| 484 |     { | 
| 485 |         if (i > maxImmediateUInt) | 
| 486 |             return fromNumberOutsideIntegerRange(value: i); | 
| 487 |         return makeInt(value: static_cast<intptr_t>(i)); | 
| 488 |     } | 
| 489 |  | 
| 490 |     ALWAYS_INLINE JSValue JSImmediate::from(double d) | 
| 491 |     { | 
| 492 |         const int intVal = static_cast<int>(d); | 
| 493 |  | 
| 494 |         // Check for data loss from conversion to int. | 
| 495 |         if (intVal != d || (!intVal && std::signbit(x: d))) | 
| 496 |             return fromNumberOutsideIntegerRange(value: d); | 
| 497 |  | 
| 498 |         return from(i: intVal); | 
| 499 |     } | 
| 500 |  | 
| 501 |     ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(JSValue v) | 
| 502 |     { | 
| 503 |         ASSERT(isIntegerNumber(v)); | 
| 504 |         return intValue(v); | 
| 505 |     } | 
| 506 |  | 
| 507 |     ALWAYS_INLINE double JSImmediate::toDouble(JSValue v) | 
| 508 |     { | 
| 509 |         ASSERT(isImmediate(v)); | 
| 510 |  | 
| 511 |         if (isIntegerNumber(v)) | 
| 512 |             return intValue(v); | 
| 513 |  | 
| 514 | #if USE(JSVALUE64) | 
| 515 |         if (isNumber(v)) { | 
| 516 |             ASSERT(isDouble(v)); | 
| 517 |             return doubleValue(v); | 
| 518 |         } | 
| 519 | #else | 
| 520 |         ASSERT(!isNumber(v)); | 
| 521 | #endif | 
| 522 |  | 
| 523 |         if (rawValue(v) == FullTagTypeUndefined) | 
| 524 |             return nonInlineNaN(); | 
| 525 |  | 
| 526 |         ASSERT(JSImmediate::isBoolean(v) || (v == JSImmediate::nullImmediate())); | 
| 527 |         return rawValue(v) >> ExtendedPayloadShift; | 
| 528 |     } | 
| 529 |  | 
| 530 |     ALWAYS_INLINE bool JSImmediate::getUInt32(JSValue v, uint32_t& i) | 
| 531 |     { | 
| 532 |         i = uintValue(v); | 
| 533 |         return isPositiveIntegerNumber(v); | 
| 534 |     } | 
| 535 |  | 
| 536 |     ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(JSValue v, int32_t& i) | 
| 537 |     { | 
| 538 |         i = intValue(v); | 
| 539 |         return isIntegerNumber(v); | 
| 540 |     } | 
| 541 |  | 
| 542 |     ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(JSValue v, uint32_t& i) | 
| 543 |     { | 
| 544 |         return getUInt32(v, i); | 
| 545 |     } | 
| 546 |  | 
| 547 |     inline JSValue::JSValue(JSNullTag) | 
| 548 |     { | 
| 549 |         *this = JSImmediate::nullImmediate(); | 
| 550 |     } | 
| 551 |      | 
| 552 |     inline JSValue::JSValue(JSUndefinedTag) | 
| 553 |     { | 
| 554 |         *this = JSImmediate::undefinedImmediate(); | 
| 555 |     } | 
| 556 |  | 
| 557 |     inline JSValue::JSValue(JSTrueTag) | 
| 558 |     { | 
| 559 |         *this = JSImmediate::trueImmediate(); | 
| 560 |     } | 
| 561 |  | 
| 562 |     inline JSValue::JSValue(JSFalseTag) | 
| 563 |     { | 
| 564 |         *this = JSImmediate::falseImmediate(); | 
| 565 |     } | 
| 566 |  | 
| 567 |     inline bool JSValue::isUndefinedOrNull() const | 
| 568 |     { | 
| 569 |         return JSImmediate::isUndefinedOrNull(v: asValue()); | 
| 570 |     } | 
| 571 |  | 
| 572 |     inline bool JSValue::isBoolean() const | 
| 573 |     { | 
| 574 |         return JSImmediate::isBoolean(v: asValue()); | 
| 575 |     } | 
| 576 |  | 
| 577 |     inline bool JSValue::isTrue() const | 
| 578 |     { | 
| 579 |         return asValue() == JSImmediate::trueImmediate(); | 
| 580 |     } | 
| 581 |  | 
| 582 |     inline bool JSValue::isFalse() const | 
| 583 |     { | 
| 584 |         return asValue() == JSImmediate::falseImmediate(); | 
| 585 |     } | 
| 586 |  | 
| 587 |     inline bool JSValue::getBoolean(bool& v) const | 
| 588 |     { | 
| 589 |         if (JSImmediate::isBoolean(v: asValue())) { | 
| 590 |             v = JSImmediate::toBoolean(v: asValue()); | 
| 591 |             return true; | 
| 592 |         } | 
| 593 |          | 
| 594 |         return false; | 
| 595 |     } | 
| 596 |  | 
| 597 |     inline bool JSValue::getBoolean() const | 
| 598 |     { | 
| 599 |         return asValue() == jsBoolean(b: true); | 
| 600 |     } | 
| 601 |  | 
| 602 |     inline bool JSValue::isCell() const | 
| 603 |     { | 
| 604 |         return !JSImmediate::isImmediate(v: asValue()); | 
| 605 |     } | 
| 606 |  | 
| 607 |     inline bool JSValue::isInt32() const | 
| 608 |     { | 
| 609 |         return JSImmediate::isIntegerNumber(v: asValue()); | 
| 610 |     } | 
| 611 |  | 
| 612 |     inline int32_t JSValue::asInt32() const | 
| 613 |     { | 
| 614 |         ASSERT(isInt32()); | 
| 615 |         return JSImmediate::getTruncatedInt32(v: asValue()); | 
| 616 |     } | 
| 617 |  | 
| 618 |     inline bool JSValue::isUInt32() const | 
| 619 |     { | 
| 620 |         return JSImmediate::isPositiveIntegerNumber(v: asValue()); | 
| 621 |     } | 
| 622 |  | 
| 623 |     inline uint32_t JSValue::asUInt32() const | 
| 624 |     { | 
| 625 |         ASSERT(isUInt32()); | 
| 626 |         return JSImmediate::getTruncatedUInt32(v: asValue()); | 
| 627 |     } | 
| 628 |  | 
| 629 |     class JSFastMath { | 
| 630 |     public: | 
| 631 |         static ALWAYS_INLINE bool canDoFastBitwiseOperations(JSValue v1, JSValue v2) | 
| 632 |         { | 
| 633 |             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); | 
| 634 |         } | 
| 635 |  | 
| 636 |         static ALWAYS_INLINE JSValue equal(JSValue v1, JSValue v2) | 
| 637 |         { | 
| 638 |             ASSERT(canDoFastBitwiseOperations(v1, v2)); | 
| 639 |             return jsBoolean(b: v1 == v2); | 
| 640 |         } | 
| 641 |  | 
| 642 |         static ALWAYS_INLINE JSValue notEqual(JSValue v1, JSValue v2) | 
| 643 |         { | 
| 644 |             ASSERT(canDoFastBitwiseOperations(v1, v2)); | 
| 645 |             return jsBoolean(b: v1 != v2); | 
| 646 |         } | 
| 647 |  | 
| 648 |         static ALWAYS_INLINE JSValue andImmediateNumbers(JSValue v1, JSValue v2) | 
| 649 |         { | 
| 650 |             ASSERT(canDoFastBitwiseOperations(v1, v2)); | 
| 651 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v: v1) & JSImmediate::rawValue(v: v2)); | 
| 652 |         } | 
| 653 |  | 
| 654 |         static ALWAYS_INLINE JSValue xorImmediateNumbers(JSValue v1, JSValue v2) | 
| 655 |         { | 
| 656 |             ASSERT(canDoFastBitwiseOperations(v1, v2)); | 
| 657 |             return JSImmediate::makeValue(integer: (JSImmediate::rawValue(v: v1) ^ JSImmediate::rawValue(v: v2)) | JSImmediate::TagTypeNumber); | 
| 658 |         } | 
| 659 |  | 
| 660 |         static ALWAYS_INLINE JSValue orImmediateNumbers(JSValue v1, JSValue v2) | 
| 661 |         { | 
| 662 |             ASSERT(canDoFastBitwiseOperations(v1, v2)); | 
| 663 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v: v1) | JSImmediate::rawValue(v: v2)); | 
| 664 |         } | 
| 665 |  | 
| 666 |         static ALWAYS_INLINE bool canDoFastRshift(JSValue v1, JSValue v2) | 
| 667 |         { | 
| 668 |             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2); | 
| 669 |         } | 
| 670 |  | 
| 671 |         static ALWAYS_INLINE bool canDoFastUrshift(JSValue v1, JSValue v2) | 
| 672 |         { | 
| 673 |             return JSImmediate::areBothImmediateIntegerNumbers(v1, v2) && !(JSImmediate::rawValue(v: v1) & JSImmediate::signBit); | 
| 674 |         } | 
| 675 |  | 
| 676 |         static ALWAYS_INLINE JSValue rightShiftImmediateNumbers(JSValue val, JSValue shift) | 
| 677 |         { | 
| 678 |             ASSERT(canDoFastRshift(val, shift) || canDoFastUrshift(val, shift)); | 
| 679 | #if USE(JSVALUE64) | 
| 680 |             return JSImmediate::makeValue(integer: static_cast<intptr_t>(static_cast<uint32_t>(static_cast<int32_t>(JSImmediate::rawValue(v: val)) >> ((JSImmediate::rawValue(v: shift) >> JSImmediate::IntegerPayloadShift) & 0x1f))) | JSImmediate::TagTypeNumber); | 
| 681 | #else | 
| 682 |             return JSImmediate::makeValue((JSImmediate::rawValue(val) >> ((JSImmediate::rawValue(shift) >> JSImmediate::IntegerPayloadShift) & 0x1f)) | JSImmediate::TagTypeNumber); | 
| 683 | #endif | 
| 684 |         } | 
| 685 |  | 
| 686 |         static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v) | 
| 687 |         { | 
| 688 |             // Number is non-negative and an operation involving two of these can't overflow. | 
| 689 |             // Checking for allowed negative numbers takes more time than it's worth on SunSpider. | 
| 690 |             return (JSImmediate::rawValue(v) & (JSImmediate::TagTypeNumber + (JSImmediate::signBit | (JSImmediate::signBit >> 1)))) == JSImmediate::TagTypeNumber; | 
| 691 |         } | 
| 692 |  | 
| 693 |         static ALWAYS_INLINE bool canDoFastAdditiveOperations(JSValue v1, JSValue v2) | 
| 694 |         { | 
| 695 |             // Number is non-negative and an operation involving two of these can't overflow. | 
| 696 |             // Checking for allowed negative numbers takes more time than it's worth on SunSpider. | 
| 697 |             return canDoFastAdditiveOperations(v: v1) && canDoFastAdditiveOperations(v: v2); | 
| 698 |         } | 
| 699 |  | 
| 700 |         static ALWAYS_INLINE JSValue addImmediateNumbers(JSValue v1, JSValue v2) | 
| 701 |         { | 
| 702 |             ASSERT(canDoFastAdditiveOperations(v1, v2)); | 
| 703 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v: v1) + JSImmediate::rawValue(v: v2) - JSImmediate::TagTypeNumber); | 
| 704 |         } | 
| 705 |  | 
| 706 |         static ALWAYS_INLINE JSValue subImmediateNumbers(JSValue v1, JSValue v2) | 
| 707 |         { | 
| 708 |             ASSERT(canDoFastAdditiveOperations(v1, v2)); | 
| 709 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v: v1) - JSImmediate::rawValue(v: v2) + JSImmediate::TagTypeNumber); | 
| 710 |         } | 
| 711 |  | 
| 712 |         static ALWAYS_INLINE JSValue incImmediateNumber(JSValue v) | 
| 713 |         { | 
| 714 |             ASSERT(canDoFastAdditiveOperations(v)); | 
| 715 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v) + (1 << JSImmediate::IntegerPayloadShift)); | 
| 716 |         } | 
| 717 |  | 
| 718 |         static ALWAYS_INLINE JSValue decImmediateNumber(JSValue v) | 
| 719 |         { | 
| 720 |             ASSERT(canDoFastAdditiveOperations(v)); | 
| 721 |             return JSImmediate::makeValue(integer: JSImmediate::rawValue(v) - (1 << JSImmediate::IntegerPayloadShift)); | 
| 722 |         } | 
| 723 |     }; | 
| 724 |  | 
| 725 | } // namespace JSC | 
| 726 |  | 
| 727 | #endif // !USE(JSVALUE32_64) | 
| 728 |  | 
| 729 | #endif // JSImmediate_h | 
| 730 |  |