From 681ceebc9625294243613e8737c5c2aac485462f Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 1 Sep 2016 15:34:57 +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/jit/qv4assembler.cpp | 38 +++++++-- src/qml/jit/qv4assembler_p.h | 5 ++ src/qml/jit/qv4isel_masm.cpp | 85 ++++++++++++++----- src/qml/jit/qv4isel_masm_p.h | 4 +- src/qml/jsruntime/qv4value_p.h | 186 ++++++++++++++++++----------------------- 5 files changed, 186 insertions(+), 132 deletions(-) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 929726f..b7dbc81 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -133,8 +133,30 @@ void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBl 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(RelationalCondition cond, RegisterID left } } -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::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe // 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, diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 532a311..ba9ca66 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/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); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index b6df5fb..cfd0862 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -703,7 +703,7 @@ void InstructionSelection::loadString(const QString &str, IR::Expr *target) #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::convertTypeToDouble(IR::Expr *source, IR::Expr *targe // 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,12 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe _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::IsManagedOrUndefined_Shift), Assembler::ScratchRegister); + Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3)); + + // nope, not integer convertible, so check for a double: + Assembler::Jump fallback = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(3)); // it's a double _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); @@ -1212,7 +1214,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe 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 +1786,9 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr { 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 +1804,14 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr } // 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 +1822,7 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I } 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 +1835,54 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I _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; } diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 6e9b02b..f6d9364 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/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); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 5abf5ad..942b6ee 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -70,23 +70,27 @@ 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. */ quint64 _val; @@ -137,7 +141,7 @@ public: { quint32 v; memcpy(&v, &b, 4); - setTagValue(Managed_Type, v); + setTagValue(Managed_Type_Internal, v); } #endif @@ -153,12 +157,32 @@ 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 @@ -166,101 +190,65 @@ public: 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 48 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-16, + Tag_Shift = 32, + IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift }; - - - enum ValueTypeInternal { - Null_Type_Internal = Null_Type, - Boolean_Type_Internal = Boolean_Type, - Integer_Type_Internal = Integer_Type + enum { + Managed_Type_Internal = 0 }; #endif + enum ValueTypeInternal { + Empty_Type_Internal = Immediate_Mask | 0, + ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 47 + Null_Type_Internal = ConvertibleToInt | 0x08000u, + Boolean_Type_Internal = ConvertibleToInt | 0x04000u, + Integer_Type_Internal = ConvertibleToInt | 0x02000u, + }; - inline unsigned type() const { - return tag() & Type_Mask; - } + inline bool isUndefined() const { return tag() == Managed_Type_Internal && value() == 0; } // 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 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 (tag() >> (IsManagedOrUndefined_Shift - Tag_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 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; @@ -500,14 +488,14 @@ struct Q_QML_PRIVATE_EXPORT Primitive : public Value inline Primitive Primitive::undefinedValue() { Primitive v; - v.setTagValue(Undefined_Type, 0); + v.setM(nullptr); return v; } inline Primitive Primitive::emptyValue() { Primitive v; - v.setTagValue(Value::Empty_Type, 0); + v.setEmpty(0); return v; } @@ -553,31 +541,23 @@ inline Primitive Primitive::fromUInt32(uint i) 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; -- 2.9.3