aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4value_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4value_p.h')
-rw-r--r--src/qml/jsruntime/qv4value_p.h249
1 files changed, 132 insertions, 117 deletions
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 7454cbfff4..30cdcaa1cb 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -39,6 +39,14 @@
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
+#if defined(Q_CC_GNU)
+# define Q_ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(Q_CC_MSVC)
+# define Q_ALWAYS_INLINE __forceinline
+#else
+# define Q_ALWAYS_INLINE inline
+#endif
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -73,30 +81,38 @@ struct Q_QML_PRIVATE_EXPORT Value
Bit 15-17 is then used to encode other immediates.
*/
+ quint64 _val;
+
+ Q_ALWAYS_INLINE quint64 val() const { return _val; }
+ Q_ALWAYS_INLINE void setVal(quint64 v) { _val = v; }
+ Q_ALWAYS_INLINE void setValue(quint32 v) { setTagValue(tag(), v); }
+ Q_ALWAYS_INLINE void setTag(quint32 t) { setTagValue(t, value()); }
- union {
- quint64 val;
-#if QT_POINTER_SIZE == 8
- Heap::Base *m;
-#else
- double dbl;
-#endif
- struct {
-#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
- uint tag;
-#endif
- union {
- uint uint_32;
- int int_32;
-#if QT_POINTER_SIZE == 4
- Heap::Base *m;
-#endif
- };
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- uint tag;
+ static inline int valueOffset() { return 0; }
+ static inline int tagOffset() { return 4; }
+ Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
+ Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
+#else // !Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 4; }
+ static inline int tagOffset() { return 0; }
+ Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; }
+ Q_ALWAYS_INLINE quint32 tag() const { return _val & quint64(~quint32(0)); }
+ Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; }
+#endif
+
+#if QT_POINTER_SIZE == 8
+ Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; }
+ Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); }
+#else // QT_POINTER_SIZE == 4
+ Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; }
+ Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); }
#endif
- };
- };
+
+ Q_ALWAYS_INLINE int int_32() const { int i; quint32 v = value(); memcpy(&i, &v, 4); return i; }
+ Q_ALWAYS_INLINE void setInt_32(int i) { quint32 u; memcpy(&u, &i, 4); setValue(u); }
+ Q_ALWAYS_INLINE uint uint_32() const { return value(); }
#if QT_POINTER_SIZE == 4
enum Masks {
@@ -169,116 +185,118 @@ struct Q_QML_PRIVATE_EXPORT Value
#endif
inline unsigned type() const {
- return tag & Type_Mask;
+ return tag() & Type_Mask;
}
// used internally in property
- inline bool isEmpty() const { return tag == Empty_Type; }
+ inline bool isEmpty() const { return tag() == Empty_Type; }
- inline bool isUndefined() const { return tag == Undefined_Type; }
- inline bool isNull() const { return tag == _Null_Type; }
- inline bool isBoolean() const { return tag == _Boolean_Type; }
+ inline bool isUndefined() const { return tag() == Undefined_Type; }
+ inline bool isNull() const { return tag() == _Null_Type; }
+ inline bool isBoolean() const { return tag ()== _Boolean_Type; }
#if QT_POINTER_SIZE == 8
- inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; }
- inline bool isDouble() const { return (val >> IsDouble_Shift); }
- inline bool isNumber() const { return (val >> IsNumber_Shift); }
- inline bool isManaged() const { return !(val >> IsManaged_Shift); }
- inline bool isNullOrUndefined() const { return ((val >> IsManaged_Shift) & ~2) == 1; }
- inline bool integerCompatible() const { return ((val >> IsConvertibleToInt_Shift) & ~2) == 1; }
+ inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; }
+ inline bool isDouble() const { return (_val >> IsDouble_Shift); }
+ inline bool isNumber() const { return (_val >> IsNumber_Shift); }
+ inline bool isManaged() const { return !(_val >> IsManaged_Shift); }
+ inline bool isNullOrUndefined() const { return ((_val >> IsManaged_Shift) & ~2) == 1; }
+ inline bool integerCompatible() const { return ((_val >> IsConvertibleToInt_Shift) & ~2) == 1; }
static inline bool integerCompatible(Value a, Value b) {
return a.integerCompatible() && b.integerCompatible();
}
static inline bool bothDouble(Value a, Value b) {
return a.isDouble() && b.isDouble();
}
- double doubleValue() const {
- Q_ASSERT(isDouble());
- union {
- quint64 i;
- double d;
- } v;
- v.i = val ^ NaNEncodeMask;
- return v.d;
- }
- void setDouble(double d) {
- union {
- quint64 i;
- double d;
- } v;
- v.d = d;
- val = v.i ^ NaNEncodeMask;
- Q_ASSERT(isDouble());
- }
- inline bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; }
+ inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; }
#else
- inline bool isInteger() const { return tag == _Integer_Type; }
- inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
- inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
- inline bool isManaged() const { return tag == Managed_Type; }
- inline bool isNullOrUndefined() const { return (tag & IsNullOrUndefined_Mask) == Undefined_Type; }
- inline bool integerCompatible() const { return (tag & ConvertibleToInt) == ConvertibleToInt; }
+ inline bool isInteger() const { return tag() == _Integer_Type; }
+ inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
+ inline bool isNumber() const { return tag() == _Integer_Type || (tag() & NotDouble_Mask) != NotDouble_Mask; }
+ inline bool isManaged() const { return tag() == Managed_Type; }
+ inline bool isNullOrUndefined() const { return (tag() & IsNullOrUndefined_Mask) == Undefined_Type; }
+ inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; }
static inline bool integerCompatible(Value a, Value b) {
- return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
+ return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt;
}
static inline bool bothDouble(Value a, Value b) {
- return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
+ return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
+ }
+ inline bool isNaN() const { return (tag() & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
+#endif
+ Q_ALWAYS_INLINE double doubleValue() const {
+ Q_ASSERT(isDouble());
+ double d;
+ quint64 v = _val;
+#if QT_POINTER_SIZE == 8
+ v ^= NaNEncodeMask;
+#endif
+ memcpy(&d, &v, 8);
+ return d;
}
- double doubleValue() const { Q_ASSERT(isDouble()); return dbl; }
- void setDouble(double d) { dbl = d; Q_ASSERT(isDouble()); }
- inline bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
+ Q_ALWAYS_INLINE void setDouble(double d) {
+ memcpy(&_val, &d, 8);
+#if QT_POINTER_SIZE == 8
+ _val ^= NaNEncodeMask;
#endif
+ Q_ASSERT(isDouble());
+ }
inline bool isString() const;
inline bool isObject() const;
inline bool isInt32() {
- if (tag == _Integer_Type)
+ if (tag() == _Integer_Type)
return true;
if (isDouble()) {
double d = doubleValue();
int i = (int)d;
if (i == d) {
- int_32 = i;
- tag = _Integer_Type;
+ setInt_32(i);
+ setTag(_Integer_Type);
return true;
}
}
return false;
}
double asDouble() const {
- if (tag == _Integer_Type)
- return int_32;
+ if (tag() == _Integer_Type)
+ return int_32();
return doubleValue();
}
bool booleanValue() const {
- return int_32;
+ return int_32();
}
int integerValue() const {
- return int_32;
+ return int_32();
}
- String *stringValue() const {
- return m ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0;
+ Q_ALWAYS_INLINE String *stringValue() const {
+ return m() ? reinterpret_cast<String*>(const_cast<Value *>(this)) : 0;
}
- Object *objectValue() const {
- return m ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0;
+ Q_ALWAYS_INLINE Object *objectValue() const {
+ return m() ? reinterpret_cast<Object*>(const_cast<Value *>(this)) : 0;
}
- Managed *managed() const {
- return m ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0;
+ Q_ALWAYS_INLINE Managed *managed() const {
+ return m() ? reinterpret_cast<Managed*>(const_cast<Value *>(this)) : 0;
}
- Heap::Base *heapObject() const {
- return m;
+ Q_ALWAYS_INLINE Heap::Base *heapObject() const {
+ return m();
}
- quint64 rawValue() const {
- return val;
+ Q_ALWAYS_INLINE quint64 &rawValueRef() {
+ return _val;
+ }
+ Q_ALWAYS_INLINE quint64 rawValue() const {
+ return _val;
}
+ Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; }
static inline Value fromHeapObject(Heap::Base *m)
{
Value v;
- v.m = m;
+ v.setRawValue(0);
+ v.setM(m);
#if QT_POINTER_SIZE == 4
- v.tag = Managed_Type;
+ v.setTag(Managed_Type);
#endif
return v;
}
@@ -300,20 +318,20 @@ struct Q_QML_PRIVATE_EXPORT Value
inline bool tryIntegerConversion() {
bool b = integerCompatible();
if (b)
- tag = _Integer_Type;
+ setTag(_Integer_Type);
return b;
}
template <typename T>
const T *as() const {
- if (!m || !isManaged())
+ if (!m() || !isManaged())
return 0;
- Q_ASSERT(m->vtable);
+ Q_ASSERT(m()->vtable);
#if !defined(QT_NO_QOBJECT_CHECK)
static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this));
#endif
- const VTable *vt = m->vtable;
+ const VTable *vt = m()->vtable;
while (vt) {
if (vt == T::staticVTable())
return static_cast<const T *>(this);
@@ -338,8 +356,8 @@ struct Q_QML_PRIVATE_EXPORT Value
uint asArrayLength(bool *ok) const;
#endif
- ReturnedValue asReturnedValue() const { return val; }
- static Value fromReturnedValue(ReturnedValue val) { Value v; v.val = val; return v; }
+ ReturnedValue asReturnedValue() const { return _val; }
+ static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; }
// Section 9.12
bool sameValue(Value other) const;
@@ -347,20 +365,19 @@ struct Q_QML_PRIVATE_EXPORT Value
inline void mark(ExecutionEngine *e);
Value &operator =(const ScopedValue &v);
- Value &operator=(ReturnedValue v) { val = v; return *this; }
+ Value &operator=(ReturnedValue v) { _val = v; return *this; }
Value &operator=(Managed *m) {
if (!m) {
- tag = Undefined_Type;
- uint_32 = 0;
+ setTagValue(Undefined_Type, 0);
} else {
- val = reinterpret_cast<Value *>(m)->val;
+ _val = reinterpret_cast<Value *>(m)->_val;
}
return *this;
}
Value &operator=(Heap::Base *o) {
- m = o;
+ setM(o);
#if QT_POINTER_SIZE == 4
- tag = Managed_Type;
+ setTag(Managed_Type);
#endif
return *this;
}
@@ -368,7 +385,7 @@ struct Q_QML_PRIVATE_EXPORT Value
template<typename T>
Value &operator=(const Scoped<T> &t);
Value &operator=(const Value &v) {
- val = v.val;
+ _val = v._val;
return *this;
}
};
@@ -377,13 +394,13 @@ inline bool Value::isString() const
{
if (!isManaged())
return false;
- return m && m->vtable->isString;
+ return m() && m()->vtable->isString;
}
inline bool Value::isObject() const
{
if (!isManaged())
return false;
- return m && m->vtable->isObject;
+ return m() && m()->vtable->isObject;
}
inline bool Value::isPrimitive() const
@@ -394,7 +411,7 @@ inline bool Value::isPrimitive() const
inline double Value::toNumber() const
{
if (isInteger())
- return int_32;
+ return int_32();
if (isDouble())
return doubleValue();
return toNumberImpl();
@@ -408,10 +425,10 @@ inline uint Value::asArrayIndex() const
if (!isNumber())
return UINT_MAX;
if (isInteger())
- return int_32 >= 0 ? (uint)int_32 : UINT_MAX;
+ return int_32() >= 0 ? (uint)int_32() : UINT_MAX;
#else
- if (isInteger() && int_32 >= 0)
- return (uint)int_32;
+ if (isInteger() && int_32() >= 0)
+ return (uint)int_32();
if (!isDouble())
return UINT_MAX;
#endif
@@ -453,10 +470,11 @@ inline Primitive Primitive::undefinedValue()
{
Primitive v;
#if QT_POINTER_SIZE == 8
- v.val = quint64(Undefined_Type) << Tag_Shift;
+ v.setRawValue(quint64(Undefined_Type) << Tag_Shift);
#else
- v.tag = Undefined_Type;
- v.int_32 = 0;
+ v.setRawValue(0);
+ v.setTag(Undefined_Type);
+ v.setValue(0);
#endif
return v;
}
@@ -464,8 +482,7 @@ inline Primitive Primitive::undefinedValue()
inline Primitive Primitive::emptyValue()
{
Primitive v;
- v.tag = Value::Empty_Type;
- v.uint_32 = 0;
+ v.setTagValue(Value::Empty_Type, 0);
return v;
}
@@ -473,10 +490,9 @@ inline Primitive Primitive::nullValue()
{
Primitive v;
#if QT_POINTER_SIZE == 8
- v.val = quint64(_Null_Type) << Tag_Shift;
+ v.setRawValue(quint64(_Null_Type) << Tag_Shift);
#else
- v.tag = _Null_Type;
- v.int_32 = 0;
+ v.setTagValue(_Null_Type, 0);
#endif
return v;
}
@@ -484,8 +500,7 @@ inline Primitive Primitive::nullValue()
inline Primitive Primitive::fromBoolean(bool b)
{
Primitive v;
- v.tag = _Boolean_Type;
- v.int_32 = (bool)b;
+ v.setTagValue(_Boolean_Type, b);
return v;
}
@@ -499,8 +514,8 @@ inline Primitive Primitive::fromDouble(double d)
inline Primitive Primitive::fromInt32(int i)
{
Primitive v;
- v.tag = _Integer_Type;
- v.int_32 = i;
+ v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
+ v.setInt_32(i);
return v;
}
@@ -508,8 +523,8 @@ inline Primitive Primitive::fromUInt32(uint i)
{
Primitive v;
if (i < INT_MAX) {
- v.tag = _Integer_Type;
- v.int_32 = (int)i;
+ v.setTagValue(_Integer_Type, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors.
+ v.setInt_32((int)i);
} else {
v.setDouble(i);
}
@@ -530,7 +545,7 @@ struct Encode {
Encode(double d) {
Value v;
v.setDouble(d);
- val = v.val;
+ val = v.rawValue();
}
Encode(int i) {
val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i;
@@ -541,7 +556,7 @@ struct Encode {
} else {
Value v;
v.setDouble(i);
- val = v.val;
+ val = v.rawValue();
}
}
Encode(ReturnedValue v) {
@@ -567,7 +582,7 @@ ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
inline int Value::toInt32() const
{
if (isInteger())
- return int_32;
+ return int_32();
double d = isNumber() ? doubleValue() : toNumberImpl();
const double D32 = 4294967296.0;