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