diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-28 14:47:40 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-31 08:01:00 +0000 |
commit | da6fd9c762561d41ce3372c98a555771d18241d6 (patch) | |
tree | 622337d93665e270253cb9a8c5d137736557e543 /src/qml | |
parent | ec465af245e90598039c4aabab9641922db34394 (diff) |
Fix encoding of primitive constants when cross-compiling
QV4::Primitive is using host value encoding, which can differ from the
target. The source of QV4::Primitive in the code generator is usually
IR::Const, transformed via convertToValue(). That function becomes a
template that converts to a simple target primitive type.
Change-Id: If028aea9551d77d81eec306f60fd995c25b76710
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4isel_util_p.h | 76 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler.cpp | 12 | ||||
-rw-r--r-- | src/qml/jit/qv4assembler_p.h | 43 | ||||
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 12 |
4 files changed, 100 insertions, 43 deletions
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 1755193d32..e949e6f0ad 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -58,6 +58,59 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct TargetPrimitive32 { + static TargetPrimitive32 emptyValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Empty) << 32; return p; } + static TargetPrimitive32 nullValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Null) << 32; return p; } + static TargetPrimitive32 undefinedValue() { TargetPrimitive32 p; p._val = quint64(Value::Managed_Type_Internal_32) << 32; return p; } + static TargetPrimitive32 fromBoolean(bool b) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive32 fromInt32(int v) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive32 fromDouble(double v) { + TargetPrimitive32 p; + memcpy(&p._val, &v, 8); + return p; + } + static TargetPrimitive32 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + +struct TargetPrimitive64 { + static TargetPrimitive64 emptyValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Empty) << 32; return p; } + static TargetPrimitive64 nullValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Null) << 32; return p; } + static TargetPrimitive64 undefinedValue() { TargetPrimitive64 p; p._val = 0; return p; } + static TargetPrimitive64 fromBoolean(bool b) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive64 fromInt32(int v) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive64 fromDouble(double v) { + TargetPrimitive64 p; + memcpy(&p._val, &v, 8); + p._val ^= Value::NaNEncodeMask; + return p; + } + static TargetPrimitive64 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + inline bool canConvertToSignedInteger(double value) { int ival = (int) value; @@ -72,36 +125,37 @@ inline bool canConvertToUnsignedInteger(double value) return uval == value && !(value == 0 && isNegative(value)); } -inline Primitive convertToValue(IR::Const *c) +template <typename PrimitiveType = Primitive> +inline PrimitiveType convertToValue(IR::Const *c) { switch (c->type) { case IR::MissingType: - return Primitive::emptyValue(); + return PrimitiveType::emptyValue(); case IR::NullType: - return Primitive::nullValue(); + return PrimitiveType::nullValue(); case IR::UndefinedType: - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); case IR::BoolType: - return Primitive::fromBoolean(c->value != 0); + return PrimitiveType::fromBoolean(c->value != 0); case IR::SInt32Type: - return Primitive::fromInt32(int(c->value)); + return PrimitiveType::fromInt32(int(c->value)); case IR::UInt32Type: - return Primitive::fromUInt32(unsigned(c->value)); + return PrimitiveType::fromUInt32(unsigned(c->value)); case IR::DoubleType: - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); case IR::NumberType: { int ival = (int)c->value; if (canConvertToSignedInteger(c->value)) { - return Primitive::fromInt32(ival); + return PrimitiveType::fromInt32(ival); } else { - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); } } default: Q_UNREACHABLE(); } // unreachable, but the function must return something - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); } class ConvertTemps diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index daa732810b..da2cd49a63 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -319,15 +319,15 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>: template <typename TargetConfiguration> typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg) { - return loadConstant(convertToValue(c), baseReg); + return loadConstant(convertToValue<TargetPrimitive>(c), baseReg); } template <typename TargetConfiguration> -typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg) +typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); - const int index = _jsGenerator->registerConstant(v.asReturnedValue()); + const int index = _jsGenerator->registerConstant(v.rawValue()); return Address(baseReg, index * sizeof(QV4::Value)); } @@ -339,7 +339,7 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString } template <typename TargetConfiguration> -void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination) +void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination) { Address addr = loadAddress(ScratchRegister, destination); storeValue(value, addr); @@ -518,7 +518,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo } else if (IR::Temp *t = s->expr->asTemp()) { RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t); } else if (IR::Const *c = s->expr->asConst()) { - QV4::Primitive retVal = convertToValue(c); + auto retVal = convertToValue<TargetPrimitive>(c); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); } else { Q_UNREACHABLE(); @@ -535,7 +535,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo ret(); exceptionReturnLabel = label(); - QV4::Primitive retVal = Primitive::undefinedValue(); + auto retVal = TargetPrimitive::undefinedValue(); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); jump(leaveStackFrame); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index ad6c29dd49..fed51e5e94 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -154,6 +154,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using Label = typename JITAssembler::Label; using ValueTypeInternal = Value::ValueTypeInternal_32; + using TargetPrimitive = TargetPrimitive32; static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { @@ -171,9 +172,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->storeDouble(source, ptr); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination) { - as->store32(TrustedImm32(value.int_32()), destination); + as->store32(TrustedImm32(value.value()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); } @@ -243,9 +244,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo } } - static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal) + static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal) { - as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister); + as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister); as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister); } @@ -387,6 +388,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using Label = typename JITAssembler::Label; using ValueTypeInternal = Value::ValueTypeInternal_64; + using TargetPrimitive = TargetPrimitive64; static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { @@ -463,12 +465,12 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo } } - static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal) + static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal) { as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination) { as->store64(TrustedImm64(value.rawValue()), destination); } @@ -505,7 +507,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer addr = as->loadTempAddress(temp); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -518,7 +520,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer addr = as->loadArgLocalAddress(dest, al); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -527,7 +529,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo { Q_UNUSED(argumentNumber); - QV4::Value v = convertToValue(c); + auto v = convertToValue<TargetPrimitive64>(c); as->move(TrustedImm64(v.rawValue()), dest); } @@ -536,7 +538,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Q_UNUSED(argumentNumber); if (!expr) { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } else if (IR::Temp *t = expr->asTemp()){ loadArgumentInRegister(as, t, dest, argumentNumber); @@ -755,6 +757,7 @@ public: using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>; using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal; + using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive; // V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage // collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned @@ -978,7 +981,7 @@ public: Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al); Pointer loadStringAddress(RegisterID reg, const QString &string); Address loadConstant(IR::Const *c, RegisterID baseReg); - Address loadConstant(const Primitive &v, RegisterID baseReg); + Address loadConstant(const TargetPrimitive &v, RegisterID baseReg); void loadStringRef(RegisterID reg, const QString &string); Pointer stackSlotPointer(IR::Temp *t) const { @@ -1240,12 +1243,12 @@ public: TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target)); } - void storeValue(QV4::Primitive value, Address destination) + void storeValue(TargetPrimitive value, Address destination) { RegisterSizeDependentOps::storeValue(this, value, destination); } - void storeValue(QV4::Primitive value, IR::Expr* temp); + void storeValue(TargetPrimitive value, IR::Expr* temp); void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave, const RegisterInformation &fpRegistersToSave); @@ -1422,8 +1425,8 @@ public: Address tagAddr = addr; tagAddr.offset += 4; - QV4::Primitive v = convertToValue(c); - store32(TrustedImm32(v.int_32()), addr); + auto v = convertToValue<TargetPrimitive>(c); + store32(TrustedImm32(v.value()), addr); store32(TrustedImm32(v.tag()), tagAddr); return Pointer(addr); } @@ -1439,7 +1442,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr); } void storeBool(RegisterID src, RegisterID dest) @@ -1483,7 +1486,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr); } void storeInt32(RegisterID reg, IR::Expr *target) @@ -1552,7 +1555,7 @@ public: RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg) { if (IR::Const *c = e->asConst()) { - move(TrustedImm32(convertToValue(c).int_32()), scratchReg); + move(TrustedImm32(convertToValue<Primitive>(c).int_32()), scratchReg); return scratchReg; } @@ -1595,7 +1598,7 @@ public: // it's not in signed int range, so load it as a double, and truncate it down loadDouble(addr, FPGpr0); - Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg); + Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg); subDouble(inversionAddress, FPGpr0); Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg); canNeverHappen.link(this); @@ -1675,7 +1678,7 @@ void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source) } else if (source->asTemp() || source->asArgLocal()) { RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); } else if (IR::Const *c = source->asConst()) { - QV4::Primitive v = convertToValue(c); + auto v = convertToValue<TargetPrimitive>(c); storeValue(v, result); } else { Q_UNREACHABLE(); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 126fb4382b..dd48fdfc55 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -256,7 +256,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &na template <typename JITAssembler> void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result) { - _as->storeValue(Primitive::fromBoolean(false), result); + _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result); } template <typename JITAssembler> @@ -376,7 +376,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayValueCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); // Value _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); @@ -400,7 +400,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayGetterSetterCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); // Getter _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); @@ -486,7 +486,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(TrustedImm32(convertToValue(sourceConst).int_32()), + _as->move(TrustedImm32(convertToValue<Primitive>(sourceConst).int_32()), (RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); @@ -495,7 +495,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E } } - _as->storeValue(convertToValue(sourceConst), target); + _as->storeValue(convertToValue<typename JITAssembler::TargetPrimitive>(sourceConst), target); } template <typename JITAssembler> @@ -1320,7 +1320,7 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR:: _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); if (!thisObject) - _as->storeValue(QV4::Primitive::undefinedValue(), p); + _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p); else _as->copyValue(p, thisObject); |