]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSCJSValueInlines.h
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / 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 isTrue() || isFalse();
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 // If this is a primitive, we'll need to synthesize the prototype -
686 // and if it's a string there are special properties to check first.
687 JSObject* object;
688 if (UNLIKELY(!isObject())) {
689 if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
690 return slot.getValue(exec, propertyName);
691 object = synthesizePrototype(exec);
692 } else
693 object = asObject(asCell());
694
695 if (object->getPropertySlot(exec, propertyName, slot))
696 return slot.getValue(exec, propertyName);
697 return jsUndefined();
698 }
699
700 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
701 {
702 PropertySlot slot(asValue());
703 return get(exec, propertyName, slot);
704 }
705
706 ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned 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 (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
713 return slot.getValue(exec, propertyName);
714 object = synthesizePrototype(exec);
715 } else
716 object = asObject(asCell());
717
718 if (object->getPropertySlot(exec, propertyName, slot))
719 return slot.getValue(exec, propertyName);
720 return jsUndefined();
721 }
722
723 inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
724 {
725 if (UNLIKELY(!isCell())) {
726 putToPrimitive(exec, propertyName, value, slot);
727 return;
728 }
729 asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
730 }
731
732 inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
733 {
734 if (UNLIKELY(!isCell())) {
735 putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
736 return;
737 }
738 asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
739 }
740
741 inline JSValue JSValue::structureOrUndefined() const
742 {
743 if (isCell())
744 return JSValue(asCell()->structure());
745 return jsUndefined();
746 }
747
748 // ECMA 11.9.3
749 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
750 {
751 if (v1.isInt32() && v2.isInt32())
752 return v1 == v2;
753
754 return equalSlowCase(exec, v1, v2);
755 }
756
757 ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
758 {
759 VM& vm = exec->vm();
760 do {
761 if (v1.isNumber() && v2.isNumber())
762 return v1.asNumber() == v2.asNumber();
763
764 bool s1 = v1.isString();
765 bool s2 = v2.isString();
766 if (s1 && s2)
767 return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
768
769 if (v1.isUndefinedOrNull()) {
770 if (v2.isUndefinedOrNull())
771 return true;
772 if (!v2.isCell())
773 return false;
774 return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
775 }
776
777 if (v2.isUndefinedOrNull()) {
778 if (!v1.isCell())
779 return false;
780 return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
781 }
782
783 if (v1.isObject()) {
784 if (v2.isObject())
785 return v1 == v2;
786 JSValue p1 = v1.toPrimitive(exec);
787 if (exec->hadException())
788 return false;
789 v1 = p1;
790 if (v1.isInt32() && v2.isInt32())
791 return v1 == v2;
792 continue;
793 }
794
795 if (v2.isObject()) {
796 JSValue p2 = v2.toPrimitive(exec);
797 if (exec->hadException())
798 return false;
799 v2 = p2;
800 if (v1.isInt32() && v2.isInt32())
801 return v1 == v2;
802 continue;
803 }
804
805 if (s1 || s2) {
806 double d1 = v1.toNumber(exec);
807 double d2 = v2.toNumber(exec);
808 return d1 == d2;
809 }
810
811 if (v1.isBoolean()) {
812 if (v2.isNumber())
813 return static_cast<double>(v1.asBoolean()) == v2.asNumber();
814 } else if (v2.isBoolean()) {
815 if (v1.isNumber())
816 return v1.asNumber() == static_cast<double>(v2.asBoolean());
817 }
818
819 return v1 == v2;
820 } while (true);
821 }
822
823 // ECMA 11.9.3
824 ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
825 {
826 ASSERT(v1.isCell() && v2.isCell());
827
828 if (v1.asCell()->isString() && v2.asCell()->isString())
829 return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
830
831 return v1 == v2;
832 }
833
834 inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
835 {
836 if (v1.isInt32() && v2.isInt32())
837 return v1 == v2;
838
839 if (v1.isNumber() && v2.isNumber())
840 return v1.asNumber() == v2.asNumber();
841
842 if (!v1.isCell() || !v2.isCell())
843 return v1 == v2;
844
845 return strictEqualSlowCaseInline(exec, v1, v2);
846 }
847
848 inline int32_t JSValue::asInt32ForArithmetic() const
849 {
850 if (isBoolean())
851 return asBoolean();
852 return asInt32();
853 }
854
855 inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
856 {
857 if (v1.isInt32() && v2.isInt32())
858 return triState(v1 == v2);
859
860 if (v1.isNumber() && v2.isNumber())
861 return triState(v1.asNumber() == v2.asNumber());
862
863 if (!v1.isCell() || !v2.isCell())
864 return triState(v1 == v2);
865
866 if (v1.asCell()->isString() && v2.asCell()->isString()) {
867 const StringImpl* v1String = asString(v1)->tryGetValueImpl();
868 const StringImpl* v2String = asString(v2)->tryGetValueImpl();
869 if (!v1String || !v2String)
870 return MixedTriState;
871 return triState(WTF::equal(*v1String, *v2String));
872 }
873
874 return triState(v1 == v2);
875 }
876
877 inline TriState JSValue::pureToBoolean() const
878 {
879 if (isInt32())
880 return asInt32() ? TrueTriState : FalseTriState;
881 if (isDouble())
882 return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN
883 if (isCell())
884 return asCell()->pureToBoolean();
885 return isTrue() ? TrueTriState : FalseTriState;
886 }
887
888 } // namespace JSC
889
890 #endif // JSValueInlines_h
891