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