1// Copyright (C) 2016 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 QV4VALUE_P_H
4#define QV4VALUE_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 <limits.h>
18#include <cmath>
19
20#include <QtCore/QString>
21#include "qv4global_p.h"
22#include <private/qv4heap_p.h>
23#include <private/qv4internalclass_p.h>
24#include <private/qv4staticvalue_p.h>
25
26#include <private/qnumeric_p.h>
27#include <private/qv4calldata_p.h>
28
29QT_BEGIN_NAMESPACE
30
31namespace QV4 {
32
33namespace Heap {
34 struct Base;
35}
36
37struct Q_QML_EXPORT Value : public StaticValue
38{
39 using ManagedPtr = Managed *;
40
41 static constexpr Value fromStaticValue(StaticValue staticValue)
42 {
43 return {staticValue._val};
44 }
45
46 static constexpr Value undefinded()
47 {
48 return fromStaticValue(staticValue: Encode::undefined());
49 }
50
51 inline bool isString() const;
52 inline bool isStringOrSymbol() const;
53 inline bool isSymbol() const;
54 inline bool isObject() const;
55 inline bool isFunctionObject() const;
56
57 QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
58 if (!isString())
59 return nullptr;
60 return reinterpret_cast<String *>(const_cast<Value *>(this));
61 }
62 QML_NEARLY_ALWAYS_INLINE StringOrSymbol *stringOrSymbolValue() const {
63 if (!isStringOrSymbol())
64 return nullptr;
65 return reinterpret_cast<StringOrSymbol *>(const_cast<Value *>(this));
66 }
67 QML_NEARLY_ALWAYS_INLINE Symbol *symbolValue() const {
68 if (!isSymbol())
69 return nullptr;
70 return reinterpret_cast<Symbol *>(const_cast<Value *>(this));
71 }
72 QML_NEARLY_ALWAYS_INLINE Object *objectValue() const {
73 if (!isObject())
74 return nullptr;
75 return reinterpret_cast<Object*>(const_cast<Value *>(this));
76 }
77 QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const {
78 if (!isManaged())
79 return nullptr;
80 return reinterpret_cast<Managed*>(const_cast<Value *>(this));
81 }
82 QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const {
83 return isManagedOrUndefined() ? m() : nullptr;
84 }
85
86 static inline Value fromHeapObject(HeapBasePtr m)
87 {
88 Value v;
89 v.setM(m);
90 return v;
91 }
92
93 int toUInt16() const;
94 inline int toInt32() const;
95 inline unsigned int toUInt32() const;
96 qint64 toLength() const;
97 inline qint64 toIndex() const;
98
99 bool toBoolean() const {
100 if (integerCompatible())
101 return static_cast<bool>(int_32());
102
103 return toBooleanImpl(val: *this);
104 }
105 static bool toBooleanImpl(Value val);
106 double toInteger() const;
107 inline ReturnedValue convertedToNumber() const;
108 inline double toNumber() const;
109 static double toNumberImpl(Value v);
110 double toNumberImpl() const { return toNumberImpl(v: *this); }
111
112 QString toQStringNoThrow() const;
113 QString toQString() const;
114 QString toQString(bool *ok) const;
115
116 Heap::String *toString(ExecutionEngine *e) const {
117 if (isString())
118 return reinterpret_cast<Heap::String *>(m());
119 return toString(e, val: *this);
120 }
121 QV4::PropertyKey toPropertyKey(ExecutionEngine *e) const;
122
123 static Heap::String *toString(ExecutionEngine *e, Value val);
124 Heap::Object *toObject(ExecutionEngine *e) const {
125 if (isObject())
126 return reinterpret_cast<Heap::Object *>(m());
127 return toObject(e, val: *this);
128 }
129 static Heap::Object *toObject(ExecutionEngine *e, Value val);
130
131 inline bool isPrimitive() const;
132
133 template <typename T>
134 const T *as() const {
135 if (!isManaged())
136 return nullptr;
137
138 Q_ASSERT(m()->internalClass->vtable);
139#if !defined(QT_NO_QOBJECT_CHECK)
140 static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this));
141#endif
142 const VTable *vt = m()->internalClass->vtable;
143 while (vt) {
144 if (vt == T::staticVTable())
145 return static_cast<const T *>(this);
146 vt = vt->parent;
147 }
148 return nullptr;
149 }
150 template <typename T>
151 T *as() {
152 if (isManaged())
153 return const_cast<T *>(const_cast<const Value *>(this)->as<T>());
154 else
155 return nullptr;
156 }
157
158 template<typename T> inline T *cast() {
159 return static_cast<T *>(managed());
160 }
161 template<typename T> inline const T *cast() const {
162 return static_cast<const T *>(managed());
163 }
164
165 uint asArrayLength(bool *ok) const;
166
167 static constexpr Value fromReturnedValue(ReturnedValue val)
168 {
169 return fromStaticValue(staticValue: StaticValue::fromReturnedValue(val));
170 }
171
172 // As per ES specs
173 bool sameValue(Value other) const;
174 bool sameValueZero(Value other) const;
175
176 inline void mark(MarkStack *markStack);
177
178 static double toInteger(double d) { return StaticValue::toInteger(d); }
179 static int toInt32(double d) { return StaticValue::toInt32(d); }
180 static unsigned int toUInt32(double d) { return StaticValue::toUInt32(d); }
181 inline static constexpr Value emptyValue()
182 {
183 return fromStaticValue(staticValue: StaticValue::emptyValue());
184 }
185 static inline constexpr Value fromBoolean(bool b)
186 {
187 return fromStaticValue(staticValue: StaticValue::fromBoolean(b));
188 }
189 static inline constexpr Value fromInt32(int i)
190 {
191 return fromStaticValue(staticValue: StaticValue::fromInt32(i));
192 }
193 inline static constexpr Value undefinedValue()
194 {
195 return fromStaticValue(staticValue: StaticValue::undefinedValue());
196 }
197 static inline constexpr Value nullValue()
198 {
199 return fromStaticValue(staticValue: StaticValue::nullValue());
200 }
201 static inline Value fromDouble(double d)
202 {
203 return fromStaticValue(staticValue: StaticValue::fromDouble(d));
204 }
205 static inline Value fromUInt32(uint i)
206 {
207 return fromStaticValue(staticValue: StaticValue::fromUInt32(i));
208 }
209
210 Value &operator =(const ScopedValue &v);
211 Value &operator=(ReturnedValue v)
212 {
213 StaticValue::operator=(v);
214 return *this;
215 }
216 Value &operator=(ManagedPtr m) {
217 if (!m) {
218 setM(nullptr);
219 } else {
220 _val = reinterpret_cast<Value *>(m)->_val;
221 }
222 return *this;
223 }
224 Value &operator=(HeapBasePtr o) {
225 setM(o);
226 return *this;
227 }
228
229 template<typename T>
230 Value &operator=(const Scoped<T> &t);
231};
232Q_STATIC_ASSERT(std::is_trivial_v<Value>);
233Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
234
235template<>
236inline StaticValue &StaticValue::operator=<Value>(const Value &value)
237{
238 _val = value._val;
239 return *this;
240}
241
242template<typename Managed>
243inline StaticValue &StaticValue::operator=(const Managed &m)
244{
245 *static_cast<Value *>(this) = m;
246 return *this;
247}
248
249template<>
250inline Value &StaticValue::asValue<Value>()
251{
252 return *static_cast<Value *>(this);
253}
254
255template<>
256inline const Value &StaticValue::asValue<Value>() const
257{
258 return *static_cast<const Value *>(this);
259}
260
261template<>
262inline Value *CallData::argValues<Value>()
263{
264 return static_cast<Value *>(static_cast<StaticValue *>(args));
265}
266
267template<>
268inline const Value *CallData::argValues<Value>() const
269{
270 return static_cast<const Value *>(static_cast<const StaticValue *>(args));
271}
272
273template<typename HeapBase>
274inline Encode::Encode(HeapBase *o)
275{
276 val = Value::fromHeapObject(m: o).asReturnedValue();
277}
278
279inline void Value::mark(MarkStack *markStack)
280{
281 HeapBasePtr o = heapObject();
282 if (o)
283 o->mark(markStack);
284}
285
286inline bool Value::isString() const
287{
288 HeapBasePtr b = heapObject();
289 return b && b->internalClass->vtable->isString;
290}
291
292bool Value::isStringOrSymbol() const
293{
294 HeapBasePtr b = heapObject();
295 return b && b->internalClass->vtable->isStringOrSymbol;
296}
297
298bool Value::isSymbol() const
299{
300 HeapBasePtr b = heapObject();
301 return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
302}
303
304inline bool Value::isObject() const
305
306{
307 HeapBasePtr b = heapObject();
308 return b && b->internalClass->vtable->isObject;
309}
310
311inline bool Value::isFunctionObject() const
312{
313 HeapBasePtr b = heapObject();
314 if (!b)
315 return false;
316 const VTable *vtable = b->internalClass->vtable;
317 return vtable->call || vtable->callAsConstructor;
318}
319
320inline bool Value::isPrimitive() const
321{
322 return !isObject();
323}
324
325inline double Value::toNumber() const
326{
327 if (isInteger())
328 return int_32();
329 if (isDouble())
330 return doubleValue();
331 return toNumberImpl();
332}
333
334inline ReturnedValue Value::convertedToNumber() const
335{
336 if (isInteger() || isDouble())
337 return asReturnedValue();
338 Value v;
339 v.setDouble(toNumberImpl());
340 return v.asReturnedValue();
341}
342
343inline
344ReturnedValue Heap::Base::asReturnedValue() const
345{
346 return Value::fromHeapObject(m: const_cast<Value::HeapBasePtr>(this)).asReturnedValue();
347}
348
349// For source compat with older code in other modules
350using Primitive = Value;
351
352template<typename T>
353ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
354
355inline int Value::toInt32() const
356{
357 if (Q_LIKELY(integerCompatible()))
358 return int_32();
359
360 if (Q_LIKELY(isDouble()))
361 return QJSNumberCoercion::toInteger(d: doubleValue());
362
363 return QJSNumberCoercion::toInteger(d: toNumberImpl());
364}
365
366inline unsigned int Value::toUInt32() const
367{
368 return static_cast<unsigned int>(toInt32());
369}
370
371inline qint64 Value::toLength() const
372{
373 if (Q_LIKELY(integerCompatible()))
374 return int_32() < 0 ? 0 : int_32();
375 double i = Value::toInteger(d: isDouble() ? doubleValue() : toNumberImpl());
376 if (i <= 0)
377 return 0;
378 if (i > (static_cast<qint64>(1) << 53) - 1)
379 return (static_cast<qint64>(1) << 53) - 1;
380 return static_cast<qint64>(i);
381}
382
383inline qint64 Value::toIndex() const
384{
385 qint64 idx;
386 if (Q_LIKELY(integerCompatible())) {
387 idx = int_32();
388 } else {
389 idx = static_cast<qint64>(Value::toInteger(d: isDouble() ? doubleValue() : toNumberImpl()));
390 }
391 if (idx > (static_cast<qint64>(1) << 53) - 1)
392 idx = -1;
393 return idx;
394}
395
396inline double Value::toInteger() const
397{
398 if (integerCompatible())
399 return int_32();
400
401 return Value::toInteger(d: isDouble() ? doubleValue() : toNumberImpl());
402}
403
404
405template <size_t o>
406struct HeapValue : Value {
407 static constexpr size_t offset = o;
408 HeapBasePtr base() {
409 HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
410 Q_ASSERT(base->inUse());
411 return base;
412 }
413
414 void set(EngineBase *e, const Value &newVal) {
415 WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue());
416 }
417 void set(EngineBase *e, HeapBasePtr b) {
418 WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue());
419 }
420 void set(EngineBase *e, ReturnedValue rv) {
421 WriteBarrier::write(e, base(), data_ptr(), rv);
422 }
423};
424
425template <size_t o>
426struct ValueArray {
427 static constexpr size_t offset = o;
428 uint size;
429 uint alloc;
430 Value values[1];
431
432 Value::HeapBasePtr base() {
433 Value::HeapBasePtr base = reinterpret_cast<Value::HeapBasePtr>(this)
434 - (offset/sizeof(Heap::Base));
435 Q_ASSERT(base->inUse());
436 return base;
437 }
438
439 void set(EngineBase *e, uint index, Value v) {
440 WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
441 }
442 void set(EngineBase *e, uint index, Value::HeapBasePtr b) {
443 WriteBarrier::write(e, base(), values[index].data_ptr(), Value::fromHeapObject(m: b).asReturnedValue());
444 }
445 inline const Value &operator[] (uint index) const {
446 Q_ASSERT(index < alloc);
447 return values[index];
448 }
449 inline const Value *data() const {
450 return values;
451 }
452
453 void mark(MarkStack *markStack) {
454 for (Value *v = values, *end = values + alloc; v < end; ++v)
455 v->mark(markStack);
456 }
457};
458
459// It's really important that the offset of values in this structure is
460// constant across all architecture, otherwise JIT cross-compiled code will
461// have wrong offsets between host and target.
462Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
463
464class OptionalReturnedValue {
465 ReturnedValue value;
466public:
467
468 OptionalReturnedValue() : value(Value::emptyValue().asReturnedValue()) {}
469 explicit OptionalReturnedValue(ReturnedValue v)
470 : value(v)
471 {
472 Q_ASSERT(!Value::fromReturnedValue(v).isEmpty());
473 }
474
475 ReturnedValue operator->() const { return value; }
476 ReturnedValue operator*() const { return value; }
477 explicit operator bool() const { return !Value::fromReturnedValue(val: value).isEmpty(); }
478};
479
480}
481
482QT_END_NAMESPACE
483
484#endif // QV4VALUE_DEF_P_H
485

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qml/jsruntime/qv4value_p.h