1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 #ifndef QV4VALUE_P_H
40 #define QV4VALUE_P_H
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51 //
52 
53 #include <limits.h>
54 #include <cmath>
55 
56 #include <QtCore/QString>
57 #include "qv4global_p.h"
58 #include <private/qv4heap_p.h>
59 #include <private/qv4internalclass_p.h>
60 #include <private/qv4staticvalue_p.h>
61 
62 #include <private/qnumeric_p.h>
63 #include <private/qv4calldata_p.h>
64 
65 QT_BEGIN_NAMESPACE
66 
67 namespace QV4 {
68 
69 namespace Heap {
70     struct Base;
71 }
72 
73 struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
74 {
75     using HeapBasePtr = Heap::Base *;
76     using ManagedPtr = Managed *;
77 
78     Value() = default;
ValueValue79     constexpr Value(quint64 val) : StaticValue(val) {}
80 
fromStaticValueValue81     static constexpr Value fromStaticValue(StaticValue staticValue)
82     {
83         return {staticValue._val};
84     }
85 
86 #if QT_POINTER_SIZE == 8
mValue87     QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
88     {
89         HeapBasePtr b;
90 #ifdef __ia64
91 // Restore bits 49-47 to bits 63-61, undoing the workaround explained in
92 // setM below.
93         quint64 _tmp;
94 
95         _tmp = _val & (7L << 47); // 0x3800000000000
96         _tmp = (_tmp << 14) | (_val ^ _tmp);
97         memcpy(&b, &_tmp, 8);
98 #else
99         memcpy(&b, &_val, 8);
100 #endif
101         return b;
102     }
setMValue103     QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
104     {
105         memcpy(&_val, &b, 8);
106 #ifdef __ia64
107 // On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
108 // number.  Since this implementation is not 64-bit clean, we move bits 63-61
109 // to bits 49-47 and hope for the best.  This is undone in *m(), above.
110         _val |= ((_val & (7L << 61)) >> 14);
111         _val &= ((1L << 50)-1);
112 #endif
113     }
114 #elif QT_POINTER_SIZE == 4
mValue115     QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
116     {
117         Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
118         HeapBasePtr b;
119         quint32 v = value();
120         memcpy(&b, &v, 4);
121         return b;
122     }
setMValue123     QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
124     {
125         quint32 v;
126         memcpy(&v, &b, 4);
127         setTagValue(Managed_Type_Internal, v);
128     }
129 #else
130 #  error "unsupported pointer size"
131 #endif
132 
133     inline bool isString() const;
134     inline bool isStringOrSymbol() const;
135     inline bool isSymbol() const;
136     inline bool isObject() const;
137     inline bool isFunctionObject() const;
138 
stringValueValue139     QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
140         if (!isString())
141             return nullptr;
142         return reinterpret_cast<String *>(const_cast<Value *>(this));
143     }
stringOrSymbolValueValue144     QML_NEARLY_ALWAYS_INLINE StringOrSymbol *stringOrSymbolValue() const {
145         if (!isStringOrSymbol())
146             return nullptr;
147         return reinterpret_cast<StringOrSymbol *>(const_cast<Value *>(this));
148     }
symbolValueValue149     QML_NEARLY_ALWAYS_INLINE Symbol *symbolValue() const {
150         if (!isSymbol())
151             return nullptr;
152         return reinterpret_cast<Symbol *>(const_cast<Value *>(this));
153     }
objectValueValue154     QML_NEARLY_ALWAYS_INLINE Object *objectValue() const {
155         if (!isObject())
156             return nullptr;
157         return reinterpret_cast<Object*>(const_cast<Value *>(this));
158     }
managedValue159     QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const {
160         if (!isManaged())
161             return nullptr;
162         return reinterpret_cast<Managed*>(const_cast<Value *>(this));
163     }
heapObjectValue164     QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const {
165         return isManagedOrUndefined() ? m() : nullptr;
166     }
167 
fromHeapObjectValue168     static inline Value fromHeapObject(HeapBasePtr m)
169     {
170         Value v;
171         v.setM(m);
172         return v;
173     }
174 
175     int toUInt16() const;
176     inline int toInt32() const;
177     inline unsigned int toUInt32() const;
178     qint64 toLength() const;
179     inline qint64 toIndex() const;
180 
toBooleanValue181     bool toBoolean() const {
182         if (integerCompatible())
183             return static_cast<bool>(int_32());
184 
185         return toBooleanImpl(*this);
186     }
187     static bool toBooleanImpl(Value val);
188     double toInteger() const;
189     inline ReturnedValue convertedToNumber() const;
190     inline double toNumber() const;
191     static double toNumberImpl(Value v);
toNumberImplValue192     double toNumberImpl() const { return toNumberImpl(*this); }
193     QString toQStringNoThrow() const;
194     QString toQString() const;
toStringValue195     Heap::String *toString(ExecutionEngine *e) const {
196         if (isString())
197             return reinterpret_cast<Heap::String *>(m());
198         return toString(e, *this);
199     }
200     QV4::PropertyKey toPropertyKey(ExecutionEngine *e) const;
201 
202     static Heap::String *toString(ExecutionEngine *e, Value val);
toObjectValue203     Heap::Object *toObject(ExecutionEngine *e) const {
204         if (isObject())
205             return reinterpret_cast<Heap::Object *>(m());
206         return toObject(e, *this);
207     }
208     static Heap::Object *toObject(ExecutionEngine *e, Value val);
209 
210     inline bool isPrimitive() const;
211 
212     template <typename T>
asValue213     const T *as() const {
214         if (!isManaged())
215             return nullptr;
216 
217         Q_ASSERT(m()->internalClass->vtable);
218 #if !defined(QT_NO_QOBJECT_CHECK)
219         static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this));
220 #endif
221         const VTable *vt = m()->internalClass->vtable;
222         while (vt) {
223             if (vt == T::staticVTable())
224                 return static_cast<const T *>(this);
225             vt = vt->parent;
226         }
227         return nullptr;
228     }
229     template <typename T>
asValue230     T *as() {
231         if (isManaged())
232             return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
233         else
234             return nullptr;
235     }
236 
castValue237     template<typename T> inline T *cast() {
238         return static_cast<T *>(managed());
239     }
castValue240     template<typename T> inline const T *cast() const {
241         return static_cast<const T *>(managed());
242     }
243 
244     uint asArrayLength(bool *ok) const;
245 
fromReturnedValueValue246     static constexpr Value fromReturnedValue(ReturnedValue val)
247     {
248         return fromStaticValue(StaticValue::fromReturnedValue(val));
249     }
250 
251     // As per ES specs
252     bool sameValue(Value other) const;
253     bool sameValueZero(Value other) const;
254 
255     inline void mark(MarkStack *markStack);
256 
toIntegerValue257     static double toInteger(double d) { return StaticValue::toInteger(d); }
toInt32Value258     static int toInt32(double d) { return StaticValue::toInt32(d); }
toUInt32Value259     static unsigned int toUInt32(double d) { return StaticValue::toUInt32(d); }
emptyValueValue260     inline static constexpr Value emptyValue()
261     {
262         return fromStaticValue(StaticValue::emptyValue());
263     }
fromBooleanValue264     static inline constexpr Value fromBoolean(bool b)
265     {
266         return fromStaticValue(StaticValue::fromBoolean(b));
267     }
fromInt32Value268     static inline constexpr Value fromInt32(int i)
269     {
270         return fromStaticValue(StaticValue::fromInt32(i));
271     }
undefinedValueValue272     inline static constexpr Value undefinedValue()
273     {
274         return fromStaticValue(StaticValue::undefinedValue());
275     }
nullValueValue276     static inline constexpr Value nullValue()
277     {
278         return fromStaticValue(StaticValue::nullValue());
279     }
fromDoubleValue280     static inline Value fromDouble(double d)
281     {
282         return fromStaticValue(StaticValue::fromDouble(d));
283     }
fromUInt32Value284     static inline Value fromUInt32(uint i)
285     {
286         return fromStaticValue(StaticValue::fromUInt32(i));
287     }
288 
289     Value &operator =(const ScopedValue &v);
290     Value &operator=(ReturnedValue v)
291     {
292         StaticValue::operator=(v);
293         return *this;
294     }
295     Value &operator=(ManagedPtr m) {
296         if (!m) {
297             setM(nullptr);
298         } else {
299             _val = reinterpret_cast<Value *>(m)->_val;
300         }
301         return *this;
302     }
303     Value &operator=(HeapBasePtr o) {
304         setM(o);
305         return *this;
306     }
307 
308     template<typename T>
309     Value &operator=(const Scoped<T> &t);
310 };
311 Q_STATIC_ASSERT(std::is_trivial<Value>::value);
312 Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
313 
314 template<>
315 inline StaticValue &StaticValue::operator=<Value>(const Value &value)
316 {
317     _val = value._val;
318     return *this;
319 }
320 
321 template<typename Managed>
322 inline StaticValue &StaticValue::operator=(const Managed &m)
323 {
324     *static_cast<Value *>(this) = m;
325     return *this;
326 }
327 
328 template<>
329 inline Value &StaticValue::asValue<Value>()
330 {
331     return *static_cast<Value *>(this);
332 }
333 
334 template<>
335 inline const Value &StaticValue::asValue<Value>() const
336 {
337     return *static_cast<const Value *>(this);
338 }
339 
340 template<>
341 inline Value *CallData::argValues<Value>()
342 {
343     return static_cast<Value *>(static_cast<StaticValue *>(args));
344 }
345 
346 template<>
347 inline const Value *CallData::argValues<Value>() const
348 {
349     return static_cast<const Value *>(static_cast<const StaticValue *>(args));
350 }
351 
352 template<typename HeapBase>
Encode(HeapBase * o)353 inline Encode::Encode(HeapBase *o)
354 {
355     val = Value::fromHeapObject(o).asReturnedValue();
356 }
357 
mark(MarkStack * markStack)358 inline void Value::mark(MarkStack *markStack)
359 {
360     HeapBasePtr o = heapObject();
361     if (o)
362         o->mark(markStack);
363 }
364 
isString()365 inline bool Value::isString() const
366 {
367     HeapBasePtr b = heapObject();
368     return b && b->internalClass->vtable->isString;
369 }
370 
isStringOrSymbol()371 bool Value::isStringOrSymbol() const
372 {
373     HeapBasePtr b = heapObject();
374     return b && b->internalClass->vtable->isStringOrSymbol;
375 }
376 
isSymbol()377 bool Value::isSymbol() const
378 {
379     HeapBasePtr b = heapObject();
380     return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
381 }
382 
isObject()383 inline bool Value::isObject() const
384 
385 {
386     HeapBasePtr b = heapObject();
387     return b && b->internalClass->vtable->isObject;
388 }
389 
isFunctionObject()390 inline bool Value::isFunctionObject() const
391 {
392     HeapBasePtr b = heapObject();
393     return b && b->internalClass->vtable->isFunctionObject;
394 }
395 
isPrimitive()396 inline bool Value::isPrimitive() const
397 {
398     return !isObject();
399 }
400 
toNumber()401 inline double Value::toNumber() const
402 {
403     if (isInteger())
404         return int_32();
405     if (isDouble())
406         return doubleValue();
407     return toNumberImpl();
408 }
409 
convertedToNumber()410 inline ReturnedValue Value::convertedToNumber() const
411 {
412     if (isInteger() || isDouble())
413         return asReturnedValue();
414     Value v;
415     v.setDouble(toNumberImpl());
416     return v.asReturnedValue();
417 }
418 
419 inline
asReturnedValue()420 ReturnedValue Heap::Base::asReturnedValue() const
421 {
422     return Value::fromHeapObject(const_cast<Value::HeapBasePtr>(this)).asReturnedValue();
423 }
424 
425 // For source compat with older code in other modules
426 using Primitive = Value;
427 
428 template<typename T>
429 ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
430 
toInt32()431 inline int Value::toInt32() const
432 {
433     if (Q_LIKELY(integerCompatible()))
434         return int_32();
435 
436     if (Q_LIKELY(isDouble()))
437         return Double::toInt32(doubleValue());
438 
439     return Double::toInt32(toNumberImpl());
440 }
441 
toUInt32()442 inline unsigned int Value::toUInt32() const
443 {
444     return static_cast<unsigned int>(toInt32());
445 }
446 
toLength()447 inline qint64 Value::toLength() const
448 {
449     if (Q_LIKELY(integerCompatible()))
450         return int_32() < 0 ? 0 : int_32();
451     double i = Value::toInteger(isDouble() ? doubleValue() : toNumberImpl());
452     if (i <= 0)
453         return 0;
454     if (i > (static_cast<qint64>(1) << 53) - 1)
455         return (static_cast<qint64>(1) << 53) - 1;
456     return static_cast<qint64>(i);
457 }
458 
toIndex()459 inline qint64 Value::toIndex() const
460 {
461     qint64 idx;
462     if (Q_LIKELY(integerCompatible())) {
463         idx = int_32();
464     } else {
465         idx = static_cast<qint64>(Value::toInteger(isDouble() ? doubleValue() : toNumberImpl()));
466     }
467     if (idx > (static_cast<qint64>(1) << 53) - 1)
468         idx = -1;
469     return idx;
470 }
471 
toInteger()472 inline double Value::toInteger() const
473 {
474     if (integerCompatible())
475         return int_32();
476 
477     return Value::toInteger(isDouble() ? doubleValue() : toNumberImpl());
478 }
479 
480 
481 template <size_t o>
482 struct HeapValue : Value {
483     static Q_CONSTEXPR size_t offset = o;
baseHeapValue484     HeapBasePtr base() {
485         HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
486         Q_ASSERT(base->inUse());
487         return base;
488     }
489 
setHeapValue490     void set(EngineBase *e, const Value &newVal) {
491         WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue());
492     }
setHeapValue493     void set(EngineBase *e, HeapBasePtr b) {
494         WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue());
495     }
496 };
497 
498 template <size_t o>
499 struct ValueArray {
500     static Q_CONSTEXPR size_t offset = o;
501     uint size;
502     uint alloc;
503     Value values[1];
504 
baseValueArray505     Value::HeapBasePtr base() {
506         Value::HeapBasePtr base = reinterpret_cast<Value::HeapBasePtr>(this)
507                 - (offset/sizeof(Heap::Base));
508         Q_ASSERT(base->inUse());
509         return base;
510     }
511 
setValueArray512     void set(EngineBase *e, uint index, Value v) {
513         WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
514     }
setValueArray515     void set(EngineBase *e, uint index, Value::HeapBasePtr b) {
516         WriteBarrier::write(e, base(), values[index].data_ptr(), Value::fromHeapObject(b).asReturnedValue());
517     }
518     inline const Value &operator[] (uint index) const {
519         Q_ASSERT(index < alloc);
520         return values[index];
521     }
dataValueArray522     inline const Value *data() const {
523         return values;
524     }
525 
insertDataValueArray526     void insertData(EngineBase *e, uint index, Value v) {
527         for (uint i = size - 1; i > index; --i) {
528             values[i] = values[i - 1];
529         }
530         set(e, index, v);
531     }
532     void removeData(EngineBase *e, uint index, int n = 1) {
533         Q_UNUSED(e);
534         for (uint i = index; i < size - n; ++i) {
535             values[i] = values[i + n];
536         }
537     }
538 
markValueArray539     void mark(MarkStack *markStack) {
540         for (Value *v = values, *end = values + alloc; v < end; ++v)
541             v->mark(markStack);
542     }
543 };
544 
545 // It's really important that the offset of values in this structure is
546 // constant across all architecture,  otherwise JIT cross-compiled code will
547 // have wrong offsets between host and target.
548 Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
549 
550 class OptionalReturnedValue {
551     ReturnedValue value;
552 public:
553 
OptionalReturnedValue()554     OptionalReturnedValue() : value(Value::emptyValue().asReturnedValue()) {}
OptionalReturnedValue(ReturnedValue v)555     explicit OptionalReturnedValue(ReturnedValue v)
556         : value(v)
557     {
558         Q_ASSERT(!Value::fromReturnedValue(v).isEmpty());
559     }
560 
561     ReturnedValue operator->() const { return value; }
562     ReturnedValue operator*() const { return value; }
563     explicit operator bool() const { return !Value::fromReturnedValue(value).isEmpty(); }
564 };
565 
566 }
567 
568 QT_END_NAMESPACE
569 
570 #endif // QV4VALUE_DEF_P_H
571