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
65QT_BEGIN_NAMESPACE
66
67namespace QV4 {
68
69namespace Heap {
70 struct Base;
71}
72
73struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
74{
75 using HeapBasePtr = Heap::Base *;
76 using ManagedPtr = Managed *;
77
78 Value() = default;
79 constexpr Value(quint64 val) : StaticValue(val) {}
80
81 static constexpr Value fromStaticValue(StaticValue staticValue)
82 {
83 return {staticValue._val};
84 }
85
86#if QT_POINTER_SIZE == 8
87 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 }
103 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
115 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 }
123 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
139 QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
140 if (!isString())
141 return nullptr;
142 return reinterpret_cast<String *>(const_cast<Value *>(this));
143 }
144 QML_NEARLY_ALWAYS_INLINE StringOrSymbol *stringOrSymbolValue() const {
145 if (!isStringOrSymbol())
146 return nullptr;
147 return reinterpret_cast<StringOrSymbol *>(const_cast<Value *>(this));
148 }
149 QML_NEARLY_ALWAYS_INLINE Symbol *symbolValue() const {
150 if (!isSymbol())
151 return nullptr;
152 return reinterpret_cast<Symbol *>(const_cast<Value *>(this));
153 }
154 QML_NEARLY_ALWAYS_INLINE Object *objectValue() const {
155 if (!isObject())
156 return nullptr;
157 return reinterpret_cast<Object*>(const_cast<Value *>(this));
158 }
159 QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const {
160 if (!isManaged())
161 return nullptr;
162 return reinterpret_cast<Managed*>(const_cast<Value *>(this));
163 }
164 QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const {
165 return isManagedOrUndefined() ? m() : nullptr;
166 }
167
168 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
181 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);
192 double toNumberImpl() const { return toNumberImpl(*this); }
193 QString toQStringNoThrow() const;
194 QString toQString() const;
195 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);
203 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>
213 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>
230 T *as() {
231 if (isManaged())
232 return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
233 else
234 return nullptr;
235 }
236
237 template<typename T> inline T *cast() {
238 return static_cast<T *>(managed());
239 }
240 template<typename T> inline const T *cast() const {
241 return static_cast<const T *>(managed());
242 }
243
244 uint asArrayLength(bool *ok) const;
245
246 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
257 static double toInteger(double d) { return StaticValue::toInteger(d); }
258 static int toInt32(double d) { return StaticValue::toInt32(d); }
259 static unsigned int toUInt32(double d) { return StaticValue::toUInt32(d); }
260 inline static constexpr Value emptyValue()
261 {
262 return fromStaticValue(StaticValue::emptyValue());
263 }
264 static inline constexpr Value fromBoolean(bool b)
265 {
266 return fromStaticValue(StaticValue::fromBoolean(b));
267 }
268 static inline constexpr Value fromInt32(int i)
269 {
270 return fromStaticValue(StaticValue::fromInt32(i));
271 }
272 inline static constexpr Value undefinedValue()
273 {
274 return fromStaticValue(StaticValue::undefinedValue());
275 }
276 static inline constexpr Value nullValue()
277 {
278 return fromStaticValue(StaticValue::nullValue());
279 }
280 static inline Value fromDouble(double d)
281 {
282 return fromStaticValue(StaticValue::fromDouble(d));
283 }
284 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};
311Q_STATIC_ASSERT(std::is_trivial<Value>::value);
312Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
313
314template<>
315inline StaticValue &StaticValue::operator=<Value>(const Value &value)
316{
317 _val = value._val;
318 return *this;
319}
320
321template<typename Managed>
322inline StaticValue &StaticValue::operator=(const Managed &m)
323{
324 *static_cast<Value *>(this) = m;
325 return *this;
326}
327
328template<>
329inline Value &StaticValue::asValue<Value>()
330{
331 return *static_cast<Value *>(this);
332}
333
334template<>
335inline const Value &StaticValue::asValue<Value>() const
336{
337 return *static_cast<const Value *>(this);
338}
339
340template<>
341inline Value *CallData::argValues<Value>()
342{
343 return static_cast<Value *>(static_cast<StaticValue *>(args));
344}
345
346template<>
347inline const Value *CallData::argValues<Value>() const
348{
349 return static_cast<const Value *>(static_cast<const StaticValue *>(args));
350}
351
352template<typename HeapBase>
353inline Encode::Encode(HeapBase *o)
354{
355 val = Value::fromHeapObject(o).asReturnedValue();
356}
357
358inline void Value::mark(MarkStack *markStack)
359{
360 HeapBasePtr o = heapObject();
361 if (o)
362 o->mark(markStack);
363}
364
365inline bool Value::isString() const
366{
367 HeapBasePtr b = heapObject();
368 return b && b->internalClass->vtable->isString;
369}
370
371bool Value::isStringOrSymbol() const
372{
373 HeapBasePtr b = heapObject();
374 return b && b->internalClass->vtable->isStringOrSymbol;
375}
376
377bool Value::isSymbol() const
378{
379 HeapBasePtr b = heapObject();
380 return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
381}
382
383inline bool Value::isObject() const
384
385{
386 HeapBasePtr b = heapObject();
387 return b && b->internalClass->vtable->isObject;
388}
389
390inline bool Value::isFunctionObject() const
391{
392 HeapBasePtr b = heapObject();
393 return b && b->internalClass->vtable->isFunctionObject;
394}
395
396inline bool Value::isPrimitive() const
397{
398 return !isObject();
399}
400
401inline double Value::toNumber() const
402{
403 if (isInteger())
404 return int_32();
405 if (isDouble())
406 return doubleValue();
407 return toNumberImpl();
408}
409
410inline 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
419inline
420ReturnedValue 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
426using Primitive = Value;
427
428template<typename T>
429ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
430
431inline 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
442inline unsigned int Value::toUInt32() const
443{
444 return static_cast<unsigned int>(toInt32());
445}
446
447inline 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
459inline 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
472inline double Value::toInteger() const
473{
474 if (integerCompatible())
475 return int_32();
476
477 return Value::toInteger(isDouble() ? doubleValue() : toNumberImpl());
478}
479
480
481template <size_t o>
482struct HeapValue : Value {
483 static Q_CONSTEXPR size_t offset = o;
484 HeapBasePtr base() {
485 HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
486 Q_ASSERT(base->inUse());
487 return base;
488 }
489
490 void set(EngineBase *e, const Value &newVal) {
491 WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue());
492 }
493 void set(EngineBase *e, HeapBasePtr b) {
494 WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue());
495 }
496};
497
498template <size_t o>
499struct ValueArray {
500 static Q_CONSTEXPR size_t offset = o;
501 uint size;
502 uint alloc;
503 Value values[1];
504
505 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
512 void set(EngineBase *e, uint index, Value v) {
513 WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
514 }
515 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 }
522 inline const Value *data() const {
523 return values;
524 }
525
526 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
539 void mark(MarkStack *markStack) {
540 Value *v = values;
541 const Value *end = v + alloc;
542 if (alloc > 32*1024) {
543 // drain from time to time to avoid overflows in the js stack
544 Value::HeapBasePtr *currentBase = markStack->top;
545 while (v < end) {
546 v->mark(markStack);
547 ++v;
548 if (markStack->top >= currentBase + 32*1024) {
549 Value::HeapBasePtr *oldBase = markStack->base;
550 markStack->base = currentBase;
551 markStack->drain();
552 markStack->base = oldBase;
553 }
554 }
555 } else {
556 while (v < end) {
557 v->mark(markStack);
558 ++v;
559 }
560 }
561 }
562};
563
564// It's really important that the offset of values in this structure is
565// constant across all architecture, otherwise JIT cross-compiled code will
566// have wrong offsets between host and target.
567Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
568
569class OptionalReturnedValue {
570 ReturnedValue value;
571public:
572
573 OptionalReturnedValue() : value(Value::emptyValue().asReturnedValue()) {}
574 explicit OptionalReturnedValue(ReturnedValue v)
575 : value(v)
576 {
577 Q_ASSERT(!Value::fromReturnedValue(v).isEmpty());
578 }
579
580 ReturnedValue operator->() const { return value; }
581 ReturnedValue operator*() const { return value; }
582 explicit operator bool() const { return !Value::fromReturnedValue(value).isEmpty(); }
583};
584
585}
586
587QT_END_NAMESPACE
588
589#endif // QV4VALUE_DEF_P_H
590