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