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