Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4value_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 #ifndef QV4VALUE_P_H
34 #define QV4VALUE_P_H
35
36 #include <limits.h>
37
38 #include <QtCore/QString>
39 #include "qv4global_p.h"
40 #include <private/qv4heap_p.h>
41
42 #ifndef Q_ALWAYS_INLINE
43 #if defined(Q_CC_GNU)
44 #  define Q_ALWAYS_INLINE inline __attribute__((always_inline))
45 #elif defined(Q_CC_MSVC)
46 #  define Q_ALWAYS_INLINE __forceinline
47 #else
48 #  define Q_ALWAYS_INLINE inline
49 #endif
50 #endif // Q_ALWAYS_INLINE
51
52 QT_BEGIN_NAMESPACE
53
54 namespace QV4 {
55
56 namespace Heap {
57     struct Base;
58 }
59
60 typedef uint Bool;
61
62 struct Q_QML_PRIVATE_EXPORT Value
63 {
64     /*
65         We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
66
67         In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double NaN (actually -qNaN)
68         is indicated by a number that has the top 13 bits set. The other values are usually set to 0 by the
69         processor, and are thus free for us to store other data. We keep pointers in there for managed objects,
70         and encode the other types using the free space given to use by the unused bits for NaN values. This also
71         works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory.
72
73         On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that
74         will make the number a NaN. The Masks below are used for encoding the other types.
75
76         On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will get encoded
77         with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These
78         can be used, as the highest valid pointer on a 64 bit system is 2^48-1.
79
80         If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer.
81         This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set).
82
83         Bit 15-17 is then used to encode other immediates.
84     */
85
86     quint64 _val;
87
88     Q_ALWAYS_INLINE quint64 val() const { return _val; }
89     Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; }
90     Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); }
91     Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); }
92
93 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
94     static inline int valueOffset() { return 0; }
95     static inline int tagOffset() { return 4; }
96     Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
97     Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
98     Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
99 #else // !Q_LITTLE_ENDIAN
100     static inline int valueOffset() { return 4; }
101     static inline int tagOffset() { return 0; }
102     Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; }
103     Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); }
104     Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; }
105 #endif
106
107 #if QT_POINTER_SIZE == 8
108     Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; }
109     Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); }
110 #else // QT_POINTER_SIZE == 4
111     Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; }
112     Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); }
113 #endif
114
115     Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; }
116     Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); }
117     Q_ALWAYS_INLINE uint uint_32() const { return value(); }
118
119 #if QT_POINTER_SIZE == 4
120     enum Masks {
121         SilentNaNBit           =                  0x00040000,
122         NaN_Mask               =                  0x7ff80000,
123         NotDouble_Mask         =                  0x7ffa0000,
124         Type_Mask              =                  0xffffc000,
125         Immediate_Mask         = NotDouble_Mask | 0x00004000 | SilentNaNBit,
126         IsNullOrUndefined_Mask = Immediate_Mask |    0x08000,
127         Tag_Shift = 32
128     };
129     enum ValueType {
130         Undefined_Type = Immediate_Mask | 0x00000,
131         Null_Type      = Immediate_Mask | 0x10000,
132         Boolean_Type   = Immediate_Mask | 0x08000,
133         Integer_Type   = Immediate_Mask | 0x18000,
134         Managed_Type   = NotDouble_Mask | 0x00000 | SilentNaNBit,
135         Empty_Type     = NotDouble_Mask | 0x18000 | SilentNaNBit
136     };
137
138     enum ImmediateFlags {
139         ConvertibleToInt = Immediate_Mask | 0x1
140     };
141
142     enum ValueTypeInternal {
143         _Null_Type = Null_Type | ConvertibleToInt,
144         _Boolean_Type = Boolean_Type | ConvertibleToInt,
145         _Integer_Type = Integer_Type | ConvertibleToInt,
146
147     };
148 #else
149     static const quint64 NaNEncodeMask = 0xffff800000000000ll;
150     static const quint64 IsInt32Mask  = 0x0002000000000000ll;
151     static const quint64 IsDoubleMask = 0xfffc000000000000ll;
152     static const quint64 IsNumberMask = IsInt32Mask|IsDoubleMask;
153     static const quint64 IsNullOrUndefinedMask = 0x0000800000000000ll;
154     static const quint64 IsNullOrBooleanMask = 0x0001000000000000ll;
155     static const quint64 IsConvertibleToIntMask = IsInt32Mask|IsNullOrBooleanMask;
156
157     enum Masks {
158         NaN_Mask = 0x7ff80000,
159         Type_Mask = 0xffff8000,
160         IsDouble_Mask = 0xfffc0000,
161         Immediate_Mask = 0x00018000,
162         IsNullOrUndefined_Mask = 0x00008000,
163         IsNullOrBoolean_Mask = 0x00010000,
164         Tag_Shift = 32
165     };
166     enum ValueType {
167         Undefined_Type = IsNullOrUndefined_Mask,
168         Null_Type = IsNullOrUndefined_Mask|IsNullOrBoolean_Mask,
169         Boolean_Type = IsNullOrBoolean_Mask,
170         Integer_Type = 0x20000|IsNullOrBoolean_Mask,
171         Managed_Type = 0,
172         Empty_Type = Undefined_Type | 0x4000
173     };
174     enum {
175         IsDouble_Shift = 64-14,
176         IsNumber_Shift = 64-15,
177         IsConvertibleToInt_Shift = 64-16,
178         IsManaged_Shift = 64-17
179     };
180
181
182     enum ValueTypeInternal {
183         _Null_Type = Null_Type,
184         _Boolean_Type = Boolean_Type,
185         _Integer_Type = Integer_Type
186     };
187 #endif
188
189     inline unsigned type() const {
190         return tag() & Type_Mask;
191     }
192
193     // used internally in property
194     inline bool isEmpty() const { return tag() == Empty_Type; }
195
196     inline bool isUndefined() const { return tag() == Undefined_Type; }
197     inline bool isNull() const { return tag() == _Null_Type; }
198     inline bool isBoolean() const { return tag ()== _Boolean_Type; }
199 #if QT_POINTER_SIZE == 8
200     inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; }
201     inline bool isDouble() const { return (_val >> IsDouble_Shift); }
202     inline bool isNumber() const { return (_val >> IsNumber_Shift); }
203     inline bool isManaged() const { return !(_val >> IsManaged_Shift); }
204     inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; }
205     inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; }
206     static inline bool integerCompatible(Value a, Value b) {
207         return a.integerCompatible() && b.integerCompatible();
208     }
209     static inline bool bothDouble(Value a, Value b) {
210         return a.isDouble() && b.isDouble();
211     }
212     inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; }
213 #else
214     inline bool isInteger() const { return tag() == _Integer_Type; }
215     inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
216     inline bool isNumber() const { return tag() == _Integer_Type || (tag() & NotDouble_Mask) != NotDouble_Mask; }
217     inline bool isManaged() const { return tag() == Managed_Type; }
218     inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; }
219     inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; }
220     static inline bool integerCompatible(Value a, Value b) {
221         return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt;
222     }
223     static inline bool bothDouble(Value a, Value b) {
224         return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
225     }
226     inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
227 #endif
228     Q_ALWAYS_INLINE double doubleValue() const {
229         Q_ASSERT(isDouble());
230         double d;
231         quint64 v = _val;
232 #if QT_POINTER_SIZE == 8
233         v ^= NaNEncodeMask;
234 #endif
235         memcpy(&d, &v, 8);
236         return d;
237     }
238     Q_ALWAYS_INLINE void setDouble(double d) {
239         memcpy(&_val, &d, 8);
240 #if QT_POINTER_SIZE == 8
241         _val ^= NaNEncodeMask;
242 #endif
243         Q_ASSERT(isDouble());
244     }
245     inline bool isString() const;
246     inline bool isObject() const;
247     inline bool isInt32() {
248         if (tag() == _Integer_Type)
249             return true;
250         if (isDouble()) {
251             double d = doubleValue();
252             int i = (int)d;
253             if (i == d) {
254                 setInt_32(i);
255                 setTag(_Integer_Type);
256                 return true;
257             }
258         }
259         return false;
260     }
261     double asDouble() const {
262         if (tag() == _Integer_Type)
263             return int_32();
264         return doubleValue();
265     }
266
267     bool booleanValue() const {
268         return int_32();
269     }
270     int integerValue() const {
271         return int_32();
272     }
273
274     Q_ALWAYS_INLINE String *stringValue() const {
275         return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0;
276     }
277     Q_ALWAYS_INLINE Object *objectValue() const {
278         return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0;
279     }
280     Q_ALWAYS_INLINE Managed *managed() const {
281         return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0;
282     }
283     Q_ALWAYS_INLINE Heap::Base *heapObject() const {
284         return m();
285     }
286
287     Q_ALWAYS_INLINE quint64 &rawValueRef() {
288         return _val;
289     }
290     Q_ALWAYS_INLINE quint64 rawValue() const {
291         return _val;
292     }
293     Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
294
295     static inline Value fromHeapObject(Heap::Base *m)
296     {
297         Value v;
298         v.setRawValue(0);
299         v.setM(m);
300 #if QT_POINTER_SIZE == 4
301         v.setTag(Managed_Type);
302 #endif
303         return v;
304     }
305
306     int toUInt16() const;
307     inline int toInt32() const;
308     inline unsigned int toUInt32() const;
309
310     bool toBoolean() const;
311     double toInteger() const;
312     inline double toNumber() const;
313     double toNumberImpl() const;
314     QString toQStringNoThrow() const;
315     QString toQString() const;
316     Heap::String *toString(ExecutionEngine *e) const;
317     Heap::Object *toObject(ExecutionEngine *e) const;
318
319     inline bool isPrimitive() const;
320     inline bool tryIntegerConversion() {
321         bool b = integerCompatible();
322         if (b)
323             setTag(_Integer_Type);
324         return b;
325     }
326
327     template <typename T>
328     const T *as() const {
329         if (!m() || !isManaged())
330             return 0;
331
332         Q_ASSERT(m()->vtable());
333 #if !defined(QT_NO_QOBJECT_CHECK)
334         static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this));
335 #endif
336         const VTable *vt = m()->vtable();
337         while (vt) {
338             if (vt == T::staticVTable())
339                 return static_cast<const T *>(this);
340             vt = vt->parent;
341         }
342         return 0;
343     }
344     template <typename T>
345     T *as() {
346         return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
347     }
348
349     template<typename T> inline T *cast() {
350         return static_cast<T *>(managed());
351     }
352     template<typename T> inline const T *cast() const {
353         return static_cast<const T *>(managed());
354     }
355
356     inline uint asArrayIndex() const;
357 #ifndef V4_BOOTSTRAP
358     uint asArrayLength(bool *ok) const;
359 #endif
360
361     ReturnedValue asReturnedValue() const { return _val; }
362     static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; }
363
364     // Section 9.12
365     bool sameValue(Value other) const;
366
367     inline void mark(ExecutionEngine *e);
368
369     Value &operator =(const ScopedValue &v);
370     Value &operator=(ReturnedValue v) { _val = v; return *this; }
371     Value &operator=(Managed *m) {
372         if (!m) {
373             setTagValue(Undefined_Type, 0);
374         } else {
375             _val = reinterpret_cast<Value *>(m)->_val;
376         }
377         return *this;
378     }
379     Value &operator=(Heap::Base *o) {
380         setM(o);
381 #if QT_POINTER_SIZE == 4
382         setTag(Managed_Type);
383 #endif
384         return *this;
385     }
386
387     template<typename T>
388     Value &operator=(const Scoped<T> &t);
389     Value &operator=(const Value &v) {
390         _val = v._val;
391         return *this;
392     }
393 };
394
395 inline bool Value::isString() const
396 {
397     if (!isManaged())
398         return false;
399     return m() && m()->vtable()->isString;
400 }
401 inline bool Value::isObject() const
402 {
403     if (!isManaged())
404         return false;
405     return m() && m()->vtable()->isObject;
406 }
407
408 inline bool Value::isPrimitive() const
409 {
410     return !isObject();
411 }
412
413 inline double Value::toNumber() const
414 {
415     if (isInteger())
416         return int_32();
417     if (isDouble())
418         return doubleValue();
419     return toNumberImpl();
420 }
421
422
423 #ifndef V4_BOOTSTRAP
424 inline uint Value::asArrayIndex() const
425 {
426 #if QT_POINTER_SIZE == 8
427     if (!isNumber())
428         return UINT_MAX;
429     if (isInteger())
430         return int_32() >= 0 ? (uint)int_32() : UINT_MAX;
431 #else
432     if (isInteger() && int_32() >= 0)
433         return (uint)int_32();
434     if (!isDouble())
435         return UINT_MAX;
436 #endif
437     double d = doubleValue();
438     uint idx = (uint)d;
439     if (idx != d)
440         return UINT_MAX;
441     return idx;
442 }
443 #endif
444
445 inline
446 ReturnedValue Heap::Base::asReturnedValue() const
447 {
448     return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue();
449 }
450
451
452
453 struct Q_QML_PRIVATE_EXPORT Primitive : public Value
454 {
455     inline static Primitive emptyValue();
456     static inline Primitive fromBoolean(bool b);
457     static inline Primitive fromInt32(int i);
458     inline static Primitive undefinedValue();
459     static inline Primitive nullValue();
460     static inline Primitive fromDouble(double d);
461     static inline Primitive fromUInt32(uint i);
462
463     using Value::toInt32;
464     using Value::toUInt32;
465
466     static double toInteger(double fromNumber);
467     static int toInt32(double value);
468     static unsigned int toUInt32(double value);
469 };
470
471 inline Primitive Primitive::undefinedValue()
472 {
473     Primitive v;
474 #if QT_POINTER_SIZE == 8
475     v.setRawValue(quint64(Undefined_Type) << Tag_Shift);
476 #else
477     v.setRawValue(0);
478     v.setTag(Undefined_Type);
479     v.setValue(0);
480 #endif
481     return v;
482 }
483
484 inline Primitive Primitive::emptyValue()
485 {
486     Primitive v;
487     v.setTagValue(Value::Empty_Type, 0);
488     return v;
489 }
490
491 inline Primitive Primitive::nullValue()
492 {
493     Primitive v;
494 #if QT_POINTER_SIZE == 8
495     v.setRawValue(quint64(_Null_Type) << Tag_Shift);
496 #else
497     v.setTagValue(_Null_Type, 0);
498 #endif
499     return v;
500 }
501
502 inline Primitive Primitive::fromBoolean(bool b)
503 {
504     Primitive v;
505     v.setTagValue(_Boolean_Type, b);
506     return v;
507 }
508
509 inline Primitive Primitive::fromDouble(double d)
510 {
511     Primitive v;
512     v.setDouble(d);
513     return v;
514 }
515
516 inline Primitive Primitive::fromInt32(int i)
517 {
518     Primitive v;
519     v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
520     v.setInt_32(i);
521     return v;
522 }
523
524 inline Primitive Primitive::fromUInt32(uint i)
525 {
526     Primitive v;
527     if (i < INT_MAX) {
528         v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
529         v.setInt_32((int)i);
530     } else {
531         v.setDouble(i);
532     }
533     return v;
534 }
535
536 struct Encode {
537     static ReturnedValue undefined() {
538         return quint64(Value::Undefined_Type) << Value::Tag_Shift;
539     }
540     static ReturnedValue null() {
541         return quint64(Value::_Null_Type) << Value::Tag_Shift;
542     }
543
544     Encode(bool b) {
545         val = (quint64(Value::_Boolean_Type) << Value::Tag_Shift) | (uint)b;
546     }
547     Encode(double d) {
548         Value v;
549         v.setDouble(d);
550         val = v.rawValue();
551     }
552     Encode(int i) {
553         val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i;
554     }
555     Encode(uint i) {
556         if (i <= INT_MAX) {
557             val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | i;
558         } else {
559             Value v;
560             v.setDouble(i);
561             val = v.rawValue();
562         }
563     }
564     Encode(ReturnedValue v) {
565         val = v;
566     }
567
568     Encode(Heap::Base *o) {
569         Q_ASSERT(o);
570         val = Value::fromHeapObject(o).asReturnedValue();
571     }
572
573     operator ReturnedValue() const {
574         return val;
575     }
576     quint64 val;
577 private:
578     Encode(void *);
579 };
580
581 template<typename T>
582 ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
583
584 inline int Value::toInt32() const
585 {
586     if (isInteger())
587         return int_32();
588     double d = isNumber() ? doubleValue() : toNumberImpl();
589
590     const double D32 = 4294967296.0;
591     const double D31 = D32 / 2.0;
592
593     if ((d >= -D31 && d < D31))
594         return static_cast<int>(d);
595
596     return Primitive::toInt32(d);
597 }
598
599 inline unsigned int Value::toUInt32() const
600 {
601     return (unsigned int)toInt32();
602 }
603
604
605 }
606
607 QT_END_NAMESPACE
608
609 #endif // QV4VALUE_DEF_P_H