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