Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4staticvalue_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4STATICVALUE_P_H
4#define QV4STATICVALUE_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <qjsnumbercoercion.h>
18
19#include <QtCore/private/qnumeric_p.h>
20#include <private/qtqmlglobal_p.h>
21
22#include <cstring>
23
24#ifdef QT_NO_DEBUG
25#define QV4_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
26#else
27#define QV4_NEARLY_ALWAYS_INLINE inline
28#endif
29
31
32namespace QV4 {
33
34// ReturnedValue is used to return values from runtime methods
35// the type has to be a primitive type (no struct or union), so that the compiler
36// will return it in a register on all platforms.
37// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
39
40namespace Heap {
41struct Base;
42}
43
45{
47
48 StaticValue() = default;
49 constexpr StaticValue(quint64 val) : _val(val) {}
50
52 {
53 _val = v;
54 return *this;
55 }
56
57 template<typename Value>
59
60 template<typename Value>
61 const Value &asValue() const;
62
63 template<typename Value>
65
66 /*
67 We use 8 bytes for a value. In order to store all possible values we employ a variant of NaN
68 boxing. A "special" Double is indicated by a number that has the 11 exponent bits set to 1.
69 Those can be NaN, positive or negative infinity. We only store one variant of NaN: The sign
70 bit has to be off and the bit after the exponent ("quiet bit") has to be on. However, since
71 the exponent bits are enough to identify special doubles, we can use a different bit as
72 discriminator to tell us how the rest of the bits (including quiet and sign) are to be
73 interpreted. This bit is bit 48. If set, we have an unmanaged value, which includes the
74 special doubles and various other values. If unset, we have a managed value, and all of the
75 other bits can be used to assemble a pointer.
76
77 On 32bit systems the pointer can just live in the lower 4 bytes. On 64 bit systems the lower
78 48 bits can be used for verbatim pointer bits. However, since all our heap objects are
79 aligned to 32 bytes, we can use the 5 least significant bits of the pointer to store, e.g.
80 pointer tags on android. The same holds for the 3 bits between the double exponent and
81 bit 48.
82
83 With that out of the way, we can use the other bits to store different values.
84
85 We xor Doubles with (0x7ff48000 << 32). That has the effect that any double with all the
86 exponent bits set to 0 is one of our special doubles. Those special doubles then get the
87 other two bits in the mask (Special and Number) set to 1, as they cannot have 1s in those
88 positions to begin with.
89
90 We dedicate further bits to integer-convertible and bool-or-int. With those bits we can
91 describe all values we need to store.
92
93 Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
94
95 Specific bit-sequences:
96 0 = always 0
97 1 = always 1
98 x = stored value
99 y = stored value, shifted to different position
100 a = xor-ed bits, where at least one bit is set
101 b = xor-ed bits
102
103 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
104 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
105 ------------------------------------------------------------------------+--------------
106 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
107 y0000000 0000yyy0 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxyyyyy | Managed (heap pointer)
108 00000000 00001101 10000000 00000000 00000000 00000000 00000000 00000000 | NaN
109 00000000 00000101 10000000 00000000 00000000 00000000 00000000 00000000 | +Inf
110 10000000 00000101 10000000 00000000 00000000 00000000 00000000 00000000 | -Inf
111 xaaaaaaa aaaaxbxb bxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
112 00000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
113 00000000 00000011 00000000 00000000 00000000 00000000 00000000 00000000 | Null
114 00000000 00000011 10000000 00000000 00000000 00000000 00000000 0000000x | Bool
115 00000000 00000011 11000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
116 ^ ^^^ ^^
117 | ||| ||
118 | ||| |+-> Number
119 | ||| +--> Int or Bool
120 | ||+----> Unmanaged
121 | |+-----> Integer compatible
122 | +------> Special double
123 +--------------------> Double sign, also used for special doubles
124 */
125
127
129 QV4_NEARLY_ALWAYS_INLINE constexpr quint64 rawValue() const { return _val; }
130 QV4_NEARLY_ALWAYS_INLINE constexpr void setRawValue(quint64 raw) { _val = raw; }
131
132#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
133 static inline int valueOffset() { return 0; }
134 static inline int tagOffset() { return 4; }
135#else // !Q_LITTLE_ENDIAN
136 static inline int valueOffset() { return 4; }
137 static inline int tagOffset() { return 0; }
138#endif
139 static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << Tag_Shift | value; }
141 QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
142 QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> Tag_Shift; }
144
145 QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
146 {
147 return int(value());
148 }
154
159
160 enum class TagBit {
161 // s: sign bit
162 // e: double exponent bit
163 // u: upper 3 bits if managed
164 // m: bit 48, denotes "unmanaged" if 1
165 // p: significant pointer bits (some re-used for non-managed)
166 // seeeeeeeeeeeuuumpppp
167 SpecialNegative = 0b10000000000000000000 << 12,
168 SpecialQNaN = 0b00000000000010000000 << 12,
169 Special = 0b00000000000001000000 << 12,
170 IntCompat = 0b00000000000000100000 << 12,
171 Unmanaged = 0b00000000000000010000 << 12,
172 IntOrBool = 0b00000000000000001000 << 12,
173 Number = 0b00000000000000000100 << 12,
174 };
175
176 static inline constexpr quint64 tagBitMask(TagBit bit) { return quint64(bit) << Tag_Shift; }
177
189
190 enum {
192
194 IsIntegerConvertible_Value = 3, // Unmanaged | IntCompat after shifting
195
197 IsIntegerOrBool_Value = 7, // Unmanaged | IntCompat | IntOrBool after shifting
198 };
199
200 static_assert(IsIntegerConvertible_Value ==
203
204 static_assert(IsIntegerOrBool_Value ==
207
208 static constexpr quint64 ExponentMask = 0b0111111111110000ull << 48;
209
210 static constexpr quint64 Top1Mask = 0b1000000000000000ull << 48;
211 static constexpr quint64 Upper3Mask = 0b0000000000001110ull << 48;
212 static constexpr quint64 Lower5Mask = 0b0000000000011111ull;
213
219
221
226
227 // Things we can immediately determine by just looking at the upper 4 bytes.
228 enum class QuickType : quint32 {
229 // Managed takes precedence over all others. That is, other bits may be set if it's managed.
230 // However, since all others include the Unmanaged bit, we can still check them with simple
231 // equality operations.
233
235 Null = Null_Type,
238
242 MinusNaN = NaN | quint32(TagBit::SpecialNegative), // Can happen with UMinus on NaN
243 // All other values are doubles
244 };
245
246 // Aliases for easier porting. Remove those when possible
248 enum {
254 };
255
256 inline Type type() const
257 {
258 const quint64 masked = _val & DoubleMask;
259 if (masked >= DoubleDiscriminator)
260 return Double_Type;
261
262 // Any bit set in the exponent would have been caught above, as well as both bits being set.
263 // None of them being set as well as only Special being set means "managed".
264 // Only Unmanaged being set means "unmanaged". That's all remaining options.
265 if (masked != tagBitMask(TagBit::Unmanaged)) {
268 }
269
270 const Type ret = Type(tag());
271 Q_ASSERT(
272 ret == Empty_Type ||
273 ret == Null_Type ||
274 ret == Boolean_Type ||
275 ret == Integer_Type);
276 return ret;
277 }
278
279 inline quint64 quickType() const { return (_val >> QuickType_Shift); }
280
281 // used internally in property
282 inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
283 inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
284 inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
285 inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
286 inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
287 inline bool isUndefined() const { return _val == 0; }
288
289 inline bool isDouble() const
290 {
291 // If any of the flipped exponent bits are 1, it's a regular double, and the masked tag is
292 // larger than Unmanaged | Special.
293 //
294 // If all (flipped) exponent bits are 0:
295 // 1. If Unmanaged bit is 0, it's managed
296 // 2. If the Unmanaged bit it is 1, and the Special bit is 0, it's not a special double
297 // 3. If both are 1, it is a special double and the masked tag equals Unmanaged | Special.
298
299 return (_val & DoubleMask) >= DoubleDiscriminator;
300 }
301
302 inline bool isNumber() const
303 {
304 // If any of the flipped exponent bits are 1, it's a regular double, and the masked tag is
305 // larger than Unmanaged | Number.
306 //
307 // If all (flipped) exponent bits are 0:
308 // 1. If Unmanaged bit is 0, it's managed
309 // 2. If the Unmanaged bit it is 1, and the Number bit is 0, it's not number
310 // 3. If both are 1, it is a number and masked tag equals Unmanaged | Number.
311
312 return (_val & NumberMask) >= NumberDiscriminator;
313 }
314
315 inline bool isManagedOrUndefined() const { return (_val & ManagedMask) == 0; }
316
317 // If any other bit is set in addition to the managed mask, it's not undefined.
318 inline bool isManaged() const
319 {
320 return isManagedOrUndefined() && !isUndefined();
321 }
322
323 inline bool isIntOrBool() const
324 {
325 // It's an int or bool if all the exponent bits are 0,
326 // and the "int or bool" bit as well as the "umanaged" bit are set,
328 }
329
330 inline bool integerCompatible() const {
331 Q_ASSERT(!isEmpty());
333 }
334
336 return a.integerCompatible() && b.integerCompatible();
337 }
338
339 static inline bool bothDouble(StaticValue a, StaticValue b) {
340 return a.isDouble() && b.isDouble();
341 }
342
343 inline bool isNaN() const
344 {
345 switch (QuickType(tag())) {
346 case QuickType::NaN:
348 return true;
349 default:
350 return false;
351 }
352 }
353
354 inline bool isPositiveInt() const {
355 return isInteger() && int_32() >= 0;
356 }
357
360 double d;
361 const quint64 unmasked = _val ^ EncodeMask;
362 memcpy(&d, &unmasked, 8);
363 return d;
364 }
365
367 if (qt_is_nan(d)) {
368 // We cannot store just any NaN. It has to be a NaN with only the quiet bit
369 // set in the upper bits of the mantissa and the sign bit off.
370 // qt_qnan() happens to produce such a thing via std::numeric_limits,
371 // but this is actually not guaranteed. Therefore, we make our own.
373 Q_ASSERT(isNaN());
374 } else {
375 memcpy(&_val, &d, 8);
376 _val ^= EncodeMask;
377 }
378
380 }
381
382 inline bool isInt32() {
384 return true;
385 if (isDouble()) {
386 double d = doubleValue();
387 if (isInt32(d)) {
388 setInt_32(int(d));
389 return true;
390 }
391 }
392 return false;
393 }
394
395 QV4_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
396 int i = QJSNumberCoercion::toInteger(d);
397 return (i == d && !(d == 0 && std::signbit(d)));
398 }
399
400 double asDouble() const {
402 return int_32();
403 return doubleValue();
404 }
405
406 bool booleanValue() const {
407 return int_32();
408 }
409
410 int integerValue() const {
411 return int_32();
412 }
413
414 inline bool tryIntegerConversion() {
415 bool b = integerCompatible();
416 if (b)
418 return b;
419 }
420
421 bool toBoolean() const {
422 if (integerCompatible())
423 return static_cast<bool>(int_32());
424
426 return false;
427
428 // double
429 const double d = doubleValue();
430 return d && !std::isnan(d);
431 }
432
433 inline int toInt32() const
434 {
435 switch (type()) {
436 case Null_Type:
437 case Boolean_Type:
438 case Integer_Type:
439 return int_32();
440 case Double_Type:
441 return QJSNumberCoercion::toInteger(doubleValue());
442 case Empty_Type:
443 case Undefined_Type:
444 case Managed_Type:
445 return 0; // Coercion of NaN to int, results in 0;
446 }
447
448 Q_UNREACHABLE_RETURN(0);
449 }
450
452 constexpr ReturnedValue asReturnedValue() const { return _val; }
453 constexpr static StaticValue fromReturnedValue(ReturnedValue val) { return {val}; }
454
455 inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(QuickType::Empty), 0) }; }
456 static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(QuickType::Boolean), b) }; }
457 static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(QuickType::Integer), quint32(i)) }; }
458 inline static constexpr StaticValue undefinedValue() { return { 0 }; }
459 static inline constexpr StaticValue nullValue() { return { tagValue(quint32(QuickType::Null), 0) }; }
460
461 static inline StaticValue fromDouble(double d)
462 {
464 v.setDouble(d);
465 return v;
466 }
467
469 {
471 if (i < uint(std::numeric_limits<int>::max())) {
473 } else {
474 v.setDouble(i);
475 }
476 return v;
477 }
478
479 static double toInteger(double d)
480 {
481 if (std::isnan(d))
482 return +0;
483 if (!d || std::isinf(d))
484 return d;
485 return d >= 0 ? std::floor(d) : std::ceil(d);
486 }
487
488 static int toInt32(double d)
489 {
490 return QJSNumberCoercion::toInteger(d);
491 }
492
493 static unsigned int toUInt32(double d)
494 {
495 return static_cast<uint>(toInt32(d));
496 }
497
498 // While a value containing a Heap::Base* is not actually static, we still implement
499 // the setting and retrieving of heap pointers here in order to have the encoding
500 // scheme completely in one place.
501
502#if QT_POINTER_SIZE == 8
503
504 // All pointer shifts are from more significant to less significant bits.
505 // When encoding, we shift right by that amount. When decoding, we shift left.
506 // Negative numbers mean shifting the other direction. 0 means no shifting.
507 //
508 // The IA64 and Sparc64 cases are mostly there to demonstrate the idea. Sparc64
509 // and IA64 are not officially supported, but we can expect more platforms with
510 // similar "problems" in the future.
511 enum PointerShift {
512#if 0 && defined(Q_OS_ANDROID) && defined(Q_PROCESSOR_ARM_64)
513 // We used to assume that Android on arm64 uses the top byte to store pointer tags.
514 // However, at least currently, the pointer tags are only applied on new/malloc and
515 // delete/free, not on mmap() and munmap(). We manage the JS heap directly using
516 // mmap, so we don't have to preserve any tags.
517 //
518 // If this ever changes, here is how to preserve the top byte:
519 // Move it to Upper3 and Lower5.
520 Top1Shift = 0,
521 Upper3Shift = 12,
522 Lower5Shift = 56,
523#elif defined(Q_PROCESSOR_IA64)
524 // On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
525 // number. We can move those to Upper3.
526 Top1Shift = 0,
527 Upper3Shift = 12,
528 Lower5Shift = 0,
529#elif defined(Q_PROCESSOR_SPARC_64)
530 // Sparc64 wants to use 52 bits for pointers.
531 // Upper3 can stay where it is, bit48 moves to the top bit.
532 Top1Shift = -15,
533 Upper3Shift = 0,
534 Lower5Shift = 0,
535#elif 0 // TODO: Once we need 5-level page tables, add the appropriate check here.
536 // With 5-level page tables (as possible on linux) we need 57 address bits.
537 // Upper3 can stay where it is, bit48 moves to the top bit, the rest moves to Lower5.
538 Top1Shift = -15,
539 Upper3Shift = 0,
540 Lower5Shift = 52,
541#else
542 Top1Shift = 0,
543 Upper3Shift = 0,
544 Lower5Shift = 0
545#endif
546 };
547
548 template<int Offset, quint64 Mask>
549 static constexpr quint64 movePointerBits(quint64 val)
550 {
551 if constexpr (Offset > 0)
552 return (val & ~Mask) | ((val & Mask) >> Offset);
553 if constexpr (Offset < 0)
554 return (val & ~Mask) | ((val & Mask) << -Offset);
555 return val;
556 }
557
558 template<int Offset, quint64 Mask>
559 static constexpr quint64 storePointerBits(quint64 val)
560 {
561 constexpr quint64 OriginMask = movePointerBits<-Offset, Mask>(Mask);
562 return movePointerBits<Offset, OriginMask>(val);
563 }
564
565 template<int Offset, quint64 Mask>
566 static constexpr quint64 retrievePointerBits(quint64 val)
567 {
568 return movePointerBits<-Offset, Mask>(val);
569 }
570
572 {
574
575 // Re-assemble the pointer from its fragments.
576 const quint64 tmp = retrievePointerBits<Top1Shift, Top1Mask>(
577 retrievePointerBits<Upper3Shift, Upper3Mask>(
578 retrievePointerBits<Lower5Shift, Lower5Mask>(_val)));
579
581 memcpy(&b, &tmp, 8);
582 return b;
583 }
585 {
586 quint64 tmp;
587 memcpy(&tmp, &b, 8);
588
589 // Has to be aligned to 32 bytes
590 Q_ASSERT(!(tmp & Lower5Mask));
591
592 // MinGW produces a bogus warning about array bounds.
593 // There is no array access here.
595 QT_WARNING_DISABLE_GCC("-Warray-bounds")
596
597 // Encode the pointer.
598 _val = storePointerBits<Top1Shift, Top1Mask>(
599 storePointerBits<Upper3Shift, Upper3Mask>(
600 storePointerBits<Lower5Shift, Lower5Mask>(tmp)));
601
603 }
604#elif QT_POINTER_SIZE == 4
606 {
607 Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
609 quint32 v = value();
610 memcpy(&b, &v, 4);
611 return b;
612 }
614 {
615 quint32 v;
616 memcpy(&v, &b, 4);
618 }
619#else
620# error "unsupported pointer size"
621#endif
622};
623Q_STATIC_ASSERT(std::is_trivial_v<StaticValue>);
624
625struct Encode {
626 static constexpr ReturnedValue undefined() {
627 return StaticValue::undefinedValue().asReturnedValue();
628 }
629 static constexpr ReturnedValue null() {
630 return StaticValue::nullValue().asReturnedValue();
631 }
632
633 explicit constexpr Encode(bool b)
634 : val(StaticValue::fromBoolean(b).asReturnedValue())
635 {
636 }
637 explicit Encode(double d) {
638 val = StaticValue::fromDouble(d).asReturnedValue();
639 }
640 explicit constexpr Encode(int i)
641 : val(StaticValue::fromInt32(i).asReturnedValue())
642 {
643 }
644 explicit Encode(uint i) {
645 val = StaticValue::fromUInt32(i).asReturnedValue();
646 }
647 explicit constexpr Encode(ReturnedValue v)
648 : val(v)
649 {
650 }
652 : val(v.asReturnedValue())
653 {
654 }
655
656 template<typename HeapBase>
657 explicit Encode(HeapBase *o);
658
659 explicit Encode(StaticValue *o) {
660 Q_ASSERT(o);
661 val = o->asReturnedValue();
662 }
663
665 if (StaticValue::isInt32(d))
666 return Encode(static_cast<int>(d));
667 else
668 return Encode(d);
669 }
670
671 constexpr operator ReturnedValue() const {
672 return val;
673 }
675private:
676 explicit Encode(void *);
677};
678
679}
680
682
683#endif // QV4STATICVALUE_P_H
Combined button and popup list for selecting options.
quint64 ReturnedValue
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_GCC(text)
#define QT_WARNING_PUSH
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
quint16 Offset
return ret
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:112
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat * val
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QML_NEARLY_ALWAYS_INLINE
unsigned int quint32
Definition qtypes.h:50
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
#define QV4_NEARLY_ALWAYS_INLINE
constexpr Encode(int i)
Encode(StaticValue *o)
static ReturnedValue smallestNumber(double d)
constexpr Encode(StaticValue v)
static constexpr ReturnedValue undefined()
constexpr Encode(bool b)
static constexpr ReturnedValue null()
constexpr Encode(ReturnedValue v)
QV4_NEARLY_ALWAYS_INLINE constexpr void setTagValue(quint32 tag, quint32 value)
bool isNumber() const
StaticValue & operator=(ReturnedValue v)
QV4_NEARLY_ALWAYS_INLINE constexpr quint64 rawValue() const
static constexpr quint64 DoubleMask
quint64 quickType() const
static bool integerCompatible(StaticValue a, StaticValue b)
const Value & asValue() const
static StaticValue fromDouble(double d)
bool isInteger() const
bool isManagedOrUndefined() const
static int toInt32(double d)
StaticValue & operator=(const Value &)
static int tagOffset()
static constexpr StaticValue fromBoolean(bool b)
constexpr ReturnedValue asReturnedValue() const
bool isIntOrBool() const
static constexpr quint64 NumberDiscriminator
static QV4_NEARLY_ALWAYS_INLINE bool isInt32(double d)
static constexpr quint64 IntOrBoolMask
static double toInteger(double d)
static constexpr quint64 Upper3Mask
static int valueOffset()
static constexpr quint64 IntCompatMask
QV4_NEARLY_ALWAYS_INLINE double doubleValue() const
static constexpr quint64 DoubleDiscriminator
QV4_NEARLY_ALWAYS_INLINE void setDouble(double d)
bool isPositiveInt() const
static constexpr StaticValue fromInt32(int i)
QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const
static StaticValue fromUInt32(uint i)
bool isManaged() const
QV4_NEARLY_ALWAYS_INLINE constexpr void setInt_32(int i)
static constexpr quint64 EncodeMask
bool integerCompatible() const
static constexpr quint64 tagBitMask(TagBit bit)
QV4_NEARLY_ALWAYS_INLINE uint uint_32() const
bool toBoolean() const
static constexpr quint64 ManagedMask
Heap::Base * HeapBasePtr
static constexpr StaticValue emptyValue()
static constexpr quint64 NumberMask
static constexpr quint64 Lower5Mask
static constexpr quint64 tagValue(quint32 tag, quint32 value)
Value & asValue()
static unsigned int toUInt32(double d)
static constexpr StaticValue undefinedValue()
QV4_NEARLY_ALWAYS_INLINE constexpr void setRawValue(quint64 raw)
bool isNullOrUndefined() const
int integerValue() const
bool isDouble() const
bool isBoolean() const
bool isUndefined() const
constexpr StaticValue(quint64 val)
QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const
bool booleanValue() const
QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
ReturnedValue * data_ptr()
static constexpr quint64 ExponentMask
static constexpr StaticValue nullValue()
static bool bothDouble(StaticValue a, StaticValue b)
static constexpr quint64 Top1Mask
QV4_NEARLY_ALWAYS_INLINE constexpr void setTag(quint32 tag)
static constexpr StaticValue fromReturnedValue(ReturnedValue val)
QV4_NEARLY_ALWAYS_INLINE constexpr void setEmpty()
StaticValue()=default
QV4_NEARLY_ALWAYS_INLINE constexpr quint64 & rawValueRef()
double asDouble() const
Definition moc.h:23