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