diff --git a/Add-a-facility-to-version-type-information.patch b/Add-a-facility-to-version-type-information.patch new file mode 100644 index 0000000..3fa458c --- /dev/null +++ b/Add-a-facility-to-version-type-information.patch @@ -0,0 +1,41 @@ +From ad48b299b7fe0bbed2749adc66725e4f12661f79 Mon Sep 17 00:00:00 2001 +From: hjk +Date: Fri, 16 Sep 2016 14:30:14 +0200 +Subject: [PATCH] Add a facility to version type information for debugging + +This serves the same purpose as qtbase/corelib/global/qhooks.cpp, +but is meant to be in sync with changes in Qt Declarative internals. + +Change-Id: I5a4a7d9ca5c340367581749e05d09380590c46fb +Reviewed-by: Ulf Hermann +--- + src/qml/debugger/qqmldebug.cpp | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp +index 35dc110..ea98bb1 100644 +--- a/src/qml/debugger/qqmldebug.cpp ++++ b/src/qml/debugger/qqmldebug.cpp +@@ -119,4 +119,22 @@ bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, + return false; + } + ++enum { HookCount = 3 }; ++ ++// Only add to the end, and bump version if you do. ++quintptr Q_QML_EXPORT qtDeclarativeHookData[] = { ++ // Version of this Array. Bump if you add to end. ++ 1, ++ ++ // Number of entries in this array. ++ HookCount, ++ ++ // TypeInformationVersion, an integral value, bumped whenever private ++ // object sizes or member offsets that are used in Qt Creator's ++ // data structure "pretty printing" change. ++ 1 ++}; ++ ++Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0])); ++ + QT_END_NAMESPACE diff --git a/V4-Always-set-the-tag-when-boxing-a-pointer.patch b/V4-Always-set-the-tag-when-boxing-a-pointer.patch new file mode 100644 index 0000000..1ab2d0b --- /dev/null +++ b/V4-Always-set-the-tag-when-boxing-a-pointer.patch @@ -0,0 +1,371 @@ +From aa7c3b35ef9b737c574f436ea35452019a2ff29c Mon Sep 17 00:00:00 2001 +From: Erik Verbruggen +Date: Thu, 16 Jun 2016 13:39:57 +0200 +Subject: [PATCH 1/1] V4: Always set the tag when boxing a pointer in + QV4::Value. + +All setters now store tags, so no-one can play loosy-goosy with the +boxed values (and accidentally forget to "tag" a value, resulting in +random garbage). + +Change-Id: Ia0b78aa038d3ff46d5292b14bd593de310da16a0 +Reviewed-by: Simon Hausmann +--- + .../qmldbg_debugger/qqmlnativedebugservice.cpp | 2 +- + src/qml/jsruntime/qv4arraydata.cpp | 10 +-- + src/qml/jsruntime/qv4objectiterator.cpp | 5 -- + src/qml/jsruntime/qv4persistent.cpp | 9 +-- + src/qml/jsruntime/qv4scopedvalue_p.h | 16 +--- + src/qml/jsruntime/qv4value_p.h | 94 ++++++++++++---------- + 6 files changed, 63 insertions(+), 73 deletions(-) + +Index: qtdeclarative-opensource-src-5.6.1/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +@@ -549,7 +549,7 @@ void NativeDebugger::handleExpressions(Q + dict[QStringLiteral("name")] = name; + dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined"); + output.append(dict); +- } else if (result.ptr && result.ptr->_val) { ++ } else if (result.ptr && result.ptr->rawValue()) { + collector.collect(&output, QString(), name, *result); + } else { + QJsonObject dict; +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4arraydata.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4arraydata.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4arraydata.cpp +@@ -93,8 +93,8 @@ Q_STATIC_ASSERT(sizeof(Heap::ArrayData) + + static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value) + { +- Value v = Value::fromReturnedValue(*target); +- v.setValue(value); ++ Value v; ++ v.setTagValue(Value::fromReturnedValue(*target).tag(), value); + *target = v.asReturnedValue(); + } + +@@ -189,7 +189,7 @@ void ArrayData::realloc(Object *o, Type + n->value = i; + } else { + storeValue(lastFree, i); +- sparse->arrayData[i].setTag(Value::Empty_Type); ++ sparse->arrayData[i].setEmpty(); + lastFree = &sparse->arrayData[i].rawValueRef(); + } + } +@@ -198,7 +198,7 @@ void ArrayData::realloc(Object *o, Type + if (toCopy < sparse->alloc) { + for (uint i = toCopy; i < sparse->alloc; ++i) { + storeValue(lastFree, i); +- sparse->arrayData[i].setTag(Value::Empty_Type); ++ sparse->arrayData[i].setEmpty(); + lastFree = &sparse->arrayData[i].rawValueRef(); + } + storeValue(lastFree, UINT_MAX); +@@ -396,7 +396,7 @@ uint SparseArrayData::allocate(Object *o + // found two slots in a row + uint idx = Value::fromReturnedValue(*last).uint_32(); + Value lastV = Value::fromReturnedValue(*last); +- lastV.setValue(dd->arrayData[lastV.value() + 1].value()); ++ lastV.setTagValue(lastV.tag(), dd->arrayData[lastV.value() + 1].value()); + *last = lastV.rawValue(); + dd->attrs[idx] = Attr_Accessor; + return idx; +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4objectiterator.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4objectiterator.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4objectiterator.cpp +@@ -68,11 +68,6 @@ void ObjectIterator::init(const Object * + object->setM(o ? o->m() : 0); + current->setM(o ? o->m() : 0); + +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- object->setTag(QV4::Value::Managed_Type); +- current->setTag(QV4::Value::Managed_Type); +-#endif +- + if (object->as()) { + Scope scope(engine); + Scoped (scope, object->asReturnedValue())->fullyCreate(); +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4persistent.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4persistent.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4persistent.cpp +@@ -79,11 +79,9 @@ Page *allocatePage(PersistentValueStorag + if (p->header.next) + p->header.next->header.prev = &p->header.next; + for (int i = 0; i < kEntriesPerPage - 1; ++i) { +- p->values[i].setTag(QV4::Value::Empty_Type); +- p->values[i].setInt_32(i + 1); ++ p->values[i].setEmpty(i + 1); + } +- p->values[kEntriesPerPage - 1].setTag(QV4::Value::Empty_Type); +- p->values[kEntriesPerPage - 1].setInt_32(-1); ++ p->values[kEntriesPerPage - 1].setEmpty(-1); + + storage->firstPage = p; + +@@ -205,8 +203,7 @@ void PersistentValueStorage::free(Value + + Page *p = getPage(v); + +- v->setTag(QV4::Value::Empty_Type); +- v->setInt_32(p->header.freeList); ++ v->setEmpty(p->header.freeList); + p->header.freeList = v - p->values; + if (!--p->header.refCount) + freePage(p); +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4scopedvalue_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h +@@ -120,9 +120,6 @@ struct ScopedValue + { + ptr = scope.engine->jsStackTop++; + ptr->setM(o); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- ptr->setTag(QV4::Value::Managed_Type); +-#endif + } + + ScopedValue(const Scope &scope, Managed *m) +@@ -144,9 +141,6 @@ struct ScopedValue + + ScopedValue &operator=(Heap::Base *o) { + ptr->setM(o); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- ptr->setTag(QV4::Value::Managed_Type); +-#endif + return *this; + } + +@@ -186,18 +180,12 @@ struct Scoped + + inline void setPointer(const Managed *p) { + ptr->setM(p ? p->m() : 0); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- ptr->setTag(QV4::Value::Managed_Type); +-#endif + } + + Scoped(const Scope &scope) + { + ptr = scope.engine->jsStackTop++; + ptr->setM(0); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- ptr->setTag(QV4::Value::Managed_Type); +-#endif + } + + Scoped(const Scope &scope, const Value &v) +@@ -339,14 +327,14 @@ struct ScopedCallData { + + inline Value &Value::operator =(const ScopedValue &v) + { +- _val = v.ptr->val(); ++ _val = v.ptr->rawValue(); + return *this; + } + + template + inline Value &Value::operator=(const Scoped &t) + { +- _val = t.ptr->val(); ++ _val = t.ptr->rawValue(); + return *this; + } + +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4value_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h +@@ -66,6 +66,7 @@ typedef uint Bool; + + struct Q_QML_PRIVATE_EXPORT Value + { ++private: + /* + We use two different ways of encoding JS values. One for 32bit and one for 64bit systems. + +@@ -90,10 +91,10 @@ struct Q_QML_PRIVATE_EXPORT Value + + 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) { memcpy(&_val, &v, 4); } +- Q_ALWAYS_INLINE void setTag(quint32 t) { memcpy(4 + (quint8 *)&_val, &t, 4); } ++public: ++ Q_ALWAYS_INLINE quint64 &rawValueRef() { return _val; } ++ Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } ++ Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } + + #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + static inline int valueOffset() { return 0; } +@@ -113,17 +114,52 @@ struct Q_QML_PRIVATE_EXPORT Value + Q_ALWAYS_INLINE Heap::Base *m() const { Q_UNREACHABLE(); return Q_NULLPTR; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { Q_UNUSED(b); Q_UNREACHABLE(); } + #elif defined(QV4_USE_64_BIT_VALUE_ENCODING) +- Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, QT_POINTER_SIZE); return b; } +- Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, QT_POINTER_SIZE); } ++ 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 // !QV4_USE_64_BIT_VALUE_ENCODING +- Q_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); 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); } ++ Q_ALWAYS_INLINE Heap::Base *m() const ++ { ++ Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); ++ 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); ++ setTagValue(Managed_Type, 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 int int_32() const ++ { ++ return int(value()); ++ } ++ Q_ALWAYS_INLINE void setInt_32(int i) ++ { ++ setTagValue(Integer_Type_Internal, quint32(i)); ++ } + Q_ALWAYS_INLINE uint uint_32() const { return value(); } + ++ Q_ALWAYS_INLINE void setEmpty() ++ { ++ setTagValue(Empty_Type, value()); ++ } ++ ++ Q_ALWAYS_INLINE void setEmpty(int i) ++ { ++ setTagValue(Empty_Type, quint32(i)); ++ } + #ifndef QV4_USE_64_BIT_VALUE_ENCODING + enum Masks { + SilentNaNBit = 0x00040000, +@@ -260,7 +296,6 @@ struct Q_QML_PRIVATE_EXPORT Value + int i = (int)d; + if (i == d) { + setInt_32(i); +- setTag(Integer_Type_Internal); + return true; + } + } +@@ -292,22 +327,10 @@ struct Q_QML_PRIVATE_EXPORT Value + return m(); + } + +- 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.setRawValue(0); + v.setM(m); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- v.setTag(Managed_Type); +-#endif + return v; + } + +@@ -328,7 +351,7 @@ struct Q_QML_PRIVATE_EXPORT Value + inline bool tryIntegerConversion() { + bool b = integerCompatible(); + if (b) +- setTag(Integer_Type_Internal); ++ setTagValue(Integer_Type_Internal, value()); + return b; + } + +@@ -378,7 +401,7 @@ struct Q_QML_PRIVATE_EXPORT Value + Value &operator=(ReturnedValue v) { _val = v; return *this; } + Value &operator=(Managed *m) { + if (!m) { +- setTagValue(Undefined_Type, 0); ++ setM(0); + } else { + _val = reinterpret_cast(m)->_val; + } +@@ -386,9 +409,6 @@ struct Q_QML_PRIVATE_EXPORT Value + } + Value &operator=(Heap::Base *o) { + setM(o); +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- setTag(Managed_Type); +-#endif + return *this; + } + +@@ -479,13 +499,7 @@ struct Q_QML_PRIVATE_EXPORT Primitive : + inline Primitive Primitive::undefinedValue() + { + Primitive v; +-#ifdef QV4_USE_64_BIT_VALUE_ENCODING +- v.setRawValue(quint64(Undefined_Type) << Tag_Shift); +-#else +- v.setRawValue(0); +- v.setTag(Undefined_Type); +- v.setValue(0); +-#endif ++ v.setTagValue(Undefined_Type, 0); + return v; + } + +@@ -499,11 +513,7 @@ inline Primitive Primitive::emptyValue() + inline Primitive Primitive::nullValue() + { + Primitive v; +-#ifndef QV4_USE_64_BIT_VALUE_ENCODING +- v.setRawValue(quint64(Null_Type_Internal) << Tag_Shift); +-#else + v.setTagValue(Null_Type_Internal, 0); +-#endif + return v; + } + +@@ -524,7 +534,7 @@ inline Primitive Primitive::fromDouble(d + inline Primitive Primitive::fromInt32(int i) + { + Primitive v; +- v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. ++ v.setTagValue(Integer_Type_Internal, 0); + v.setInt_32(i); + return v; + } +@@ -533,8 +543,7 @@ inline Primitive Primitive::fromUInt32(u + { + Primitive v; + if (i < INT_MAX) { +- v.setTagValue(Integer_Type_Internal, 0); // For mingw482, because it complains, and for VS9, because of internal compiler errors. +- v.setInt_32((int)i); ++ v.setTagValue(Integer_Type_Internal, i); + } else { + v.setDouble(i); + } diff --git a/V4-Free-up-2-address-bits-in-64bit-mode.patch b/V4-Free-up-2-address-bits-in-64bit-mode.patch new file mode 100644 index 0000000..dd593bc --- /dev/null +++ b/V4-Free-up-2-address-bits-in-64bit-mode.patch @@ -0,0 +1,778 @@ +From 60c669f13fd331788a2e2aab8af926d6aa7c46a6 Mon Sep 17 00:00:00 2001 +From: Erik Verbruggen +Date: Fri, 23 Sep 2016 11:34:12 +0200 +Subject: [PATCH] V4: Free up 2 address bits in 64bit mode + +This allows for the OS to use 49 address bits. It also maps JS Undefined +to the C++ nullptr on 64bit. + +Task-number: QTBUG-54822 +Change-Id: I7cc90620f499be1506a61aac77d72d067308838c +--- + src/qml/debugger/qqmldebug.cpp | 2 +- + src/qml/jit/qv4assembler.cpp | 38 +++++- + src/qml/jit/qv4assembler_p.h | 5 + + src/qml/jit/qv4isel_masm.cpp | 98 ++++++++++---- + src/qml/jit/qv4isel_masm_p.h | 4 +- + src/qml/jsruntime/qv4scopedvalue_p.h | 2 +- + src/qml/jsruntime/qv4value_p.h | 246 ++++++++++++++++++++--------------- + src/qml/jsruntime/qv4vme_moth.cpp | 26 ++-- + 8 files changed, 269 insertions(+), 152 deletions(-) + +Index: qtdeclarative-opensource-src-5.6.1/src/qml/debugger/qqmldebug.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/debugger/qqmldebug.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/debugger/qqmldebug.cpp +@@ -132,7 +132,7 @@ quintptr Q_QML_EXPORT qtDeclarativeHookD + // TypeInformationVersion, an integral value, bumped whenever private + // object sizes or member offsets that are used in Qt Creator's + // data structure "pretty printing" change. +- 1 ++ 2 + }; + + Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0])); +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4assembler.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jit/qv4assembler.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4assembler.cpp +@@ -133,8 +133,30 @@ void Assembler::generateCJumpOnNonZero(R + generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock); + } + +-void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left,TrustedImm32 right, +- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, ++#ifdef QV4_USE_64_BIT_VALUE_ENCODING ++void Assembler::generateCJumpOnCompare(RelationalCondition cond, ++ RegisterID left, ++ TrustedImm64 right, ++ IR::BasicBlock *currentBlock, ++ IR::BasicBlock *trueBlock, ++ IR::BasicBlock *falseBlock) ++{ ++ if (trueBlock == _nextBlock) { ++ Jump target = branch64(invert(cond), left, right); ++ addPatch(falseBlock, target); ++ } else { ++ Jump target = branch64(cond, left, right); ++ addPatch(trueBlock, target); ++ jumpToBlock(currentBlock, falseBlock); ++ } ++} ++#endif ++ ++void Assembler::generateCJumpOnCompare(RelationalCondition cond, ++ RegisterID left, ++ TrustedImm32 right, ++ IR::BasicBlock *currentBlock, ++ IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock) + { + if (trueBlock == _nextBlock) { +@@ -147,8 +169,11 @@ void Assembler::generateCJumpOnCompare(R + } + } + +-void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right, +- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, ++void Assembler::generateCJumpOnCompare(RelationalCondition cond, ++ RegisterID left, ++ RegisterID right, ++ IR::BasicBlock *currentBlock, ++ IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock) + { + if (trueBlock == _nextBlock) { +@@ -334,9 +359,8 @@ Assembler::Jump Assembler::genTryDoubleC + // not an int, check if it's a double: + isNoInt.link(this); + #ifdef QV4_USE_64_BIT_VALUE_ENCODING +- and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); +- Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, +- Assembler::TrustedImm32(0)); ++ rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister); ++ Assembler::Jump isNoDbl = branch32(Equal, ScratchRegister, TrustedImm32(0)); + #else + and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); + Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister, +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4assembler_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jit/qv4assembler_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4assembler_p.h +@@ -374,6 +374,11 @@ public: + void addPatch(DataLabelPtr patch, IR::BasicBlock *target); + void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock, + IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); ++#ifdef QV4_USE_64_BIT_VALUE_ENCODING ++ void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm64 right, ++ IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, ++ IR::BasicBlock *falseBlock); ++#endif + void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right, + IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, + IR::BasicBlock *falseBlock); +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4isel_masm.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jit/qv4isel_masm.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4isel_masm.cpp +@@ -703,7 +703,7 @@ void InstructionSelection::loadString(co + #else + _as->store32(Assembler::ReturnValueRegister, destAddr); + destAddr.offset += 4; +- _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type), destAddr); ++ _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr); + #endif + } + +@@ -1103,7 +1103,7 @@ void InstructionSelection::convertTypeTo + // not an int, check if it's NOT a double: + isNoInt.link(_as); + #ifdef QV4_USE_64_BIT_VALUE_ENCODING +- _as->and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); ++ _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister); + Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, + Assembler::TrustedImm32(0)); + #else +@@ -1194,10 +1194,15 @@ void InstructionSelection::convertTypeTo + _as->load64(addr, Assembler::ScratchRegister); + _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); + +- // check if it's a number +- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ScratchRegister); +- Assembler::Jump isInt = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(1)); +- Assembler::Jump fallback = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); ++ // check if it's integer convertible ++ _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister); ++ Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3)); ++ ++ // nope, not integer convertible, so check for a double: ++ _as->urshift64(Assembler::TrustedImm32( ++ QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift), ++ Assembler::ScratchRegister); ++ Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); + + // it's a double + _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); +@@ -1212,7 +1217,7 @@ void InstructionSelection::convertTypeTo + generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt, + _as->loadAddress(Assembler::ScratchRegister, source)); + +- isInt.link(_as); ++ isIntConvertible.link(_as); + success.link(_as); + IR::Temp *targetTemp = target->asTemp(); + if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { +@@ -1784,9 +1789,9 @@ void InstructionSelection::visitCJumpStr + { + Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual); + +- if (visitCJumpStrictNullUndefined(IR::NullType, binop, trueBlock, falseBlock)) ++ if (visitCJumpStrictNull(binop, trueBlock, falseBlock)) + return; +- if (visitCJumpStrictNullUndefined(IR::UndefinedType, binop, trueBlock, falseBlock)) ++ if (visitCJumpStrictUndefined(binop, trueBlock, falseBlock)) + return; + if (visitCJumpStrictBool(binop, trueBlock, falseBlock)) + return; +@@ -1802,16 +1807,14 @@ void InstructionSelection::visitCJumpStr + } + + // Only load the non-null temp. +-bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, +- IR::BasicBlock *trueBlock, +- IR::BasicBlock *falseBlock) ++bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, ++ IR::BasicBlock *trueBlock, ++ IR::BasicBlock *falseBlock) + { +- Q_ASSERT(nullOrUndef == IR::NullType || nullOrUndef == IR::UndefinedType); +- + IR::Expr *varSrc = 0; +- if (binop->left->type == IR::VarType && binop->right->type == nullOrUndef) ++ if (binop->left->type == IR::VarType && binop->right->type == IR::NullType) + varSrc = binop->left; +- else if (binop->left->type == nullOrUndef && binop->right->type == IR::VarType) ++ else if (binop->left->type == IR::NullType && binop->right->type == IR::VarType) + varSrc = binop->right; + if (!varSrc) + return false; +@@ -1822,7 +1825,7 @@ bool InstructionSelection::visitCJumpStr + } + + if (IR::Const *c = varSrc->asConst()) { +- if (c->type == nullOrUndef) ++ if (c->type == IR::NullType) + _as->jumpToBlock(_block, trueBlock); + else + _as->jumpToBlock(_block, falseBlock); +@@ -1835,9 +1838,54 @@ bool InstructionSelection::visitCJumpStr + _as->load32(tagAddr, tagReg); + + Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal +- : Assembler::NotEqual; +- const Assembler::TrustedImm32 tag(nullOrUndef == IR::NullType ? int(QV4::Value::Null_Type_Internal) +- : int(QV4::Value::Undefined_Type)); ++ : Assembler::NotEqual; ++ const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal); ++ _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); ++ return true; ++} ++ ++bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop, ++ IR::BasicBlock *trueBlock, ++ IR::BasicBlock *falseBlock) ++{ ++ IR::Expr *varSrc = 0; ++ if (binop->left->type == IR::VarType && binop->right->type == IR::UndefinedType) ++ varSrc = binop->left; ++ else if (binop->left->type == IR::UndefinedType && binop->right->type == IR::VarType) ++ varSrc = binop->right; ++ if (!varSrc) ++ return false; ++ ++ if (varSrc->asTemp() && varSrc->asTemp()->kind == IR::Temp::PhysicalRegister) { ++ _as->jumpToBlock(_block, falseBlock); ++ return true; ++ } ++ ++ if (IR::Const *c = varSrc->asConst()) { ++ if (c->type == IR::UndefinedType) ++ _as->jumpToBlock(_block, trueBlock); ++ else ++ _as->jumpToBlock(_block, falseBlock); ++ return true; ++ } ++ ++ Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal ++ : Assembler::NotEqual; ++ const Assembler::RegisterID tagReg = Assembler::ScratchRegister; ++#ifdef QV4_USE_64_BIT_VALUE_ENCODING ++ Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc); ++ _as->load64(addr, tagReg); ++ const Assembler::TrustedImm64 tag(0); ++#else // !QV4_USE_64_BIT_VALUE_ENCODING ++ Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); ++ _as->load32(tagAddr, tagReg); ++ Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0)); ++ _as->addPatch(falseBlock, j); ++ ++ tagAddr.offset += 4; ++ _as->load32(tagAddr, tagReg); ++ const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal); ++#endif + _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); + return true; + } +@@ -1928,10 +1976,14 @@ bool InstructionSelection::visitCJumpNul + if (binop->op == IR::OpNotEqual) + qSwap(trueBlock, falseBlock); + Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal))); +- Assembler::Jump isUndefined = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Undefined_Type))); ++ Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal))); ++ tagAddr.offset -= 4; ++ _as->load32(tagAddr, tagReg); ++ Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0)); + _as->addPatch(trueBlock, isNull); +- _as->addPatch(trueBlock, isUndefined); +- _as->jumpToBlock(_block, falseBlock); ++ _as->addPatch(falseBlock, isNotUndefinedTag); ++ _as->addPatch(falseBlock, isNotUndefinedValue); ++ _as->jumpToBlock(_block, trueBlock); + + return true; + } +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4isel_masm_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jit/qv4isel_masm_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jit/qv4isel_masm_p.h +@@ -166,8 +166,8 @@ protected: + bool visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right, + IR::BasicBlock *iftrue, IR::BasicBlock *iffalse); + void visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); +- bool visitCJumpStrictNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, +- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); ++ bool visitCJumpStrictNull(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); ++ bool visitCJumpStrictUndefined(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); + bool visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); + bool visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, + IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4scopedvalue_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4scopedvalue_p.h +@@ -309,7 +309,7 @@ struct ScopedCallData { + { + int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); + ptr = reinterpret_cast(scope.alloc(size)); +- ptr->tag = QV4::Value::Integer_Type; ++ ptr->tag = QV4::Value::Integer_Type_Internal; + ptr->argc = argc; + } + +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4value_p.h ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4value_p.h +@@ -70,23 +70,85 @@ private: + /* + We use two different ways of encoding JS values. One for 32bit and one for 64bit systems. + +- In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double NaN (actually -qNaN) +- is indicated by a number that has the top 13 bits set. The other values are usually set to 0 by the +- processor, and are thus free for us to store other data. We keep pointers in there for managed objects, +- and encode the other types using the free space given to use by the unused bits for NaN values. This also +- works for pointers on 64 bit systems, as they all currently only have 48 bits of addressable memory. +- +- On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value that +- will make the number a NaN. The Masks below are used for encoding the other types. +- +- On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will get encoded +- with the 13 highest bits all 0. We are now using special values for bits 14-17 to encode our values. These +- can be used, as the highest valid pointer on a 64 bit system is 2^48-1. +- +- If they are all 0, we have a pointer to a Managed object. If bit 14 is set we have an integer. +- This makes testing for pointers and numbers very fast (we have a number if any of the highest 14 bits is set). +- +- Bit 15-17 is then used to encode other immediates. ++ In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double ++ NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a ++ signalling NaN it is the top 14 bits. The other values are usually set to 0 by the ++ processor, and are thus free for us to store other data. We keep pointers in there for ++ managed objects, and encode the other types using the free space given to use by the unused ++ bits for NaN values. This also works for pointers on 64 bit systems, as they all currently ++ only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for ++ pointers.) ++ ++ On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value ++ that will make the number a NaN. The Masks below are used for encoding the other types. ++ ++ On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will ++ get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between ++ managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave ++ the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is ++ set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are ++ used to encode Null/Int/Bool. ++ ++ On both 32bit and 64bit, Undefined is encoded as a managed pointer with value 0. This is ++ the same as a nullptr. ++ ++ Specific bit-sequences: ++ 0 = always 0 ++ 1 = always 1 ++ x = stored value ++ a,b,c,d = specific bit values, see notes ++ ++ 64bit: ++ ++ 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 | ++ 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value ++ ------------------------------------------------------------------------+-------------- ++ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined ++ 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer) ++ a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf ++ dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double ++ 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole) ++ 00000000 00000011 10000000 00000000 00000000 00000000 00000000 00000000 | Null ++ 00000000 00000011 01000000 00000000 00000000 00000000 00000000 0000000x | Bool ++ 00000000 00000011 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int ++ ++ Notes: ++ - a: xor-ed signbit, always 1 for NaN ++ - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value ++ - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0 ++ - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++ ++ and JS ++ - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0 ++ - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1, ++ so: (val >> (64-15)) == 1 ++ - Null, Bool, and Int have bit 48 set, indicating integer-convertible ++ - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where ++ any non double results in a NaN ++ ++ 32bit: ++ ++ 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 | ++ 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value ++ ------------------------------------------------------------------------+-------------- ++ 01111111 11111100 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined ++ 01111111 11111100 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer) ++ a1111111 1111bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf ++ xddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double ++ 01111111 11111110 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole) ++ 01111111 11111111 10000000 00000000 00000000 00000000 00000000 00000000 | Null ++ 01111111 11111111 01000000 00000000 00000000 00000000 00000000 0000000x | Bool ++ 01111111 11111111 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int ++ ++ Notes: ++ - the upper 32 bits are the tag, the lower 32 bits the value ++ - Undefined has a nullptr in the value, Managed has a non-nullptr stored in the value ++ - a: sign bit, always 0 for NaN ++ - b,c: 00=inf, 01 = sNaN, 10 = qNaN, 11 = boxed value ++ - d: stored double value, as long as not *all* of them are 1, because that's a boxed value ++ (see above) ++ - empty, Null, Bool, and Int have bit 63 set to 0, bits 62-50 set to 1 (same as undefined ++ and managed), and bit 49 set to 1 (where undefined and managed have it set to 0) ++ - Null, Bool, and Int have bit 48 set, indicating integer-convertible + */ + + quint64 _val; +@@ -137,7 +199,7 @@ public: + { + quint32 v; + memcpy(&v, &b, 4); +- setTagValue(Managed_Type, v); ++ setTagValue(Managed_Type_Internal, v); + } + #endif + +@@ -153,113 +215,96 @@ public: + + Q_ALWAYS_INLINE void setEmpty() + { +- setTagValue(Empty_Type, value()); ++ setTagValue(Empty_Type_Internal, value()); + } + + Q_ALWAYS_INLINE void setEmpty(int i) + { +- setTagValue(Empty_Type, quint32(i)); ++ setTagValue(Empty_Type_Internal, quint32(i)); ++ } ++ ++ enum Type { ++ Undefined_Type, ++ Managed_Type, ++ Empty_Type, ++ Integer_Type, ++ Boolean_Type, ++ Null_Type, ++ Double_Type ++ }; ++ ++ inline Type type() const { ++ if (isUndefined()) return Undefined_Type; ++ if (isManaged()) return Managed_Type; ++ if (isEmpty()) return Empty_Type; ++ if (isInteger()) return Integer_Type; ++ if (isBoolean()) return Boolean_Type; ++ if (isNull()) return Null_Type; ++ Q_ASSERT(isDouble()); return Double_Type; + } + #ifndef QV4_USE_64_BIT_VALUE_ENCODING + enum Masks { + SilentNaNBit = 0x00040000, + NaN_Mask = 0x7ff80000, + NotDouble_Mask = 0x7ffa0000, +- Type_Mask = 0xffffc000, +- Immediate_Mask = NotDouble_Mask | 0x00004000 | SilentNaNBit, +- IsNullOrUndefined_Mask = Immediate_Mask | 0x08000, ++ Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit, + Tag_Shift = 32 + }; +- enum ValueType { +- Undefined_Type = Immediate_Mask | 0x00000, +- Null_Type = Immediate_Mask | 0x10000, +- Boolean_Type = Immediate_Mask | 0x08000, +- Integer_Type = Immediate_Mask | 0x18000, +- Managed_Type = NotDouble_Mask | 0x00000 | SilentNaNBit, +- Empty_Type = NotDouble_Mask | 0x18000 | SilentNaNBit +- }; +- +- enum ImmediateFlags { +- ConvertibleToInt = Immediate_Mask | 0x1 +- }; +- +- enum ValueTypeInternal { +- Null_Type_Internal = Null_Type | ConvertibleToInt, +- Boolean_Type_Internal = Boolean_Type | ConvertibleToInt, +- Integer_Type_Internal = Integer_Type | ConvertibleToInt, + ++ enum { ++ Managed_Type_Internal = NotDouble_Mask + }; + #else +- static const quint64 NaNEncodeMask = 0xffff800000000000ll; +- static const quint64 IsInt32Mask = 0x0002000000000000ll; +- static const quint64 IsDoubleMask = 0xfffc000000000000ll; +- static const quint64 IsNumberMask = IsInt32Mask|IsDoubleMask; +- static const quint64 IsNullOrUndefinedMask = 0x0000800000000000ll; +- static const quint64 IsNullOrBooleanMask = 0x0001000000000000ll; +- static const quint64 IsConvertibleToIntMask = IsInt32Mask|IsNullOrBooleanMask; ++ static const quint64 NaNEncodeMask = 0xfffc000000000000ll; ++ static const quint64 Immediate_Mask = 0x00020000u; // bit 49 + + enum Masks { + NaN_Mask = 0x7ff80000, +- Type_Mask = 0xffff8000, +- IsDouble_Mask = 0xfffc0000, +- Immediate_Mask = 0x00018000, +- IsNullOrUndefined_Mask = 0x00008000, +- IsNullOrBoolean_Mask = 0x00010000, +- Tag_Shift = 32 +- }; +- enum ValueType { +- Undefined_Type = IsNullOrUndefined_Mask, +- Null_Type = IsNullOrUndefined_Mask|IsNullOrBoolean_Mask, +- Boolean_Type = IsNullOrBoolean_Mask, +- Integer_Type = 0x20000|IsNullOrBoolean_Mask, +- Managed_Type = 0, +- Empty_Type = Undefined_Type | 0x4000 + }; + enum { + IsDouble_Shift = 64-14, +- IsNumber_Shift = 64-15, +- IsConvertibleToInt_Shift = 64-16, +- IsManaged_Shift = 64-17 ++ IsManagedOrUndefined_Shift = 64-15, ++ IsIntegerConvertible_Shift = 64-16, ++ Tag_Shift = 32, ++ IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift, ++ Managed_Type_Internal = 0 + }; +- +- ++#endif + enum ValueTypeInternal { +- Null_Type_Internal = Null_Type, +- Boolean_Type_Internal = Boolean_Type, +- Integer_Type_Internal = Integer_Type ++ Empty_Type_Internal = Immediate_Mask | 0, ++ ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48 ++ Null_Type_Internal = ConvertibleToInt | 0x08000u, ++ Boolean_Type_Internal = ConvertibleToInt | 0x04000u, ++ Integer_Type_Internal = ConvertibleToInt | 0x02000u + }; +-#endif +- +- inline unsigned type() const { +- return tag() & Type_Mask; +- } + + // used internally in property +- inline bool isEmpty() const { return tag() == Empty_Type; } +- +- inline bool isUndefined() const { return tag() == Undefined_Type; } ++ inline bool isEmpty() const { return tag() == Empty_Type_Internal; } + inline bool isNull() const { return tag() == Null_Type_Internal; } +- inline bool isBoolean() const { return tag ()== Boolean_Type_Internal; } ++ inline bool isBoolean() const { return tag() == Boolean_Type_Internal; } ++ inline bool isInteger() const { return tag() == Integer_Type_Internal; } ++ inline bool isNullOrUndefined() const { return isNull() || isUndefined(); } ++ inline bool isNumber() const { return isDouble() || isInteger(); } ++ + #ifdef QV4_USE_64_BIT_VALUE_ENCODING +- inline bool isInteger() const { return (_val >> IsNumber_Shift) == 1; } ++ inline bool isUndefined() const { return _val == 0; } + 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 isManaged() const { return !isUndefined() && ((_val >> IsManagedOrUndefined_Shift) == 0); } ++ ++ inline bool integerCompatible() const { ++ return (_val >> IsIntegerConvertible_Shift) == 3; ++ } + 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(); + } +- inline bool isNaN() const { return (tag() & 0x7fff8000) == 0x00078000; } ++ inline bool isNaN() const { return (tag() & 0x7ffc0000 ) == 0x00040000; } + #else +- inline bool isInteger() const { return tag() == Integer_Type_Internal; } ++ inline bool isUndefined() const { return tag() == Managed_Type_Internal && value() == 0; } + inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } +- inline bool isNumber() const { return tag() == Integer_Type_Internal || (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 isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } + inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } + static inline bool integerCompatible(Value a, Value b) { + return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; +@@ -499,14 +544,14 @@ struct Q_QML_PRIVATE_EXPORT Primitive : + inline Primitive Primitive::undefinedValue() + { + Primitive v; +- v.setTagValue(Undefined_Type, 0); ++ v.setM(Q_NULLPTR); + return v; + } + + inline Primitive Primitive::emptyValue() + { + Primitive v; +- v.setTagValue(Value::Empty_Type, 0); ++ v.setEmpty(0); + return v; + } + +@@ -534,7 +579,6 @@ inline Primitive Primitive::fromDouble(d + inline Primitive Primitive::fromInt32(int i) + { + Primitive v; +- v.setTagValue(Integer_Type_Internal, 0); + v.setInt_32(i); + return v; + } +@@ -552,31 +596,23 @@ inline Primitive Primitive::fromUInt32(u + + struct Encode { + static ReturnedValue undefined() { +- return quint64(Value::Undefined_Type) << Value::Tag_Shift; ++ return Primitive::undefinedValue().rawValue(); + } + static ReturnedValue null() { +- return quint64(Value::Null_Type_Internal) << Value::Tag_Shift; ++ return Primitive::nullValue().rawValue(); + } + + Encode(bool b) { +- val = (quint64(Value::Boolean_Type_Internal) << Value::Tag_Shift) | (uint)b; ++ val = Primitive::fromBoolean(b).rawValue(); + } + Encode(double d) { +- Value v; +- v.setDouble(d); +- val = v.rawValue(); ++ val = Primitive::fromDouble(d).rawValue(); + } + Encode(int i) { +- val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | (uint)i; ++ val = Primitive::fromInt32(i).rawValue(); + } + Encode(uint i) { +- if (i <= INT_MAX) { +- val = (quint64(Value::Integer_Type_Internal) << Value::Tag_Shift) | i; +- } else { +- Value v; +- v.setDouble(i); +- val = v.rawValue(); +- } ++ val = Primitive::fromUInt32(i).rawValue(); + } + Encode(ReturnedValue v) { + val = v; +Index: qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4vme_moth.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.6.1.orig/src/qml/jsruntime/qv4vme_moth.cpp ++++ qtdeclarative-opensource-src-5.6.1/src/qml/jsruntime/qv4vme_moth.cpp +@@ -563,7 +563,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + #endif // DO_TRACE_INSTR + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::callValue(engine, VALUE(instr.dest), callData)); +@@ -573,7 +573,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callProperty(engine, instr.name, callData)); +@@ -582,7 +582,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CallPropertyLookup) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callPropertyLookup(engine, instr.lookupIndex, callData)); +@@ -592,7 +592,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlScopeObjectProperty(engine, instr.index, callData)); +@@ -602,7 +602,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callQmlContextObjectProperty(engine, instr.index, callData)); +@@ -611,7 +611,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CallElement) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::callElement(engine, VALUE(instr.index), callData)); +@@ -620,7 +620,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CallActivationProperty) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::callActivationProperty(engine, instr.name, callData)); +@@ -629,7 +629,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CallGlobalLookup) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::callGlobalLookup(engine, instr.index, callData)); +@@ -735,7 +735,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CreateValue) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::constructValue(engine, VALUE(instr.func), callData)); +@@ -744,7 +744,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CreateProperty) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::constructProperty(engine, instr.name, callData)); +@@ -753,7 +753,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(ConstructPropertyLookup) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = VALUE(instr.base); + STOREVALUE(instr.result, Runtime::constructPropertyLookup(engine, instr.index, callData)); +@@ -762,7 +762,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(CreateActivationProperty) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::constructActivationProperty(engine, instr.name, callData)); +@@ -771,7 +771,7 @@ QV4::ReturnedValue VME::run(ExecutionEng + MOTH_BEGIN_INSTR(ConstructGlobalLookup) + Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + QV4::CallData *callData = reinterpret_cast(stack + instr.callData); +- callData->tag = QV4::Value::Integer_Type; ++ callData->tag = QV4::Value::Integer_Type_Internal; + callData->argc = instr.argc; + callData->thisObject = QV4::Primitive::undefinedValue(); + STOREVALUE(instr.result, Runtime::constructGlobalLookup(engine, instr.index, callData)); diff --git a/libqt5-qtdeclarative.changes b/libqt5-qtdeclarative.changes index e1a179a..f2c5ddf 100644 --- a/libqt5-qtdeclarative.changes +++ b/libqt5-qtdeclarative.changes @@ -1,3 +1,19 @@ +------------------------------------------------------------------- +Wed Sep 28 17:06:29 UTC 2016 - fabian@ritter-vogt.de + +- Add new version of V4-Free-up-2-address-bits-in-64bit-mode.patch + * Fix testcase failure (boo#989341, QTBUG#54822) +- Only apply patch on AArch64 to avoid regressions where patch not + needed (it's experimental) + +------------------------------------------------------------------- +Mon Sep 26 07:15:48 UTC 2016 - fvogt@suse.com + +- Add upstream patches for aarch64 with VA_BITS=48 (boo#989341, QTBUG#54822) + * V4-Always-set-the-tag-when-boxing-a-pointer.patch + * Add-a-facility-to-version-type-information.patch + * V4-Free-up-2-address-bits-in-64bit-mode.patchv4-set-tag.patch + ------------------------------------------------------------------- Sat Sep 24 18:39:01 UTC 2016 - hrvoje.senjan@gmail.com diff --git a/libqt5-qtdeclarative.spec b/libqt5-qtdeclarative.spec index 076d0dd..c9de497 100644 --- a/libqt5-qtdeclarative.spec +++ b/libqt5-qtdeclarative.spec @@ -37,6 +37,12 @@ Source1: baselibs.conf Patch0: overflow.patch # PATCH-FIX-OPENSUSE: qtdeclarative-opensource-src-5.6.0-qml_no-lifetime-dse.patch - fix crashes with i586 and Plasma (boo #985768) Patch2: qtdeclarative-opensource-src-5.6.0-qml_no-lifetime-dse.patch +# PATCH-FIX-UPSTREAM V4-Always-set-the-tag-when-boxing-a-pointer.patch +Patch3: V4-Always-set-the-tag-when-boxing-a-pointer.patch +# PATCH-FIX-UPSTREAM Add-a-facility-to-version-type-information.patch +Patch4: Add-a-facility-to-version-type-information.patch +# PATCH-FIX-UPSTREAM V4-Free-up-2-address-bits-in-64bit-mode.patch +Patch5: V4-Free-up-2-address-bits-in-64bit-mode.patch BuildRequires: fdupes BuildRequires: libQt5Core-private-headers-devel >= %{version} BuildRequires: libQt5Gui-private-headers-devel >= %{version} @@ -75,6 +81,11 @@ handling. %setup -q -n qtdeclarative-opensource-src-%{real_version} %patch0 -p1 %patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%ifarch aarch64 +%patch5 -p1 +%endif %package -n %libname Summary: Qt 5 Declarative Library