Merge "Merge remote-tracking branch 'origin/5.9' into dev" into refs/staging/dev
This commit is contained in:
commit
0abdf6db0e
|
@ -26,9 +26,10 @@
|
||||||
#ifndef ARM64Assembler_h
|
#ifndef ARM64Assembler_h
|
||||||
#define ARM64Assembler_h
|
#define ARM64Assembler_h
|
||||||
|
|
||||||
#if ENABLE(ASSEMBLER) && CPU(ARM64)
|
#if ENABLE(ASSEMBLER) && (CPU(ARM64) || defined(V4_BOOTSTRAP))
|
||||||
|
|
||||||
#include "AssemblerBuffer.h"
|
#include "AssemblerBuffer.h"
|
||||||
|
#include "AbstractMacroAssembler.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <wtf/Assertions.h>
|
#include <wtf/Assertions.h>
|
||||||
#include <wtf/Vector.h>
|
#include <wtf/Vector.h>
|
||||||
|
@ -520,8 +521,8 @@ typedef enum {
|
||||||
#undef DECLARE_REGISTER
|
#undef DECLARE_REGISTER
|
||||||
} FPRegisterID;
|
} FPRegisterID;
|
||||||
|
|
||||||
static constexpr bool isSp(RegisterID reg) { return reg == sp; }
|
static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return reg == sp; }
|
||||||
static constexpr bool isZr(RegisterID reg) { return reg == zr; }
|
static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return reg == zr; }
|
||||||
|
|
||||||
} // namespace ARM64Registers
|
} // namespace ARM64Registers
|
||||||
|
|
||||||
|
@ -530,15 +531,15 @@ public:
|
||||||
typedef ARM64Registers::RegisterID RegisterID;
|
typedef ARM64Registers::RegisterID RegisterID;
|
||||||
typedef ARM64Registers::FPRegisterID FPRegisterID;
|
typedef ARM64Registers::FPRegisterID FPRegisterID;
|
||||||
|
|
||||||
static constexpr RegisterID firstRegister() { return ARM64Registers::x0; }
|
static Q_DECL_CONSTEXPR RegisterID firstRegister() { return ARM64Registers::x0; }
|
||||||
static constexpr RegisterID lastRegister() { return ARM64Registers::sp; }
|
static Q_DECL_CONSTEXPR RegisterID lastRegister() { return ARM64Registers::sp; }
|
||||||
|
|
||||||
static constexpr FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
|
static Q_DECL_CONSTEXPR FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
|
||||||
static constexpr FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
|
static Q_DECL_CONSTEXPR FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
|
static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
|
||||||
static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
|
static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ARM64Assembler()
|
ARM64Assembler()
|
||||||
|
@ -653,9 +654,7 @@ public:
|
||||||
}
|
}
|
||||||
void operator=(const LinkRecord& other)
|
void operator=(const LinkRecord& other)
|
||||||
{
|
{
|
||||||
data.copyTypes.content[0] = other.data.copyTypes.content[0];
|
data.realTypes = other.data.realTypes;
|
||||||
data.copyTypes.content[1] = other.data.copyTypes.content[1];
|
|
||||||
data.copyTypes.content[2] = other.data.copyTypes.content[2];
|
|
||||||
}
|
}
|
||||||
intptr_t from() const { return data.realTypes.m_from; }
|
intptr_t from() const { return data.realTypes.m_from; }
|
||||||
void setFrom(intptr_t from) { data.realTypes.m_from = from; }
|
void setFrom(intptr_t from) { data.realTypes.m_from = from; }
|
||||||
|
@ -671,8 +670,8 @@ public:
|
||||||
private:
|
private:
|
||||||
union {
|
union {
|
||||||
struct RealTypes {
|
struct RealTypes {
|
||||||
intptr_t m_from : 48;
|
int64_t m_from : 48;
|
||||||
intptr_t m_to : 48;
|
int64_t m_to : 48;
|
||||||
JumpType m_type : 8;
|
JumpType m_type : 8;
|
||||||
JumpLinkType m_linkType : 8;
|
JumpLinkType m_linkType : 8;
|
||||||
Condition m_condition : 4;
|
Condition m_condition : 4;
|
||||||
|
@ -680,10 +679,6 @@ public:
|
||||||
RegisterID m_compareRegister : 6;
|
RegisterID m_compareRegister : 6;
|
||||||
bool m_is64Bit : 1;
|
bool m_is64Bit : 1;
|
||||||
} realTypes;
|
} realTypes;
|
||||||
struct CopyTypes {
|
|
||||||
uint64_t content[3];
|
|
||||||
} copyTypes;
|
|
||||||
COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct);
|
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -743,6 +738,89 @@ public:
|
||||||
return isValidSignedImm9(offset);
|
return isValidSignedImm9(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Jump:
|
||||||
|
//
|
||||||
|
// A jump object is a reference to a jump instruction that has been planted
|
||||||
|
// into the code buffer - it is typically used to link the jump, setting the
|
||||||
|
// relative offset such that when executed it will jump to the desired
|
||||||
|
// destination.
|
||||||
|
template <typename LabelType>
|
||||||
|
class Jump {
|
||||||
|
template<class TemplateAssemblerType>
|
||||||
|
friend class AbstractMacroAssembler;
|
||||||
|
friend class Call;
|
||||||
|
template <typename, template <typename> class> friend class LinkBufferBase;
|
||||||
|
public:
|
||||||
|
Jump()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid)
|
||||||
|
: m_label(jmp)
|
||||||
|
, m_type(type)
|
||||||
|
, m_condition(condition)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister)
|
||||||
|
: m_label(jmp)
|
||||||
|
, m_type(type)
|
||||||
|
, m_condition(condition)
|
||||||
|
, m_is64Bit(is64Bit)
|
||||||
|
, m_compareRegister(compareRegister)
|
||||||
|
{
|
||||||
|
ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister)
|
||||||
|
: m_label(jmp)
|
||||||
|
, m_type(type)
|
||||||
|
, m_condition(condition)
|
||||||
|
, m_bitNumber(bitNumber)
|
||||||
|
, m_compareRegister(compareRegister)
|
||||||
|
{
|
||||||
|
ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelType label() const
|
||||||
|
{
|
||||||
|
LabelType result;
|
||||||
|
result.m_label = m_label;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void link(AbstractMacroAssembler<ARM64Assembler>* masm) const
|
||||||
|
{
|
||||||
|
if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
|
||||||
|
masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
|
||||||
|
else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
|
||||||
|
masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
|
||||||
|
else
|
||||||
|
masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void linkTo(LabelType label, AbstractMacroAssembler<ARM64Assembler>* masm) const
|
||||||
|
{
|
||||||
|
if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
|
||||||
|
masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
|
||||||
|
else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
|
||||||
|
masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
|
||||||
|
else
|
||||||
|
masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSet() const { return m_label.isSet(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AssemblerLabel m_label;
|
||||||
|
ARM64Assembler::JumpType m_type;
|
||||||
|
ARM64Assembler::Condition m_condition;
|
||||||
|
bool m_is64Bit;
|
||||||
|
unsigned m_bitNumber;
|
||||||
|
ARM64Assembler::RegisterID m_compareRegister;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int encodeFPImm(double d)
|
int encodeFPImm(double d)
|
||||||
{
|
{
|
||||||
|
@ -2857,11 +2935,11 @@ public:
|
||||||
|
|
||||||
expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
|
expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
|
||||||
ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
|
ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 1 && rd == rdFirst);
|
||||||
result |= static_cast<uintptr_t>(imm16) << 16;
|
result |= static_cast<uint64_t>(imm16) << 16;
|
||||||
|
|
||||||
expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
|
expected = disassembleMoveWideImediate(address + 2, sf, opc, hw, imm16, rd);
|
||||||
ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
|
ASSERT_UNUSED(expected, expected && sf && opc == MoveWideOp_K && hw == 2 && rd == rdFirst);
|
||||||
result |= static_cast<uintptr_t>(imm16) << 32;
|
result |= static_cast<uint64_t>(imm16) << 32;
|
||||||
|
|
||||||
return reinterpret_cast<void*>(result);
|
return reinterpret_cast<void*>(result);
|
||||||
}
|
}
|
||||||
|
@ -2932,7 +3010,10 @@ public:
|
||||||
|
|
||||||
static void cacheFlush(void* code, size_t size)
|
static void cacheFlush(void* code, size_t size)
|
||||||
{
|
{
|
||||||
#if OS(IOS)
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
UNUSED_PARAM(code)
|
||||||
|
UNUSED_PARAM(size)
|
||||||
|
#elif OS(IOS)
|
||||||
sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
|
sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
|
||||||
#elif OS(LINUX)
|
#elif OS(LINUX)
|
||||||
size_t page = pageSize();
|
size_t page = pageSize();
|
||||||
|
@ -2989,7 +3070,7 @@ public:
|
||||||
case JumpCondition: {
|
case JumpCondition: {
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
||||||
intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
int64_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
||||||
|
|
||||||
if (((relative << 43) >> 43) == relative)
|
if (((relative << 43) >> 43) == relative)
|
||||||
return LinkJumpConditionDirect;
|
return LinkJumpConditionDirect;
|
||||||
|
@ -2999,7 +3080,7 @@ public:
|
||||||
case JumpCompareAndBranch: {
|
case JumpCompareAndBranch: {
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
||||||
intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
int64_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
||||||
|
|
||||||
if (((relative << 43) >> 43) == relative)
|
if (((relative << 43) >> 43) == relative)
|
||||||
return LinkJumpCompareAndBranchDirect;
|
return LinkJumpCompareAndBranchDirect;
|
||||||
|
@ -3009,7 +3090,7 @@ public:
|
||||||
case JumpTestBit: {
|
case JumpTestBit: {
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 0x3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 0x3));
|
||||||
intptr_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
int64_t relative = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(from));
|
||||||
|
|
||||||
if (((relative << 50) >> 50) == relative)
|
if (((relative << 50) >> 50) == relative)
|
||||||
return LinkJumpTestBitDirect;
|
return LinkJumpTestBitDirect;
|
||||||
|
@ -3121,7 +3202,7 @@ private:
|
||||||
{
|
{
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
||||||
intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
int64_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
||||||
ASSERT(((offset << 38) >> 38) == offset);
|
ASSERT(((offset << 38) >> 38) == offset);
|
||||||
|
|
||||||
bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
|
bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
|
||||||
|
@ -3142,7 +3223,7 @@ private:
|
||||||
{
|
{
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
||||||
intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
int64_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
||||||
ASSERT(((offset << 38) >> 38) == offset);
|
ASSERT(((offset << 38) >> 38) == offset);
|
||||||
|
|
||||||
bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
|
bool useDirect = ((offset << 45) >> 45) == offset; // Fits in 19 bits
|
||||||
|
@ -3163,7 +3244,7 @@ private:
|
||||||
{
|
{
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(from) & 3));
|
||||||
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
ASSERT(!(reinterpret_cast<intptr_t>(to) & 3));
|
||||||
intptr_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
int64_t offset = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from)) >> 2;
|
||||||
ASSERT(static_cast<int>(offset) == offset);
|
ASSERT(static_cast<int>(offset) == offset);
|
||||||
ASSERT(((offset << 38) >> 38) == offset);
|
ASSERT(((offset << 38) >> 38) == offset);
|
||||||
|
|
||||||
|
@ -3766,6 +3847,8 @@ private:
|
||||||
#undef DATASIZE
|
#undef DATASIZE
|
||||||
#undef MEMOPSIZE
|
#undef MEMOPSIZE
|
||||||
#undef CHECK_FP_MEMOP_DATASIZE
|
#undef CHECK_FP_MEMOP_DATASIZE
|
||||||
|
#undef JUMP_ENUM_WITH_SIZE
|
||||||
|
#undef JUMP_ENUM_SIZE
|
||||||
|
|
||||||
#endif // ENABLE(ASSEMBLER) && CPU(ARM64)
|
#endif // ENABLE(ASSEMBLER) && CPU(ARM64)
|
||||||
|
|
||||||
|
|
|
@ -2867,6 +2867,9 @@ private:
|
||||||
int m_indexOfTailOfLastWatchpoint;
|
int m_indexOfTailOfLastWatchpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef JUMP_ENUM_WITH_SIZE
|
||||||
|
#undef JUMP_ENUM_SIZE
|
||||||
|
|
||||||
} // namespace JSC
|
} // namespace JSC
|
||||||
|
|
||||||
#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
|
#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
typedef MacroAssemblerCodePtr CodePtr;
|
typedef MacroAssemblerCodePtr CodePtr;
|
||||||
typedef MacroAssemblerCodeRef CodeRef;
|
typedef MacroAssemblerCodeRef CodeRef;
|
||||||
|
|
||||||
#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
|
#if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP)
|
||||||
class Jump;
|
class Jump;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -455,7 +455,7 @@ public:
|
||||||
AssemblerLabel m_label;
|
AssemblerLabel m_label;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
|
#if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP)
|
||||||
using Jump = typename AssemblerType::template Jump<Label>;
|
using Jump = typename AssemblerType::template Jump<Label>;
|
||||||
friend Jump;
|
friend Jump;
|
||||||
#endif
|
#endif
|
||||||
|
@ -510,7 +510,7 @@ public:
|
||||||
// into the code buffer - it is typically used to link the jump, setting the
|
// into the code buffer - it is typically used to link the jump, setting the
|
||||||
// relative offset such that when executed it will jump to the desired
|
// relative offset such that when executed it will jump to the desired
|
||||||
// destination.
|
// destination.
|
||||||
#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
|
#if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP)
|
||||||
class Jump {
|
class Jump {
|
||||||
template<class TemplateAssemblerType>
|
template<class TemplateAssemblerType>
|
||||||
friend class AbstractMacroAssembler;
|
friend class AbstractMacroAssembler;
|
||||||
|
|
|
@ -505,7 +505,7 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CPU(ARM64)
|
#if CPU(ARM64) || defined(V4_BOOTSTRAP)
|
||||||
template <>
|
template <>
|
||||||
class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>>
|
class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>>
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,12 +31,12 @@
|
||||||
#if ENABLE(ASSEMBLER)
|
#if ENABLE(ASSEMBLER)
|
||||||
|
|
||||||
#include "MacroAssemblerARMv7.h"
|
#include "MacroAssemblerARMv7.h"
|
||||||
|
#include "MacroAssemblerARM64.h"
|
||||||
|
|
||||||
#if CPU(ARM_THUMB2)
|
#if CPU(ARM_THUMB2)
|
||||||
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; };
|
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; };
|
||||||
|
|
||||||
#elif CPU(ARM64)
|
#elif CPU(ARM64)
|
||||||
#include "MacroAssemblerARM64.h"
|
|
||||||
namespace JSC { typedef MacroAssemblerARM64 MacroAssemblerBase; };
|
namespace JSC { typedef MacroAssemblerARM64 MacroAssemblerBase; };
|
||||||
|
|
||||||
#elif CPU(ARM_TRADITIONAL)
|
#elif CPU(ARM_TRADITIONAL)
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#ifndef MacroAssemblerARM64_h
|
#ifndef MacroAssemblerARM64_h
|
||||||
#define MacroAssemblerARM64_h
|
#define MacroAssemblerARM64_h
|
||||||
|
|
||||||
#if ENABLE(ASSEMBLER)
|
#if ENABLE(ASSEMBLER) && (CPU(ARM64) || defined(V4_BOOTSTRAP))
|
||||||
|
|
||||||
#include "ARM64Assembler.h"
|
#include "ARM64Assembler.h"
|
||||||
#include "AbstractMacroAssembler.h"
|
#include "AbstractMacroAssembler.h"
|
||||||
|
@ -42,7 +42,7 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler> {
|
||||||
friend class DataLabelPtr;
|
friend class DataLabelPtr;
|
||||||
friend class DataLabel32;
|
friend class DataLabel32;
|
||||||
friend class DataLabelCompact;
|
friend class DataLabelCompact;
|
||||||
friend class Jump;
|
// template <typename> friend class Jump;
|
||||||
friend class Label;
|
friend class Label;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -119,9 +119,9 @@ public:
|
||||||
private:
|
private:
|
||||||
static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
|
static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
|
||||||
static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
|
static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
|
||||||
static const intptr_t maskHalfWord0 = 0xffffl;
|
static const int64_t maskHalfWord0 = 0xffffl;
|
||||||
static const intptr_t maskHalfWord1 = 0xffff0000l;
|
static const int64_t maskHalfWord1 = 0xffff0000l;
|
||||||
static const intptr_t maskUpperWord = 0xffffffff00000000l;
|
static const int64_t maskUpperWord = 0xffffffff00000000l;
|
||||||
|
|
||||||
// 4 instructions - 3 to load the function pointer, + blr.
|
// 4 instructions - 3 to load the function pointer, + blr.
|
||||||
static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
|
static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
|
||||||
|
@ -209,6 +209,33 @@ public:
|
||||||
static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
|
static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
|
||||||
static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; }
|
static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; }
|
||||||
|
|
||||||
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
void loadPtr(ImplicitAddress address, RegisterID dest)
|
||||||
|
{
|
||||||
|
load32(address, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subPtr(TrustedImm32 imm, RegisterID dest)
|
||||||
|
{
|
||||||
|
sub32(imm, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPtr(TrustedImm32 imm, RegisterID dest)
|
||||||
|
{
|
||||||
|
add32(imm, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
|
||||||
|
{
|
||||||
|
add32(imm, src, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void storePtr(RegisterID src, ImplicitAddress address)
|
||||||
|
{
|
||||||
|
store32(src, address);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Integer operations:
|
// Integer operations:
|
||||||
|
|
||||||
void add32(RegisterID a, RegisterID b, RegisterID dest)
|
void add32(RegisterID a, RegisterID b, RegisterID dest)
|
||||||
|
@ -2757,6 +2784,7 @@ public:
|
||||||
return branch32(cond, left, dataTempRegister);
|
return branch32(cond, left, dataTempRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(V4_BOOTSTRAP)
|
||||||
PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
|
PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
|
||||||
{
|
{
|
||||||
m_makeJumpPatchable = true;
|
m_makeJumpPatchable = true;
|
||||||
|
@ -2764,6 +2792,7 @@ public:
|
||||||
m_makeJumpPatchable = false;
|
m_makeJumpPatchable = false;
|
||||||
return PatchableJump(result);
|
return PatchableJump(result);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
|
PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
|
||||||
{
|
{
|
||||||
|
@ -3000,7 +3029,7 @@ private:
|
||||||
return m_cachedMemoryTempRegister.registerIDInvalidate();
|
return m_cachedMemoryTempRegister.registerIDInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool isInIntRange(intptr_t value)
|
ALWAYS_INLINE bool isInIntRange(int64_t value)
|
||||||
{
|
{
|
||||||
return value == ((value << 32) >> 32);
|
return value == ((value << 32) >> 32);
|
||||||
}
|
}
|
||||||
|
@ -3354,6 +3383,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename, template <typename> class> friend class LinkBufferBase;
|
template <typename, template <typename> class> friend class LinkBufferBase;
|
||||||
|
template <typename> friend class BranchCompactingLinkBuffer;
|
||||||
|
template <typename> friend struct BranchCompactingExecutableOffsetCalculator;
|
||||||
void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
|
void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
|
||||||
int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
|
int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,17 @@ HEADERS += $$PWD/stubs/WTFStubs.h
|
||||||
|
|
||||||
SOURCES += $$PWD/stubs/Options.cpp
|
SOURCES += $$PWD/stubs/Options.cpp
|
||||||
|
|
||||||
HEADERS += $$PWD/stubs/wtf/*.h
|
HEADERS += $$PWD/stubs/wtf/FastAllocBase.h \
|
||||||
|
$$PWD/stubs/wtf/FastMalloc.h \
|
||||||
|
$$PWD/stubs/wtf/Noncopyable.h \
|
||||||
|
$$PWD/stubs/wtf/OwnPtr.h \
|
||||||
|
$$PWD/stubs/wtf/PassOwnPtr.h \
|
||||||
|
$$PWD/stubs/wtf/PassRefPtr.h \
|
||||||
|
$$PWD/stubs/wtf/RefCounted.h \
|
||||||
|
$$PWD/stubs/wtf/RefPtr.h \
|
||||||
|
$$PWD/stubs/wtf/TypeTraits.h \
|
||||||
|
$$PWD/stubs/wtf/UnusedParam.h \
|
||||||
|
$$PWD/stubs/wtf/Vector.h
|
||||||
|
|
||||||
SOURCES += $$PWD/disassembler/Disassembler.cpp
|
SOURCES += $$PWD/disassembler/Disassembler.cpp
|
||||||
SOURCES += $$PWD/disassembler/UDis86Disassembler.cpp
|
SOURCES += $$PWD/disassembler/UDis86Disassembler.cpp
|
||||||
|
@ -67,8 +77,21 @@ SOURCES += $$PWD/disassembler/ARM64Disassembler.cpp
|
||||||
SOURCES += $$PWD/disassembler/ARM64/A64DOpcode.cpp
|
SOURCES += $$PWD/disassembler/ARM64/A64DOpcode.cpp
|
||||||
HEADERS += $$PWD/disassembler/ARM64/A64DOpcode.h
|
HEADERS += $$PWD/disassembler/ARM64/A64DOpcode.h
|
||||||
|
|
||||||
SOURCES += $$PWD/yarr/*.cpp
|
!qmldevtools_build {
|
||||||
HEADERS += $$PWD/yarr/*.h
|
SOURCES += $$PWD/yarr/YarrCanonicalizeUCS2.cpp \
|
||||||
|
$$PWD/yarr/YarrInterpreter.cpp \
|
||||||
|
$$PWD/yarr/YarrJIT.cpp \
|
||||||
|
$$PWD/yarr/YarrPattern.cpp \
|
||||||
|
$$PWD/yarr/YarrSyntaxChecker.cpp
|
||||||
|
|
||||||
|
HEADERS += $$PWD/yarr/Yarr.h \
|
||||||
|
$$PWD/yarr/YarrCanonicalizeUCS2.h \
|
||||||
|
$$PWD/yarr/YarrInterpreter.h \
|
||||||
|
$$PWD/yarr/YarrJIT.h \
|
||||||
|
$$PWD/yarr/YarrParser.h \
|
||||||
|
$$PWD/yarr/YarrPattern.h \
|
||||||
|
$$PWD/yarr/YarrSyntaxChecker.h
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Generate RegExpJitTables.h
|
# Generate RegExpJitTables.h
|
||||||
|
|
|
@ -107,7 +107,7 @@ struct ExecutableAllocator {
|
||||||
size = size + (iaddr - roundAddr);
|
size = size + (iaddr - roundAddr);
|
||||||
addr = reinterpret_cast<void*>(roundAddr);
|
addr = reinterpret_cast<void*>(roundAddr);
|
||||||
|
|
||||||
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
|
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) && !defined(V4_BOOTSTRAP)
|
||||||
# if OS(WINDOWS)
|
# if OS(WINDOWS)
|
||||||
DWORD oldProtect;
|
DWORD oldProtect;
|
||||||
# if !OS(WINRT)
|
# if !OS(WINRT)
|
||||||
|
@ -140,6 +140,7 @@ struct ExecutableAllocator {
|
||||||
size = size + (iaddr - roundAddr);
|
size = size + (iaddr - roundAddr);
|
||||||
addr = reinterpret_cast<void*>(roundAddr);
|
addr = reinterpret_cast<void*>(roundAddr);
|
||||||
|
|
||||||
|
#if !defined(V4_BOOTSTRAP)
|
||||||
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
|
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
|
||||||
# if OS(WINDOWS)
|
# if OS(WINDOWS)
|
||||||
DWORD oldProtect;
|
DWORD oldProtect;
|
||||||
|
@ -160,6 +161,10 @@ struct ExecutableAllocator {
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# error "Only W^X is supported"
|
# error "Only W^X is supported"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
(void)addr; // suppress unused parameter warning
|
||||||
|
(void)size; // suppress unused parameter warning
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,24 +219,6 @@ QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString qmlsqldatabase_databasesPath(QV4::ExecutionEngine *engine)
|
|
||||||
{
|
|
||||||
return engine->qmlEngine()->offlineStoragePath() +
|
|
||||||
QDir::separator() + QLatin1String("Databases");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qmlsqldatabase_initDatabasesPath(QV4::ExecutionEngine *engine)
|
|
||||||
{
|
|
||||||
QString databasesPath = qmlsqldatabase_databasesPath(engine);
|
|
||||||
if (!QDir().mkpath(databasesPath))
|
|
||||||
qWarning() << "LocalStorage: can't create path - " << databasesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV4::ExecutionEngine *engine)
|
|
||||||
{
|
|
||||||
return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
|
static ReturnedValue qmlsqldatabase_rows_index(const QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
|
||||||
{
|
{
|
||||||
Scope scope(v4);
|
Scope scope(v4);
|
||||||
|
@ -450,7 +432,8 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
|
||||||
if (ok) {
|
if (ok) {
|
||||||
*w->d()->version = to_version;
|
*w->d()->version = to_version;
|
||||||
#if QT_CONFIG(settings)
|
#if QT_CONFIG(settings)
|
||||||
QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(), scope.engine) + QLatin1String(".ini"), QSettings::IniFormat);
|
const QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(scope.engine->qmlEngine());
|
||||||
|
QSettings ini(enginePrivate->offlineStorageDatabaseDirectory() + db.connectionName() + QLatin1String(".ini"), QSettings::IniFormat);
|
||||||
ini.setValue(QLatin1String("Version"), to_version);
|
ini.setValue(QLatin1String("Version"), to_version);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -723,24 +706,23 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
|
||||||
if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
|
if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
|
||||||
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
|
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
|
||||||
|
|
||||||
qmlsqldatabase_initDatabasesPath(scope.engine);
|
|
||||||
|
|
||||||
QSqlDatabase database;
|
|
||||||
|
|
||||||
QV4::ScopedValue v(scope);
|
QV4::ScopedValue v(scope);
|
||||||
QString dbname = (v = (*args)[0])->toQStringNoThrow();
|
QString dbname = (v = (*args)[0])->toQStringNoThrow();
|
||||||
QString dbversion = (v = (*args)[1])->toQStringNoThrow();
|
QString dbversion = (v = (*args)[1])->toQStringNoThrow();
|
||||||
QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
|
QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
|
||||||
int dbestimatedsize = (v = (*args)[3])->toInt32();
|
int dbestimatedsize = (v = (*args)[3])->toInt32();
|
||||||
FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
|
FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
|
||||||
|
QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname);
|
||||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
QFileInfo dbFile(basename);
|
||||||
md5.addData(dbname.toUtf8());
|
if (!QDir().mkpath(dbFile.dir().absolutePath())) {
|
||||||
QString dbid(QLatin1String(md5.result().toHex()));
|
const QString message = QQmlEngine::tr("LocalStorage: can't create path %1").
|
||||||
|
arg(QDir::toNativeSeparators(dbFile.dir().absolutePath()));
|
||||||
QString basename = qmlsqldatabase_databaseFile(dbid, scope.engine);
|
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message);
|
||||||
|
}
|
||||||
|
QString dbid = dbFile.fileName();
|
||||||
bool created = false;
|
bool created = false;
|
||||||
QString version = dbversion;
|
QString version = dbversion;
|
||||||
|
QSqlDatabase database;
|
||||||
|
|
||||||
{
|
{
|
||||||
QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
|
QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
|
||||||
|
|
|
@ -167,9 +167,9 @@ additional features. See the \l {qtqml-javascript-hostenvironment.html}
|
||||||
The QML engine provides automatic type conversion between QVariantList and
|
The QML engine provides automatic type conversion between QVariantList and
|
||||||
JavaScript arrays, and between QVariantMap and JavaScript objects.
|
JavaScript arrays, and between QVariantMap and JavaScript objects.
|
||||||
|
|
||||||
For example, the function defined in QML below left expects two arguments, an
|
For example, the function defined in QML below expects two arguments, an
|
||||||
array and an object, and prints their contents using the standard JavaScript
|
array and an object, and prints their contents using the standard JavaScript
|
||||||
syntax for array and object item access. The C++ code below right calls this
|
syntax for array and object item access. The C++ code below calls this
|
||||||
function, passing a QVariantList and a QVariantMap, which are automatically
|
function, passing a QVariantList and a QVariantMap, which are automatically
|
||||||
converted to JavaScript array and object values, repectively:
|
converted to JavaScript array and object values, repectively:
|
||||||
|
|
||||||
|
@ -204,9 +204,9 @@ when it is passed to C++.
|
||||||
The QML engine provides automatic type conversion between QDateTime values and
|
The QML engine provides automatic type conversion between QDateTime values and
|
||||||
JavaScript \c Date objects.
|
JavaScript \c Date objects.
|
||||||
|
|
||||||
For example, the function defined in QML below left expects a JavaScript
|
For example, the function defined in QML below expects a JavaScript
|
||||||
\c Date object, and also returns a new \c Date object with the current date and
|
\c Date object, and also returns a new \c Date object with the current date and
|
||||||
time. The C++ code below right calls this function, passing a QDateTime value
|
time. The C++ code below calls this function, passing a QDateTime value
|
||||||
that is automatically converted by the engine into a \c Date object when it is
|
that is automatically converted by the engine into a \c Date object when it is
|
||||||
passed to the \c readDate() function. In turn, the readDate() function returns
|
passed to the \c readDate() function. In turn, the readDate() function returns
|
||||||
a \c Date object that is automatically converted into a QDateTime value when it
|
a \c Date object that is automatically converted into a QDateTime value when it
|
||||||
|
@ -215,7 +215,7 @@ is received in C++:
|
||||||
\table
|
\table
|
||||||
\header
|
\header
|
||||||
\row
|
\row
|
||||||
|
\li QML
|
||||||
\li
|
\li
|
||||||
\qml
|
\qml
|
||||||
// MyItem.qml
|
// MyItem.qml
|
||||||
|
@ -227,6 +227,7 @@ Item {
|
||||||
}
|
}
|
||||||
\endqml
|
\endqml
|
||||||
\row
|
\row
|
||||||
|
\li C++
|
||||||
\li
|
\li
|
||||||
\code
|
\code
|
||||||
// C++
|
// C++
|
||||||
|
|
|
@ -390,8 +390,8 @@ that is a public slot:
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
If an instance of \c MessageBoard was set as the context data for a file \c
|
If an instance of \c MessageBoard was set as the context data for a file \c
|
||||||
MyItem.qml, as shown below left, then \c MyItem.qml could invoke the two
|
MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
|
||||||
methods, as shown below right:
|
examples below:
|
||||||
|
|
||||||
\table
|
\table
|
||||||
\row
|
\row
|
||||||
|
|
|
@ -379,16 +379,7 @@ void Assembler<TargetConfiguration>::leaveStandardStackFrame(const RegisterInfor
|
||||||
Q_ASSERT(slotAddr.offset == 0);
|
Q_ASSERT(slotAddr.offset == 0);
|
||||||
|
|
||||||
const int frameSize = _stackLayout->calculateStackFrameSize();
|
const int frameSize = _stackLayout->calculateStackFrameSize();
|
||||||
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
|
platformLeaveStandardStackFrame(this, frameSize);
|
||||||
// work well for large immediates.
|
|
||||||
#if CPU(ARM_THUMB2)
|
|
||||||
move(TrustedImm32(frameSize), JSC::ARMRegisters::r3);
|
|
||||||
add32(JSC::ARMRegisters::r3, StackPointerRegister);
|
|
||||||
#else
|
|
||||||
addPtr(TrustedImm32(frameSize), StackPointerRegister);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
platformLeaveStandardStackFrame(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -709,8 +700,13 @@ JSC::MacroAssemblerCodeRef Assembler<TargetConfiguration>::link(int *codeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
|
template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
|
||||||
#if defined(V4_BOOTSTRAP) && CPU(X86_64)
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
#if !CPU(ARM_THUMB2)
|
||||||
template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
|
template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
|
||||||
#endif
|
#endif
|
||||||
|
#if !CPU(ARM64)
|
||||||
|
template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -145,11 +145,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
using RegisterID = typename JITAssembler::RegisterID;
|
using RegisterID = typename JITAssembler::RegisterID;
|
||||||
using FPRegisterID = typename JITAssembler::FPRegisterID;
|
using FPRegisterID = typename JITAssembler::FPRegisterID;
|
||||||
using RelationalCondition = typename JITAssembler::RelationalCondition;
|
using RelationalCondition = typename JITAssembler::RelationalCondition;
|
||||||
|
using ResultCondition = typename JITAssembler::ResultCondition;
|
||||||
using Address = typename JITAssembler::Address;
|
using Address = typename JITAssembler::Address;
|
||||||
using Pointer = typename JITAssembler::Pointer;
|
using Pointer = typename JITAssembler::Pointer;
|
||||||
using TrustedImm32 = typename JITAssembler::TrustedImm32;
|
using TrustedImm32 = typename JITAssembler::TrustedImm32;
|
||||||
using TrustedImm64 = typename JITAssembler::TrustedImm64;
|
using TrustedImm64 = typename JITAssembler::TrustedImm64;
|
||||||
using Jump = typename JITAssembler::Jump;
|
using Jump = typename JITAssembler::Jump;
|
||||||
|
using Label = typename JITAssembler::Label;
|
||||||
|
|
||||||
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
|
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
|
||||||
{
|
{
|
||||||
|
@ -352,6 +354,19 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
|
return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
|
||||||
TrustedImm32(Value::NotDouble_Mask));
|
TrustedImm32(Value::NotDouble_Mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initializeLocalVariables(JITAssembler *as, int localsCount)
|
||||||
|
{
|
||||||
|
as->move(TrustedImm32(0), TargetPlatform::ReturnValueRegister);
|
||||||
|
as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister);
|
||||||
|
Label loop = as->label();
|
||||||
|
as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
|
||||||
|
as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister);
|
||||||
|
as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
|
||||||
|
as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister);
|
||||||
|
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
|
||||||
|
jump.linkTo(loop, as);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
|
template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
|
||||||
|
@ -364,8 +379,10 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
using TrustedImm64 = typename JITAssembler::TrustedImm64;
|
using TrustedImm64 = typename JITAssembler::TrustedImm64;
|
||||||
using Pointer = typename JITAssembler::Pointer;
|
using Pointer = typename JITAssembler::Pointer;
|
||||||
using RelationalCondition = typename JITAssembler::RelationalCondition;
|
using RelationalCondition = typename JITAssembler::RelationalCondition;
|
||||||
|
using ResultCondition = typename JITAssembler::ResultCondition;
|
||||||
using BranchTruncateType = typename JITAssembler::BranchTruncateType;
|
using BranchTruncateType = typename JITAssembler::BranchTruncateType;
|
||||||
using Jump = typename JITAssembler::Jump;
|
using Jump = typename JITAssembler::Jump;
|
||||||
|
using Label = typename JITAssembler::Label;
|
||||||
|
|
||||||
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
|
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
|
||||||
{
|
{
|
||||||
|
@ -464,7 +481,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
{
|
{
|
||||||
// Use ReturnValueRegister as "scratch" register because loadArgument
|
// Use ReturnValueRegister as "scratch" register because loadArgument
|
||||||
// and storeArgument are functions that may need a scratch register themselves.
|
// and storeArgument are functions that may need a scratch register themselves.
|
||||||
as->loadArgumentInRegister(source, TargetPlatform::ReturnValueRegister, 0);
|
loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0);
|
||||||
as->storeReturnValue(destination);
|
as->storeReturnValue(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,6 +494,12 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
as->move64ToDouble(TargetPlatform::ReturnValueRegister, target);
|
as->move64ToDouble(TargetPlatform::ReturnValueRegister, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loadArgumentInRegister(JITAssembler *as, Address addressOfValue, RegisterID dest, int argumentNumber)
|
||||||
|
{
|
||||||
|
Q_UNUSED(argumentNumber);
|
||||||
|
as->load64(addressOfValue, dest);
|
||||||
|
}
|
||||||
|
|
||||||
static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
|
static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
|
||||||
{
|
{
|
||||||
Q_UNUSED(argumentNumber);
|
Q_UNUSED(argumentNumber);
|
||||||
|
@ -625,6 +648,17 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
|
||||||
return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
|
return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
|
||||||
TrustedImm32(0));
|
TrustedImm32(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initializeLocalVariables(JITAssembler *as, int localsCount)
|
||||||
|
{
|
||||||
|
as->move(TrustedImm64(0), TargetPlatform::ReturnValueRegister);
|
||||||
|
as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister);
|
||||||
|
Label loop = as->label();
|
||||||
|
as->store64(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
|
||||||
|
as->add64(TrustedImm32(8), TargetPlatform::LocalsRegister);
|
||||||
|
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
|
||||||
|
jump.linkTo(loop, as);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TargetConfiguration>
|
template <typename TargetConfiguration>
|
||||||
|
@ -1338,9 +1372,8 @@ public:
|
||||||
if (prepareCall(function))
|
if (prepareCall(function))
|
||||||
loadArgumentOnStackOrRegister<0>(arg1);
|
loadArgumentOnStackOrRegister<0>(arg1);
|
||||||
|
|
||||||
#ifdef RESTORE_EBX_ON_CALL
|
if (JITTargetPlatform::gotRegister != -1)
|
||||||
load32(this->ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
|
load32(Address(JITTargetPlatform::FramePointerRegister, JITTargetPlatform::savedGOTRegisterSlotOnStack()), static_cast<RegisterID>(JITTargetPlatform::gotRegister)); // restore the GOT ptr
|
||||||
#endif
|
|
||||||
|
|
||||||
callAbsolute(functionName, function);
|
callAbsolute(functionName, function);
|
||||||
|
|
||||||
|
@ -1585,6 +1618,15 @@ public:
|
||||||
|
|
||||||
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
|
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
|
||||||
const StackLayout &stackLayout() const { return *_stackLayout.data(); }
|
const StackLayout &stackLayout() const { return *_stackLayout.data(); }
|
||||||
|
void initializeLocalVariables()
|
||||||
|
{
|
||||||
|
const int locals = _stackLayout->calculateJSStackFrameSize();
|
||||||
|
if (locals <= 0)
|
||||||
|
return;
|
||||||
|
loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister);
|
||||||
|
RegisterSizeDependentOps::initializeLocalVariables(this, locals);
|
||||||
|
storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
|
||||||
|
}
|
||||||
|
|
||||||
Label exceptionReturnLabel;
|
Label exceptionReturnLabel;
|
||||||
IR::BasicBlock * catchBlock;
|
IR::BasicBlock * catchBlock;
|
||||||
|
|
|
@ -41,8 +41,128 @@
|
||||||
|
|
||||||
#if ENABLE(ASSEMBLER)
|
#if ENABLE(ASSEMBLER)
|
||||||
|
|
||||||
using namespace QV4;
|
QT_BEGIN_NAMESPACE
|
||||||
using namespace JIT;
|
|
||||||
|
namespace QV4 {
|
||||||
|
namespace JIT {
|
||||||
|
|
||||||
|
template <typename JITAssembler>
|
||||||
|
struct ArchitectureSpecificBinaryOperation
|
||||||
|
{
|
||||||
|
using FPRegisterID = typename JITAssembler::FPRegisterID;
|
||||||
|
|
||||||
|
static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(as);
|
||||||
|
Q_UNUSED(lhs);
|
||||||
|
Q_UNUSED(rhs);
|
||||||
|
Q_UNUSED(targetReg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(as);
|
||||||
|
Q_UNUSED(lhs);
|
||||||
|
Q_UNUSED(rhs);
|
||||||
|
Q_UNUSED(targetReg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(as);
|
||||||
|
Q_UNUSED(lhs);
|
||||||
|
Q_UNUSED(rhs);
|
||||||
|
Q_UNUSED(targetReg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
Q_UNUSED(as);
|
||||||
|
Q_UNUSED(lhs);
|
||||||
|
Q_UNUSED(rhs);
|
||||||
|
Q_UNUSED(targetReg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if CPU(X86)
|
||||||
|
template <>
|
||||||
|
struct ArchitectureSpecificBinaryOperation<Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>>>
|
||||||
|
{
|
||||||
|
using JITAssembler = Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>>;
|
||||||
|
using FPRegisterID = JITAssembler::FPRegisterID;
|
||||||
|
using Address = JITAssembler::Address;
|
||||||
|
|
||||||
|
static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
||||||
|
as->addDouble(addr, targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IR::Temp *t = rhs->asTemp()) { // Y = X + [temp-memory-address] -> Y = X; Y += [temp-memory-address]
|
||||||
|
if (t->kind != IR::Temp::PhysicalRegister) {
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
as->addDouble(as->loadTempAddress(t), targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
||||||
|
as->mulDouble(addr, targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IR::Temp *t = rhs->asTemp()) { // Y = X * [temp-memory-address] -> Y = X; Y *= [temp-memory-address]
|
||||||
|
if (t->kind != IR::Temp::PhysicalRegister) {
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
as->mulDouble(as->loadTempAddress(t), targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
||||||
|
as->subDouble(addr, targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IR::Temp *t = rhs->asTemp()) { // Y = X - [temp-memory-address] -> Y = X; Y -= [temp-memory-address]
|
||||||
|
if (t->kind != IR::Temp::PhysicalRegister) {
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
as->subDouble(as->loadTempAddress(t), targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
|
||||||
|
{
|
||||||
|
if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
||||||
|
as->divDouble(addr, targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IR::Temp *t = rhs->asTemp()) { // Y = X / [temp-memory-address] -> Y = X; Y /= [temp-memory-address]
|
||||||
|
if (t->kind != IR::Temp::PhysicalRegister) {
|
||||||
|
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
||||||
|
as->divDouble(as->loadTempAddress(t), targetReg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#define OP(op) \
|
#define OP(op) \
|
||||||
{ "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
|
{ "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
|
||||||
|
@ -162,21 +282,9 @@ void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta
|
||||||
if (lhs->asConst())
|
if (lhs->asConst())
|
||||||
std::swap(lhs, rhs); // Y = constant + X -> Y = X + constant
|
std::swap(lhs, rhs); // Y = constant + X -> Y = X + constant
|
||||||
|
|
||||||
#if CPU(X86)
|
if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleAdd(as, lhs, rhs, targetReg))
|
||||||
if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
|
||||||
as->addDouble(addr, targetReg);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (IR::Temp *t = rhs->asTemp()) { // Y = X + [temp-memory-address] -> Y = X; Y += [temp-memory-address]
|
|
||||||
if (t->kind != IR::Temp::PhysicalRegister) {
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
as->addDouble(as->loadTempAddress(t), targetReg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
|
as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -184,40 +292,16 @@ void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta
|
||||||
if (lhs->asConst())
|
if (lhs->asConst())
|
||||||
std::swap(lhs, rhs); // Y = constant * X -> Y = X * constant
|
std::swap(lhs, rhs); // Y = constant * X -> Y = X * constant
|
||||||
|
|
||||||
#if CPU(X86)
|
if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleMul(as, lhs, rhs, targetReg))
|
||||||
if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
|
||||||
as->mulDouble(addr, targetReg);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (IR::Temp *t = rhs->asTemp()) { // Y = X * [temp-memory-address] -> Y = X; Y *= [temp-memory-address]
|
|
||||||
if (t->kind != IR::Temp::PhysicalRegister) {
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
as->mulDouble(as->loadTempAddress(t), targetReg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
|
as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IR::OpSub:
|
case IR::OpSub:
|
||||||
#if CPU(X86)
|
if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleSub(as, lhs, rhs, targetReg))
|
||||||
if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
|
||||||
as->subDouble(addr, targetReg);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (IR::Temp *t = rhs->asTemp()) { // Y = X - [temp-memory-address] -> Y = X; Y -= [temp-memory-address]
|
|
||||||
if (t->kind != IR::Temp::PhysicalRegister) {
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
as->subDouble(as->loadTempAddress(t), targetReg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
|
if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
|
||||||
&& targetTemp
|
&& targetTemp
|
||||||
&& targetTemp->kind == IR::Temp::PhysicalRegister
|
&& targetTemp->kind == IR::Temp::PhysicalRegister
|
||||||
|
@ -231,21 +315,8 @@ void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *ta
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IR::OpDiv:
|
case IR::OpDiv:
|
||||||
#if CPU(X86)
|
if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleDiv(as, lhs, rhs, targetReg))
|
||||||
if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
|
|
||||||
as->divDouble(addr, targetReg);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (IR::Temp *t = rhs->asTemp()) { // Y = X / [temp-memory-address] -> Y = X; Y /= [temp-memory-address]
|
|
||||||
if (t->kind != IR::Temp::PhysicalRegister) {
|
|
||||||
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
|
|
||||||
as->divDouble(as->loadTempAddress(t), targetReg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
|
if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
|
||||||
&& targetTemp
|
&& targetTemp
|
||||||
|
@ -577,8 +648,19 @@ typename JITAssembler::Jump Binop<JITAssembler>::genInlineBinop(IR::Expr *leftSo
|
||||||
}
|
}
|
||||||
|
|
||||||
template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
|
template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
|
||||||
#if defined(V4_BOOTSTRAP) && CPU(X86_64)
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
#if !CPU(ARM_THUMB2)
|
||||||
template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
|
template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
|
||||||
#endif
|
#endif
|
||||||
|
#if !CPU(ARM64)
|
||||||
|
template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>>;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // end of namespace JIT
|
||||||
|
} // end of namespace QV4
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -114,37 +114,12 @@ void InstructionSelection<JITAssembler>::run(int functionIndex)
|
||||||
fpRegistersToSave.size());
|
fpRegistersToSave.size());
|
||||||
_as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
|
_as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
|
||||||
|
|
||||||
#ifdef ARGUMENTS_IN_REGISTERS
|
if (JITTargetPlatform::RegisterArgumentCount > 0)
|
||||||
_as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
|
_as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
|
||||||
#else
|
else
|
||||||
_as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
|
_as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
|
||||||
#endif
|
|
||||||
|
|
||||||
const int locals = _as->stackLayout().calculateJSStackFrameSize();
|
|
||||||
if (locals > 0) {
|
|
||||||
_as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister);
|
|
||||||
#ifdef VALUE_FITS_IN_REGISTER
|
|
||||||
_as->move(TrustedImm64(0), JITTargetPlatform::ReturnValueRegister);
|
|
||||||
_as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
|
|
||||||
Label loop = _as->label();
|
|
||||||
_as->store64(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
|
|
||||||
_as->add64(TrustedImm32(8), JITTargetPlatform::LocalsRegister);
|
|
||||||
Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
|
|
||||||
jump.linkTo(loop, _as);
|
|
||||||
#else
|
|
||||||
_as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
|
|
||||||
_as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
|
|
||||||
Label loop = _as->label();
|
|
||||||
_as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
|
|
||||||
_as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
|
|
||||||
_as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
|
|
||||||
_as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
|
|
||||||
Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
|
|
||||||
jump.linkTo(loop, _as);
|
|
||||||
#endif
|
|
||||||
_as->storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_as->initializeLocalVariables();
|
||||||
|
|
||||||
int lastLine = 0;
|
int lastLine = 0;
|
||||||
for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
|
for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
|
||||||
|
@ -474,13 +449,7 @@ void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
|
||||||
{
|
{
|
||||||
_as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
|
_as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
|
||||||
_as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
|
_as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
|
||||||
#if defined(VALUE_FITS_IN_REGISTER)
|
_as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
|
||||||
_as->load64(Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)),
|
|
||||||
JITTargetPlatform::ReturnValueRegister);
|
|
||||||
_as->storeReturnValue(temp);
|
|
||||||
#else
|
|
||||||
_as->copyValue(temp, Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename JITAssembler>
|
template <typename JITAssembler>
|
||||||
|
@ -1374,12 +1343,10 @@ void InstructionSelection<JITAssembler>::calculateRegistersToSave(const Register
|
||||||
fpRegistersToSave.clear();
|
fpRegistersToSave.clear();
|
||||||
|
|
||||||
for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
|
for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
|
||||||
#if defined(RESTORE_EBX_ON_CALL)
|
if (JITTargetPlatform::gotRegister != -1 && ri.isRegularRegister() && ri.reg<RegisterID>() == JITTargetPlatform::gotRegister) {
|
||||||
if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
|
|
||||||
regularRegistersToSave.append(ri);
|
regularRegistersToSave.append(ri);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif // RESTORE_EBX_ON_CALL
|
|
||||||
if (ri.isCallerSaved())
|
if (ri.isCallerSaved())
|
||||||
continue;
|
continue;
|
||||||
if (ri.isRegularRegister()) {
|
if (ri.isRegularRegister()) {
|
||||||
|
@ -1666,20 +1633,21 @@ QT_BEGIN_NAMESPACE
|
||||||
namespace QV4 { namespace JIT {
|
namespace QV4 { namespace JIT {
|
||||||
template class Q_QML_EXPORT InstructionSelection<>;
|
template class Q_QML_EXPORT InstructionSelection<>;
|
||||||
template class Q_QML_EXPORT ISelFactory<>;
|
template class Q_QML_EXPORT ISelFactory<>;
|
||||||
#if defined(V4_BOOTSTRAP) && CPU(X86_64)
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
|
||||||
Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
|
Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
|
||||||
{
|
{
|
||||||
using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
|
using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
|
||||||
|
using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
|
||||||
|
|
||||||
if (architecture == QLatin1String("armv7"))
|
if (architecture == QLatin1String("armv7"))
|
||||||
return new ISelFactory<ARMv7CrossAssembler>;
|
return new ISelFactory<ARMv7CrossAssembler>;
|
||||||
|
else if (architecture == QLatin1String("armv8"))
|
||||||
|
return new ISelFactory<ARM64CrossAssembler>;
|
||||||
|
|
||||||
QString hostArch;
|
QString hostArch;
|
||||||
#if CPU(ARM_THUMB2)
|
#if CPU(ARM_THUMB2)
|
||||||
hostArch = QStringLiteral("armv7");
|
hostArch = QStringLiteral("armv7");
|
||||||
#elif CPU(ARM64)
|
|
||||||
hostArch = QStringLiteral("armv8");
|
|
||||||
#elif CPU(MIPS)
|
#elif CPU(MIPS)
|
||||||
hostArch = QStringLiteral("mips");
|
hostArch = QStringLiteral("mips");
|
||||||
#elif CPU(X86)
|
#elif CPU(X86)
|
||||||
|
|
|
@ -155,7 +155,6 @@ protected:
|
||||||
|
|
||||||
using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
|
using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
|
||||||
|
|
||||||
#if !defined(ARGUMENTS_IN_REGISTERS)
|
|
||||||
Address addressForArgument(int index) const
|
Address addressForArgument(int index) const
|
||||||
{
|
{
|
||||||
// FramePointerRegister points to its old value on the stack, and above
|
// FramePointerRegister points to its old value on the stack, and above
|
||||||
|
@ -163,7 +162,6 @@ protected:
|
||||||
// values before reaching the first argument.
|
// values before reaching the first argument.
|
||||||
return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
|
return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
Pointer baseAddressForCallArguments()
|
Pointer baseAddressForCallArguments()
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,6 +97,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerX86;
|
using PlatformAssembler = JSC::MacroAssemblerX86;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
|
|
||||||
enum { RegAllocIsSupported = 1 };
|
enum { RegAllocIsSupported = 1 };
|
||||||
|
|
||||||
|
@ -130,10 +131,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
||||||
# undef VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 4;
|
static const int RegisterSize = 4;
|
||||||
|
|
||||||
# undef ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 0;
|
static const int RegisterArgumentCount = 0;
|
||||||
static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
|
static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
|
||||||
|
|
||||||
|
@ -141,15 +140,18 @@ public:
|
||||||
static const int StackShadowSpace = 0;
|
static const int StackShadowSpace = 0;
|
||||||
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
||||||
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
|
{
|
||||||
|
if (frameSize > 0)
|
||||||
|
as->add32(TrustedImm32(frameSize), StackPointerRegister);
|
||||||
|
as->pop(FramePointerRegister);
|
||||||
|
}
|
||||||
|
|
||||||
#if OS(WINDOWS) || OS(QNX) || \
|
#if OS(WINDOWS) || OS(QNX) || \
|
||||||
((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
|
((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
|
||||||
|
|
||||||
#define RESTORE_EBX_ON_CALL
|
static const int gotRegister = JSC::X86Registers::ebx;
|
||||||
using Address = PlatformAssembler::Address;
|
static int savedGOTRegisterSlotOnStack() {
|
||||||
static Address ebxAddressOnStack()
|
|
||||||
{
|
|
||||||
static int ebxIdx = -1;
|
static int ebxIdx = -1;
|
||||||
if (ebxIdx == -1) {
|
if (ebxIdx == -1) {
|
||||||
int calleeSaves = 0;
|
int calleeSaves = 0;
|
||||||
|
@ -165,8 +167,11 @@ public:
|
||||||
Q_ASSERT(ebxIdx >= 0);
|
Q_ASSERT(ebxIdx >= 0);
|
||||||
ebxIdx += 1;
|
ebxIdx += 1;
|
||||||
}
|
}
|
||||||
return Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
|
return ebxIdx * -int(sizeof(void*));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
#endif // x86
|
#endif // x86
|
||||||
|
@ -179,6 +184,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerX86_64;
|
using PlatformAssembler = JSC::MacroAssemblerX86_64;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
|
|
||||||
enum { RegAllocIsSupported = 1 };
|
enum { RegAllocIsSupported = 1 };
|
||||||
|
|
||||||
|
@ -216,10 +222,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
||||||
#define VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 8;
|
static const int RegisterSize = 8;
|
||||||
|
|
||||||
#define ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 6;
|
static const int RegisterArgumentCount = 6;
|
||||||
static RegisterID registerForArgument(int index)
|
static RegisterID registerForArgument(int index)
|
||||||
{
|
{
|
||||||
|
@ -239,7 +243,15 @@ public:
|
||||||
static const int StackShadowSpace = 0;
|
static const int StackShadowSpace = 0;
|
||||||
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
||||||
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
|
{
|
||||||
|
if (frameSize > 0)
|
||||||
|
as->add64(TrustedImm32(frameSize), StackPointerRegister);
|
||||||
|
as->pop(FramePointerRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
};
|
};
|
||||||
#endif // Linux/MacOS on x86_64
|
#endif // Linux/MacOS on x86_64
|
||||||
|
|
||||||
|
@ -251,6 +263,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerX86_64;
|
using PlatformAssembler = JSC::MacroAssemblerX86_64;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
|
|
||||||
// Register allocation is not (yet) supported on win64, because the ABI related stack handling
|
// Register allocation is not (yet) supported on win64, because the ABI related stack handling
|
||||||
// is not completely implemented. Specifically, the saving of xmm registers, and the saving of
|
// is not completely implemented. Specifically, the saving of xmm registers, and the saving of
|
||||||
|
@ -285,10 +298,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
|
||||||
#define VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 8;
|
static const int RegisterSize = 8;
|
||||||
|
|
||||||
#define ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 4;
|
static const int RegisterArgumentCount = 4;
|
||||||
static RegisterID registerForArgument(int index)
|
static RegisterID registerForArgument(int index)
|
||||||
{
|
{
|
||||||
|
@ -306,7 +317,15 @@ public:
|
||||||
static const int StackShadowSpace = 32;
|
static const int StackShadowSpace = 32;
|
||||||
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
|
||||||
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
|
{
|
||||||
|
if (frameSize > 0)
|
||||||
|
as->add64(TrustedImm32(frameSize), StackPointerRegister);
|
||||||
|
as->pop(FramePointerRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
};
|
};
|
||||||
#endif // Windows on x86_64
|
#endif // Windows on x86_64
|
||||||
|
|
||||||
|
@ -318,6 +337,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerARMv7;
|
using PlatformAssembler = JSC::MacroAssemblerARMv7;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
|
|
||||||
enum { RegAllocIsSupported = 1 };
|
enum { RegAllocIsSupported = 1 };
|
||||||
|
|
||||||
|
@ -389,10 +409,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
||||||
#undef VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 4;
|
static const int RegisterSize = 4;
|
||||||
|
|
||||||
#define ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 4;
|
static const int RegisterArgumentCount = 4;
|
||||||
static RegisterID registerForArgument(int index)
|
static RegisterID registerForArgument(int index)
|
||||||
{
|
{
|
||||||
|
@ -417,15 +435,24 @@ public:
|
||||||
as->push(FramePointerRegister);
|
as->push(FramePointerRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as)
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
{
|
{
|
||||||
|
if (frameSize > 0) {
|
||||||
|
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
|
||||||
|
// work well for large immediates.
|
||||||
|
as->move(TrustedImm32(frameSize), JSC::ARMRegisters::r3);
|
||||||
|
as->add32(JSC::ARMRegisters::r3, StackPointerRegister);
|
||||||
|
}
|
||||||
as->pop(FramePointerRegister);
|
as->pop(FramePointerRegister);
|
||||||
as->pop(JSC::ARMRegisters::lr);
|
as->pop(JSC::ARMRegisters::lr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
};
|
};
|
||||||
#endif // ARM (32 bit)
|
#endif // ARM (32 bit)
|
||||||
|
|
||||||
#if CPU(ARM64)
|
#if CPU(ARM64) || defined(V4_BOOTSTRAP)
|
||||||
template <>
|
template <>
|
||||||
class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
|
class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
|
||||||
{
|
{
|
||||||
|
@ -433,6 +460,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerARM64;
|
using PlatformAssembler = JSC::MacroAssemblerARM64;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
|
|
||||||
enum { RegAllocIsSupported = 1 };
|
enum { RegAllocIsSupported = 1 };
|
||||||
|
|
||||||
|
@ -510,10 +538,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
||||||
#define VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 8;
|
static const int RegisterSize = 8;
|
||||||
|
|
||||||
#define ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 8;
|
static const int RegisterArgumentCount = 8;
|
||||||
static RegisterID registerForArgument(int index)
|
static RegisterID registerForArgument(int index)
|
||||||
{
|
{
|
||||||
|
@ -541,10 +567,15 @@ public:
|
||||||
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
|
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as)
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
{
|
{
|
||||||
|
if (frameSize > 0)
|
||||||
|
as->add64(TrustedImm32(frameSize), StackPointerRegister);
|
||||||
as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
|
as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
};
|
};
|
||||||
#endif // ARM64
|
#endif // ARM64
|
||||||
|
|
||||||
|
@ -556,6 +587,7 @@ public:
|
||||||
using PlatformAssembler = JSC::MacroAssemblerMIPS;
|
using PlatformAssembler = JSC::MacroAssemblerMIPS;
|
||||||
using RegisterID = PlatformAssembler::RegisterID;
|
using RegisterID = PlatformAssembler::RegisterID;
|
||||||
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
using FPRegisterID = PlatformAssembler::FPRegisterID;
|
||||||
|
using TrustedImm32 = PlatformAssembler::TrustedImm32;
|
||||||
enum { RegAllocIsSupported = 1 };
|
enum { RegAllocIsSupported = 1 };
|
||||||
|
|
||||||
static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
|
static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
|
||||||
|
@ -598,10 +630,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
|
||||||
#undef VALUE_FITS_IN_REGISTER
|
|
||||||
static const int RegisterSize = 4;
|
static const int RegisterSize = 4;
|
||||||
|
|
||||||
#define ARGUMENTS_IN_REGISTERS
|
|
||||||
static const int RegisterArgumentCount = 4;
|
static const int RegisterArgumentCount = 4;
|
||||||
static RegisterID registerForArgument(int index)
|
static RegisterID registerForArgument(int index)
|
||||||
{
|
{
|
||||||
|
@ -626,11 +656,17 @@ public:
|
||||||
as->push(FramePointerRegister);
|
as->push(FramePointerRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void platformLeaveStandardStackFrame(PlatformAssembler *as)
|
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
|
||||||
{
|
{
|
||||||
|
if (frameSize > 0)
|
||||||
|
as->add32(TrustedImm32(frameSize), StackPointerRegister);
|
||||||
as->pop(FramePointerRegister);
|
as->pop(FramePointerRegister);
|
||||||
as->pop(JSC::MIPSRegisters::ra);
|
as->pop(JSC::MIPSRegisters::ra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int gotRegister = -1;
|
||||||
|
static int savedGOTRegisterSlotOnStack() { return -1; }
|
||||||
};
|
};
|
||||||
#endif // Linux on MIPS (32 bit)
|
#endif // Linux on MIPS (32 bit)
|
||||||
|
|
||||||
|
|
|
@ -145,8 +145,13 @@ void Unop<JITAssembler>::generateCompl(IR::Expr *source, IR::Expr *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
|
template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
|
||||||
#if defined(V4_BOOTSTRAP) && CPU(X86_64)
|
#if defined(V4_BOOTSTRAP)
|
||||||
|
#if !CPU(ARM_THUMB2)
|
||||||
template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
|
template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
|
||||||
#endif
|
#endif
|
||||||
|
#if !CPU(ARM64)
|
||||||
|
template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>>;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -61,7 +61,8 @@ DEFINE_OBJECT_VTABLE(Object);
|
||||||
void Object::setInternalClass(InternalClass *ic)
|
void Object::setInternalClass(InternalClass *ic)
|
||||||
{
|
{
|
||||||
d()->internalClass = ic;
|
d()->internalClass = ic;
|
||||||
if ((!d()->memberData && ic->size) || (d()->memberData->size < ic->size))
|
bool hasMD = d()->memberData != nullptr;
|
||||||
|
if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size))
|
||||||
d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
|
d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1264,12 +1264,16 @@ ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine)
|
||||||
*/
|
*/
|
||||||
void Runtime::method_pushWithScope(const Value &o, NoThrowEngine *engine)
|
void Runtime::method_pushWithScope(const Value &o, NoThrowEngine *engine)
|
||||||
{
|
{
|
||||||
engine->pushContext(engine->currentContext->newWithContext(o.toObject(engine)));
|
QV4::Value *v = engine->jsAlloca(1);
|
||||||
|
Heap::Object *withObject = o.toObject(engine);
|
||||||
|
*v = withObject;
|
||||||
|
engine->pushContext(engine->currentContext->newWithContext(withObject));
|
||||||
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
|
void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
|
||||||
{
|
{
|
||||||
|
engine->jsAlloca(1); // keep this symmetric with pushWithScope
|
||||||
ExecutionContext *c = engine->currentContext;
|
ExecutionContext *c = engine->currentContext;
|
||||||
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
|
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
|
||||||
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
||||||
|
@ -1279,7 +1283,7 @@ void Runtime::method_popScope(NoThrowEngine *engine)
|
||||||
{
|
{
|
||||||
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
|
||||||
engine->popContext();
|
engine->popContext();
|
||||||
engine->jsStackTop -= 2;
|
engine->jsStackTop -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
|
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
|
||||||
|
|
|
@ -328,11 +328,16 @@ void Chunk::freeAll()
|
||||||
|
|
||||||
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
|
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
|
||||||
{
|
{
|
||||||
|
// qDebug() << "sortIntoBins:";
|
||||||
HeapItem *base = realBase();
|
HeapItem *base = realBase();
|
||||||
#if QT_POINTER_SIZE == 8
|
#if QT_POINTER_SIZE == 8
|
||||||
const int start = 0;
|
const int start = 0;
|
||||||
#else
|
#else
|
||||||
const int start = 1;
|
const int start = 1;
|
||||||
|
#endif
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
uint freeSlots = 0;
|
||||||
|
uint allocatedSlots = 0;
|
||||||
#endif
|
#endif
|
||||||
for (int i = start; i < EntriesInBitmap; ++i) {
|
for (int i = start; i < EntriesInBitmap; ++i) {
|
||||||
quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]);
|
quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]);
|
||||||
|
@ -340,28 +345,48 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
|
||||||
if (!i)
|
if (!i)
|
||||||
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
|
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
|
||||||
#endif
|
#endif
|
||||||
uint index = qCountTrailingZeroBits(usedSlots + 1);
|
#ifndef QT_NO_DEBUG
|
||||||
if (index == Bits)
|
allocatedSlots += qPopulationCount(usedSlots);
|
||||||
continue;
|
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
|
||||||
uint freeStart = i*Bits + index;
|
#endif
|
||||||
usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
|
while (1) {
|
||||||
while (i < EntriesInBitmap && !usedSlots) {
|
uint index = qCountTrailingZeroBits(usedSlots + 1);
|
||||||
++i;
|
if (index == Bits)
|
||||||
usedSlots = (objectBitmap[i]|extendsBitmap[i]);
|
break;
|
||||||
}
|
uint freeStart = i*Bits + index;
|
||||||
if (i == EntriesInBitmap)
|
usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
|
||||||
usedSlots = 1;
|
while (!usedSlots) {
|
||||||
HeapItem *freeItem = base + freeStart;
|
++i;
|
||||||
|
if (i == EntriesInBitmap) {
|
||||||
|
usedSlots = (quintptr)-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usedSlots = (objectBitmap[i]|extendsBitmap[i]);
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
allocatedSlots += qPopulationCount(usedSlots);
|
||||||
|
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
HeapItem *freeItem = base + freeStart;
|
||||||
|
|
||||||
uint freeEnd = i*Bits + qCountTrailingZeroBits(usedSlots);
|
index = qCountTrailingZeroBits(usedSlots);
|
||||||
uint nSlots = freeEnd - freeStart;
|
usedSlots |= (quintptr(1) << index) - 1;
|
||||||
Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
|
uint freeEnd = i*Bits + index;
|
||||||
freeItem->freeData.availableSlots = nSlots;
|
uint nSlots = freeEnd - freeStart;
|
||||||
uint bin = qMin(nBins - 1, nSlots);
|
#ifndef QT_NO_DEBUG
|
||||||
freeItem->freeData.next = bins[bin];
|
// qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots;
|
||||||
bins[bin] = freeItem;
|
freeSlots += nSlots;
|
||||||
// DEBUG << "binnig item" << freeItem << nSlots << bin << freeItem->freeData.availableSlots;
|
#endif
|
||||||
|
Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
|
||||||
|
freeItem->freeData.availableSlots = nSlots;
|
||||||
|
uint bin = qMin(nBins - 1, nSlots);
|
||||||
|
freeItem->freeData.next = bins[bin];
|
||||||
|
bins[bin] = freeItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
Q_ASSERT(freeSlots + allocatedSlots == EntriesInBitmap*8*sizeof(quintptr));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -427,28 +452,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
for (uint b = bin + 1; b < NumBins - 1; ++b) {
|
|
||||||
if ((m = freeBins[b])) {
|
|
||||||
Q_ASSERT(binForSlots(m->freeData.availableSlots) == b);
|
|
||||||
freeBins[b] = m->freeData.next;
|
|
||||||
// DEBUG << "looking for empty bin" << bin << "size" << size << "found" << b;
|
|
||||||
uint remainingSlots = m->freeData.availableSlots - slotsRequired;
|
|
||||||
// DEBUG << "found free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
|
|
||||||
if (remainingSlots < 2) {
|
|
||||||
// avoid too much fragmentation and rather mark the memory as used
|
|
||||||
size += remainingSlots*Chunk::SlotSize;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
HeapItem *remainder = m + slotsRequired;
|
|
||||||
remainder->freeData.availableSlots = remainingSlots;
|
|
||||||
uint binForRemainder = binForSlots(remainingSlots);
|
|
||||||
remainder->freeData.next = freeBins[binForRemainder];
|
|
||||||
freeBins[binForRemainder] = remainder;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (nFree >= slotsRequired) {
|
if (nFree >= slotsRequired) {
|
||||||
// use bump allocation
|
// use bump allocation
|
||||||
Q_ASSERT(nextFree);
|
Q_ASSERT(nextFree);
|
||||||
|
@ -467,13 +471,11 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
|
||||||
|
|
||||||
size_t remainingSlots = m->freeData.availableSlots - slotsRequired;
|
size_t remainingSlots = m->freeData.availableSlots - slotsRequired;
|
||||||
// DEBUG << "found large free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
|
// DEBUG << "found large free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
|
||||||
if (remainingSlots < 2) {
|
if (remainingSlots == 0)
|
||||||
// avoid too much fragmentation and rather mark the memory as used
|
|
||||||
size += remainingSlots*Chunk::SlotSize;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
HeapItem *remainder = m + slotsRequired;
|
HeapItem *remainder = m + slotsRequired;
|
||||||
if (remainingSlots >= 2*NumBins) {
|
if (remainingSlots > nFree) {
|
||||||
if (nFree) {
|
if (nFree) {
|
||||||
size_t bin = binForSlots(nFree);
|
size_t bin = binForSlots(nFree);
|
||||||
nextFree->freeData.next = freeBins[bin];
|
nextFree->freeData.next = freeBins[bin];
|
||||||
|
@ -493,6 +495,24 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
|
||||||
last = &m->freeData.next;
|
last = &m->freeData.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slotsRequired < NumBins - 1) {
|
||||||
|
// check if we can split up another slot
|
||||||
|
for (size_t i = slotsRequired + 1; i < NumBins - 1; ++i) {
|
||||||
|
m = freeBins[i];
|
||||||
|
if (m) {
|
||||||
|
freeBins[i] = m->freeData.next; // take it out of the list
|
||||||
|
// qDebug() << "got item" << slotsRequired << "from slot" << i;
|
||||||
|
size_t remainingSlots = i - slotsRequired;
|
||||||
|
Q_ASSERT(remainingSlots < NumBins - 1);
|
||||||
|
HeapItem *remainder = m + slotsRequired;
|
||||||
|
remainder->freeData.availableSlots = remainingSlots;
|
||||||
|
remainder->freeData.next = freeBins[remainingSlots];
|
||||||
|
freeBins[remainingSlots] = remainder;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!m) {
|
if (!m) {
|
||||||
if (!forceAllocation)
|
if (!forceAllocation)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -622,14 +642,24 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
static int lastAllocRequestedSlots = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
|
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
|
||||||
{
|
{
|
||||||
if (aggressiveGC)
|
|
||||||
runGC();
|
|
||||||
|
|
||||||
const size_t stringSize = align(sizeof(Heap::String));
|
const size_t stringSize = align(sizeof(Heap::String));
|
||||||
unmanagedHeapSize += unmanagedSize;
|
#ifndef QT_NO_DEBUG
|
||||||
|
lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool didGCRun = false;
|
bool didGCRun = false;
|
||||||
|
if (aggressiveGC) {
|
||||||
|
runGC();
|
||||||
|
didGCRun = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unmanagedHeapSize += unmanagedSize;
|
||||||
if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
|
if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
|
||||||
runGC();
|
runGC();
|
||||||
|
|
||||||
|
@ -655,8 +685,15 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
|
||||||
|
|
||||||
Heap::Base *MemoryManager::allocData(std::size_t size)
|
Heap::Base *MemoryManager::allocData(std::size_t size)
|
||||||
{
|
{
|
||||||
if (aggressiveGC)
|
#ifndef QT_NO_DEBUG
|
||||||
|
lastAllocRequestedSlots = size >> Chunk::SlotSizeShift;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool didRunGC = false;
|
||||||
|
if (aggressiveGC) {
|
||||||
runGC();
|
runGC();
|
||||||
|
didRunGC = true;
|
||||||
|
}
|
||||||
#ifdef DETAILED_MM_STATS
|
#ifdef DETAILED_MM_STATS
|
||||||
willAllocate(size);
|
willAllocate(size);
|
||||||
#endif // DETAILED_MM_STATS
|
#endif // DETAILED_MM_STATS
|
||||||
|
@ -671,7 +708,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
|
||||||
|
|
||||||
HeapItem *m = blockAllocator.allocate(size);
|
HeapItem *m = blockAllocator.allocate(size);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
if (shouldRunGC())
|
if (!didRunGC && shouldRunGC())
|
||||||
runGC();
|
runGC();
|
||||||
m = blockAllocator.allocate(size, true);
|
m = blockAllocator.allocate(size, true);
|
||||||
}
|
}
|
||||||
|
@ -817,6 +854,26 @@ bool MemoryManager::shouldRunGC() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t dumpBins(BlockAllocator *b, bool printOutput = true)
|
||||||
|
{
|
||||||
|
size_t totalFragmentedSlots = 0;
|
||||||
|
if (printOutput)
|
||||||
|
qDebug() << "Fragmentation map:";
|
||||||
|
for (uint i = 0; i < BlockAllocator::NumBins; ++i) {
|
||||||
|
uint nEntries = 0;
|
||||||
|
HeapItem *h = b->freeBins[i];
|
||||||
|
while (h) {
|
||||||
|
++nEntries;
|
||||||
|
totalFragmentedSlots += h->freeData.availableSlots;
|
||||||
|
h = h->freeData.next;
|
||||||
|
}
|
||||||
|
if (printOutput)
|
||||||
|
qDebug() << " number of entries in slot" << i << ":" << nEntries;
|
||||||
|
}
|
||||||
|
if (printOutput)
|
||||||
|
qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize;
|
||||||
|
return totalFragmentedSlots*Chunk::SlotSize;
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryManager::runGC()
|
void MemoryManager::runGC()
|
||||||
{
|
{
|
||||||
|
@ -833,31 +890,56 @@ void MemoryManager::runGC()
|
||||||
sweep();
|
sweep();
|
||||||
// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
|
// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
|
||||||
} else {
|
} else {
|
||||||
|
bool triggeredByUnmanagedHeap = (unmanagedHeapSize > unmanagedHeapSizeGCLimit);
|
||||||
|
size_t oldUnmanagedSize = unmanagedHeapSize;
|
||||||
const size_t totalMem = getAllocatedMem();
|
const size_t totalMem = getAllocatedMem();
|
||||||
|
const size_t usedBefore = getUsedMem();
|
||||||
|
const size_t largeItemsBefore = getLargeItemsMem();
|
||||||
|
|
||||||
|
qDebug() << "========== GC ==========";
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
|
||||||
|
#endif
|
||||||
|
qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks";
|
||||||
|
qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore);
|
||||||
|
dumpBins(&blockAllocator);
|
||||||
|
|
||||||
QElapsedTimer t;
|
QElapsedTimer t;
|
||||||
t.start();
|
t.start();
|
||||||
mark();
|
mark();
|
||||||
qint64 markTime = t.restart();
|
qint64 markTime = t.restart();
|
||||||
const size_t usedBefore = getUsedMem();
|
|
||||||
const size_t largeItemsBefore = getLargeItemsMem();
|
|
||||||
sweep();
|
sweep();
|
||||||
const size_t usedAfter = getUsedMem();
|
const size_t usedAfter = getUsedMem();
|
||||||
const size_t largeItemsAfter = getLargeItemsMem();
|
const size_t largeItemsAfter = getLargeItemsMem();
|
||||||
qint64 sweepTime = t.elapsed();
|
qint64 sweepTime = t.elapsed();
|
||||||
|
|
||||||
qDebug() << "========== GC ==========";
|
if (triggeredByUnmanagedHeap) {
|
||||||
|
qDebug() << "triggered by unmanaged heap:";
|
||||||
|
qDebug() << " old unmanaged heap size:" << oldUnmanagedSize;
|
||||||
|
qDebug() << " new unmanaged heap:" << unmanagedHeapSize;
|
||||||
|
qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
|
||||||
|
}
|
||||||
|
size_t memInBins = dumpBins(&blockAllocator);
|
||||||
qDebug() << "Marked object in" << markTime << "ms.";
|
qDebug() << "Marked object in" << markTime << "ms.";
|
||||||
qDebug() << "Sweeped object in" << sweepTime << "ms.";
|
qDebug() << "Sweeped object in" << sweepTime << "ms.";
|
||||||
qDebug() << "Allocated" << totalMem << "bytes";
|
|
||||||
qDebug() << "Used memory before GC:" << usedBefore;
|
qDebug() << "Used memory before GC:" << usedBefore;
|
||||||
qDebug() << "Used memory after GC:" << usedAfter;
|
qDebug() << "Used memory after GC:" << usedAfter;
|
||||||
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
|
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
|
||||||
qDebug() << "Large item memory before GC:" << largeItemsBefore;
|
size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
|
||||||
qDebug() << "Large item memory after GC:" << largeItemsAfter;
|
if (lost)
|
||||||
qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
|
qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||||
|
if (largeItemsBefore || largeItemsAfter) {
|
||||||
|
qDebug() << "Large item memory before GC:" << largeItemsBefore;
|
||||||
|
qDebug() << "Large item memory after GC:" << largeItemsAfter;
|
||||||
|
qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
|
||||||
|
}
|
||||||
qDebug() << "======== End GC ========";
|
qDebug() << "======== End GC ========";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aggressiveGC) {
|
||||||
|
// ensure we don't 'loose' any memory
|
||||||
|
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MemoryManager::getUsedMem() const
|
size_t MemoryManager::getUsedMem() const
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include <QtCore/qmetaobject.h>
|
#include <QtCore/qmetaobject.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtCore/qcoreapplication.h>
|
#include <QtCore/qcoreapplication.h>
|
||||||
|
#include <QtCore/qcryptographichash.h>
|
||||||
#include <QtCore/qdir.h>
|
#include <QtCore/qdir.h>
|
||||||
#include <QtCore/qmutex.h>
|
#include <QtCore/qmutex.h>
|
||||||
#include <QtCore/qthread.h>
|
#include <QtCore/qthread.h>
|
||||||
|
@ -564,7 +565,7 @@ The following functions are also on the Qt object.
|
||||||
\l{Screen} attached object. In practice the array corresponds to the screen
|
\l{Screen} attached object. In practice the array corresponds to the screen
|
||||||
list returned by QGuiApplication::screens(). In addition to examining
|
list returned by QGuiApplication::screens(). In addition to examining
|
||||||
properties like name, width, height, etc., the array elements can also be
|
properties like name, width, height, etc., the array elements can also be
|
||||||
assigned to the targetScreen property of Window items, thus serving as an
|
assigned to the screen property of Window items, thus serving as an
|
||||||
alternative to the C++ side's QWindow::setScreen(). This property has been
|
alternative to the C++ side's QWindow::setScreen(). This property has been
|
||||||
added in Qt 5.9.
|
added in Qt 5.9.
|
||||||
|
|
||||||
|
@ -585,7 +586,7 @@ The following functions are also on the Qt object.
|
||||||
\li application.font
|
\li application.font
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\sa Screen, Window, Window.targetScreen
|
\sa Screen, Window, Window.screen
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -2178,6 +2179,27 @@ QString QQmlEngine::offlineStoragePath() const
|
||||||
return d->offlineStoragePath;
|
return d->offlineStoragePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the file path where a \l{QtQuick.LocalStorage}{Local Storage}
|
||||||
|
database with the identifier \a databaseName is (or would be) located.
|
||||||
|
|
||||||
|
\sa LocalStorage.openDatabaseSync()
|
||||||
|
\since 5.9
|
||||||
|
*/
|
||||||
|
QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) const
|
||||||
|
{
|
||||||
|
Q_D(const QQmlEngine);
|
||||||
|
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||||
|
md5.addData(databaseName.toUtf8());
|
||||||
|
return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
|
||||||
|
{
|
||||||
|
Q_Q(const QQmlEngine);
|
||||||
|
return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
|
||||||
|
}
|
||||||
|
|
||||||
QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion)
|
QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion)
|
||||||
{
|
{
|
||||||
QList<QQmlType *> types;
|
QList<QQmlType *> types;
|
||||||
|
|
|
@ -136,6 +136,7 @@ public:
|
||||||
|
|
||||||
void setOfflineStoragePath(const QString& dir);
|
void setOfflineStoragePath(const QString& dir);
|
||||||
QString offlineStoragePath() const;
|
QString offlineStoragePath() const;
|
||||||
|
QString offlineStorageDatabaseFilePath(const QString &databaseName) const;
|
||||||
|
|
||||||
QUrl baseUrl() const;
|
QUrl baseUrl() const;
|
||||||
void setBaseUrl(const QUrl &);
|
void setBaseUrl(const QUrl &);
|
||||||
|
|
|
@ -205,6 +205,7 @@ public:
|
||||||
inline void deleteInEngineThread(T *);
|
inline void deleteInEngineThread(T *);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline static void deleteInEngineThread(QQmlEngine *, T *);
|
inline static void deleteInEngineThread(QQmlEngine *, T *);
|
||||||
|
QString offlineStorageDatabaseDirectory() const;
|
||||||
|
|
||||||
// These methods may be called from the loader thread
|
// These methods may be called from the loader thread
|
||||||
inline QQmlPropertyCache *cache(QQmlType *, int);
|
inline QQmlPropertyCache *cache(QQmlType *, int);
|
||||||
|
|
|
@ -58,5 +58,12 @@ QT_BEGIN_NAMESPACE
|
||||||
#define Q_QML_EXPORT
|
#define Q_QML_EXPORT
|
||||||
#define Q_QML_PRIVATE_EXPORT
|
#define Q_QML_PRIVATE_EXPORT
|
||||||
|
|
||||||
|
/* Some classes built into QtQmlDevTools are marked Q_AUTOTEST_EXPORT but we
|
||||||
|
have nothing to export in this static library */
|
||||||
|
#if defined(Q_AUTOTEST_EXPORT)
|
||||||
|
#undef Q_AUTOTEST_EXPORT
|
||||||
|
#endif
|
||||||
|
#define Q_AUTOTEST_EXPORT
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
#endif // QTQMLGLOBAL_P_H
|
#endif // QTQMLGLOBAL_P_H
|
||||||
|
|
|
@ -640,6 +640,17 @@ void QQuickCanvasItem::releaseResources()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QQuickCanvasItem::event(QEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::PolishRequest:
|
||||||
|
polish();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return QQuickItem::event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QQuickCanvasItem::invalidateSceneGraph()
|
void QQuickCanvasItem::invalidateSceneGraph()
|
||||||
{
|
{
|
||||||
Q_D(QQuickCanvasItem);
|
Q_D(QQuickCanvasItem);
|
||||||
|
@ -651,6 +662,12 @@ void QQuickCanvasItem::invalidateSceneGraph()
|
||||||
d->textureProvider = 0;
|
d->textureProvider = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QQuickCanvasItem::schedulePolish()
|
||||||
|
{
|
||||||
|
auto polishRequestEvent = new QEvent(QEvent::PolishRequest);
|
||||||
|
QCoreApplication::postEvent(this, polishRequestEvent);
|
||||||
|
}
|
||||||
|
|
||||||
void QQuickCanvasItem::componentComplete()
|
void QQuickCanvasItem::componentComplete()
|
||||||
{
|
{
|
||||||
QQuickItem::componentComplete();
|
QQuickItem::componentComplete();
|
||||||
|
@ -892,8 +909,9 @@ void QQuickCanvasItem::requestAnimationFrame(QQmlV4Function *args)
|
||||||
|
|
||||||
d->animationCallbacks.insert(++id, QV4::PersistentValue(scope.engine, f->asReturnedValue()));
|
d->animationCallbacks.insert(++id, QV4::PersistentValue(scope.engine, f->asReturnedValue()));
|
||||||
|
|
||||||
|
// QTBUG-55778: Calling polish directly here can lead to a polish loop
|
||||||
if (isVisible())
|
if (isVisible())
|
||||||
polish();
|
schedulePolish();
|
||||||
|
|
||||||
args->setReturnValue(QV4::Encode(id));
|
args->setReturnValue(QV4::Encode(id));
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,7 @@ private Q_SLOTS:
|
||||||
void sceneGraphInitialized();
|
void sceneGraphInitialized();
|
||||||
void checkAnimationCallbacks();
|
void checkAnimationCallbacks();
|
||||||
void invalidateSceneGraph();
|
void invalidateSceneGraph();
|
||||||
|
void schedulePolish();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void componentComplete() Q_DECL_OVERRIDE;
|
void componentComplete() Q_DECL_OVERRIDE;
|
||||||
|
@ -190,6 +191,7 @@ protected:
|
||||||
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
|
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
|
||||||
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
|
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
|
||||||
void releaseResources() Q_DECL_OVERRIDE;
|
void releaseResources() Q_DECL_OVERRIDE;
|
||||||
|
bool event(QEvent *event) Q_DECL_OVERRIDE;
|
||||||
private:
|
private:
|
||||||
Q_DECLARE_PRIVATE(QQuickCanvasItem)
|
Q_DECLARE_PRIVATE(QQuickCanvasItem)
|
||||||
Q_INVOKABLE void delayedCreate();
|
Q_INVOKABLE void delayedCreate();
|
||||||
|
|
|
@ -1879,7 +1879,7 @@ void QQuickJSContext2D::method_get_lineWidth(const QV4::BuiltinFunction *, QV4::
|
||||||
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
||||||
CHECK_CONTEXT(r)
|
CHECK_CONTEXT(r)
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->context->state.lineWidth);
|
RETURN_RESULT(QV4::Encode(r->d()->context->state.lineWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
||||||
|
@ -1906,7 +1906,7 @@ void QQuickJSContext2D::method_get_miterLimit(const QV4::BuiltinFunction *, QV4:
|
||||||
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
||||||
CHECK_CONTEXT(r)
|
CHECK_CONTEXT(r)
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->context->state.miterLimit);
|
RETURN_RESULT(QV4::Encode(r->d()->context->state.miterLimit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickJSContext2D::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
void QQuickJSContext2D::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
||||||
|
@ -1933,7 +1933,7 @@ void QQuickJSContext2D::method_get_shadowBlur(const QV4::BuiltinFunction *, QV4:
|
||||||
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
||||||
CHECK_CONTEXT(r)
|
CHECK_CONTEXT(r)
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->context->state.shadowBlur);
|
RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowBlur));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
||||||
|
@ -1990,7 +1990,7 @@ void QQuickJSContext2D::method_get_shadowOffsetX(const QV4::BuiltinFunction *, Q
|
||||||
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
||||||
CHECK_CONTEXT(r)
|
CHECK_CONTEXT(r)
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->context->state.shadowOffsetX);
|
RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetX));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
||||||
|
@ -2016,7 +2016,7 @@ void QQuickJSContext2D::method_get_shadowOffsetY(const QV4::BuiltinFunction *, Q
|
||||||
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
|
||||||
CHECK_CONTEXT(r)
|
CHECK_CONTEXT(r)
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->context->state.shadowOffsetY);
|
RETURN_RESULT(QV4::Encode(r->d()->context->state.shadowOffsetY));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
|
||||||
|
@ -3043,7 +3043,7 @@ void QQuickJSContext2DPixelData::proto_get_length(const QV4::BuiltinFunction *,
|
||||||
if (!r || r->d()->image->isNull())
|
if (!r || r->d()->image->isNull())
|
||||||
RETURN_UNDEFINED();
|
RETURN_UNDEFINED();
|
||||||
|
|
||||||
RETURN_RESULT(r->d()->image->width() * r->d()->image->height() * 4);
|
RETURN_RESULT(QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty)
|
QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty)
|
||||||
|
|
|
@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
|
||||||
.arg(current));
|
.arg(current));
|
||||||
}
|
}
|
||||||
if (!requestedUrl.isEmpty()) {
|
if (!requestedUrl.isEmpty()) {
|
||||||
if (QQuickPixmap::isCached(requestedUrl, QSize()))
|
if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
|
||||||
pixmap = new QQuickPixmap(engine, requestedUrl);
|
pixmap = new QQuickPixmap(engine, requestedUrl);
|
||||||
else
|
else
|
||||||
pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
|
pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
|
||||||
|
|
|
@ -207,9 +207,9 @@ QT_BEGIN_NAMESPACE
|
||||||
By default it is set to the value of the QScreen that the window uses.
|
By default it is set to the value of the QScreen that the window uses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QQuickScreenInfo::QQuickScreenInfo(QObject *parent)
|
QQuickScreenInfo::QQuickScreenInfo(QObject *parent, QScreen *wrappedScreen)
|
||||||
: QObject(parent),
|
: QObject(parent)
|
||||||
m_screen(nullptr)
|
, m_screen(wrappedScreen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
|
||||||
Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
|
Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QQuickScreenInfo(QObject *parent = nullptr);
|
QQuickScreenInfo(QObject *parent = nullptr, QScreen *wrappedScreen = nullptr);
|
||||||
|
|
||||||
QString name() const;
|
QString name() const;
|
||||||
int width() const;
|
int width() const;
|
||||||
|
|
|
@ -4172,25 +4172,25 @@ void QQuickWindow::resetOpenGLState()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty variant Window::targetScreen
|
\qmlproperty variant Window::screen
|
||||||
|
|
||||||
Specifies the screen the window should be placed on. Equivalent to
|
The screen with which the window is associated.
|
||||||
QWindow::setScreen().
|
|
||||||
|
|
||||||
The value must be an element from the Qt.application.screens array.
|
If specified before showing a window, will result in the window being shown
|
||||||
|
on that screen, unless an explicit window position has been set. The value
|
||||||
|
must be an element from the Qt.application.screens array.
|
||||||
|
|
||||||
By default the value is null which leads to using the primary screen.
|
\note To ensure that the window is associated with the desired screen when
|
||||||
|
the underlying native window is created, make sure this property is set as
|
||||||
\note To ensure that the window is associated with the desired screen right
|
early as possible and that the setting of its value is not deferred. This
|
||||||
upon the underlying native window's initial creation, make sure this
|
can be particularly important on embedded platforms without a windowing system,
|
||||||
property is set as early as possible and that the setting of its value is
|
where only one window per screen is allowed at a time. Setting the screen after
|
||||||
not deferred. This can be particularly important on embedded platforms
|
a window has been created does not move the window if the new screen is part of
|
||||||
without a windowing system, where only one window per screen is allowed at a
|
the same virtual desktop as the old screen.
|
||||||
time.
|
|
||||||
|
|
||||||
\since 5.9
|
\since 5.9
|
||||||
|
|
||||||
\sa QWindow::setScreen(), QScreen, Qt.application
|
\sa QWindow::setScreen(), QWindow::screen(), QScreen, Qt.application
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -59,7 +59,6 @@ public:
|
||||||
: complete(false)
|
: complete(false)
|
||||||
, visible(false)
|
, visible(false)
|
||||||
, visibility(QQuickWindow::AutomaticVisibility)
|
, visibility(QQuickWindow::AutomaticVisibility)
|
||||||
, targetScreen(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +66,6 @@ public:
|
||||||
bool visible;
|
bool visible;
|
||||||
QQuickWindow::Visibility visibility;
|
QQuickWindow::Visibility visibility;
|
||||||
QV4::PersistentValue rootItemMarker;
|
QV4::PersistentValue rootItemMarker;
|
||||||
QObject *targetScreen;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
|
QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
|
||||||
|
@ -75,6 +73,7 @@ QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
|
||||||
{
|
{
|
||||||
connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
|
connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
|
||||||
connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
|
connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
|
||||||
|
connect(this, &QWindow::screenChanged, this, &QQuickWindowQmlImpl::screenChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickWindowQmlImpl::setVisible(bool visible)
|
void QQuickWindowQmlImpl::setVisible(bool visible)
|
||||||
|
@ -175,24 +174,15 @@ void QQuickWindowQmlImpl::setWindowVisibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject *QQuickWindowQmlImpl::targetScreen() const
|
QObject *QQuickWindowQmlImpl::screen() const
|
||||||
{
|
{
|
||||||
Q_D(const QQuickWindowQmlImpl);
|
return new QQuickScreenInfo(const_cast<QQuickWindowQmlImpl *>(this), QWindow::screen());
|
||||||
return d->targetScreen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickWindowQmlImpl::setTargetScreen(QObject *screen)
|
void QQuickWindowQmlImpl::setScreen(QObject *screen)
|
||||||
{
|
{
|
||||||
Q_D(QQuickWindowQmlImpl);
|
QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
|
||||||
if (d->targetScreen != screen) {
|
QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr);
|
||||||
d->targetScreen = screen;
|
|
||||||
emit targetScreenChanged();
|
|
||||||
QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
|
|
||||||
if (screenWrapper)
|
|
||||||
setScreen(screenWrapper->wrappedScreen());
|
|
||||||
else
|
|
||||||
setScreen(nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQuickWindowModule::defineModule()
|
void QQuickWindowModule::defineModule()
|
||||||
|
|
|
@ -67,7 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
|
||||||
|
|
||||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
|
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
|
||||||
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
|
Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
|
||||||
Q_PROPERTY(QObject *targetScreen READ targetScreen WRITE setTargetScreen NOTIFY targetScreenChanged REVISION 2)
|
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION 2)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR);
|
QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR);
|
||||||
|
@ -75,15 +75,15 @@ public:
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
void setVisibility(Visibility visibility);
|
void setVisibility(Visibility visibility);
|
||||||
|
|
||||||
QObject *targetScreen() const;
|
QObject *screen() const;
|
||||||
void setTargetScreen(QObject *screen);
|
void setScreen(QObject *screen);
|
||||||
|
|
||||||
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
|
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void visibleChanged(bool arg);
|
void visibleChanged(bool arg);
|
||||||
void visibilityChanged(QWindow::Visibility visibility);
|
void visibilityChanged(QWindow::Visibility visibility);
|
||||||
Q_REVISION(2) void targetScreenChanged();
|
Q_REVISION(2) void screenChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void classBegin() Q_DECL_OVERRIDE;
|
void classBegin() Q_DECL_OVERRIDE;
|
||||||
|
|
|
@ -127,7 +127,7 @@ QSGRendererInterface::~QSGRendererInterface()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Queries a graphics \a resource. Returns null when the resource in question is
|
Queries a graphics \a resource in \a window. Returns null when the resource in question is
|
||||||
not supported or not available.
|
not supported or not available.
|
||||||
|
|
||||||
When successful, the returned pointer is either a direct pointer to an
|
When successful, the returned pointer is either a direct pointer to an
|
||||||
|
|
|
@ -1541,9 +1541,9 @@ void QQuickPixmap::clear(QObject *obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize)
|
bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options)
|
||||||
{
|
{
|
||||||
QQuickPixmapKey key = { &url, &requestSize, QQuickImageProviderOptions() };
|
QQuickPixmapKey key = { &url, &requestSize, options };
|
||||||
QQuickPixmapStore *store = pixmapStore();
|
QQuickPixmapStore *store = pixmapStore();
|
||||||
|
|
||||||
return store->m_cache.contains(key);
|
return store->m_cache.contains(key);
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
bool connectDownloadProgress(QObject *, int);
|
bool connectDownloadProgress(QObject *, int);
|
||||||
|
|
||||||
static void purgeCache();
|
static void purgeCache();
|
||||||
static bool isCached(const QUrl &url, const QSize &requestSize);
|
static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options);
|
||||||
|
|
||||||
static const QLatin1String itemGrabberScheme;
|
static const QLatin1String itemGrabberScheme;
|
||||||
|
|
||||||
|
|
|
@ -337,6 +337,7 @@ private slots:
|
||||||
void constkw_data();
|
void constkw_data();
|
||||||
void constkw();
|
void constkw();
|
||||||
void redefineGlobalProp();
|
void redefineGlobalProp();
|
||||||
|
void freeze_empty_object();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
||||||
|
@ -8289,6 +8290,18 @@ void tst_qqmlecmascript::redefineGlobalProp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmlecmascript::freeze_empty_object()
|
||||||
|
{
|
||||||
|
// this shouldn't crash
|
||||||
|
QJSEngine engine;
|
||||||
|
QJSValue v = engine.evaluate(QString::fromLatin1(
|
||||||
|
"var obj = {};\n"
|
||||||
|
"Object.freeze(obj);\n"
|
||||||
|
));
|
||||||
|
QVERIFY(!v.isError());
|
||||||
|
QCOMPARE(v.toBool(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QTEST_MAIN(tst_qqmlecmascript)
|
QTEST_MAIN(tst_qqmlecmascript)
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ private slots:
|
||||||
void baseUrl();
|
void baseUrl();
|
||||||
void contextForObject();
|
void contextForObject();
|
||||||
void offlineStoragePath();
|
void offlineStoragePath();
|
||||||
|
void offlineDatabaseStoragePath();
|
||||||
void clearComponentCache();
|
void clearComponentCache();
|
||||||
void trimComponentCache();
|
void trimComponentCache();
|
||||||
void trimComponentCache_data();
|
void trimComponentCache_data();
|
||||||
|
@ -252,6 +253,34 @@ void tst_qqmlengine::offlineStoragePath()
|
||||||
QCOMPARE(engine.offlineStoragePath(), QDir::homePath());
|
QCOMPARE(engine.offlineStoragePath(), QDir::homePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qqmlengine::offlineDatabaseStoragePath()
|
||||||
|
{
|
||||||
|
// Without these set, QDesktopServices::storageLocation returns
|
||||||
|
// strings with extra "//" at the end. We set them to ignore this problem.
|
||||||
|
qApp->setApplicationName("tst_qqmlengine");
|
||||||
|
qApp->setOrganizationName("QtProject");
|
||||||
|
qApp->setOrganizationDomain("www.qt-project.org");
|
||||||
|
|
||||||
|
QQmlEngine engine;
|
||||||
|
QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
|
||||||
|
const QString databaseName = QLatin1String("foo");
|
||||||
|
QString databaseLocation = engine.offlineStorageDatabaseFilePath(databaseName);
|
||||||
|
QCOMPARE(dataLocation.isEmpty(), databaseLocation.isEmpty());
|
||||||
|
|
||||||
|
QDir dir(dataLocation);
|
||||||
|
dir.mkpath("QML");
|
||||||
|
dir.cd("QML");
|
||||||
|
dir.mkpath("OfflineStorage");
|
||||||
|
dir.cd("OfflineStorage");
|
||||||
|
dir.mkpath("Databases");
|
||||||
|
dir.cd("Databases");
|
||||||
|
QCOMPARE(QFileInfo(databaseLocation).dir().path(), dir.path());
|
||||||
|
|
||||||
|
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||||
|
md5.addData(databaseName.toUtf8());
|
||||||
|
QCOMPARE(databaseLocation, QDir::toNativeSeparators(dir.filePath(QLatin1String(md5.result().toHex()))));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_qqmlengine::clearComponentCache()
|
void tst_qqmlengine::clearComponentCache()
|
||||||
{
|
{
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import QtQuick.Window 2.3 as Window
|
||||||
|
|
||||||
Window.Window {
|
Window.Window {
|
||||||
color: "#00FF00"
|
color: "#00FF00"
|
||||||
targetScreen: Qt.application.screens[0]
|
screen: Qt.application.screens[0]
|
||||||
Item {
|
Item {
|
||||||
objectName: "item"
|
objectName: "item"
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,8 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
|
||||||
|
|
||||||
// ### translation binding simplification
|
// ### translation binding simplification
|
||||||
|
|
||||||
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, /*executable allocator*/nullptr, &irDocument.jsModule, &irDocument.jsGenerator));
|
QV4::ExecutableAllocator allocator;
|
||||||
|
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
|
||||||
// Disable lookups in non-standalone (aka QML) mode
|
// Disable lookups in non-standalone (aka QML) mode
|
||||||
isel->setUseFastLookups(false);
|
isel->setUseFastLookups(false);
|
||||||
irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
|
irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
|
||||||
|
|
|
@ -2,7 +2,8 @@ TEMPLATE = subdirs
|
||||||
QT_FOR_CONFIG += qml-private
|
QT_FOR_CONFIG += qml-private
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
qmlmin \
|
qmlmin \
|
||||||
qmlimportscanner
|
qmlimportscanner \
|
||||||
|
qmlcachegen
|
||||||
|
|
||||||
!android|android_app {
|
!android|android_app {
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
|
@ -27,7 +28,7 @@ SUBDIRS += \
|
||||||
qml.depends = qmlimportscanner
|
qml.depends = qmlimportscanner
|
||||||
qmleasing.depends = qmlimportscanner
|
qmleasing.depends = qmlimportscanner
|
||||||
|
|
||||||
# qmlmin, qmlimportscanner & qmlbundle are build tools.
|
# qmlmin, qmlimportscanner & qmlcachegen are build tools.
|
||||||
# qmlscene is needed by the autotests.
|
# qmlscene is needed by the autotests.
|
||||||
# qmltestrunner may be useful for manual testing.
|
# qmltestrunner may be useful for manual testing.
|
||||||
# qmlplugindump cannot be a build tool, because it loads target plugins.
|
# qmlplugindump cannot be a build tool, because it loads target plugins.
|
||||||
|
|
Loading…
Reference in New Issue