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