[SCM] qtdeclarative packaging branch, experimental, updated. debian/5.7.0-3-4-gfe1dbcb

Dmitry Shachnev mitya57 at moszumanska.debian.org
Wed Oct 5 20:05:06 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/qt/qtdeclarative.git;a=commitdiff;h=fe1dbcb

The following commit has been merged in the experimental branch:
commit fe1dbcb345b61e49bdee829ff8c5005e53b8fd16
Author: Dmitry Shachnev <mitya57 at gmail.com>
Date:   Wed Oct 5 23:04:38 2016 +0300

    Backport upstream patch to allow using 49 address bits in 64-bit mode.
    
    This should fix issues on arm64.
---
 debian/changelog                        |   2 +
 debian/patches/series                   |   1 +
 debian/patches/use_49_address_bits.diff | 737 ++++++++++++++++++++++++++++++++
 3 files changed, 740 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index ffd8a93..34c7130 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -9,6 +9,8 @@ qtdeclarative-opensource-src (5.7.0-4) UNRELEASED; urgency=medium
     on top of the above patch.
   * Add a patch to make the qqmlapplicationengine test pass when JIT is not
     available (fix_tst_qqmlapplicationengine.diff, forwarded upstream).
+  * Backport upstream patch to allow using 49 address bits in 64-bit mode
+    (use_49_address_bits.diff). This should fix issues on arm64.
 
  -- Debian Qt/KDE Maintainers <debian-qt-kde at lists.debian.org>  Wed, 05 Oct 2016 22:45:29 +0300
 
diff --git a/debian/patches/series b/debian/patches/series
index 2431283..59eec11 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -3,6 +3,7 @@ no_lifetime_dse.diff
 no_value_without_tag.diff
 fix_engine_64bits_big_endian.diff
 fix-V4-on-big-endian.patch
+use_49_address_bits.diff
 
 # Forwarded upstream
 fix_tst_qqmlapplicationengine.diff
diff --git a/debian/patches/use_49_address_bits.diff b/debian/patches/use_49_address_bits.diff
new file mode 100644
index 0000000..158fbb8
--- /dev/null
+++ b/debian/patches/use_49_address_bits.diff
@@ -0,0 +1,737 @@
+Description: 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.
+Origin: upstream, https://code.qt.io/cgit/qt/qtdeclarative.git/commit/?id=2afb54fb51091765
+Last-Update: 2016-10-05
+
+--- a/src/qml/jit/qv4assembler.cpp
++++ b/src/qml/jit/qv4assembler.cpp
+@@ -139,8 +139,30 @@
+     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) {
+@@ -153,8 +175,11 @@
+     }
+ }
+ 
+-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) {
+@@ -338,9 +363,8 @@
+     // 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,
+--- a/src/qml/jit/qv4assembler_p.h
++++ b/src/qml/jit/qv4assembler_p.h
+@@ -380,6 +380,11 @@
+     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);
+--- a/src/qml/jit/qv4isel_masm.cpp
++++ b/src/qml/jit/qv4isel_masm.cpp
+@@ -709,7 +709,7 @@
+ #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
+ }
+ 
+@@ -1109,7 +1109,7 @@
+         // 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
+@@ -1200,10 +1200,15 @@
+         _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);
+@@ -1218,7 +1223,7 @@
+         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) {
+@@ -1790,9 +1795,9 @@
+ {
+     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;
+@@ -1808,16 +1813,14 @@
+ }
+ 
+ // 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;
+@@ -1828,7 +1831,7 @@
+     }
+ 
+     if (IR::Const *c = varSrc->asConst()) {
+-        if (c->type == nullOrUndef)
++        if (c->type == IR::NullType)
+             _as->jumpToBlock(_block, trueBlock);
+         else
+             _as->jumpToBlock(_block, falseBlock);
+@@ -1841,9 +1844,54 @@
+     _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;
+ }
+@@ -1934,10 +1982,14 @@
+     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;
+ }
+--- a/src/qml/jit/qv4isel_masm_p.h
++++ b/src/qml/jit/qv4isel_masm_p.h
+@@ -172,8 +172,8 @@
+     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);
+--- a/src/qml/jsruntime/qv4scopedvalue_p.h
++++ b/src/qml/jsruntime/qv4scopedvalue_p.h
+@@ -315,7 +315,7 @@
+     {
+         int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value);
+         ptr = reinterpret_cast<CallData *>(scope.alloc(size));
+-        ptr->tag = QV4::Value::Integer_Type;
++        ptr->tag = QV4::Value::Integer_Type_Internal;
+         ptr->argc = argc;
+     }
+ 
+--- a/src/qml/jsruntime/qv4value_p.h
++++ b/src/qml/jsruntime/qv4value_p.h
+@@ -76,23 +76,85 @@
+     /*
+         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;
+@@ -140,7 +202,7 @@
+     {
+         quint32 v;
+         memcpy(&v, &b, 4);
+-        setTagValue(Managed_Type, v);
++        setTagValue(Managed_Type_Internal, v);
+     }
+ #endif
+ 
+@@ -156,12 +218,32 @@
+ 
+     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
+@@ -169,101 +251,64 @@
+         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;
+@@ -503,14 +548,14 @@
+ 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;
+ }
+ 
+@@ -538,7 +583,6 @@
+ inline Primitive Primitive::fromInt32(int i)
+ {
+     Primitive v;
+-    v.setTagValue(Integer_Type_Internal, 0);
+     v.setInt_32(i);
+     return v;
+ }
+@@ -556,31 +600,23 @@
+ 
+ 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;
+--- a/src/qml/jsruntime/qv4vme_moth.cpp
++++ b/src/qml/jsruntime/qv4vme_moth.cpp
+@@ -569,7 +569,7 @@
+ #endif // DO_TRACE_INSTR
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -579,7 +579,7 @@
+         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<QV4::CallData *>(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));
+@@ -588,7 +588,7 @@
+     MOTH_BEGIN_INSTR(CallPropertyLookup)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -598,7 +598,7 @@
+         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<QV4::CallData *>(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));
+@@ -608,7 +608,7 @@
+         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<QV4::CallData *>(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));
+@@ -617,7 +617,7 @@
+     MOTH_BEGIN_INSTR(CallElement)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -626,7 +626,7 @@
+     MOTH_BEGIN_INSTR(CallActivationProperty)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -635,7 +635,7 @@
+     MOTH_BEGIN_INSTR(CallGlobalLookup)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -741,7 +741,7 @@
+     MOTH_BEGIN_INSTR(CreateValue)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -750,7 +750,7 @@
+     MOTH_BEGIN_INSTR(CreateProperty)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -759,7 +759,7 @@
+     MOTH_BEGIN_INSTR(ConstructPropertyLookup)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -768,7 +768,7 @@
+     MOTH_BEGIN_INSTR(CreateActivationProperty)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));
+@@ -777,7 +777,7 @@
+     MOTH_BEGIN_INSTR(ConstructGlobalLookup)
+         Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+         QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(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));

-- 
qtdeclarative packaging



More information about the pkg-kde-commits mailing list