Implement ES6 Symbol
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSCJSValueInlines.h
1 /*
2  * Copyright (C) 2011, 2012 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 JSValueInlines_h
27 #define JSValueInlines_h
28
29 #include "Identifier.h"
30 #include "InternalFunction.h"
31 #include "JSCJSValue.h"
32 #include "JSCellInlines.h"
33 #include "JSFunction.h"
34 #include <wtf/text/StringImpl.h>
35
36 namespace JSC {
37
38 ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
39 {
40     if (isInt32())
41         return asInt32();
42     return JSC::toInt32(toNumber(exec));
43 }
44
45 inline uint32_t JSValue::toUInt32(ExecState* exec) const
46 {
47     // See comment on JSC::toUInt32, above.
48     return toInt32(exec);
49 }
50
51 inline bool JSValue::isUInt32() const
52 {
53     return isInt32() && asInt32() >= 0;
54 }
55
56 inline uint32_t JSValue::asUInt32() const
57 {
58     ASSERT(isUInt32());
59     return asInt32();
60 }
61
62 inline double JSValue::asNumber() const
63 {
64     ASSERT(isNumber());
65     return isInt32() ? asInt32() : asDouble();
66 }
67
68 inline JSValue jsNaN()
69 {
70     return JSValue(PNaN);
71 }
72
73 inline JSValue::JSValue(char i)
74 {
75     *this = JSValue(static_cast<int32_t>(i));
76 }
77
78 inline JSValue::JSValue(unsigned char i)
79 {
80     *this = JSValue(static_cast<int32_t>(i));
81 }
82
83 inline JSValue::JSValue(short i)
84 {
85     *this = JSValue(static_cast<int32_t>(i));
86 }
87
88 inline JSValue::JSValue(unsigned short i)
89 {
90     *this = JSValue(static_cast<int32_t>(i));
91 }
92
93 inline JSValue::JSValue(unsigned i)
94 {
95     if (static_cast<int32_t>(i) < 0) {
96         *this = JSValue(EncodeAsDouble, static_cast<double>(i));
97         return;
98     }
99     *this = JSValue(static_cast<int32_t>(i));
100 }
101
102 inline JSValue::JSValue(long i)
103 {
104     if (static_cast<int32_t>(i) != i) {
105         *this = JSValue(EncodeAsDouble, static_cast<double>(i));
106         return;
107     }
108     *this = JSValue(static_cast<int32_t>(i));
109 }
110
111 inline JSValue::JSValue(unsigned long i)
112 {
113     if (static_cast<uint32_t>(i) != i) {
114         *this = JSValue(EncodeAsDouble, static_cast<double>(i));
115         return;
116     }
117     *this = JSValue(static_cast<uint32_t>(i));
118 }
119
120 inline JSValue::JSValue(long long i)
121 {
122     if (static_cast<int32_t>(i) != i) {
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(unsigned long long i)
130 {
131     if (static_cast<uint32_t>(i) != i) {
132         *this = JSValue(EncodeAsDouble, static_cast<double>(i));
133         return;
134     }
135     *this = JSValue(static_cast<uint32_t>(i));
136 }
137
138 inline JSValue::JSValue(double d)
139 {
140     const int32_t asInt32 = static_cast<int32_t>(d);
141     if (asInt32 != d || (!asInt32 && std::signbit(d))) { // true for -0.0
142         *this = JSValue(EncodeAsDouble, d);
143         return;
144     }
145     *this = JSValue(static_cast<int32_t>(d));
146 }
147
148 inline EncodedJSValue JSValue::encode(JSValue value)
149 {
150     return value.u.asInt64;
151 }
152
153 inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
154 {
155     JSValue v;
156     v.u.asInt64 = encodedJSValue;
157     return v;
158 }
159
160 #if USE(JSVALUE32_64)
161 inline JSValue::JSValue()
162 {
163     u.asBits.tag = EmptyValueTag;
164     u.asBits.payload = 0;
165 }
166
167 inline JSValue::JSValue(JSNullTag)
168 {
169     u.asBits.tag = NullTag;
170     u.asBits.payload = 0;
171 }
172     
173 inline JSValue::JSValue(JSUndefinedTag)
174 {
175     u.asBits.tag = UndefinedTag;
176     u.asBits.payload = 0;
177 }
178     
179 inline JSValue::JSValue(JSTrueTag)
180 {
181     u.asBits.tag = BooleanTag;
182     u.asBits.payload = 1;
183 }
184     
185 inline JSValue::JSValue(JSFalseTag)
186 {
187     u.asBits.tag = BooleanTag;
188     u.asBits.payload = 0;
189 }
190
191 inline JSValue::JSValue(HashTableDeletedValueTag)
192 {
193     u.asBits.tag = DeletedValueTag;
194     u.asBits.payload = 0;
195 }
196
197 inline JSValue::JSValue(JSCell* ptr)
198 {
199     if (ptr)
200         u.asBits.tag = CellTag;
201     else
202         u.asBits.tag = EmptyValueTag;
203     u.asBits.payload = reinterpret_cast<int32_t>(ptr);
204 }
205
206 inline JSValue::JSValue(const JSCell* ptr)
207 {
208     if (ptr)
209         u.asBits.tag = CellTag;
210     else
211         u.asBits.tag = EmptyValueTag;
212     u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
213 }
214
215 inline JSValue::operator UnspecifiedBoolType*() const
216 {
217     ASSERT(tag() != DeletedValueTag);
218     return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
219 }
220
221 inline bool JSValue::operator==(const JSValue& other) const
222 {
223     return u.asInt64 == other.u.asInt64;
224 }
225
226 inline bool JSValue::operator!=(const JSValue& other) const
227 {
228     return u.asInt64 != other.u.asInt64;
229 }
230
231 inline bool JSValue::isEmpty() const
232 {
233     return tag() == EmptyValueTag;
234 }
235
236 inline bool JSValue::isUndefined() const
237 {
238     return tag() == UndefinedTag;
239 }
240
241 inline bool JSValue::isNull() const
242 {
243     return tag() == NullTag;
244 }
245
246 inline bool JSValue::isUndefinedOrNull() const
247 {
248     return isUndefined() || isNull();
249 }
250
251 inline bool JSValue::isCell() const
252 {
253     return tag() == CellTag;
254 }
255
256 inline bool JSValue::isInt32() const
257 {
258     return tag() == Int32Tag;
259 }
260
261 inline bool JSValue::isDouble() const
262 {
263     return tag() < LowestTag;
264 }
265
266 inline bool JSValue::isTrue() const
267 {
268     return tag() == BooleanTag && payload();
269 }
270
271 inline bool JSValue::isFalse() const
272 {
273     return tag() == BooleanTag && !payload();
274 }
275
276 inline uint32_t JSValue::tag() const
277 {
278     return u.asBits.tag;
279 }
280     
281 inline int32_t JSValue::payload() const
282 {
283     return u.asBits.payload;
284 }
285     
286 inline int32_t JSValue::asInt32() const
287 {
288     ASSERT(isInt32());
289     return u.asBits.payload;
290 }
291     
292 inline double JSValue::asDouble() const
293 {
294     ASSERT(isDouble());
295     return u.asDouble;
296 }
297     
298 ALWAYS_INLINE JSCell* JSValue::asCell() const
299 {
300     ASSERT(isCell());
301     return reinterpret_cast<JSCell*>(u.asBits.payload);
302 }
303
304 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
305 {
306     ASSERT(!isImpureNaN(d));
307     u.asDouble = d;
308 }
309
310 inline JSValue::JSValue(int i)
311 {
312     u.asBits.tag = Int32Tag;
313     u.asBits.payload = i;
314 }
315
316 #if !ENABLE(JIT)
317 inline JSValue::JSValue(int32_t tag, int32_t payload)
318 {
319     u.asBits.tag = tag;
320     u.asBits.payload = payload;
321 }
322 #endif
323
324 inline bool JSValue::isNumber() const
325 {
326     return isInt32() || isDouble();
327 }
328
329 inline bool JSValue::isBoolean() const
330 {
331     return tag() == BooleanTag;
332 }
333
334 inline bool JSValue::asBoolean() const
335 {
336     ASSERT(isBoolean());
337     return payload();
338 }
339
340 #else // !USE(JSVALUE32_64) i.e. USE(JSVALUE64)
341
342 // 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.
343 inline JSValue::JSValue()
344 {
345     u.asInt64 = ValueEmpty;
346 }
347
348 // 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.
349 inline JSValue::JSValue(HashTableDeletedValueTag)
350 {
351     u.asInt64 = ValueDeleted;
352 }
353
354 inline JSValue::JSValue(JSCell* ptr)
355 {
356     u.asInt64 = reinterpret_cast<uintptr_t>(ptr);
357 }
358
359 inline JSValue::JSValue(const JSCell* ptr)
360 {
361     u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr));
362 }
363
364 inline JSValue::operator UnspecifiedBoolType*() const
365 {
366     return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
367 }
368
369 inline bool JSValue::operator==(const JSValue& other) const
370 {
371     return u.asInt64 == other.u.asInt64;
372 }
373
374 inline bool JSValue::operator!=(const JSValue& other) const
375 {
376     return u.asInt64 != other.u.asInt64;
377 }
378
379 inline bool JSValue::isEmpty() const
380 {
381     return u.asInt64 == ValueEmpty;
382 }
383
384 inline bool JSValue::isUndefined() const
385 {
386     return asValue() == JSValue(JSUndefined);
387 }
388
389 inline bool JSValue::isNull() const
390 {
391     return asValue() == JSValue(JSNull);
392 }
393
394 inline bool JSValue::isTrue() const
395 {
396     return asValue() == JSValue(JSTrue);
397 }
398
399 inline bool JSValue::isFalse() const
400 {
401     return asValue() == JSValue(JSFalse);
402 }
403
404 inline bool JSValue::asBoolean() const
405 {
406     ASSERT(isBoolean());
407     return asValue() == JSValue(JSTrue);
408 }
409
410 inline int32_t JSValue::asInt32() const
411 {
412     ASSERT(isInt32());
413     return static_cast<int32_t>(u.asInt64);
414 }
415
416 inline bool JSValue::isDouble() const
417 {
418     return isNumber() && !isInt32();
419 }
420
421 inline JSValue::JSValue(JSNullTag)
422 {
423     u.asInt64 = ValueNull;
424 }
425     
426 inline JSValue::JSValue(JSUndefinedTag)
427 {
428     u.asInt64 = ValueUndefined;
429 }
430
431 inline JSValue::JSValue(JSTrueTag)
432 {
433     u.asInt64 = ValueTrue;
434 }
435
436 inline JSValue::JSValue(JSFalseTag)
437 {
438     u.asInt64 = ValueFalse;
439 }
440
441 inline bool JSValue::isUndefinedOrNull() const
442 {
443     // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
444     return (u.asInt64 & ~TagBitUndefined) == ValueNull;
445 }
446
447 inline bool JSValue::isBoolean() const
448 {
449     return (u.asInt64 & ~1) == ValueFalse;
450 }
451
452 inline bool JSValue::isCell() const
453 {
454     return !(u.asInt64 & TagMask);
455 }
456
457 inline bool JSValue::isInt32() const
458 {
459     return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
460 }
461
462 inline int64_t reinterpretDoubleToInt64(double value)
463 {
464     return bitwise_cast<int64_t>(value);
465 }
466 inline double reinterpretInt64ToDouble(int64_t value)
467 {
468     return bitwise_cast<double>(value);
469 }
470
471 ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
472 {
473     ASSERT(!isImpureNaN(d));
474     u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
475 }
476
477 inline JSValue::JSValue(int i)
478 {
479     u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
480 }
481
482 inline double JSValue::asDouble() const
483 {
484     ASSERT(isDouble());
485     return reinterpretInt64ToDouble(u.asInt64 - DoubleEncodeOffset);
486 }
487
488 inline bool JSValue::isNumber() const
489 {
490     return u.asInt64 & TagTypeNumber;
491 }
492
493 ALWAYS_INLINE JSCell* JSValue::asCell() const
494 {
495     ASSERT(isCell());
496     return u.ptr;
497 }
498
499 #endif // USE(JSVALUE64)
500
501 inline int64_t tryConvertToInt52(double number)
502 {
503     if (number != number)
504         return JSValue::notInt52;
505 #if OS(WINDOWS) && CPU(X86)
506     // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
507     // from an infinity to a 64-bit integer. We leave this routine with the floating point error
508     // left in a register, causing undefined behavior in later floating point operations.
509     //
510     // To avoid this issue, we check for infinity here, and return false in that case.
511     if (std::isinf(number))
512         return JSValue::notInt52;
513 #endif
514     int64_t asInt64 = static_cast<int64_t>(number);
515     if (asInt64 != number)
516         return JSValue::notInt52;
517     if (!asInt64 && std::signbit(number))
518         return JSValue::notInt52;
519     if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
520         return JSValue::notInt52;
521     if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
522         return JSValue::notInt52;
523     return asInt64;
524 }
525
526 inline bool isInt52(double number)
527 {
528     return tryConvertToInt52(number) != JSValue::notInt52;
529 }
530
531 inline bool JSValue::isMachineInt() const
532 {
533     if (isInt32())
534         return true;
535     if (!isNumber())
536         return false;
537     return isInt52(asDouble());
538 }
539
540 inline int64_t JSValue::asMachineInt() const
541 {
542     ASSERT(isMachineInt());
543     if (isInt32())
544         return asInt32();
545     return static_cast<int64_t>(asDouble());
546 }
547
548 inline bool JSValue::isString() const
549 {
550     return isCell() && asCell()->isString();
551 }
552
553 inline bool JSValue::isSymbol() const
554 {
555     return isCell() && asCell()->isSymbol();
556 }
557
558 inline bool JSValue::isPrimitive() const
559 {
560     return !isCell() || asCell()->isString() || asCell()->isSymbol();
561 }
562
563 inline bool JSValue::isGetterSetter() const
564 {
565     return isCell() && asCell()->isGetterSetter();
566 }
567
568 inline bool JSValue::isCustomGetterSetter() const
569 {
570     return isCell() && asCell()->isCustomGetterSetter();
571 }
572
573 inline bool JSValue::isObject() const
574 {
575     return isCell() && asCell()->isObject();
576 }
577
578 inline bool JSValue::getString(ExecState* exec, String& s) const
579 {
580     return isCell() && asCell()->getString(exec, s);
581 }
582
583 inline String JSValue::getString(ExecState* exec) const
584 {
585     return isCell() ? asCell()->getString(exec) : String();
586 }
587
588 template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const
589 {
590     return jsValue().getString(exec);
591 }
592
593 inline JSObject* JSValue::getObject() const
594 {
595     return isCell() ? asCell()->getObject() : 0;
596 }
597
598 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
599 {
600     if (isInt32()) {
601         int32_t i = asInt32();
602         v = static_cast<uint32_t>(i);
603         return i >= 0;
604     }
605     if (isDouble()) {
606         double d = asDouble();
607         v = static_cast<uint32_t>(d);
608         return v == d;
609     }
610     return false;
611 }
612
613 ALWAYS_INLINE PropertyName JSValue::toPropertyKey(ExecState* exec) const
614 {
615     if (isString())
616         return asString(*this)->toIdentifier(exec);
617
618     JSValue primitive = toPrimitive(exec, PreferString);
619     if (primitive.isSymbol())
620         return asSymbol(primitive)->privateName();
621     return primitive.toString(exec)->toIdentifier(exec);
622 }
623
624 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
625 {
626     return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
627 }
628
629 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
630 {
631     if (isInt32()) {
632         number = asInt32();
633         value = *this;
634         return true;
635     }
636     if (isDouble()) {
637         number = asDouble();
638         value = *this;
639         return true;
640     }
641     if (isCell())
642         return asCell()->getPrimitiveNumber(exec, number, value);
643     if (isTrue()) {
644         number = 1.0;
645         value = *this;
646         return true;
647     }
648     if (isFalse() || isNull()) {
649         number = 0.0;
650         value = *this;
651         return true;
652     }
653     ASSERT(isUndefined());
654     number = PNaN;
655     value = *this;
656     return true;
657 }
658
659 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
660 {
661     if (isInt32())
662         return asInt32();
663     if (isDouble())
664         return asDouble();
665     return toNumberSlowCase(exec);
666 }
667
668 inline JSObject* JSValue::toObject(ExecState* exec) const
669 {
670     return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
671 }
672
673 inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
674 {
675     return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
676 }
677
678 inline bool JSValue::isFunction() const
679 {
680     return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
681 }
682
683 // this method is here to be after the inline declaration of JSCell::inherits
684 inline bool JSValue::inherits(const ClassInfo* classInfo) const
685 {
686     return isCell() && asCell()->inherits(classInfo);
687 }
688
689 inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const
690 {
691     return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
692 }
693
694 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
695 {
696     PropertySlot slot(asValue());
697     return get(exec, propertyName, slot);
698 }
699
700 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
701 {
702     return getPropertySlot(exec, propertyName, slot) ? 
703         slot.getValue(exec, propertyName) : jsUndefined();
704 }
705
706 ALWAYS_INLINE bool JSValue::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
707 {
708     // If this is a primitive, we'll need to synthesize the prototype -
709     // and if it's a string there are special properties to check first.
710     JSObject* object;
711     if (UNLIKELY(!isObject())) {
712         if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
713             return true;
714         object = synthesizePrototype(exec);
715     } else
716         object = asObject(asCell());
717     
718     return object->getPropertySlot(exec, propertyName, slot);
719 }
720
721 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
722 {
723     PropertySlot slot(asValue());
724     return get(exec, propertyName, slot);
725 }
726
727 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
728 {
729     // If this is a primitive, we'll need to synthesize the prototype -
730     // and if it's a string there are special properties to check first.
731     JSObject* object;
732     if (UNLIKELY(!isObject())) {
733         if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
734             return slot.getValue(exec, propertyName);
735         object = synthesizePrototype(exec);
736     } else
737         object = asObject(asCell());
738     
739     if (object->getPropertySlot(exec, propertyName, slot))
740         return slot.getValue(exec, propertyName);
741     return jsUndefined();
742 }
743
744 inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
745 {
746     if (UNLIKELY(!isCell())) {
747         putToPrimitive(exec, propertyName, value, slot);
748         return;
749     }
750     asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
751 }
752
753 inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
754 {
755     if (UNLIKELY(!isCell())) {
756         putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
757         return;
758     }
759     asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
760 }
761
762 inline JSValue JSValue::structureOrUndefined() const
763 {
764     if (isCell())
765         return JSValue(asCell()->structure());
766     return jsUndefined();
767 }
768
769 // ECMA 11.9.3
770 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
771 {
772     if (v1.isInt32() && v2.isInt32())
773         return v1 == v2;
774
775     return equalSlowCase(exec, v1, v2);
776 }
777
778 ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
779 {
780     VM& vm = exec->vm();
781     do {
782         if (v1.isNumber() && v2.isNumber())
783             return v1.asNumber() == v2.asNumber();
784
785         bool s1 = v1.isString();
786         bool s2 = v2.isString();
787         if (s1 && s2)
788             return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
789
790         if (v1.isUndefinedOrNull()) {
791             if (v2.isUndefinedOrNull())
792                 return true;
793             if (!v2.isCell())
794                 return false;
795             return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
796         }
797
798         if (v2.isUndefinedOrNull()) {
799             if (!v1.isCell())
800                 return false;
801             return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
802         }
803
804         if (v1.isObject()) {
805             if (v2.isObject())
806                 return v1 == v2;
807             JSValue p1 = v1.toPrimitive(exec);
808             if (exec->hadException())
809                 return false;
810             v1 = p1;
811             if (v1.isInt32() && v2.isInt32())
812                 return v1 == v2;
813             continue;
814         }
815
816         if (v2.isObject()) {
817             JSValue p2 = v2.toPrimitive(exec);
818             if (exec->hadException())
819                 return false;
820             v2 = p2;
821             if (v1.isInt32() && v2.isInt32())
822                 return v1 == v2;
823             continue;
824         }
825
826         bool sym1 = v1.isSymbol();
827         bool sym2 = v2.isSymbol();
828         if (sym1 || sym2) {
829             if (sym1 && sym2)
830                 return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
831             return false;
832         }
833
834         if (s1 || s2) {
835             double d1 = v1.toNumber(exec);
836             double d2 = v2.toNumber(exec);
837             return d1 == d2;
838         }
839
840         if (v1.isBoolean()) {
841             if (v2.isNumber())
842                 return static_cast<double>(v1.asBoolean()) == v2.asNumber();
843         } else if (v2.isBoolean()) {
844             if (v1.isNumber())
845                 return v1.asNumber() == static_cast<double>(v2.asBoolean());
846         }
847
848         return v1 == v2;
849     } while (true);
850 }
851
852 // ECMA 11.9.3
853 ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
854 {
855     ASSERT(v1.isCell() && v2.isCell());
856
857     if (v1.asCell()->isString() && v2.asCell()->isString())
858         return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
859     if (v1.asCell()->isSymbol() && v2.asCell()->isSymbol())
860         return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
861
862     return v1 == v2;
863 }
864
865 inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
866 {
867     if (v1.isInt32() && v2.isInt32())
868         return v1 == v2;
869
870     if (v1.isNumber() && v2.isNumber())
871         return v1.asNumber() == v2.asNumber();
872
873     if (!v1.isCell() || !v2.isCell())
874         return v1 == v2;
875
876     return strictEqualSlowCaseInline(exec, v1, v2);
877 }
878
879 inline int32_t JSValue::asInt32ForArithmetic() const
880 {
881     if (isBoolean())
882         return asBoolean();
883     return asInt32();
884 }
885
886 inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
887 {
888     if (v1.isInt32() && v2.isInt32())
889         return triState(v1 == v2);
890
891     if (v1.isNumber() && v2.isNumber())
892         return triState(v1.asNumber() == v2.asNumber());
893
894     if (!v1.isCell() || !v2.isCell())
895         return triState(v1 == v2);
896     
897     if (v1.asCell()->isString() && v2.asCell()->isString()) {
898         const StringImpl* v1String = asString(v1)->tryGetValueImpl();
899         const StringImpl* v2String = asString(v2)->tryGetValueImpl();
900         if (!v1String || !v2String)
901             return MixedTriState;
902         return triState(WTF::equal(*v1String, *v2String));
903     }
904     
905     return triState(v1 == v2);
906 }
907
908 inline TriState JSValue::pureToBoolean() const
909 {
910     if (isInt32())
911         return asInt32() ? TrueTriState : FalseTriState;
912     if (isDouble())
913         return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN
914     if (isCell())
915         return asCell()->pureToBoolean();
916     return isTrue() ? TrueTriState : FalseTriState;
917 }
918
919 } // namespace JSC
920
921 #endif // JSValueInlines_h
922