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