1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef JSValueInlineMethods_h
27#define JSValueInlineMethods_h
28
29#include "JSValue.h"
30
31namespace JSC {
32
33    ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
34    {
35        if (isInt32())
36            return asInt32();
37        return JSC::toInt32(toNumber(exec));
38    }
39
40    inline uint32_t JSValue::toUInt32(ExecState* exec) const
41    {
42        // See comment on JSC::toUInt32, above.
43        return toInt32(exec);
44    }
45
46    inline bool JSValue::isUInt32() const
47    {
48        return isInt32() && asInt32() >= 0;
49    }
50
51    inline uint32_t JSValue::asUInt32() const
52    {
53        ASSERT(isUInt32());
54        return asInt32();
55    }
56
57    inline double JSValue::uncheckedGetNumber() const
58    {
59        ASSERT(isNumber());
60        return isInt32() ? asInt32() : asDouble();
61    }
62
63    ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
64    {
65        return isNumber() ? asValue() : jsNumber(this->toNumber(exec));
66    }
67
68    inline JSValue jsNaN()
69    {
70        return JSValue(nonInlineNaN());
71    }
72
73    inline bool JSValue::getNumber(double& result) const
74    {
75        if (isInt32()) {
76            result = asInt32();
77            return true;
78        }
79        if (isDouble()) {
80            result = asDouble();
81            return true;
82        }
83        return false;
84    }
85
86    inline bool JSValue::getBoolean(bool& v) const
87    {
88        if (isTrue()) {
89            v = true;
90            return true;
91        }
92        if (isFalse()) {
93            v = false;
94            return true;
95        }
96
97        return false;
98    }
99
100    inline JSValue::JSValue(char i)
101    {
102        *this = JSValue(static_cast<int32_t>(i));
103    }
104
105    inline JSValue::JSValue(unsigned char i)
106    {
107        *this = JSValue(static_cast<int32_t>(i));
108    }
109
110    inline JSValue::JSValue(short i)
111    {
112        *this = JSValue(static_cast<int32_t>(i));
113    }
114
115    inline JSValue::JSValue(unsigned short i)
116    {
117        *this = JSValue(static_cast<int32_t>(i));
118    }
119
120    inline JSValue::JSValue(unsigned i)
121    {
122        if (static_cast<int32_t>(i) < 0) {
123            *this = JSValue(EncodeAsDouble, static_cast<double>(i));
124            return;
125        }
126        *this = JSValue(static_cast<int32_t>(i));
127    }
128
129    inline JSValue::JSValue(long i)
130    {
131        if (static_cast<int32_t>(i) != i) {
132            *this = JSValue(EncodeAsDouble, static_cast<double>(i));
133            return;
134        }
135        *this = JSValue(static_cast<int32_t>(i));
136    }
137
138    inline JSValue::JSValue(unsigned long i)
139    {
140        if (static_cast<uint32_t>(i) != i) {
141            *this = JSValue(EncodeAsDouble, static_cast<double>(i));
142            return;
143        }
144        *this = JSValue(static_cast<uint32_t>(i));
145    }
146
147    inline JSValue::JSValue(long long i)
148    {
149        if (static_cast<int32_t>(i) != i) {
150            *this = JSValue(EncodeAsDouble, static_cast<double>(i));
151            return;
152        }
153        *this = JSValue(static_cast<int32_t>(i));
154    }
155
156    inline JSValue::JSValue(unsigned long long i)
157    {
158        if (static_cast<uint32_t>(i) != i) {
159            *this = JSValue(EncodeAsDouble, static_cast<double>(i));
160            return;
161        }
162        *this = JSValue(static_cast<uint32_t>(i));
163    }
164
165    inline JSValue::JSValue(double d)
166    {
167        const int32_t asInt32 = static_cast<int32_t>(d);
168        if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
169            *this = JSValue(EncodeAsDouble, d);
170            return;
171        }
172        *this = JSValue(static_cast<int32_t>(d));
173    }
174
175#if USE(JSVALUE32_64)
176    inline EncodedJSValue JSValue::encode(JSValue value)
177    {
178        return value.u.asInt64;
179    }
180
181    inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
182    {
183        JSValue v;
184        v.u.asInt64 = encodedJSValue;
185        return v;
186    }
187
188    inline JSValue::JSValue()
189    {
190        u.asBits.tag = EmptyValueTag;
191        u.asBits.payload = 0;
192    }
193
194    inline JSValue::JSValue(JSNullTag)
195    {
196        u.asBits.tag = NullTag;
197        u.asBits.payload = 0;
198    }
199
200    inline JSValue::JSValue(JSUndefinedTag)
201    {
202        u.asBits.tag = UndefinedTag;
203        u.asBits.payload = 0;
204    }
205
206    inline JSValue::JSValue(JSTrueTag)
207    {
208        u.asBits.tag = BooleanTag;
209        u.asBits.payload = 1;
210    }
211
212    inline JSValue::JSValue(JSFalseTag)
213    {
214        u.asBits.tag = BooleanTag;
215        u.asBits.payload = 0;
216    }
217
218    inline JSValue::JSValue(HashTableDeletedValueTag)
219    {
220        u.asBits.tag = DeletedValueTag;
221        u.asBits.payload = 0;
222    }
223
224    inline JSValue::JSValue(JSCell* ptr)
225    {
226        if (ptr)
227            u.asBits.tag = CellTag;
228        else
229            u.asBits.tag = EmptyValueTag;
230        u.asBits.payload = reinterpret_cast<int32_t>(ptr);
231#if ENABLE(JSC_ZOMBIES)
232        ASSERT(!isZombie());
233#endif
234    }
235
236    inline JSValue::JSValue(const JSCell* ptr)
237    {
238        if (ptr)
239            u.asBits.tag = CellTag;
240        else
241            u.asBits.tag = EmptyValueTag;
242        u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
243#if ENABLE(JSC_ZOMBIES)
244        ASSERT(!isZombie());
245#endif
246    }
247
248    inline JSValue::operator bool() const
249    {
250        ASSERT(tag() != DeletedValueTag);
251        return tag() != EmptyValueTag;
252    }
253
254    inline bool JSValue::operator==(const JSValue& other) const
255    {
256        return u.asInt64 == other.u.asInt64;
257    }
258
259    inline bool JSValue::operator!=(const JSValue& other) const
260    {
261        return u.asInt64 != other.u.asInt64;
262    }
263
264    inline bool JSValue::isUndefined() const
265    {
266        return tag() == UndefinedTag;
267    }
268
269    inline bool JSValue::isNull() const
270    {
271        return tag() == NullTag;
272    }
273
274    inline bool JSValue::isUndefinedOrNull() const
275    {
276        return isUndefined() || isNull();
277    }
278
279    inline bool JSValue::isCell() const
280    {
281        return tag() == CellTag;
282    }
283
284    inline bool JSValue::isInt32() const
285    {
286        return tag() == Int32Tag;
287    }
288
289    inline bool JSValue::isDouble() const
290    {
291        return tag() < LowestTag;
292    }
293
294    inline bool JSValue::isTrue() const
295    {
296        return tag() == BooleanTag && payload();
297    }
298
299    inline bool JSValue::isFalse() const
300    {
301        return tag() == BooleanTag && !payload();
302    }
303
304    inline uint32_t JSValue::tag() const
305    {
306        return u.asBits.tag;
307    }
308
309    inline int32_t JSValue::payload() const
310    {
311        return u.asBits.payload;
312    }
313
314    inline int32_t JSValue::asInt32() const
315    {
316        ASSERT(isInt32());
317        return u.asBits.payload;
318    }
319
320    inline double JSValue::asDouble() const
321    {
322        ASSERT(isDouble());
323        return u.asDouble;
324    }
325
326    ALWAYS_INLINE JSCell* JSValue::asCell() const
327    {
328        ASSERT(isCell());
329        return reinterpret_cast<JSCell*>(u.asBits.payload);
330    }
331
332    ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
333    {
334        u.asDouble = d;
335    }
336
337    inline JSValue::JSValue(int i)
338    {
339        u.asBits.tag = Int32Tag;
340        u.asBits.payload = i;
341    }
342
343    inline bool JSValue::isNumber() const
344    {
345        return isInt32() || isDouble();
346    }
347
348    inline bool JSValue::isBoolean() const
349    {
350        return isTrue() || isFalse();
351    }
352
353    inline bool JSValue::getBoolean() const
354    {
355        ASSERT(isBoolean());
356        return payload();
357    }
358
359#else // USE(JSVALUE32_64)
360
361    // JSValue member functions.
362    inline EncodedJSValue JSValue::encode(JSValue value)
363    {
364        return value.u.ptr;
365    }
366
367    inline JSValue JSValue::decode(EncodedJSValue ptr)
368    {
369        return JSValue(reinterpret_cast<JSCell*>(ptr));
370    }
371
372    // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
373    inline JSValue::JSValue()
374    {
375        u.asInt64 = ValueEmpty;
376    }
377
378    // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
379    inline JSValue::JSValue(HashTableDeletedValueTag)
380    {
381        u.asInt64 = ValueDeleted;
382    }
383
384    inline JSValue::JSValue(JSCell* ptr)
385    {
386        u.ptr = ptr;
387#if ENABLE(JSC_ZOMBIES)
388        ASSERT(!isZombie());
389#endif
390    }
391
392    inline JSValue::JSValue(const JSCell* ptr)
393    {
394        u.ptr = const_cast<JSCell*>(ptr);
395#if ENABLE(JSC_ZOMBIES)
396        ASSERT(!isZombie());
397#endif
398    }
399
400    inline JSValue::operator bool() const
401    {
402        return u.ptr;
403    }
404
405    inline bool JSValue::operator==(const JSValue& other) const
406    {
407        return u.ptr == other.u.ptr;
408    }
409
410    inline bool JSValue::operator!=(const JSValue& other) const
411    {
412        return u.ptr != other.u.ptr;
413    }
414
415    inline bool JSValue::isUndefined() const
416    {
417        return asValue() == jsUndefined();
418    }
419
420    inline bool JSValue::isNull() const
421    {
422        return asValue() == jsNull();
423    }
424
425    inline bool JSValue::isTrue() const
426    {
427        return asValue() == JSValue(JSTrue);
428    }
429
430    inline bool JSValue::isFalse() const
431    {
432        return asValue() == JSValue(JSFalse);
433    }
434
435    inline bool JSValue::getBoolean() const
436    {
437        ASSERT(asValue() == jsBoolean(true) || asValue() == jsBoolean(false));
438        return asValue() == jsBoolean(true);
439    }
440
441    inline int32_t JSValue::asInt32() const
442    {
443        ASSERT(isInt32());
444        return static_cast<int32_t>(u.asInt64);
445    }
446
447    inline bool JSValue::isDouble() const
448    {
449        return isNumber() && !isInt32();
450    }
451
452    inline JSValue::JSValue(JSNullTag)
453    {
454        u.asInt64 = ValueNull;
455    }
456
457    inline JSValue::JSValue(JSUndefinedTag)
458    {
459        u.asInt64 = ValueUndefined;
460    }
461
462    inline JSValue::JSValue(JSTrueTag)
463    {
464        u.asInt64 = ValueTrue;
465    }
466
467    inline JSValue::JSValue(JSFalseTag)
468    {
469        u.asInt64 = ValueFalse;
470    }
471
472    inline bool JSValue::isUndefinedOrNull() const
473    {
474        // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
475        return (u.asInt64 & ~TagBitUndefined) == ValueNull;
476    }
477
478    inline bool JSValue::isBoolean() const
479    {
480        return (u.asInt64 & ~1) == ValueFalse;
481    }
482
483    inline bool JSValue::isCell() const
484    {
485        return !(u.asInt64 & TagMask);
486    }
487
488    inline bool JSValue::isInt32() const
489    {
490        return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
491    }
492
493    inline intptr_t reinterpretDoubleToIntptr(double value)
494    {
495        return bitwise_cast<intptr_t>(value);
496    }
497    inline double reinterpretIntptrToDouble(intptr_t value)
498    {
499        return bitwise_cast<double>(value);
500    }
501
502    ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
503    {
504        u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset;
505    }
506
507    inline JSValue::JSValue(int i)
508    {
509        u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
510    }
511
512    inline double JSValue::asDouble() const
513    {
514        return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset);
515    }
516
517    inline bool JSValue::isNumber() const
518    {
519        return u.asInt64 & TagTypeNumber;
520    }
521
522    ALWAYS_INLINE JSCell* JSValue::asCell() const
523    {
524        ASSERT(isCell());
525        return u.ptr;
526    }
527
528#endif // USE(JSVALUE64)
529
530} // namespace JSC
531
532#endif // JSValueInlineMethods_h
533