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