aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2017-03-28 14:47:40 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2017-03-31 08:01:00 +0000
commitda6fd9c762561d41ce3372c98a555771d18241d6 (patch)
tree622337d93665e270253cb9a8c5d137736557e543
parentec465af245e90598039c4aabab9641922db34394 (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>
-rw-r--r--src/qml/compiler/qv4isel_util_p.h76
-rw-r--r--src/qml/jit/qv4assembler.cpp12
-rw-r--r--src/qml/jit/qv4assembler_p.h43
-rw-r--r--src/qml/jit/qv4isel_masm.cpp12
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 &regularRegistersToSave,
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);