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
42namespace 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

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSImmediate.h