cad966281db7cd7b0e667a69b90d2dbc4d8f7ce6
[WebKit-https.git] / JavaScriptCore / runtime / JSValue.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef JSValue_h
24 #define JSValue_h
25
26 #include <math.h>
27 #include <stddef.h> // for size_t
28 #include <stdint.h>
29 #include <wtf/AlwaysInline.h>
30 #include <wtf/Assertions.h>
31 #include <wtf/HashTraits.h>
32 #include <wtf/MathExtras.h>
33
34 namespace JSC {
35
36     class ExecState;
37     class Identifier;
38     class JSCell;
39     class JSGlobalData;
40     class JSImmediate;
41     class JSObject;
42     class JSString;
43     class PropertySlot;
44     class PutPropertySlot;
45     class UString;
46
47     struct ClassInfo;
48     struct Instruction;
49
50     enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
51
52 #if USE(JSVALUE32_64)
53     typedef int64_t EncodedJSValue;
54 #else
55     typedef void* EncodedJSValue;
56 #endif
57
58     double nonInlineNaN();
59
60     // This implements ToInt32, defined in ECMA-262 9.5.
61     int32_t toInt32(double);
62
63     // This implements ToUInt32, defined in ECMA-262 9.6.
64     inline uint32_t toUInt32(double number)
65     {
66         // As commented in the spec, the operation of ToInt32 and ToUint32 only differ
67         // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6.
68         return toInt32(number);
69     }
70
71     class JSValue {
72         friend class JSImmediate;
73         friend struct EncodedJSValueHashTraits;
74         friend class JIT;
75         friend class JITStubs;
76         friend class JITStubCall;
77         friend class JSInterfaceJIT;
78         friend class SpecializedThunkJIT;
79
80     public:
81         static EncodedJSValue encode(JSValue value);
82         static JSValue decode(EncodedJSValue ptr);
83 #if USE(JSVALUE64)
84     private:
85         static JSValue makeImmediate(intptr_t value);
86         intptr_t immediateValue();
87     public:
88 #endif
89         enum JSNullTag { JSNull };
90         enum JSUndefinedTag { JSUndefined };
91         enum JSTrueTag { JSTrue };
92         enum JSFalseTag { JSFalse };
93         enum EncodeAsDoubleTag { EncodeAsDouble };
94
95         JSValue();
96         JSValue(JSNullTag);
97         JSValue(JSUndefinedTag);
98         JSValue(JSTrueTag);
99         JSValue(JSFalseTag);
100         JSValue(JSCell* ptr);
101         JSValue(const JSCell* ptr);
102
103         // Numbers
104         JSValue(EncodeAsDoubleTag, double);
105         explicit JSValue(double);
106         explicit JSValue(char);
107         explicit JSValue(unsigned char);
108         explicit JSValue(short);
109         explicit JSValue(unsigned short);
110         explicit JSValue(int);
111         explicit JSValue(unsigned);
112         explicit JSValue(long);
113         explicit JSValue(unsigned long);
114         explicit JSValue(long long);
115         explicit JSValue(unsigned long long);
116
117         operator bool() const;
118         bool operator==(const JSValue& other) const;
119         bool operator!=(const JSValue& other) const;
120
121         bool isInt32() const;
122         bool isUInt32() const;
123         bool isDouble() const;
124         bool isTrue() const;
125         bool isFalse() const;
126
127         int32_t asInt32() const;
128         uint32_t asUInt32() const;
129         double asDouble() const;
130
131         // Querying the type.
132         bool isUndefined() const;
133         bool isNull() const;
134         bool isUndefinedOrNull() const;
135         bool isBoolean() const;
136         bool isNumber() const;
137         bool isString() const;
138         bool isGetterSetter() const;
139         bool isObject() const;
140         bool inherits(const ClassInfo*) const;
141         
142         // Extracting the value.
143         bool getBoolean(bool&) const;
144         bool getBoolean() const; // false if not a boolean
145         bool getNumber(double&) const;
146         double uncheckedGetNumber() const;
147         bool getString(ExecState* exec, UString&) const;
148         UString getString(ExecState* exec) const; // null string if not a string
149         JSObject* getObject() const; // 0 if not an object
150
151         // Extracting integer values.
152         bool getUInt32(uint32_t&) const;
153         
154         // Basic conversions.
155         JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
156         bool getPrimitiveNumber(ExecState*, double& number, JSValue&);
157
158         bool toBoolean(ExecState*) const;
159
160         // toNumber conversion is expected to be side effect free if an exception has
161         // been set in the ExecState already.
162         double toNumber(ExecState*) const;
163         JSValue toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number.
164         UString toString(ExecState*) const;
165         UString toPrimitiveString(ExecState*) const;
166         JSObject* toObject(ExecState*) const;
167
168         // Integer conversions.
169         double toInteger(ExecState*) const;
170         double toIntegerPreserveNaN(ExecState*) const;
171         int32_t toInt32(ExecState*) const;
172         uint32_t toUInt32(ExecState*) const;
173
174 #if ENABLE(JSC_ZOMBIES)
175         bool isZombie() const;
176 #endif
177
178         // Floating point conversions (this is a convenience method for webcore;
179         // signle precision float is not a representation used in JS or JSC).
180         float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); }
181
182         // Object operations, with the toObject operation included.
183         JSValue get(ExecState*, const Identifier& propertyName) const;
184         JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const;
185         JSValue get(ExecState*, unsigned propertyName) const;
186         JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
187         void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
188         void putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
189         void put(ExecState*, unsigned propertyName, JSValue);
190
191         bool needsThisConversion() const;
192         JSObject* toThisObject(ExecState*) const;
193         JSValue toStrictThisObject(ExecState*) const;
194         UString toThisString(ExecState*) const;
195         JSString* toThisJSString(ExecState*) const;
196
197         static bool equal(ExecState* exec, JSValue v1, JSValue v2);
198         static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2);
199         static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
200         static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2);
201         static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2);
202         static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
203
204         JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object
205
206         bool isCell() const;
207         JSCell* asCell() const;
208         bool isValidCallee();
209
210 #ifndef NDEBUG
211         char* description();
212 #endif
213
214     private:
215         enum HashTableDeletedValueTag { HashTableDeletedValue };
216         JSValue(HashTableDeletedValueTag);
217
218         inline const JSValue asValue() const { return *this; }
219         JSObject* toObjectSlowCase(ExecState*) const;
220         JSObject* toThisObjectSlowCase(ExecState*) const;
221
222         JSObject* synthesizePrototype(ExecState*) const;
223         JSObject* synthesizeObject(ExecState*) const;
224
225 #if USE(JSVALUE32_64)
226         enum { NullTag =         0xffffffff };
227         enum { UndefinedTag =    0xfffffffe };
228         enum { Int32Tag =        0xfffffffd };
229         enum { CellTag =         0xfffffffc };
230         enum { TrueTag =         0xfffffffb };
231         enum { FalseTag =        0xfffffffa };
232         enum { EmptyValueTag =   0xfffffff9 };
233         enum { DeletedValueTag = 0xfffffff8 };
234         
235         enum { LowestTag =  DeletedValueTag };
236         
237         uint32_t tag() const;
238         int32_t payload() const;
239
240         union {
241             EncodedJSValue asEncodedJSValue;
242             double asDouble;
243 #if CPU(BIG_ENDIAN)
244             struct {
245                 int32_t tag;
246                 int32_t payload;
247             } asBits;
248 #else
249             struct {
250                 int32_t payload;
251                 int32_t tag;
252             } asBits;
253 #endif
254         } u;
255 #else // USE(JSVALUE32_64)
256         JSCell* m_ptr;
257 #endif // USE(JSVALUE32_64)
258     };
259
260 #if USE(JSVALUE32_64)
261     typedef IntHash<EncodedJSValue> EncodedJSValueHash;
262
263     struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
264         static const bool emptyValueIsZero = false;
265         static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); }
266         static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
267         static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
268     };
269 #else
270     typedef PtrHash<EncodedJSValue> EncodedJSValueHash;
271
272     struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
273         static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
274         static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
275     };
276 #endif
277
278     // Stand-alone helper functions.
279     inline JSValue jsNull()
280     {
281         return JSValue(JSValue::JSNull);
282     }
283
284     inline JSValue jsUndefined()
285     {
286         return JSValue(JSValue::JSUndefined);
287     }
288
289     inline JSValue jsBoolean(bool b)
290     {
291         return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
292     }
293
294     ALWAYS_INLINE JSValue jsDoubleNumber(double d)
295     {
296         return JSValue(JSValue::EncodeAsDouble, d);
297     }
298
299     ALWAYS_INLINE JSValue jsNumber(double d)
300     {
301         return JSValue(d);
302     }
303
304     ALWAYS_INLINE JSValue jsNumber(char i)
305     {
306         return JSValue(i);
307     }
308
309     ALWAYS_INLINE JSValue jsNumber(unsigned char i)
310     {
311         return JSValue(i);
312     }
313
314     ALWAYS_INLINE JSValue jsNumber(short i)
315     {
316         return JSValue(i);
317     }
318
319     ALWAYS_INLINE JSValue jsNumber(unsigned short i)
320     {
321         return JSValue(i);
322     }
323
324     ALWAYS_INLINE JSValue jsNumber(int i)
325     {
326         return JSValue(i);
327     }
328
329     ALWAYS_INLINE JSValue jsNumber(unsigned i)
330     {
331         return JSValue(i);
332     }
333
334     ALWAYS_INLINE JSValue jsNumber(long i)
335     {
336         return JSValue(i);
337     }
338
339     ALWAYS_INLINE JSValue jsNumber(unsigned long i)
340     {
341         return JSValue(i);
342     }
343
344     ALWAYS_INLINE JSValue jsNumber(long long i)
345     {
346         return JSValue(i);
347     }
348
349     ALWAYS_INLINE JSValue jsNumber(unsigned long long i)
350     {
351         return JSValue(i);
352     }
353
354     inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); }
355     inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; }
356
357     inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
358     inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
359
360     ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
361     {
362         if (isInt32())
363             return asInt32();
364         return JSC::toInt32(toNumber(exec));
365     }
366
367     inline uint32_t JSValue::toUInt32(ExecState* exec) const
368     {
369         // See comment on JSC::toUInt32, above.
370         return toInt32(exec);
371     }
372
373 #if USE(JSVALUE32_64)
374     inline JSValue jsNaN()
375     {
376         return JSValue(nonInlineNaN());
377     }
378
379     // JSValue member functions.
380     inline EncodedJSValue JSValue::encode(JSValue value)
381     {
382         return value.u.asEncodedJSValue;
383     }
384
385     inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
386     {
387         JSValue v;
388         v.u.asEncodedJSValue = encodedJSValue;
389 #if ENABLE(JSC_ZOMBIES)
390         ASSERT(!v.isZombie());
391 #endif
392         return v;
393     }
394
395     inline JSValue::JSValue()
396     {
397         u.asBits.tag = EmptyValueTag;
398         u.asBits.payload = 0;
399     }
400
401     inline JSValue::JSValue(JSNullTag)
402     {
403         u.asBits.tag = NullTag;
404         u.asBits.payload = 0;
405     }
406     
407     inline JSValue::JSValue(JSUndefinedTag)
408     {
409         u.asBits.tag = UndefinedTag;
410         u.asBits.payload = 0;
411     }
412     
413     inline JSValue::JSValue(JSTrueTag)
414     {
415         u.asBits.tag = TrueTag;
416         u.asBits.payload = 0;
417     }
418     
419     inline JSValue::JSValue(JSFalseTag)
420     {
421         u.asBits.tag = FalseTag;
422         u.asBits.payload = 0;
423     }
424
425     inline JSValue::JSValue(HashTableDeletedValueTag)
426     {
427         u.asBits.tag = DeletedValueTag;
428         u.asBits.payload = 0;
429     }
430
431     inline JSValue::JSValue(JSCell* ptr)
432     {
433         if (ptr)
434             u.asBits.tag = CellTag;
435         else
436             u.asBits.tag = EmptyValueTag;
437         u.asBits.payload = reinterpret_cast<int32_t>(ptr);
438 #if ENABLE(JSC_ZOMBIES)
439         ASSERT(!isZombie());
440 #endif
441     }
442
443     inline JSValue::JSValue(const JSCell* ptr)
444     {
445         if (ptr)
446             u.asBits.tag = CellTag;
447         else
448             u.asBits.tag = EmptyValueTag;
449         u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
450 #if ENABLE(JSC_ZOMBIES)
451         ASSERT(!isZombie());
452 #endif
453     }
454
455     inline JSValue::operator bool() const
456     {
457         ASSERT(tag() != DeletedValueTag);
458         return tag() != EmptyValueTag;
459     }
460
461     inline bool JSValue::operator==(const JSValue& other) const
462     {
463         return u.asEncodedJSValue == other.u.asEncodedJSValue;
464     }
465
466     inline bool JSValue::operator!=(const JSValue& other) const
467     {
468         return u.asEncodedJSValue != other.u.asEncodedJSValue;
469     }
470
471     inline bool JSValue::isUndefined() const
472     {
473         return tag() == UndefinedTag;
474     }
475
476     inline bool JSValue::isNull() const
477     {
478         return tag() == NullTag;
479     }
480
481     inline bool JSValue::isUndefinedOrNull() const
482     {
483         return isUndefined() || isNull();
484     }
485
486     inline bool JSValue::isCell() const
487     {
488         return tag() == CellTag;
489     }
490
491     inline bool JSValue::isInt32() const
492     {
493         return tag() == Int32Tag;
494     }
495
496     inline bool JSValue::isUInt32() const
497     {
498         return tag() == Int32Tag && asInt32() > -1;
499     }
500
501     inline bool JSValue::isDouble() const
502     {
503         return tag() < LowestTag;
504     }
505
506     inline bool JSValue::isTrue() const
507     {
508         return tag() == TrueTag;
509     }
510
511     inline bool JSValue::isFalse() const
512     {
513         return tag() == FalseTag;
514     }
515
516     inline uint32_t JSValue::tag() const
517     {
518         return u.asBits.tag;
519     }
520     
521     inline int32_t JSValue::payload() const
522     {
523         return u.asBits.payload;
524     }
525     
526     inline int32_t JSValue::asInt32() const
527     {
528         ASSERT(isInt32());
529         return u.asBits.payload;
530     }
531     
532     inline uint32_t JSValue::asUInt32() const
533     {
534         ASSERT(isUInt32());
535         return u.asBits.payload;
536     }
537     
538     inline double JSValue::asDouble() const
539     {
540         ASSERT(isDouble());
541         return u.asDouble;
542     }
543     
544     ALWAYS_INLINE JSCell* JSValue::asCell() const
545     {
546         ASSERT(isCell());
547         return reinterpret_cast<JSCell*>(u.asBits.payload);
548     }
549
550     ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
551     {
552         u.asDouble = d;
553     }
554
555     inline JSValue::JSValue(double d)
556     {
557         const int32_t asInt32 = static_cast<int32_t>(d);
558         if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
559             u.asDouble = d;
560             return;
561         }
562         *this = JSValue(static_cast<int32_t>(d));
563     }
564
565     inline JSValue::JSValue(char i)
566     {
567         *this = JSValue(static_cast<int32_t>(i));
568     }
569
570     inline JSValue::JSValue(unsigned char i)
571     {
572         *this = JSValue(static_cast<int32_t>(i));
573     }
574
575     inline JSValue::JSValue(short i)
576     {
577         *this = JSValue(static_cast<int32_t>(i));
578     }
579
580     inline JSValue::JSValue(unsigned short i)
581     {
582         *this = JSValue(static_cast<int32_t>(i));
583     }
584
585     inline JSValue::JSValue(int i)
586     {
587         u.asBits.tag = Int32Tag;
588         u.asBits.payload = i;
589     }
590
591     inline JSValue::JSValue(unsigned i)
592     {
593         if (static_cast<int32_t>(i) < 0) {
594             *this = JSValue(static_cast<double>(i));
595             return;
596         }
597         *this = JSValue(static_cast<int32_t>(i));
598     }
599
600     inline JSValue::JSValue(long i)
601     {
602         if (static_cast<int32_t>(i) != i) {
603             *this = JSValue(static_cast<double>(i));
604             return;
605         }
606         *this = JSValue(static_cast<int32_t>(i));
607     }
608
609     inline JSValue::JSValue(unsigned long i)
610     {
611         if (static_cast<uint32_t>(i) != i) {
612             *this = JSValue(static_cast<double>(i));
613             return;
614         }
615         *this = JSValue(static_cast<uint32_t>(i));
616     }
617
618     inline JSValue::JSValue(long long i)
619     {
620         if (static_cast<int32_t>(i) != i) {
621             *this = JSValue(static_cast<double>(i));
622             return;
623         }
624         *this = JSValue(static_cast<int32_t>(i));
625     }
626
627     inline JSValue::JSValue(unsigned long long i)
628     {
629         if (static_cast<uint32_t>(i) != i) {
630             *this = JSValue(static_cast<double>(i));
631             return;
632         }
633         *this = JSValue(static_cast<uint32_t>(i));
634     }
635
636     inline bool JSValue::isNumber() const
637     {
638         return isInt32() || isDouble();
639     }
640
641     inline bool JSValue::isBoolean() const
642     {
643         return isTrue() || isFalse();
644     }
645
646     inline bool JSValue::getBoolean(bool& v) const
647     {
648         if (isTrue()) {
649             v = true;
650             return true;
651         }
652         if (isFalse()) {
653             v = false;
654             return true;
655         }
656         
657         return false;
658     }
659
660     inline bool JSValue::getBoolean() const
661     {
662         ASSERT(isBoolean());
663         return tag() == TrueTag;
664     }
665
666     inline double JSValue::uncheckedGetNumber() const
667     {
668         ASSERT(isNumber());
669         return isInt32() ? asInt32() : asDouble();
670     }
671
672     ALWAYS_INLINE JSValue JSValue::toJSNumber(ExecState* exec) const
673     {
674         return isNumber() ? asValue() : jsNumber(this->toNumber(exec));
675     }
676
677     inline bool JSValue::getNumber(double& result) const
678     {
679         if (isInt32()) {
680             result = asInt32();
681             return true;
682         }
683         if (isDouble()) {
684             result = asDouble();
685             return true;
686         }
687         return false;
688     }
689
690 #else // USE(JSVALUE32_64)
691
692     // JSValue member functions.
693     inline EncodedJSValue JSValue::encode(JSValue value)
694     {
695         return reinterpret_cast<EncodedJSValue>(value.m_ptr);
696     }
697
698     inline JSValue JSValue::decode(EncodedJSValue ptr)
699     {
700         return JSValue(reinterpret_cast<JSCell*>(ptr));
701     }
702
703     inline JSValue JSValue::makeImmediate(intptr_t value)
704     {
705         return JSValue(reinterpret_cast<JSCell*>(value));
706     }
707
708     inline intptr_t JSValue::immediateValue()
709     {
710         return reinterpret_cast<intptr_t>(m_ptr);
711     }
712     
713     // 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.
714     inline JSValue::JSValue()
715         : m_ptr(0)
716     {
717     }
718
719     // 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.
720     inline JSValue::JSValue(HashTableDeletedValueTag)
721         : m_ptr(reinterpret_cast<JSCell*>(0x4))
722     {
723     }
724
725     inline JSValue::JSValue(JSCell* ptr)
726         : m_ptr(ptr)
727     {
728 #if ENABLE(JSC_ZOMBIES)
729         ASSERT(!isZombie());
730 #endif
731     }
732
733     inline JSValue::JSValue(const JSCell* ptr)
734         : m_ptr(const_cast<JSCell*>(ptr))
735     {
736 #if ENABLE(JSC_ZOMBIES)
737         ASSERT(!isZombie());
738 #endif
739     }
740
741     inline JSValue::operator bool() const
742     {
743         return m_ptr;
744     }
745
746     inline bool JSValue::operator==(const JSValue& other) const
747     {
748         return m_ptr == other.m_ptr;
749     }
750
751     inline bool JSValue::operator!=(const JSValue& other) const
752     {
753         return m_ptr != other.m_ptr;
754     }
755
756     inline bool JSValue::isUndefined() const
757     {
758         return asValue() == jsUndefined();
759     }
760
761     inline bool JSValue::isNull() const
762     {
763         return asValue() == jsNull();
764     }
765 #endif // USE(JSVALUE32_64)
766
767 } // namespace JSC
768
769 #endif // JSValue_h