aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-03-01 11:54:30 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-03-01 11:54:35 +0100
commit87aebe39ae80c0752695b21b5b7508d220035b85 (patch)
treea60bd61dd81b5e79532762ae014cb7612d619da2 /src
parenta48244d5aa1d14c286b7cd39afebcfff9c9dcb60 (diff)
parentafec9016d0fd51345ea93a1bbadb99b5c3fdf629 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/ARM64Assembler.h139
-rw-r--r--src/3rdparty/masm/assembler/ARMv7Assembler.h91
-rw-r--r--src/3rdparty/masm/assembler/AbstractMacroAssembler.h42
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.cpp134
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.h292
-rw-r--r--src/3rdparty/masm/assembler/MacroAssembler.h173
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM64.h45
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h84
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerMIPS.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerSH4.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86.h34
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86_64.h29
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h40
-rw-r--r--src/3rdparty/masm/masm.pri30
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h15
-rw-r--r--src/3rdparty/masm/wtf/MathExtras.h2
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp232
-rw-r--r--src/3rdparty/masm/wtf/Platform.h4
-rw-r--r--src/3rdparty/masm/yarr/YarrJIT.cpp6
-rw-r--r--src/imports/imports.pro5
-rw-r--r--src/imports/layouts/qquicklayout.cpp15
-rw-r--r--src/imports/layouts/qquickstacklayout.cpp6
-rw-r--r--src/imports/localstorage/plugin.cpp40
-rw-r--r--src/imports/sharedimage/plugin.cpp134
-rw-r--r--src/imports/sharedimage/qmldir3
-rw-r--r--src/imports/sharedimage/qsharedimageloader.cpp265
-rw-r--r--src/imports/sharedimage/qsharedimageloader_p.h81
-rw-r--r--src/imports/sharedimage/sharedimage.pro17
-rw-r--r--src/imports/sharedimage/sharedimageprovider.cpp156
-rw-r--r--src/imports/sharedimage/sharedimageprovider.h58
-rw-r--r--src/particles/qquickcustomparticle_p.h1
-rw-r--r--src/particles/qquickimageparticle.cpp58
-rw-r--r--src/particles/qquickparticlesystem.cpp13
-rw-r--r--src/particles/qquickparticlesystem_p.h5
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp7
-rw-r--r--src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp14
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h1
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp3
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp6
-rw-r--r--src/qml/compiler/compiler.pri8
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp154
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h15
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h4
-rw-r--r--src/qml/compiler/qv4codegen.cpp211
-rw-r--r--src/qml/compiler/qv4codegen_p.h24
-rw-r--r--src/qml/compiler/qv4compileddata.cpp236
-rw-r--r--src/qml/compiler/qv4compileddata_p.h87
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h3
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp70
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h6
-rw-r--r--src/qml/compiler/qv4jsir_p.h62
-rw-r--r--src/qml/compiler/qv4ssa.cpp14
-rw-r--r--src/qml/compiler/qv4ssa_p.h35
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc11
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc3
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc4
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc2
-rw-r--r--src/qml/doc/src/javascript/functionlist.qdoc1
-rw-r--r--src/qml/doc/src/javascript/imports.qdoc8
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc2
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc3
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc4
-rw-r--r--src/qml/jit/qv4assembler.cpp233
-rw-r--r--src/qml/jit/qv4assembler_p.h936
-rw-r--r--src/qml/jit/qv4binop.cpp307
-rw-r--r--src/qml/jit/qv4binop_p.h67
-rw-r--r--src/qml/jit/qv4isel_masm.cpp1201
-rw-r--r--src/qml/jit/qv4isel_masm_p.h75
-rw-r--r--src/qml/jit/qv4regalloc.cpp18
-rw-r--r--src/qml/jit/qv4targetplatform_p.h366
-rw-r--r--src/qml/jit/qv4unop.cpp60
-rw-r--r--src/qml/jit/qv4unop_p.h12
-rw-r--r--src/qml/jsruntime/jsruntime.pri4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp19
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp37
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h3
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp1
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp56
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp117
-rw-r--r--src/qml/jsruntime/qv4object_p.h72
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp120
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h1
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp27
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp35
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp42
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp20
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp7
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h2
-rw-r--r--src/qml/jsruntime/qv4value_p.h47
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/memory/qv4mm.cpp200
-rw-r--r--src/qml/parser/qqmljs.g28
-rw-r--r--src/qml/parser/qqmljsast_p.h23
-rw-r--r--src/qml/parser/qqmljsgrammar.cpp1786
-rw-r--r--src/qml/parser/qqmljsgrammar_p.h57
-rw-r--r--src/qml/parser/qqmljskeywords_p.h9
-rw-r--r--src/qml/parser/qqmljsparser.cpp314
-rw-r--r--src/qml/qml/qqml.h38
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp13
-rw-r--r--src/qml/qml/qqmlapplicationengine.h1
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h4
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp28
-rw-r--r--src/qml/qml/qqmlengine.h1
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlimport.cpp276
-rw-r--r--src/qml/qml/qqmlimport_p.h42
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp28
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h10
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp104
-rw-r--r--src/qml/qml/qqmltypeloader_p.h69
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp57
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h8
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp15
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp18
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp9
-rw-r--r--src/qml/qtqmlglobal_p.h40
-rw-r--r--src/qml/types/qqmllistmodel.cpp5
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--src/qml/types/qquickpackage.cpp2
-rw-r--r--src/qml/util/qqmladaptormodel.cpp60
-rw-r--r--src/qmldevtools/qmldevtools.pro1
-rw-r--r--src/qmldevtools/qtqmldevtoolsglobal_p.h11
-rw-r--r--src/qmltest/quicktestevent.cpp2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp20
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp21
-rw-r--r--src/quick/items/qquickanimatedimage.cpp2
-rw-r--r--src/quick/items/qquickevents_p_p.h2
-rw-r--r--src/quick/items/qquickimage.cpp32
-rw-r--r--src/quick/items/qquickimage_p_p.h2
-rw-r--r--src/quick/items/qquickimagebase.cpp47
-rw-r--r--src/quick/items/qquickimagebase_p_p.h4
-rw-r--r--src/quick/items/qquickitem.cpp40
-rw-r--r--src/quick/items/qquickitem_p.h7
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp4
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h1
-rw-r--r--src/quick/items/qquickpositioners.cpp109
-rw-r--r--src/quick/items/qquickpositioners_p.h34
-rw-r--r--src/quick/items/qquickpositioners_p_p.h44
-rw-r--r--src/quick/items/qquickscreen.cpp6
-rw-r--r--src/quick/items/qquickscreen_p.h2
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp40
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h6
-rw-r--r--src/quick/items/qquicktext.cpp89
-rw-r--r--src/quick/items/qquicktext_p.h5
-rw-r--r--src/quick/items/qquicktext_p_p.h1
-rw-r--r--src/quick/items/qquickwindow.cpp37
-rw-r--r--src/quick/items/qquickwindowmodule.cpp22
-rw-r--r--src/quick/items/qquickwindowmodule_p.h8
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp8
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h9
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp7
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.cpp2
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h1
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h98
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext.cpp4
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp20
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalimagenode.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp20
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp26
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp24
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode.cpp15
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode_p.h4
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgimagenode.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp53
-rw-r--r--src/quick/scenegraph/util/qsgtexture.h11
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.h7
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp6
-rw-r--r--src/quick/util/qquickglobal.cpp26
-rw-r--r--src/quick/util/qquickpixmapcache.cpp20
-rw-r--r--src/quick/util/qquickpixmapcache_p.h4
-rw-r--r--src/quick/util/qquickutilmodule.cpp9
-rw-r--r--src/quick/util/util.pri9
-rw-r--r--src/src.pro6
216 files changed, 7643 insertions, 3935 deletions
diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h
index ad5acdbb85..7390997af1 100644
--- a/src/3rdparty/masm/assembler/ARM64Assembler.h
+++ b/src/3rdparty/masm/assembler/ARM64Assembler.h
@@ -26,9 +26,10 @@
#ifndef ARM64Assembler_h
#define ARM64Assembler_h
-#if ENABLE(ASSEMBLER) && CPU(ARM64)
+#if ENABLE(ASSEMBLER) && (CPU(ARM64) || defined(V4_BOOTSTRAP))
#include "AssemblerBuffer.h"
+#include "AbstractMacroAssembler.h"
#include <limits.h>
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
@@ -520,8 +521,8 @@ typedef enum {
#undef DECLARE_REGISTER
} FPRegisterID;
-static constexpr bool isSp(RegisterID reg) { return reg == sp; }
-static constexpr bool isZr(RegisterID reg) { return reg == zr; }
+static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return reg == sp; }
+static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return reg == zr; }
} // namespace ARM64Registers
@@ -530,15 +531,15 @@ public:
typedef ARM64Registers::RegisterID RegisterID;
typedef ARM64Registers::FPRegisterID FPRegisterID;
- static constexpr RegisterID firstRegister() { return ARM64Registers::x0; }
- static constexpr RegisterID lastRegister() { return ARM64Registers::sp; }
+ static Q_DECL_CONSTEXPR RegisterID firstRegister() { return ARM64Registers::x0; }
+ static Q_DECL_CONSTEXPR RegisterID lastRegister() { return ARM64Registers::sp; }
- static constexpr FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
- static constexpr FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
+ static Q_DECL_CONSTEXPR FPRegisterID firstFPRegister() { return ARM64Registers::q0; }
+ static Q_DECL_CONSTEXPR FPRegisterID lastFPRegister() { return ARM64Registers::q31; }
private:
- static constexpr bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
- static constexpr bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
+ static Q_DECL_CONSTEXPR bool isSp(RegisterID reg) { return ARM64Registers::isSp(reg); }
+ static Q_DECL_CONSTEXPR bool isZr(RegisterID reg) { return ARM64Registers::isZr(reg); }
public:
ARM64Assembler()
@@ -546,7 +547,7 @@ public:
, m_indexOfTailOfLastWatchpoint(INT_MIN)
{
}
-
+
AssemblerBuffer& buffer() { return m_buffer; }
// (HS, LO, HI, LS) -> (AE, B, A, BE)
@@ -653,9 +654,7 @@ public:
}
void operator=(const LinkRecord& other)
{
- data.copyTypes.content[0] = other.data.copyTypes.content[0];
- data.copyTypes.content[1] = other.data.copyTypes.content[1];
- data.copyTypes.content[2] = other.data.copyTypes.content[2];
+ data.realTypes = other.data.realTypes;
}
intptr_t from() const { return data.realTypes.m_from; }
void setFrom(intptr_t from) { data.realTypes.m_from = from; }
@@ -671,8 +670,8 @@ public:
private:
union {
struct RealTypes {
- intptr_t m_from : 48;
- intptr_t m_to : 48;
+ int64_t m_from : 48;
+ int64_t m_to : 48;
JumpType m_type : 8;
JumpLinkType m_linkType : 8;
Condition m_condition : 4;
@@ -680,10 +679,6 @@ public:
RegisterID m_compareRegister : 6;
bool m_is64Bit : 1;
} realTypes;
- struct CopyTypes {
- uint64_t content[3];
- } copyTypes;
- COMPILE_ASSERT(sizeof(RealTypes) == sizeof(CopyTypes), LinkRecordCopyStructSizeEqualsRealStruct);
} data;
};
@@ -743,6 +738,89 @@ public:
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:
int encodeFPImm(double d)
{
@@ -2857,11 +2935,11 @@ public:
expected = disassembleMoveWideImediate(address + 1, sf, opc, hw, imm16, rd);
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);
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);
}
@@ -2932,7 +3010,10 @@ public:
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);
#elif OS(LINUX)
size_t page = pageSize();
@@ -2989,7 +3070,7 @@ public:
case JumpCondition: {
ASSERT(!(reinterpret_cast<intptr_t>(from) & 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)
return LinkJumpConditionDirect;
@@ -2999,7 +3080,7 @@ public:
case JumpCompareAndBranch: {
ASSERT(!(reinterpret_cast<intptr_t>(from) & 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)
return LinkJumpCompareAndBranchDirect;
@@ -3009,7 +3090,7 @@ public:
case JumpTestBit: {
ASSERT(!(reinterpret_cast<intptr_t>(from) & 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)
return LinkJumpTestBitDirect;
@@ -3121,7 +3202,7 @@ private:
{
ASSERT(!(reinterpret_cast<intptr_t>(from) & 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);
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>(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);
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>(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(((offset << 38) >> 38) == offset);
@@ -3766,6 +3847,8 @@ private:
#undef DATASIZE
#undef MEMOPSIZE
#undef CHECK_FP_MEMOP_DATASIZE
+#undef JUMP_ENUM_WITH_SIZE
+#undef JUMP_ENUM_SIZE
#endif // ENABLE(ASSEMBLER) && CPU(ARM64)
diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h
index f0fa07a1bf..615c72fc15 100644
--- a/src/3rdparty/masm/assembler/ARMv7Assembler.h
+++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h
@@ -27,10 +27,11 @@
#ifndef ARMAssembler_h
#define ARMAssembler_h
-#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
+#if ENABLE(ASSEMBLER) && (CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP))
#include "AssemblerBuffer.h"
#include "MacroAssemblerCodeRef.h"
+#include "AbstractMacroAssembler.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
#include <stdint.h>
@@ -491,8 +492,8 @@ public:
private:
union {
struct RealTypes {
- intptr_t m_from : 31;
- intptr_t m_to : 31;
+ int32_t m_from : 31;
+ int32_t m_to : 31;
JumpType m_type : 8;
JumpLinkType m_linkType : 8;
Condition m_condition : 16;
@@ -510,6 +511,56 @@ public:
{
}
+
+ // 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()
+ {
+ }
+
+ // Fixme: this information should be stored in the instruction stream, not in the Jump object.
+ Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
+ : m_label(jmp)
+ , m_type(type)
+ , m_condition(condition)
+ {
+ }
+
+ LabelType label() const
+ {
+ LabelType result;
+ result.m_label = m_label;
+ return result;
+ }
+
+ void link(AbstractMacroAssembler<ARMv7Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
+ }
+
+ void linkTo(LabelType label, AbstractMacroAssembler<ARMv7Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition);
+ }
+
+ bool isSet() const { return m_label.isSet(); }
+
+ private:
+ AssemblerLabel m_label;
+ ARMv7Assembler::JumpType m_type;
+ ARMv7Assembler::Condition m_condition;
+ };
+
private:
// ARMv7, Appx-A.6.3
@@ -2115,6 +2166,7 @@ public:
linkJumpAbsolute(location, to);
}
+#if !defined(V4_BOOTSTRAP)
static void linkCall(void* code, AssemblerLabel from, void* to)
{
ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
@@ -2123,12 +2175,14 @@ public:
setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to, false);
}
+#endif
static void linkPointer(void* code, AssemblerLabel where, void* value)
{
setPointer(reinterpret_cast<char*>(code) + where.m_offset, value, false);
}
+#if !defined(V4_BOOTSTRAP)
static void relinkJump(void* from, void* to)
{
ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
@@ -2146,11 +2200,12 @@ public:
setPointer(reinterpret_cast<uint16_t*>(from) - 1, to, true);
}
-
+
static void* readCallTarget(void* from)
{
return readPointer(reinterpret_cast<uint16_t*>(from) - 1);
}
+#endif
static void repatchInt32(void* where, int32_t value)
{
@@ -2179,6 +2234,7 @@ public:
cacheFlush(location, sizeof(uint16_t) * 2);
}
+#if !defined(V4_BOOTSTRAP)
static void repatchPointer(void* where, void* value)
{
ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
@@ -2190,7 +2246,8 @@ public:
{
return reinterpret_cast<void*>(readInt32(where));
}
-
+#endif
+
static void replaceWithJump(void* instructionStart, void* to)
{
ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
@@ -2264,7 +2321,7 @@ public:
unsigned debugOffset() { return m_formatter.debugOffset(); }
-#if OS(LINUX)
+#if OS(LINUX) && !defined(V4_BOOTSTRAP)
static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
{
asm volatile(
@@ -2284,7 +2341,10 @@ public:
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);
#elif OS(LINUX)
size_t page = pageSize();
@@ -2430,7 +2490,9 @@ private:
static void setPointer(void* code, void* value, bool flush)
{
- setInt32(code, reinterpret_cast<uint32_t>(value), flush);
+ // ### Deliberate "loss" of precision here. On 64-bit hosts void* is wider
+ // than uint32_t, but the target is 32-bit ARM anyway.
+ setInt32(code, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value)), flush);
}
static bool isB(void* address)
@@ -2594,6 +2656,11 @@ private:
static void linkBX(uint16_t* instruction, void* target)
{
+#if defined(V4_BOOTSTRAP)
+ UNUSED_PARAM(instruction);
+ UNUSED_PARAM(target);
+ RELEASE_ASSERT_NOT_REACHED();
+#else
// FIMXE: this should be up in the MacroAssembler layer. :-(
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
@@ -2606,6 +2673,7 @@ private:
instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
+#endif
}
void linkConditionalBX(Condition cond, uint16_t* instruction, void* target)
@@ -2638,6 +2706,9 @@ private:
instruction[-3] = OP_NOP_T2b;
linkJumpT4(instruction, target);
} else {
+#if defined(V4_BOOTSTRAP)
+ RELEASE_ASSERT_NOT_REACHED();
+#else
const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
@@ -2646,6 +2717,7 @@ private:
instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
+#endif
}
}
@@ -2795,6 +2867,9 @@ private:
int m_indexOfTailOfLastWatchpoint;
};
+#undef JUMP_ENUM_WITH_SIZE
+#undef JUMP_ENUM_SIZE
+
} // namespace JSC
#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
diff --git a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
index e90dd235c6..6fac27fdf1 100644
--- a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
+++ b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
@@ -47,7 +47,10 @@
namespace JSC {
class JumpReplacementWatchpoint;
-class LinkBuffer;
+template <typename, template <typename> class>
+class LinkBufferBase;
+template <typename>
+class BranchCompactingLinkBuffer;
class RepatchBuffer;
class Watchpoint;
namespace DFG {
@@ -63,7 +66,9 @@ public:
typedef MacroAssemblerCodePtr CodePtr;
typedef MacroAssemblerCodeRef CodeRef;
+#if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP)
class Jump;
+#endif
typedef typename AssemblerType::RegisterID RegisterID;
typedef typename AssemblerType::FPRegisterID FPRegisterID;
@@ -325,7 +330,7 @@ public:
friend class Jump;
friend class JumpReplacementWatchpoint;
friend class MacroAssemblerCodeRef;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class Watchpoint;
public:
@@ -339,6 +344,8 @@ public:
}
bool isSet() const { return m_label.isSet(); }
+
+ const AssemblerLabel &label() const { return m_label; }
private:
AssemblerLabel m_label;
};
@@ -356,7 +363,7 @@ public:
class ConvertibleLoadLabel {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
ConvertibleLoadLabel()
@@ -380,7 +387,7 @@ public:
class DataLabelPtr {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabelPtr()
{
@@ -404,7 +411,7 @@ public:
class DataLabel32 {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabel32()
{
@@ -428,7 +435,7 @@ public:
class DataLabelCompact {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabelCompact()
{
@@ -448,6 +455,11 @@ public:
AssemblerLabel m_label;
};
+#if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP)
+ using Jump = typename AssemblerType::template Jump<Label>;
+ friend Jump;
+#endif
+
// Call:
//
// A Call object is a reference to a call instruction that has been planted
@@ -498,18 +510,19 @@ public:
// 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.
+#if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP)
class Jump {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
friend class Call;
friend struct DFG::OSRExit;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
Jump()
{
}
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
// Fixme: this information should be stored in the instruction stream, not in the Jump object.
Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
: m_label(jmp)
@@ -610,10 +623,11 @@ public:
private:
AssemblerLabel m_label;
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
ARMv7Assembler::JumpType m_type;
ARMv7Assembler::Condition m_condition;
-#elif CPU(ARM64)
+#endif
+#if CPU(ARM64)
ARM64Assembler::JumpType m_type;
ARM64Assembler::Condition m_condition;
bool m_is64Bit;
@@ -624,6 +638,7 @@ public:
SH4Assembler::JumpType m_type;
#endif
};
+#endif
struct PatchableJump {
PatchableJump()
@@ -645,7 +660,7 @@ public:
// A JumpList is a set of Jump objects.
// All jumps in the set will be linked to the same destination.
class JumpList {
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
typedef Vector<Jump, 2> JumpVector;
@@ -819,7 +834,8 @@ protected:
static bool shouldBlindForSpecificArch(uint64_t) { return true; }
#endif
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
+ template <typename> friend class BranchCompactingLinkBuffer;
friend class RepatchBuffer;
static void linkJump(void* code, Jump jump, CodeLocationLabel target)
@@ -867,10 +883,12 @@ protected:
AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
}
+#if !defined(V4_BOOTSTRAP)
static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
{
return AssemblerType::readPointer(dataLabelPtr.dataLocation());
}
+#endif
static void replaceWithLoad(CodeLocationConvertibleLoad label)
{
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.cpp b/src/3rdparty/masm/assembler/LinkBuffer.cpp
index 432a7ee227..74c278135b 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.cpp
+++ b/src/3rdparty/masm/assembler/LinkBuffer.cpp
@@ -32,140 +32,6 @@
namespace JSC {
-LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly()
-{
- performFinalization();
-
- return CodeRef(m_executableMemory);
-}
-
-LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...)
-{
- ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
-
- CodeRef result = finalizeCodeWithoutDisassembly();
-
- dataLogF("Generated JIT code for ");
- va_list argList;
- va_start(argList, format);
- WTF::dataLogFV(format, argList);
- va_end(argList);
- dataLogF(":\n");
-
- dataLogF(
-#if OS(WINDOWS)
- " Code at [0x%p, 0x%p):\n",
-#else
- " Code at [%p, %p):\n",
-#endif
- result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
- disassemble(result.code(), m_size, " ", WTF::dataFile());
-
- return result;
-}
-
-void LinkBuffer::linkCode(void* ownerUID, JITCompilationEffort effort)
-{
- ASSERT(!m_code);
-#if !ENABLE(BRANCH_COMPACTION)
- m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort);
- if (!m_executableMemory)
- return;
- m_code = m_executableMemory->start();
- m_size = m_assembler->m_assembler.codeSize();
- ASSERT(m_code);
-#else
- m_initialSize = m_assembler->m_assembler.codeSize();
- m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort);
- if (!m_executableMemory)
- return;
- m_code = (uint8_t*)m_executableMemory->start();
- ASSERT(m_code);
- ExecutableAllocator::makeWritable(m_code, m_initialSize);
- uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
- uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
- int readPtr = 0;
- int writePtr = 0;
- Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = m_assembler->jumpsToLink();
- unsigned jumpCount = jumpsToLink.size();
- for (unsigned i = 0; i < jumpCount; ++i) {
- int offset = readPtr - writePtr;
- ASSERT(!(offset & 1));
-
- // Copy the instructions from the last jump to the current one.
- size_t regionSize = jumpsToLink[i].from() - readPtr;
- uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr);
- uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize);
- uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr);
- ASSERT(!(regionSize % 2));
- ASSERT(!(readPtr % 2));
- ASSERT(!(writePtr % 2));
- while (copySource != copyEnd)
- *copyDst++ = *copySource++;
- m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
- readPtr += regionSize;
- writePtr += regionSize;
-
- // Calculate absolute address of the jump target, in the case of backwards
- // branches we need to be precise, forward branches we are pessimistic
- const uint8_t* target;
- if (jumpsToLink[i].to() >= jumpsToLink[i].from())
- target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
- else
- target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
-
- JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
- // Compact branch if we can...
- if (m_assembler->canCompact(jumpsToLink[i].type())) {
- // Step back in the write stream
- int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
- if (delta) {
- writePtr -= delta;
- m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
- }
- }
- jumpsToLink[i].setFrom(writePtr);
- }
- // Copy everything after the last jump
- memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
- m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr);
-
- for (unsigned i = 0; i < jumpCount; ++i) {
- uint8_t* location = outData + jumpsToLink[i].from();
- uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
- m_assembler->link(jumpsToLink[i], location, target);
- }
-
- jumpsToLink.clear();
- m_size = writePtr + m_initialSize - readPtr;
- m_executableMemory->shrink(m_size);
-
-#if DUMP_LINK_STATISTICS
- dumpLinkStatistics(m_code, m_initialSize, m_size);
-#endif
-#if DUMP_CODE
- dumpCode(m_code, m_size);
-#endif
-#endif
-}
-
-void LinkBuffer::performFinalization()
-{
-#ifndef NDEBUG
- ASSERT(!m_completed);
- ASSERT(isValid());
- m_completed = true;
-#endif
-
-#if ENABLE(BRANCH_COMPACTION)
- ExecutableAllocator::makeExecutable(code(), m_initialSize);
-#else
- ASSERT(m_size <= INT_MAX);
- ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
-#endif
- MacroAssembler::cacheFlush(code(), m_size);
-}
-
#if DUMP_LINK_STATISTICS
void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize)
{
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.h b/src/3rdparty/masm/assembler/LinkBuffer.h
index e1882433c1..bfd0e402ca 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.h
+++ b/src/3rdparty/masm/assembler/LinkBuffer.h
@@ -36,6 +36,7 @@
#include "JITCompilationEffort.h"
#include "MacroAssembler.h"
+#include "Options.h"
#include <wtf/DataLog.h>
#include <wtf/Noncopyable.h>
@@ -43,6 +44,12 @@ namespace JSC {
class JSGlobalData;
+template <typename T>
+struct DefaultExecutableOffsetCalculator {
+ template <typename Assembler>
+ static T applyOffset(Assembler *, T src) { return src; }
+};
+
// LinkBuffer:
//
// This class assists in linking code generated by the macro assembler, once code generation
@@ -57,30 +64,24 @@ class JSGlobalData;
// * The address of a Label pointing into the code may be resolved.
// * The value referenced by a DataLabel may be set.
//
-class LinkBuffer {
- WTF_MAKE_NONCOPYABLE(LinkBuffer);
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+class LinkBufferBase {
+ WTF_MAKE_NONCOPYABLE(LinkBufferBase);
typedef MacroAssemblerCodeRef CodeRef;
typedef MacroAssemblerCodePtr CodePtr;
- typedef MacroAssembler::Label Label;
- typedef MacroAssembler::Jump Jump;
- typedef MacroAssembler::PatchableJump PatchableJump;
- typedef MacroAssembler::JumpList JumpList;
- typedef MacroAssembler::Call Call;
- typedef MacroAssembler::DataLabelCompact DataLabelCompact;
- typedef MacroAssembler::DataLabel32 DataLabel32;
- typedef MacroAssembler::DataLabelPtr DataLabelPtr;
- typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
-#if ENABLE(BRANCH_COMPACTION)
- typedef MacroAssembler::LinkRecord LinkRecord;
- typedef MacroAssembler::JumpLinkType JumpLinkType;
-#endif
+ typedef typename MacroAssembler::Label Label;
+ typedef typename MacroAssembler::Jump Jump;
+ typedef typename MacroAssembler::PatchableJump PatchableJump;
+ typedef typename MacroAssembler::JumpList JumpList;
+ typedef typename MacroAssembler::Call Call;
+ typedef typename MacroAssembler::DataLabelCompact DataLabelCompact;
+ typedef typename MacroAssembler::DataLabel32 DataLabel32;
+ typedef typename MacroAssembler::DataLabelPtr DataLabelPtr;
+ typedef typename MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
public:
- LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ LinkBufferBase(JSGlobalData& globalData, MacroAssembler* masm, JITCompilationEffort effort = JITCompilationMustSucceed)
: m_size(0)
-#if ENABLE(BRANCH_COMPACTION)
- , m_initialSize(0)
-#endif
, m_code(0)
, m_assembler(masm)
, m_globalData(&globalData)
@@ -89,10 +90,13 @@ public:
, m_effort(effort)
#endif
{
- linkCode(ownerUID, effort);
+#ifdef NDEBUG
+ UNUSED_PARAM(effort)
+#endif
+ // Simon: Moved this to the sub-classes linkCode(ownerUID, effort);
}
- ~LinkBuffer()
+ ~LinkBufferBase()
{
ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail));
}
@@ -204,8 +208,8 @@ public:
// finalizeCodeWithoutDisassembly() directly if you have your own way of
// displaying disassembly.
- CodeRef finalizeCodeWithoutDisassembly();
- CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+ inline CodeRef finalizeCodeWithoutDisassembly();
+ inline CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
CodePtr trampolineAt(Label label)
{
@@ -225,21 +229,19 @@ public:
private:
template <typename T> T applyOffset(T src)
{
-#if ENABLE(BRANCH_COMPACTION)
- src.m_offset -= m_assembler->executableOffsetFor(src.m_offset);
-#endif
- return src;
+ return ExecutableOffsetCalculator<T>::applyOffset(m_assembler, src);
}
+protected:
// Keep this private! - the underlying code should only be obtained externally via finalizeCode().
void* code()
{
return m_code;
}
- void linkCode(void* ownerUID, JITCompilationEffort);
+ inline void linkCode(void* ownerUID, JITCompilationEffort);
- void performFinalization();
+ inline void performFinalization();
#if DUMP_LINK_STATISTICS
static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize);
@@ -251,12 +253,10 @@ private:
RefPtr<ExecutableMemoryHandle> m_executableMemory;
size_t m_size;
-#if ENABLE(BRANCH_COMPACTION)
- size_t m_initialSize;
-#endif
void* m_code;
MacroAssembler* m_assembler;
JSGlobalData* m_globalData;
+protected:
#ifndef NDEBUG
bool m_completed;
JITCompilationEffort m_effort;
@@ -290,6 +290,234 @@ private:
#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithoutDisassembly()
+{
+ performFinalization();
+
+ return CodeRef(m_executableMemory);
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithDisassembly(const char* format, ...)
+{
+ ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
+
+ CodeRef result = finalizeCodeWithoutDisassembly();
+
+ dataLogF("Generated JIT code for ");
+ va_list argList;
+ va_start(argList, format);
+ WTF::dataLogFV(format, argList);
+ va_end(argList);
+ dataLogF(":\n");
+
+ dataLogF(
+#if OS(WINDOWS)
+ " Code at [0x%p, 0x%p):\n",
+#else
+ " Code at [%p, %p):\n",
+#endif
+ result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
+ disassemble(result.code(), m_size, " ", WTF::dataFile());
+
+ return result;
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::linkCode(void* ownerUID, JITCompilationEffort effort)
+{
+ UNUSED_PARAM(ownerUID)
+ UNUSED_PARAM(effort)
+ ASSERT(!m_code);
+ m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort);
+ if (!m_executableMemory)
+ return;
+ m_code = m_executableMemory->start();
+ m_size = m_assembler->m_assembler.codeSize();
+ ASSERT(m_code);
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::performFinalization()
+{
+ // NOTE: This function is specialized in LinkBuffer<MacroAssemblerARMv7>
+#ifndef NDEBUG
+ ASSERT(!m_completed);
+ ASSERT(isValid());
+ m_completed = true;
+#endif
+
+ ASSERT(m_size <= INT_MAX);
+ ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
+ MacroAssembler::cacheFlush(code(), m_size);
+}
+
+template <typename MacroAssembler>
+class LinkBuffer : public LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator>(globalData, masm, effort)
+ {
+ this->linkCode(ownerUID, effort);
+ }
+};
+
+#if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP)
+
+template <typename T>
+struct BranchCompactingExecutableOffsetCalculator {
+ template <typename Assembler>
+ static T applyOffset(Assembler *as, T src) {
+ src.m_offset -= as->executableOffsetFor(src.m_offset);
+ return src;
+ }
+};
+
+template <typename MacroAssembler>
+class BranchCompactingLinkBuffer : public LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>
+{
+public:
+ BranchCompactingLinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>(globalData, masm, effort)
+ {
+ linkCode(ownerUID, effort);
+ }
+
+ inline void performFinalization();
+
+ inline void linkCode(void* ownerUID, JITCompilationEffort);
+
+private:
+ using Base = LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>;
+#ifndef NDEBUG
+ using Base::m_completed;
+#endif
+ using Base::isValid;
+ using Base::code;
+ using Base::m_code;
+ using Base::m_size;
+ using Base::m_assembler;
+ using Base::m_executableMemory;
+ using Base::m_globalData;
+
+ using LinkRecord = typename MacroAssembler::LinkRecord;
+ using JumpLinkType = typename MacroAssembler::JumpLinkType;
+
+ size_t m_initialSize = 0;
+};
+
+template <typename MacroAssembler>
+inline void BranchCompactingLinkBuffer<MacroAssembler>::performFinalization()
+{
+#ifndef NDEBUG
+ ASSERT(!m_completed);
+ ASSERT(isValid());
+ this->m_completed = true;
+#endif
+
+ ExecutableAllocator::makeExecutable(code(), m_initialSize);
+ MacroAssembler::cacheFlush(code(), m_size);
+}
+
+template <typename MacroAssembler>
+inline void BranchCompactingLinkBuffer<MacroAssembler>::linkCode(void* ownerUID, JITCompilationEffort effort)
+{
+ UNUSED_PARAM(ownerUID)
+ UNUSED_PARAM(effort)
+ ASSERT(!m_code);
+ m_initialSize = m_assembler->m_assembler.codeSize();
+ m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort);
+ if (!m_executableMemory)
+ return;
+ m_code = (uint8_t*)m_executableMemory->start();
+ ASSERT(m_code);
+ ExecutableAllocator::makeWritable(m_code, m_initialSize);
+ uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
+ uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
+ int readPtr = 0;
+ int writePtr = 0;
+ Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = m_assembler->jumpsToLink();
+ unsigned jumpCount = unsigned(jumpsToLink.size());
+ for (unsigned i = 0; i < jumpCount; ++i) {
+ int offset = readPtr - writePtr;
+ ASSERT(!(offset & 1));
+
+ // Copy the instructions from the last jump to the current one.
+ unsigned regionSize = unsigned(jumpsToLink[i].from() - readPtr);
+ uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr);
+ uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize);
+ uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr);
+ ASSERT(!(regionSize % 2));
+ ASSERT(!(readPtr % 2));
+ ASSERT(!(writePtr % 2));
+ while (copySource != copyEnd)
+ *copyDst++ = *copySource++;
+ m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
+ readPtr += regionSize;
+ writePtr += regionSize;
+
+ // Calculate absolute address of the jump target, in the case of backwards
+ // branches we need to be precise, forward branches we are pessimistic
+ const uint8_t* target;
+ if (jumpsToLink[i].to() >= jumpsToLink[i].from())
+ target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
+ else
+ target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+
+ JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
+ // Compact branch if we can...
+ if (m_assembler->canCompact(jumpsToLink[i].type())) {
+ // Step back in the write stream
+ int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
+ if (delta) {
+ writePtr -= delta;
+ m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
+ }
+ }
+ jumpsToLink[i].setFrom(writePtr);
+ }
+ // Copy everything after the last jump
+ memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
+ m_assembler->recordLinkOffsets(readPtr, unsigned(m_initialSize), readPtr - writePtr);
+
+ for (unsigned i = 0; i < jumpCount; ++i) {
+ uint8_t* location = outData + jumpsToLink[i].from();
+ uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+ m_assembler->link(jumpsToLink[i], location, target);
+ }
+
+ jumpsToLink.clear();
+ m_size = writePtr + m_initialSize - readPtr;
+ m_executableMemory->shrink(m_size);
+}
+
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
+template <>
+class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARMv7>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>>(globalData, masm, ownerUID, effort)
+ {}
+};
+#endif
+
+#if CPU(ARM64) || defined(V4_BOOTSTRAP)
+template <>
+class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARM64>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : BranchCompactingLinkBuffer<JSC::MacroAssembler<JSC::MacroAssemblerARM64>>(globalData, masm, ownerUID, effort)
+ {}
+};
+#endif
+
+#endif
+
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h
index e122e2f3ae..7d9f156c8c 100644
--- a/src/3rdparty/masm/assembler/MacroAssembler.h
+++ b/src/3rdparty/masm/assembler/MacroAssembler.h
@@ -30,12 +30,13 @@
#if ENABLE(ASSEMBLER)
-#if CPU(ARM_THUMB2)
#include "MacroAssemblerARMv7.h"
+#include "MacroAssemblerARM64.h"
+
+#if CPU(ARM_THUMB2)
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; };
#elif CPU(ARM64)
-#include "MacroAssemblerARM64.h"
namespace JSC { typedef MacroAssemblerARM64 MacroAssemblerBase; };
#elif CPU(ARM_TRADITIONAL)
@@ -68,13 +69,53 @@ typedef MacroAssemblerSH4 MacroAssemblerBase;
namespace JSC {
+template <typename MacroAssemblerBase>
class MacroAssembler : public MacroAssemblerBase {
public:
+ using DoubleCondition = typename MacroAssemblerBase::DoubleCondition;
+ using ResultCondition = typename MacroAssemblerBase::ResultCondition;
+ using RelationalCondition = typename MacroAssemblerBase::RelationalCondition;
+ using RegisterID = typename MacroAssemblerBase::RegisterID;
+ using Address = typename MacroAssemblerBase::Address;
+ using ExtendedAddress = typename MacroAssemblerBase::ExtendedAddress;
+ using BaseIndex = typename MacroAssemblerBase::BaseIndex;
+ using ImplicitAddress = typename MacroAssemblerBase::ImplicitAddress;
+ using AbsoluteAddress = typename MacroAssemblerBase::AbsoluteAddress;
+ using TrustedImm32 = typename MacroAssemblerBase::TrustedImm32;
+ using TrustedImm64 = typename MacroAssemblerBase::TrustedImm64;
+ using TrustedImmPtr = typename MacroAssemblerBase::TrustedImmPtr;
+ using Imm32 = typename MacroAssemblerBase::Imm32;
+ using Imm64 = typename MacroAssemblerBase::Imm64;
+ using ImmPtr = typename MacroAssemblerBase::ImmPtr;
+ using Label = typename MacroAssemblerBase::Label;
+ using DataLabelPtr = typename MacroAssemblerBase::DataLabelPtr;
+ using DataLabel32 = typename MacroAssemblerBase::DataLabel32;
+ using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact;
+ using Jump = typename MacroAssemblerBase::Jump;
+ using PatchableJump = typename MacroAssemblerBase::PatchableJump;
+
using MacroAssemblerBase::pop;
using MacroAssemblerBase::jump;
using MacroAssemblerBase::branch32;
using MacroAssemblerBase::move;
+ using MacroAssemblerBase::store32;
+ using MacroAssemblerBase::add32;
+ using MacroAssemblerBase::xor32;
+ using MacroAssemblerBase::sub32;
+ using MacroAssemblerBase::load32;
+
+
+#if defined(V4_BOOTSTRAP)
+ using MacroAssemblerBase::loadPtr;
+ using MacroAssemblerBase::storePtr;
+#elif CPU(X86_64) || CPU(ARM64)
+ using MacroAssemblerBase::add64;
+ using MacroAssemblerBase::sub64;
+ using MacroAssemblerBase::xor64;
+ using MacroAssemblerBase::load64;
+ using MacroAssemblerBase::store64;
+#endif
#if ENABLE(JIT_CONSTANT_BLINDING)
using MacroAssemblerBase::add32;
@@ -100,41 +141,41 @@ public:
static DoubleCondition invert(DoubleCondition cond)
{
switch (cond) {
- case DoubleEqual:
- return DoubleNotEqualOrUnordered;
- case DoubleNotEqual:
- return DoubleEqualOrUnordered;
- case DoubleGreaterThan:
- return DoubleLessThanOrEqualOrUnordered;
- case DoubleGreaterThanOrEqual:
- return DoubleLessThanOrUnordered;
- case DoubleLessThan:
- return DoubleGreaterThanOrEqualOrUnordered;
- case DoubleLessThanOrEqual:
- return DoubleGreaterThanOrUnordered;
- case DoubleEqualOrUnordered:
- return DoubleNotEqual;
- case DoubleNotEqualOrUnordered:
- return DoubleEqual;
- case DoubleGreaterThanOrUnordered:
- return DoubleLessThanOrEqual;
- case DoubleGreaterThanOrEqualOrUnordered:
- return DoubleLessThan;
- case DoubleLessThanOrUnordered:
- return DoubleGreaterThanOrEqual;
- case DoubleLessThanOrEqualOrUnordered:
- return DoubleGreaterThan;
+ case DoubleCondition::DoubleEqual:
+ return DoubleCondition::DoubleNotEqualOrUnordered;
+ case DoubleCondition::DoubleNotEqual:
+ return DoubleCondition::DoubleEqualOrUnordered;
+ case DoubleCondition::DoubleGreaterThan:
+ return DoubleCondition::DoubleLessThanOrEqualOrUnordered;
+ case DoubleCondition::DoubleGreaterThanOrEqual:
+ return DoubleCondition::DoubleLessThanOrUnordered;
+ case DoubleCondition::DoubleLessThan:
+ return DoubleCondition::DoubleGreaterThanOrEqualOrUnordered;
+ case DoubleCondition::DoubleLessThanOrEqual:
+ return DoubleCondition::DoubleGreaterThanOrUnordered;
+ case DoubleCondition::DoubleEqualOrUnordered:
+ return DoubleCondition::DoubleNotEqual;
+ case DoubleCondition::DoubleNotEqualOrUnordered:
+ return DoubleCondition::DoubleEqual;
+ case DoubleCondition::DoubleGreaterThanOrUnordered:
+ return DoubleCondition::DoubleLessThanOrEqual;
+ case DoubleCondition::DoubleGreaterThanOrEqualOrUnordered:
+ return DoubleCondition::DoubleLessThan;
+ case DoubleCondition::DoubleLessThanOrUnordered:
+ return DoubleCondition::DoubleGreaterThanOrEqual;
+ case DoubleCondition::DoubleLessThanOrEqualOrUnordered:
+ return DoubleCondition::DoubleGreaterThan;
default:
RELEASE_ASSERT_NOT_REACHED();
- return DoubleEqual; // make compiler happy
+ return DoubleCondition::DoubleEqual; // make compiler happy
}
}
static bool isInvertible(ResultCondition cond)
{
switch (cond) {
- case Zero:
- case NonZero:
+ case ResultCondition::Zero:
+ case ResultCondition::NonZero:
return true;
default:
return false;
@@ -144,13 +185,13 @@ public:
static ResultCondition invert(ResultCondition cond)
{
switch (cond) {
- case Zero:
- return NonZero;
- case NonZero:
- return Zero;
+ case ResultCondition::Zero:
+ return ResultCondition::NonZero;
+ case ResultCondition::NonZero:
+ return ResultCondition::Zero;
default:
RELEASE_ASSERT_NOT_REACHED();
- return Zero; // Make compiler happy for release builds.
+ return ResultCondition::Zero; // Make compiler happy for release builds.
}
}
#endif
@@ -159,17 +200,17 @@ public:
// described in terms of other macro assembly methods.
void pop()
{
- addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister);
+ addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister);
}
void peek(RegisterID dest, int index = 0)
{
- loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest);
+ loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
}
Address addressForPoke(int index)
{
- return Address(stackPointerRegister, (index * sizeof(void*)));
+ return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*)));
}
void poke(RegisterID src, int index = 0)
@@ -187,10 +228,10 @@ public:
storePtr(imm, addressForPoke(index));
}
-#if CPU(X86_64) || CPU(ARM64)
+#if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP)
void peek64(RegisterID dest, int index = 0)
{
- load64(Address(stackPointerRegister, (index * sizeof(void*))), dest);
+ load64(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
}
void poke(TrustedImm64 value, int index = 0)
@@ -296,36 +337,37 @@ public:
static RelationalCondition commute(RelationalCondition condition)
{
switch (condition) {
- case Above:
- return Below;
- case AboveOrEqual:
- return BelowOrEqual;
- case Below:
- return Above;
- case BelowOrEqual:
- return AboveOrEqual;
- case GreaterThan:
- return LessThan;
- case GreaterThanOrEqual:
- return LessThanOrEqual;
- case LessThan:
- return GreaterThan;
- case LessThanOrEqual:
- return GreaterThanOrEqual;
+ case RelationalCondition::Above:
+ return RelationalCondition::Below;
+ case RelationalCondition::AboveOrEqual:
+ return RelationalCondition::BelowOrEqual;
+ case RelationalCondition::Below:
+ return RelationalCondition::Above;
+ case RelationalCondition::BelowOrEqual:
+ return RelationalCondition::AboveOrEqual;
+ case RelationalCondition::GreaterThan:
+ return RelationalCondition::LessThan;
+ case RelationalCondition::GreaterThanOrEqual:
+ return RelationalCondition::LessThanOrEqual;
+ case RelationalCondition::LessThan:
+ return RelationalCondition::GreaterThan;
+ case RelationalCondition::LessThanOrEqual:
+ return RelationalCondition::GreaterThanOrEqual;
default:
break;
}
- ASSERT(condition == Equal || condition == NotEqual);
+ ASSERT(condition == RelationalCondition::Equal || condition == RelationalCondition::NotEqual);
return condition;
}
static const unsigned BlindingModulus = 64;
bool shouldConsiderBlinding()
{
- return !(random() & (BlindingModulus - 1));
+ return !(this->random() & (BlindingModulus - 1));
}
+#if !defined(V4_BOOTSTRAP)
// Ptr methods
// On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents.
// FIXME: should this use a test for 32-bitness instead of this specific exception?
@@ -850,6 +892,7 @@ public:
{
return branchSub64(cond, src1, src2, dest);
}
+#endif // !defined(V4_BOOTSTRAP)
#if ENABLE(JIT_CONSTANT_BLINDING)
using MacroAssemblerBase::and64;
@@ -1447,6 +1490,22 @@ public:
#endif
};
+#if CPU(ARM_THUMB2)
+typedef MacroAssembler<MacroAssemblerARMv7> DefaultMacroAssembler;
+#elif CPU(ARM64)
+typedef MacroAssembler<MacroAssemblerARM64> DefaultMacroAssembler;
+#elif CPU(ARM_TRADITIONAL)
+typedef MacroAssembler<MacroAssemblerARM> DefaultMacroAssembler;
+#elif CPU(MIPS)
+typedef MacroAssembler<MacroAssemblerMIPS> DefaultMacroAssembler;
+#elif CPU(X86)
+typedef MacroAssembler<MacroAssemblerX86> DefaultMacroAssembler;
+#elif CPU(X86_64)
+typedef MacroAssembler<MacroAssemblerX86_64> DefaultMacroAssembler;
+#elif CPU(SH4)
+typedef JSC::MacroAssemblerSH4 DefaultMacroAssembler;
+#endif
+
} // namespace JSC
#else // ENABLE(ASSEMBLER)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM.h b/src/3rdparty/masm/assembler/MacroAssemblerARM.h
index 01e34c97cd..268fe5fe73 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARM.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM.h
@@ -1349,7 +1349,7 @@ protected:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
void internalCompare32(RegisterID left, TrustedImm32 right)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
index bd85b6b2c1..a11637f7ca 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
@@ -26,7 +26,7 @@
#ifndef MacroAssemblerARM64_h
#define MacroAssemblerARM64_h
-#if ENABLE(ASSEMBLER)
+#if ENABLE(ASSEMBLER) && (CPU(ARM64) || defined(V4_BOOTSTRAP))
#include "ARM64Assembler.h"
#include "AbstractMacroAssembler.h"
@@ -42,7 +42,7 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler> {
friend class DataLabelPtr;
friend class DataLabel32;
friend class DataLabelCompact;
- friend class Jump;
+// template <typename> friend class Jump;
friend class Label;
public:
@@ -119,9 +119,9 @@ public:
private:
static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31;
static const ARM64Assembler::SetFlags S = ARM64Assembler::S;
- static const intptr_t maskHalfWord0 = 0xffffl;
- static const intptr_t maskHalfWord1 = 0xffff0000l;
- static const intptr_t maskUpperWord = 0xffffffff00000000l;
+ static const int64_t maskHalfWord0 = 0xffffl;
+ static const int64_t maskHalfWord1 = 0xffff0000l;
+ static const int64_t maskUpperWord = 0xffffffff00000000l;
// 4 instructions - 3 to load the function pointer, + blr.
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(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:
void add32(RegisterID a, RegisterID b, RegisterID dest)
@@ -2757,6 +2784,7 @@ public:
return branch32(cond, left, dataTempRegister);
}
+#if !defined(V4_BOOTSTRAP)
PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right)
{
m_makeJumpPatchable = true;
@@ -2764,6 +2792,7 @@ public:
m_makeJumpPatchable = false;
return PatchableJump(result);
}
+#endif
PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
@@ -3000,7 +3029,7 @@ private:
return m_cachedMemoryTempRegister.registerIDInvalidate();
}
- ALWAYS_INLINE bool isInIntRange(intptr_t value)
+ ALWAYS_INLINE bool isInIntRange(int64_t value)
{
return value == ((value << 32) >> 32);
}
@@ -3353,7 +3382,9 @@ private:
return makeBranch(cond);
}
- friend class LinkBuffer;
+ 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); }
int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 0938383513..806f2e13b6 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -27,7 +27,7 @@
#ifndef MacroAssemblerARMv7_h
#define MacroAssemblerARMv7_h
-#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
+#if ENABLE(ASSEMBLER) && (CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP))
#include "ARMv7Assembler.h"
#include "AbstractMacroAssembler.h"
@@ -160,12 +160,41 @@ public:
{
add32(imm, dest, dest);
}
+
+#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
+#if !defined(V4_BOOTSTRAP)
void add32(AbsoluteAddress src, RegisterID dest)
{
load32(src.m_ptr, dataTempRegister);
add32(dataTempRegister, dest);
}
+#endif
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
@@ -206,6 +235,7 @@ public:
add32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void add32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
@@ -242,6 +272,7 @@ public:
m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
}
+#endif
void and32(RegisterID op1, RegisterID op2, RegisterID dest)
{
@@ -343,6 +374,7 @@ public:
or32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void or32(RegisterID src, AbsoluteAddress dest)
{
move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
@@ -350,6 +382,7 @@ public:
or32(src, dataTempRegister);
store32(dataTempRegister, addressTempRegister);
}
+#endif
void or32(TrustedImm32 imm, RegisterID dest)
{
@@ -461,6 +494,7 @@ public:
sub32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
@@ -477,6 +511,7 @@ public:
store32(dataTempRegister, address.m_ptr);
}
+#endif
void xor32(Address src, RegisterID dest)
{
@@ -526,7 +561,8 @@ public:
// operand objects to loads and store will be implicitly constructed if a
// register is passed.
-private:
+ // internal function, but public because of "using load32;" in template sub-classes to pull
+ // in the other public overloads.
void load32(ArmAddress address, RegisterID dest)
{
if (address.type == ArmAddress::HasIndex)
@@ -541,6 +577,7 @@ private:
}
}
+private:
void load16(ArmAddress address, RegisterID dest)
{
if (address.type == ArmAddress::HasIndex)
@@ -646,11 +683,13 @@ public:
load16(setupArmAddress(address), dest);
}
+#if !defined(V4_BOOTSTRAP)
void load32(const void* address, RegisterID dest)
{
move(TrustedImmPtr(address), addressTempRegister);
m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
}
+#endif
ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
{
@@ -755,6 +794,7 @@ public:
store32(dataTempRegister, setupArmAddress(address));
}
+#if !defined(V4_BOOTSTRAP)
void store32(RegisterID src, const void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
@@ -766,12 +806,14 @@ public:
move(imm, dataTempRegister);
store32(dataTempRegister, address);
}
+#endif
void store8(RegisterID src, BaseIndex address)
{
store8(src, setupArmAddress(address));
}
+#if !defined(V4_BOOTSTRAP)
void store8(RegisterID src, void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
@@ -783,6 +825,7 @@ public:
move(imm, dataTempRegister);
store8(dataTempRegister, address);
}
+#endif
void store16(RegisterID src, BaseIndex address)
{
@@ -880,11 +923,13 @@ public:
m_assembler.vmov(dest, src);
}
+#if !defined(V4_BOOTSTRAP)
void loadDouble(const void* address, FPRegisterID dest)
{
move(TrustedImmPtr(address), addressTempRegister);
m_assembler.vldr(dest, addressTempRegister, 0);
}
+#endif
void storeDouble(FPRegisterID src, ImplicitAddress address)
{
@@ -916,11 +961,13 @@ public:
m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
}
+#if !defined(V4_BOOTSTRAP)
void storeDouble(FPRegisterID src, const void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
storeDouble(src, addressTempRegister);
}
+#endif
void storeDouble(FPRegisterID src, BaseIndex address)
{
@@ -954,11 +1001,13 @@ public:
m_assembler.vadd(dest, op1, op2);
}
+#if !defined(V4_BOOTSTRAP)
void addDouble(AbsoluteAddress address, FPRegisterID dest)
{
loadDouble(address.m_ptr, fpTempRegister);
m_assembler.vadd(dest, dest, fpTempRegister);
}
+#endif
void divDouble(FPRegisterID src, FPRegisterID dest)
{
@@ -1037,6 +1086,7 @@ public:
m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
}
+#if !defined(V4_BOOTSTRAP)
void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
{
// Fixme: load directly into the fpr!
@@ -1044,6 +1094,7 @@ public:
m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
}
+#endif
void convertUInt32ToDouble(RegisterID src, FPRegisterID dest, RegisterID /*scratch*/)
{
@@ -1197,7 +1248,7 @@ public:
void push(RegisterID src)
{
// store preindexed with writeback
- m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
+ m_assembler.str(src, ARMRegisters::sp, -4 /*sizeof(void*)*/, true, true);
}
void push(Address address)
@@ -1239,10 +1290,12 @@ public:
m_assembler.mov(dest, src);
}
+#if !defined(V4_BOOTSTRAP)
void move(TrustedImmPtr imm, RegisterID dest)
{
move(TrustedImm32(imm), dest);
}
+#endif
void swap(RegisterID reg1, RegisterID reg2)
{
@@ -1383,6 +1436,7 @@ public:
return branch32(cond, addressTempRegister, right);
}
+#if !defined(V4_BOOTSTRAP)
Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, dataTempRegister);
@@ -1395,6 +1449,7 @@ public:
load32(left.m_ptr, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
+#endif
Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
@@ -1451,6 +1506,7 @@ public:
return branchTest32(cond, addressTempRegister, mask);
}
+#if !defined(V4_BOOTSTRAP)
Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
// use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
@@ -1458,6 +1514,7 @@ public:
load8(Address(addressTempRegister), addressTempRegister);
return branchTest32(cond, addressTempRegister, mask);
}
+#endif
void jump(RegisterID target)
{
@@ -1471,12 +1528,14 @@ public:
m_assembler.bx(dataTempRegister);
}
+#if !defined(V4_BOOTSTRAP)
void jump(AbsoluteAddress address)
{
move(TrustedImmPtr(address.m_ptr), dataTempRegister);
load32(Address(dataTempRegister), dataTempRegister);
m_assembler.bx(dataTempRegister);
}
+#endif
// Arithmetic control flow operations:
@@ -1517,6 +1576,7 @@ public:
return branchAdd32(cond, dest, imm, dest);
}
+#if !defined(V4_BOOTSTRAP)
Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
{
// Move the high bits of the address into addressTempRegister,
@@ -1542,6 +1602,7 @@ public:
return Jump(makeBranch(cond));
}
+#endif
Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
{
@@ -1712,6 +1773,7 @@ public:
return DataLabel32(this);
}
+#if !defined(V4_BOOTSTRAP)
ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
{
padBeforePatch();
@@ -1739,7 +1801,8 @@ public:
m_makeJumpPatchable = false;
return PatchableJump(result);
}
-
+#endif
+
PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
m_makeJumpPatchable = true;
@@ -1756,6 +1819,7 @@ public:
return PatchableJump(result);
}
+#if !defined(V4_BOOTSTRAP)
PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_makeJumpPatchable = true;
@@ -1763,6 +1827,7 @@ public:
m_makeJumpPatchable = false;
return PatchableJump(result);
}
+#endif
PatchableJump patchableJump()
{
@@ -1773,6 +1838,7 @@ public:
return PatchableJump(result);
}
+#if !defined(V4_BOOTSTRAP)
ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
@@ -1780,7 +1846,7 @@ public:
return label;
}
ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
-
+#endif
ALWAYS_INLINE Call tailRecursiveCall()
{
@@ -1801,6 +1867,7 @@ public:
return m_assembler.executableOffsetFor(location);
}
+#if !defined(V4_BOOTSTRAP)
static FunctionPtr readCallTarget(CodeLocationCall call)
{
return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
@@ -1813,7 +1880,8 @@ public:
const unsigned twoWordOpSize = 4;
return label.labelAtOffset(-twoWordOpSize * 2);
}
-
+#endif
+
static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
{
#if OS(LINUX) || OS(QNX)
@@ -1927,9 +1995,10 @@ protected:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
+#if !defined(V4_BOOTSTRAP)
static void linkCall(void* code, Call call, FunctionPtr function)
{
ARMv7Assembler::linkCall(code, call.m_label, function.value());
@@ -1944,6 +2013,7 @@ private:
{
ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
}
+#endif
bool m_makeJumpPatchable;
};
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
index 734e779c70..68584527fc 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
@@ -2802,7 +2802,7 @@ private:
// Otherwise, we can emit any number of instructions.
bool m_fixedWidth;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerSH4.h b/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
index 56fb74d45b..1e5a3113bb 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
@@ -2278,7 +2278,7 @@ protected:
return static_cast<SH4Assembler::Condition>(cond);
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void*, Call, FunctionPtr);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
index 9a33fe870e..742a4b48f7 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
@@ -54,6 +54,38 @@ public:
using MacroAssemblerX86Common::convertInt32ToDouble;
using MacroAssemblerX86Common::branchTest8;
+#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);
+ }
+
+ Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ return branchTest8(cond, Address(address.base, address.offset), mask);
+ }
+#endif
+
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.leal_mr(imm.m_value, src, dest);
@@ -306,7 +338,7 @@ public:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
index 9e74f1c29f..3566702413 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
@@ -52,6 +52,33 @@ public:
using MacroAssemblerX86Common::loadDouble;
using MacroAssemblerX86Common::convertInt32ToDouble;
+#if defined(V4_BOOTSTRAP)
+ void loadPtr(ImplicitAddress address, RegisterID dest)
+ {
+ load64(address, dest);
+ }
+
+ void subPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ sub64(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ add64(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ add64(imm, src, dest);
+ }
+
+ void storePtr(RegisterID src, ImplicitAddress address)
+ {
+ store64(src, address);
+ }
+#endif
+
void add32(TrustedImm32 imm, AbsoluteAddress address)
{
move(TrustedImmPtr(address.m_ptr), scratchRegister);
@@ -634,7 +661,7 @@ public:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index 1875ebaff0..24462ef38f 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -29,6 +29,7 @@
#if ENABLE(ASSEMBLER) && (CPU(X86) || CPU(X86_64))
#include "AssemblerBuffer.h"
+#include "AbstractMacroAssembler.h"
#include "JITCompilationEffort.h"
#include <stdint.h>
#include <wtf/Assertions.h>
@@ -252,6 +253,45 @@ public:
{
}
+ 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)
+ : m_label(jmp)
+ {
+ }
+
+ LabelType label() const
+ {
+ LabelType result;
+ result.m_label = m_label;
+ return result;
+ }
+
+ void link(AbstractMacroAssembler<X86Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
+ }
+
+ void linkTo(LabelType label, AbstractMacroAssembler<X86Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, label.label());
+ }
+
+ bool isSet() const { return m_label.isSet(); }
+
+ private:
+ AssemblerLabel m_label;
+ };
+
// Stack operations:
void push_r(RegisterID reg)
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index afa1438974..6c301fea38 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -13,6 +13,7 @@ HEADERS += $$PWD/wtf/RawPointer.h
winrt: SOURCES += $$PWD/wtf/OSAllocatorWinRT.cpp
else:win32: SOURCES += $$PWD/wtf/OSAllocatorWin.cpp
+else:integrity: SOURCES += $$PWD/wtf/OSAllocatorIntegrity.cpp
else: SOURCES += $$PWD/wtf/OSAllocatorPosix.cpp
HEADERS += $$PWD/wtf/OSAllocator.h
@@ -30,7 +31,17 @@ HEADERS += $$PWD/stubs/WTFStubs.h
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/UDis86Disassembler.cpp
@@ -66,8 +77,21 @@ SOURCES += $$PWD/disassembler/ARM64Disassembler.cpp
SOURCES += $$PWD/disassembler/ARM64/A64DOpcode.cpp
HEADERS += $$PWD/disassembler/ARM64/A64DOpcode.h
-SOURCES += $$PWD/yarr/*.cpp
-HEADERS += $$PWD/yarr/*.h
+!qmldevtools_build {
+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
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h
index 8617229b06..3b84b5c986 100644
--- a/src/3rdparty/masm/stubs/ExecutableAllocator.h
+++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h
@@ -61,7 +61,7 @@ namespace JSC {
class JSGlobalData;
struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
- ExecutableMemoryHandle(QV4::ExecutableAllocator *allocator, int size)
+ ExecutableMemoryHandle(QV4::ExecutableAllocator *allocator, size_t size)
: m_allocator(allocator)
, m_size(size)
{
@@ -79,14 +79,14 @@ struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
inline bool isManaged() const { return true; }
void* start() { return m_allocation->start(); }
- int sizeInBytes() { return m_size; }
+ size_t sizeInBytes() { return m_size; }
QV4::ExecutableAllocator::ChunkOfPages *chunk() const
{ return m_allocator->chunkForAllocation(m_allocation); }
QV4::ExecutableAllocator *m_allocator;
QV4::ExecutableAllocator::Allocation *m_allocation;
- int m_size;
+ size_t m_size;
};
struct ExecutableAllocator {
@@ -94,7 +94,7 @@ struct ExecutableAllocator {
: realAllocator(alloc)
{}
- PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, int size, void*, int)
+ PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, size_t size, void*, int)
{
return adoptRef(new ExecutableMemoryHandle(realAllocator, size));
}
@@ -107,7 +107,7 @@ struct ExecutableAllocator {
size = size + (iaddr - roundAddr);
addr = reinterpret_cast<void*>(roundAddr);
-#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
+#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) && !defined(V4_BOOTSTRAP)
# if OS(WINDOWS)
DWORD oldProtect;
# if !OS(WINRT)
@@ -140,6 +140,7 @@ struct ExecutableAllocator {
size = size + (iaddr - roundAddr);
addr = reinterpret_cast<void*>(roundAddr);
+#if !defined(V4_BOOTSTRAP)
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
# if OS(WINDOWS)
DWORD oldProtect;
@@ -161,6 +162,10 @@ struct ExecutableAllocator {
#else
# error "Only W^X is supported"
#endif
+#else
+ (void)addr; // suppress unused parameter warning
+ (void)size; // suppress unused parameter warning
+#endif
}
QV4::ExecutableAllocator *realAllocator;
diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h
index 75e3670367..3740d54beb 100644
--- a/src/3rdparty/masm/wtf/MathExtras.h
+++ b/src/3rdparty/masm/wtf/MathExtras.h
@@ -88,7 +88,7 @@ inline double wtf_ceil(double x) { return copysign(ceil(x), x); }
#endif
-#if OS(SOLARIS)
+#if OS(SOLARIS) && __cplusplus < 201103L
namespace std {
diff --git a/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp b/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp
new file mode 100644
index 0000000000..451ca147d1
--- /dev/null
+++ b/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) Rolland Dudemaine All rights reserved.
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#include <INTEGRITY.h>
+#include <memory_region.h>
+#include <set>
+#include <wtf/Assertions.h>
+#include <wtf/UnusedParam.h>
+
+#define ASP_PAGESIZE 0x1000
+
+namespace WTF {
+struct MRPair {
+ mutable MemoryRegion pmr;
+ mutable MemoryRegion vmr;
+
+ mutable bool mapped;
+
+ Address start;
+
+ MRPair(Address _start = 0) :
+ pmr(0),
+ vmr(0),
+ mapped(false),
+ start(_start)
+ {}
+
+ bool operator<(const MRPair& rhs) const
+ {
+ return this->start < rhs.start;
+ }
+};
+
+class MRContainer
+{
+private:
+ std::set<MRPair> mrset;
+ LocalMutex iteratorGuard;
+public:
+ MRContainer() {
+ CheckSuccess(CreateLocalMutex(&iteratorGuard));
+ }
+ const MRPair* getMRPair(Address start) {
+ WaitForLocalMutex(iteratorGuard);
+ auto pairIterator = mrset.find(MRPair(start));
+ const MRPair* result = ((pairIterator == mrset.end()) ? NULL : &(*pairIterator));
+ ReleaseLocalMutex(iteratorGuard);
+ return result;
+ }
+ Error deleteMRPair(const MRPair* pair) {
+ int erased = 0;
+ WaitForLocalMutex(iteratorGuard);
+ erased = mrset.erase(*pair);
+ ReleaseLocalMutex(iteratorGuard);
+ if(erased == 1)
+ return Success;
+ else
+ return ArgumentError; /* An exception could be thrown in this case */
+ }
+ Error insertMRPair(MRPair* pair) {
+ WaitForLocalMutex(iteratorGuard);
+ auto inserted = mrset.insert(*pair);
+ ReleaseLocalMutex(iteratorGuard);
+ if(inserted.second == true)
+ return Success;
+ else
+ return Failure; /* An exception could be thrown in this case */
+ }
+ ~MRContainer() {
+ CheckSuccess(CloseLocalMutex(iteratorGuard));
+ }
+};
+
+static MRContainer memoryRegionsContainer;
+
+Error setAttributes(MemoryRegion mr, bool writable, bool executable)
+{
+ Value attributes = MEMORY_READ;
+ if(writable)
+ attributes |= MEMORY_WRITE;
+ if(executable)
+ attributes |= MEMORY_EXEC;
+ return SetMemoryRegionAttributes(mr, attributes);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
+{
+ MemoryRegion VMR;
+
+ Address virtualStart, length;
+
+ CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
+ CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
+ Address addressIterator = virtualStart;
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
+ MRPair pair;
+ CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
+ CheckSuccess(setAttributes(pair.vmr, writable, executable));
+ pair.start = addressIterator;
+
+ memoryRegionsContainer.insertMRPair(&pair);
+ addressIterator += ASP_PAGESIZE;
+ }
+
+ CheckSuccess(CloseMemoryRegion(VMR));
+ return (void*)virtualStart;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ MemoryRegion VMR;
+
+ Address virtualStart, length;
+
+ CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
+ CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
+
+ Address addressIterator = virtualStart;
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
+ MRPair pair;
+ pair.start = addressIterator;
+ CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
+ CheckSuccess(setAttributes(pair.vmr, writable, executable));
+ /* Do not map the first and the last pages if guard pages are required */
+ if(!includesGuardPages || (i!=0 && i!= (bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE -1))
+ {
+ CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair.pmr));
+ CheckSuccess(MapMemoryRegion(pair.vmr, pair.pmr));
+ pair.mapped = true;
+ }
+
+ memoryRegionsContainer.insertMRPair(&pair);
+ addressIterator += ASP_PAGESIZE;
+ }
+
+ CheckSuccess(CloseMemoryRegion(VMR));
+ return (void*)virtualStart;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ CheckSuccess(setAttributes(pair->vmr, writable, executable));
+ CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair->pmr));
+ CheckSuccess(MapMemoryRegion(pair->vmr, pair->pmr));
+ pair->mapped = true;
+ address = (char*)address + ASP_PAGESIZE;
+ }
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ if(pair->mapped == false)
+ continue;
+
+ CheckSuccess(UnmapMemoryRegion(pair->vmr));
+ CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
+ pair->mapped = false;
+ address = (char*)address + ASP_PAGESIZE;
+ }
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ /* Check if the memory is still committed */
+ if(pair->mapped == true)
+ {
+ CheckSuccess(UnmapMemoryRegion(pair->vmr));
+ CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
+ pair->mapped = false;
+ }
+ CheckSuccess(AddToMemoryPool(__ghs_VirtualMemoryRegionPool, pair->vmr));
+ address = (char*)address + ASP_PAGESIZE;
+
+ memoryRegionsContainer.deleteMRPair(pair);
+ }
+}
+} // namespace WTF
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index bc62c381db..7f2023a68a 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -949,10 +949,6 @@
#define WTF_USE_ACCESSIBILITY_CONTEXT_MENUS 1
#endif
-#if CPU(ARM_THUMB2) || CPU(ARM64)
-#define ENABLE_BRANCH_COMPACTION 1
-#endif
-
#if !defined(ENABLE_THREADING_LIBDISPATCH) && HAVE(DISPATCH_H)
#define ENABLE_THREADING_LIBDISPATCH 1
#elif !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
diff --git a/src/3rdparty/masm/yarr/YarrJIT.cpp b/src/3rdparty/masm/yarr/YarrJIT.cpp
index d8211ec4b2..e4f2d97759 100644
--- a/src/3rdparty/masm/yarr/YarrJIT.cpp
+++ b/src/3rdparty/masm/yarr/YarrJIT.cpp
@@ -39,7 +39,7 @@ using namespace WTF;
namespace JSC { namespace Yarr {
template<YarrJITCompileMode compileMode>
-class YarrGenerator : private MacroAssembler {
+class YarrGenerator : private DefaultMacroAssembler {
friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const String& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
#if CPU(ARM)
@@ -599,7 +599,7 @@ class YarrGenerator : private MacroAssembler {
}
// Called at the end of code generation to link all return addresses.
- void linkDataLabels(LinkBuffer& linkBuffer)
+ void linkDataLabels(LinkBuffer<JSC::DefaultMacroAssembler>& linkBuffer)
{
ASSERT(isEmpty());
for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
@@ -2676,7 +2676,7 @@ public:
backtrack();
// Link & finalize the code.
- LinkBuffer linkBuffer(*globalData, this, REGEXP_CODE_ID);
+ LinkBuffer<JSC::DefaultMacroAssembler> linkBuffer(*globalData, this, REGEXP_CODE_ID);
m_backtrackingState.linkDataLabels(linkBuffer);
if (compileMode == MatchOnly) {
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index cad02a2980..20ade45fc8 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -5,16 +5,17 @@ SUBDIRS += \
qtqml \
folderlistmodel \
localstorage \
- models \
- statemachine
+ models
qtConfig(settings): SUBDIRS += settings
+qtConfig(statemachine): SUBDIRS += statemachine
qtHaveModule(quick) {
SUBDIRS += \
layouts \
qtquick2 \
window \
+ sharedimage \
testlib
qtConfig(opengl(es1|es2)?): \
diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp
index 55ee3b63c6..df64b593d9 100644
--- a/src/imports/layouts/qquicklayout.cpp
+++ b/src/imports/layouts/qquicklayout.cpp
@@ -696,13 +696,20 @@ QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
{
}
+static QQuickItemPrivate::ChangeTypes changeTypes =
+ QQuickItemPrivate::SiblingOrder
+ | QQuickItemPrivate::ImplicitWidth
+ | QQuickItemPrivate::ImplicitHeight
+ | QQuickItemPrivate::Destroyed
+ | QQuickItemPrivate::Visibility;
+
QQuickLayout::~QQuickLayout()
{
d_func()->m_isReady = false;
const auto childItems = d_func()->childItems;
for (QQuickItem *child : childItems)
- QQuickItemPrivate::get(child)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder);
+ QQuickItemPrivate::get(child)->removeItemChangeListener(this, changeTypes);
}
QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
@@ -766,14 +773,14 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
Q_D(QQuickLayout);
QQuickItem *item = value.item;
qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
- QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
d->m_hasItemChangeListeners = true;
if (isReady())
updateLayoutItems();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
if (isReady())
updateLayoutItems();
}
@@ -821,7 +828,7 @@ void QQuickLayout::deactivateRecur()
// When deleting a layout with children, there is no reason for the children to inform the layout that their
// e.g. visibility got changed. The layout already knows that all its children will eventually become invisible, so
// we therefore remove its change listener.
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed | QQuickItemPrivate::Visibility);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
if (QQuickLayout *layout = qobject_cast<QQuickLayout*>(item))
layout->deactivateRecur();
}
diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp
index a223dd0374..0bfe63816d 100644
--- a/src/imports/layouts/qquickstacklayout.cpp
+++ b/src/imports/layouts/qquickstacklayout.cpp
@@ -307,7 +307,11 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize)
QQuickItem *item = itemAt(d->currentIndex);
Q_ASSERT(item);
item->setPosition(QPointF(0,0)); // ### respect alignment?
- item->setSize(newSize.expandedTo(hints.min()).boundedTo(hints.max()));
+ const QSizeF oldSize(item->width(), item->height());
+ const QSizeF effectiveNewSize = newSize.expandedTo(hints.min()).boundedTo(hints.max());
+ item->setSize(effectiveNewSize);
+ if (effectiveNewSize == oldSize)
+ item->polish();
QQuickLayout::rearrange(newSize);
}
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index d3ea93c80a..60b8dad5fb 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -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)
{
Scope scope(v4);
@@ -450,7 +432,8 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
if (ok) {
*w->d()->version = to_version;
#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);
#endif
}
@@ -723,24 +706,23 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
if (scope.engine->qmlEngine()->offlineStoragePath().isEmpty())
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);
QString dbname = (v = (*args)[0])->toQStringNoThrow();
QString dbversion = (v = (*args)[1])->toQStringNoThrow();
QString dbdescription = (v = (*args)[2])->toQStringNoThrow();
int dbestimatedsize = (v = (*args)[3])->toInt32();
FunctionObject *dbcreationCallback = (v = (*args)[4])->as<FunctionObject>();
-
- QCryptographicHash md5(QCryptographicHash::Md5);
- md5.addData(dbname.toUtf8());
- QString dbid(QLatin1String(md5.result().toHex()));
-
- QString basename = qmlsqldatabase_databaseFile(dbid, scope.engine);
+ QString basename = args->v4engine()->qmlEngine()->offlineStorageDatabaseFilePath(dbname);
+ QFileInfo dbFile(basename);
+ if (!QDir().mkpath(dbFile.dir().absolutePath())) {
+ const QString message = QQmlEngine::tr("LocalStorage: can't create path %1").
+ arg(QDir::toNativeSeparators(dbFile.dir().absolutePath()));
+ V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, message);
+ }
+ QString dbid = dbFile.fileName();
bool created = false;
QString version = dbversion;
+ QSqlDatabase database;
{
QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
diff --git a/src/imports/sharedimage/plugin.cpp b/src/imports/sharedimage/plugin.cpp
new file mode 100644
index 0000000000..f20edc641c
--- /dev/null
+++ b/src/imports/sharedimage/plugin.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qqmlextensionplugin.h>
+#include <qqmlengine.h>
+#include <sharedimageprovider.h>
+
+
+/*!
+ \qmlmodule QtQuick.SharedImage 1
+ \title Qt Quick Shared Image Provider
+ \ingroup qmlmodules
+ \brief Adds an image provider which utilizes shared CPU memory
+
+ \section2 Summary
+
+ This module provides functionality to save memory in use cases where
+ several Qt Quick applications use the same local image files. It does this
+ by placing the decoded QImage data in shared system memory, making it
+ accessible to all the processes (see QSharedMemory).
+
+ This module only shares CPU memory. It does not provide sharing of GPU
+ memory or textures.
+
+ \section2 Usage
+
+ To use this module, import it like this:
+ \code
+ import QtQuick.SharedImage 1.0
+ \endcode
+
+ The sharing functionality is provided through a QQuickImageProvider. Use
+ the "image:" scheme for the URL source of the image, followed by the
+ identifier \e shared, followed by the image file path. For example:
+
+ \code
+ Image { source: "image://shared/usr/share/wallpapers/mybackground.jpg" }
+ \endcode
+
+ This will look for the file \e /usr/share/wallpapers/mybackground.jpg.
+ The first process that does this will read the image file
+ using normal Qt image loading. The decoded image data will then be placed
+ in shared memory, using the full file path as key. Later processes
+ requesting the same image will discover that the data is already available
+ in shared memory. They will then use that instead of loading the image file
+ again.
+
+ The shared image data will be kept available until the last process has deleted
+ its last reference to the shared image, at which point it is automatically released.
+
+ If system memory sharing is not available, the shared image provider falls
+ back to normal, unshared image loading.
+
+ The file path must be absolute. To use a relative path, make it absolute
+ using \e Qt.resolvedUrl() and replace the URL scheme. For example:
+
+ \code
+ ...
+ property string imagePrefix: Qt.resolvedUrl("../myimages/").replace("file://", "image://shared/")
+ Image { source: imagePrefix + "myimage.png" }
+ \endcode
+
+ The shared image module does not provide any directly usable QML types.
+*/
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_QtQuick_SharedImage);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickSharedImagePlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QtQuickSharedImagePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+
+ void registerTypes(const char *uri) Q_DECL_OVERRIDE
+ {
+ Q_ASSERT(uri == QStringLiteral("QtQuick.SharedImage"));
+ // Need to register *something* to let our version number be known:
+ qmlRegisterTypeNotAvailable(uri, 1, 0, "nosuchtype", QStringLiteral("Just a dummy type, do not use"));
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("shared", new SharedImageProvider);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/sharedimage/qmldir b/src/imports/sharedimage/qmldir
new file mode 100644
index 0000000000..64a5aa8ac1
--- /dev/null
+++ b/src/imports/sharedimage/qmldir
@@ -0,0 +1,3 @@
+module QtQuick.SharedImage
+plugin sharedimageplugin
+classname QtQuickSharedImagePlugin
diff --git a/src/imports/sharedimage/qsharedimageloader.cpp b/src/imports/sharedimage/qsharedimageloader.cpp
new file mode 100644
index 0000000000..65cbd92bb4
--- /dev/null
+++ b/src/imports/sharedimage/qsharedimageloader.cpp
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsharedimageloader_p.h"
+#include <private/qobject_p.h>
+#include <private/qimage_p.h>
+#include <QSharedMemory>
+
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSharedImage, "qt.quick.sharedimage");
+
+struct SharedImageHeader {
+ quint8 magic;
+ quint8 version;
+ quint16 offset;
+ qint32 width;
+ qint32 height;
+ qint32 bpl;
+ QImage::Format format;
+};
+Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4 == 0);
+
+#ifndef QT_NO_SHAREDMEMORY
+struct SharedImageInfo {
+ QString path;
+ QPointer<QSharedMemory> shmp;
+};
+
+void cleanupSharedImage(void *cleanupInfo)
+{
+ if (!cleanupInfo)
+ return;
+ SharedImageInfo *sii = static_cast<SharedImageInfo *>(cleanupInfo);
+ qCDebug(lcSharedImage) << "Cleanup called for" << sii->path;
+ if (sii->shmp.isNull()) {
+ qCDebug(lcSharedImage) << "shm is 0 for" << sii->path;
+ return;
+ }
+ QSharedMemory *shm = sii->shmp.data();
+ sii->shmp.clear();
+ delete shm; // destructor detaches
+ delete sii;
+}
+#else
+void cleanupSharedImage(void *) {}
+#endif
+
+class QSharedImageLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSharedImageLoader)
+
+public:
+ QSharedImageLoaderPrivate()
+ : QObjectPrivate()
+ {}
+
+ QImage load(const QString &path, QSharedImageLoader::ImageParameters *params);
+
+ void storeImageToMem(void *data, const QImage &img);
+
+ bool verifyMem(const void *data, int size);
+
+ QImage createImageFromMem(const void *data, void *cleanupInfo);
+
+};
+
+
+void QSharedImageLoaderPrivate::storeImageToMem(void *data, const QImage &img)
+{
+ Q_ASSERT(data && !img.isNull());
+
+ SharedImageHeader *h = static_cast<SharedImageHeader *>(data);
+ h->magic = 'Q';
+ h->version = 1;
+ h->offset = sizeof(SharedImageHeader);
+ h->width = img.width();
+ h->height = img.height();
+ h->bpl = img.bytesPerLine();
+ h->format = img.format();
+
+ uchar *p = static_cast<uchar *>(data) + sizeof(SharedImageHeader);
+ memcpy(p, img.constBits(), img.byteCount());
+}
+
+
+bool QSharedImageLoaderPrivate::verifyMem(const void *data, int size)
+{
+ if (!data || size < int(sizeof(SharedImageHeader)))
+ return false;
+
+ const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
+ if ((h->magic != 'Q')
+ || (h->version < 1)
+ || (h->offset < sizeof(SharedImageHeader))
+ || (h->width <= 0)
+ || (h->height <= 0)
+ || (h->bpl <= 0)
+ || (h->format <= QImage::Format_Invalid)
+ || (h->format >= QImage::NImageFormats)) {
+ return false;
+ }
+
+ int availSize = size - h->offset;
+ if (h->height * h->bpl > availSize)
+ return false;
+ if ((qt_depthForFormat(h->format) * h->width * h->height) > (8 * availSize))
+ return false;
+
+ return true;
+}
+
+
+QImage QSharedImageLoaderPrivate::createImageFromMem(const void *data, void *cleanupInfo)
+{
+ const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
+ const uchar *p = static_cast<const uchar *>(data) + h->offset;
+
+ QImage img(p, h->width, h->height, h->bpl, h->format, cleanupSharedImage, cleanupInfo);
+ return img;
+}
+
+
+QImage QSharedImageLoaderPrivate::load(const QString &path, QSharedImageLoader::ImageParameters *params)
+{
+#ifndef QT_NO_SHAREDMEMORY
+ Q_Q(QSharedImageLoader);
+
+ QImage nil;
+ if (path.isEmpty())
+ return nil;
+
+ QScopedPointer<QSharedMemory> shm(new QSharedMemory(q->key(path, params)));
+ bool locked = false;
+
+ if (!shm->attach(QSharedMemory::ReadOnly)) {
+ QImage img = q->loadFile(path, params);
+ if (img.isNull())
+ return nil;
+ int size = sizeof(SharedImageHeader) + img.byteCount();
+ if (shm->create(size)) {
+ qCDebug(lcSharedImage) << "Created new shm segment of size" << size << "for image" << path;
+ if (!shm->lock()) {
+ qCDebug(lcSharedImage) << "Lock1 failed!?" << shm->errorString();
+ return nil;
+ }
+ locked = true;
+ storeImageToMem(shm->data(), img);
+ } else if (shm->error() == QSharedMemory::AlreadyExists) {
+ // race handling: other process may have created the share while
+ // we loaded the image, so try again to just attach
+ if (!shm->attach(QSharedMemory::ReadOnly)) {
+ qCDebug(lcSharedImage) << "Attach to existing failed?" << shm->errorString();
+ return nil;
+ }
+ } else {
+ qCDebug(lcSharedImage) << "Create failed?" << shm->errorString();
+ return nil;
+ }
+ }
+
+ Q_ASSERT(shm->isAttached());
+
+ if (!locked) {
+ if (!shm->lock()) {
+ qCDebug(lcSharedImage) << "Lock2 failed!?" << shm->errorString();
+ return nil;
+ }
+ locked = true;
+ }
+
+ if (!verifyMem(shm->constData(), shm->size())) {
+ qCDebug(lcSharedImage) << "Verifymem failed!?";
+ shm->unlock();
+ return nil;
+ }
+
+ QSharedMemory *shmp = shm.take();
+ SharedImageInfo *sii = new SharedImageInfo;
+ sii->path = path;
+ sii->shmp = shmp;
+ QImage shImg = createImageFromMem(shmp->constData(), sii);
+
+ if (!shmp->unlock()) {
+ qCDebug(lcSharedImage) << "UnLock failed!?";
+ }
+
+ return shImg;
+#else
+ Q_UNUSED(path);
+ Q_UNUSED(params);
+ return QImage();
+#endif
+}
+
+
+QSharedImageLoader::QSharedImageLoader(QObject *parent)
+ : QObject(*new QSharedImageLoaderPrivate, parent)
+{
+}
+
+QSharedImageLoader::~QSharedImageLoader()
+{
+}
+
+QImage QSharedImageLoader::load(const QString &path, ImageParameters *params)
+{
+ Q_D(QSharedImageLoader);
+
+ return d->load(path, params);
+}
+
+QImage QSharedImageLoader::loadFile(const QString &path, ImageParameters *params)
+{
+ Q_UNUSED(params);
+
+ return QImage(path);
+}
+
+QString QSharedImageLoader::key(const QString &path, ImageParameters *params)
+{
+ Q_UNUSED(params);
+
+ return path;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/imports/sharedimage/qsharedimageloader_p.h b/src/imports/sharedimage/qsharedimageloader_p.h
new file mode 100644
index 0000000000..afb50e5088
--- /dev/null
+++ b/src/imports/sharedimage/qsharedimageloader_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHAREDIMAGELOADER_H
+#define QSHAREDIMAGELOADER_H
+
+#include <QImage>
+#include <QVariant>
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSharedImage);
+
+class QSharedImageLoaderPrivate;
+
+class QSharedImageLoader : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSharedImageLoader)
+
+public:
+ enum ImageParameter {
+ OriginalSize = 0,
+ RequestedSize,
+ NumImageParameters
+ };
+ typedef QVector<QVariant> ImageParameters;
+
+ QSharedImageLoader(QObject *parent = Q_NULLPTR);
+ ~QSharedImageLoader();
+
+ QImage load(const QString &path, ImageParameters *params = Q_NULLPTR);
+
+protected:
+ virtual QImage loadFile(const QString &path, ImageParameters *params);
+ virtual QString key(const QString &path, ImageParameters *params);
+
+private:
+ Q_DISABLE_COPY(QSharedImageLoader)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSHAREDIMAGELOADER_H
diff --git a/src/imports/sharedimage/sharedimage.pro b/src/imports/sharedimage/sharedimage.pro
new file mode 100644
index 0000000000..523de66ac1
--- /dev/null
+++ b/src/imports/sharedimage/sharedimage.pro
@@ -0,0 +1,17 @@
+CXX_MODULE = qml
+TARGET = sharedimageplugin
+TARGETPATH = QtQuick/SharedImage
+IMPORT_VERSION = 1.0
+
+QT *= quick qml gui-private core-private
+
+SOURCES += \
+ plugin.cpp \
+ sharedimageprovider.cpp \
+ qsharedimageloader.cpp
+
+HEADERS += \
+ sharedimageprovider.h \
+ qsharedimageloader_p.h
+
+load(qml_plugin)
diff --git a/src/imports/sharedimage/sharedimageprovider.cpp b/src/imports/sharedimage/sharedimageprovider.cpp
new file mode 100644
index 0000000000..2dd3a130e9
--- /dev/null
+++ b/src/imports/sharedimage/sharedimageprovider.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <sharedimageprovider.h>
+#include <qsharedimageloader_p.h>
+#include <qquickimageprovider.h>
+#include <private/qimage_p.h>
+#include <QImageReader>
+#include <QFileInfo>
+#include <QDir>
+
+class QuickSharedImageLoader : public QSharedImageLoader
+{
+ Q_OBJECT
+ friend class SharedImageProvider;
+
+public:
+ QuickSharedImageLoader(QObject *parent = Q_NULLPTR)
+ : QSharedImageLoader(parent)
+ {
+ }
+
+protected:
+ QImage loadFile(const QString &path, ImageParameters *params) override
+ {
+ QImageReader imgio(path);
+ QSize realSize = imgio.size();
+ QSize requestSize = params ? params->value(RequestedSize).toSize() : QSize();
+
+ // Following qquickpixmapcache's readImage, from here...
+ const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz";
+
+ if (requestSize.width() > 0 || requestSize.height() > 0) {
+ QSize s = realSize;
+ qreal ratio = 0.0;
+ if (requestSize.width() && (force_scale || requestSize.width() < s.width())) {
+ ratio = qreal(requestSize.width())/s.width();
+ }
+ if (requestSize.height() && (force_scale || requestSize.height() < s.height())) {
+ qreal hr = qreal(requestSize.height())/s.height();
+ if (ratio == 0.0 || hr < ratio)
+ ratio = hr;
+ }
+ if (ratio > 0.0) {
+ s.setHeight(qRound(s.height() * ratio));
+ s.setWidth(qRound(s.width() * ratio));
+ imgio.setScaledSize(s);
+ }
+ }
+ // ... to here
+
+ QImage image;
+ if (imgio.read(&image)) {
+ if (realSize.isEmpty())
+ realSize = image.size();
+ // Make sure we have acceptable format for texture uploader, or it will convert & lose sharing
+ // This mimics the testing & conversion normally done by the quick pixmapcache & texturefactory
+ if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied) {
+ QImage::Format newFmt = QImage::Format_RGB32;
+ if (image.hasAlphaChannel() && image.data_ptr()->checkForAlphaPixels())
+ newFmt = QImage::Format_ARGB32_Premultiplied;
+ qCDebug(lcSharedImage) << "Convert on load from format" << image.format() << "to" << newFmt;
+ image = image.convertToFormat(newFmt);
+ }
+ }
+
+ if (params && params->count() > OriginalSize)
+ params->replace(OriginalSize, realSize);
+
+ return image;
+ }
+
+ QString key(const QString &path, ImageParameters *params) override
+ {
+ QSize reqSz = params->value(RequestedSize).toSize();
+ if (!reqSz.isValid())
+ return path;
+
+ QString key = path + QStringLiteral("_%1x%2").arg(reqSz.width()).arg(reqSz.height());
+ qCDebug(lcSharedImage) << "KEY:" << key;
+ return key;
+ }
+};
+
+
+SharedImageProvider::SharedImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Image), loader(new QuickSharedImageLoader)
+{
+}
+
+QImage SharedImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ QFileInfo fi(QDir::root(), id);
+ QString path = fi.canonicalFilePath();
+ if (path.isEmpty())
+ return QImage();
+
+ QSharedImageLoader::ImageParameters params(QSharedImageLoader::NumImageParameters);
+ params[QSharedImageLoader::RequestedSize].setValue(requestedSize);
+
+ QImage img = loader->load(path, &params);
+ if (img.isNull()) {
+ // May be sharing problem, fall back to normal local load
+ img = loader->loadFile(path, &params);
+ if (!img.isNull())
+ qCWarning(lcSharedImage) << "Sharing problem; loading" << id << "unshared";
+ }
+
+ //... QSize realSize = params.value(QSharedImageLoader::OriginalSize).toSize();
+ // quickpixmapcache's readImage() reports back the original size, prior to requestedSize scaling, in the *size
+ // parameter. That value is currently ignored by quick however, which only cares about the present size of the
+ // returned image. So handling and sharing of info on pre-scaled size is currently not implemented.
+ if (size) {
+ *size = img.size();
+ }
+
+ return img;
+}
+
+#include "sharedimageprovider.moc"
diff --git a/src/imports/sharedimage/sharedimageprovider.h b/src/imports/sharedimage/sharedimageprovider.h
new file mode 100644
index 0000000000..a2f6b6ef2f
--- /dev/null
+++ b/src/imports/sharedimage/sharedimageprovider.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHAREDIMAGEPROVIDER_H
+#define SHAREDIMAGEPROVIDER_H
+
+#include <QQuickImageProvider>
+#include <QScopedPointer>
+
+class QuickSharedImageLoader;
+
+class SharedImageProvider : public QQuickImageProvider
+{
+public:
+ SharedImageProvider();
+
+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
+
+protected:
+ QScopedPointer<QuickSharedImageLoader> loader;
+};
+#endif // SHAREDIMAGEPROVIDER_H
diff --git a/src/particles/qquickcustomparticle_p.h b/src/particles/qquickcustomparticle_p.h
index 1d48786a41..e2292cb33b 100644
--- a/src/particles/qquickcustomparticle_p.h
+++ b/src/particles/qquickcustomparticle_p.h
@@ -53,7 +53,6 @@
#include "qquickparticlepainter_p.h"
#include <private/qquickopenglshadereffectnode_p.h>
#include <private/qquickopenglshadereffect_p.h>
-#include <QSignalMapper>
QT_BEGIN_NAMESPACE
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index ccfebddb0e..fde491b1ef 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -118,15 +118,15 @@ public:
Q_ASSERT(!m_fragment_code.isNull());
}
- const char *vertexShader() const { return m_vertex_code.constData(); }
- const char *fragmentShader() const { return m_fragment_code.constData(); }
+ const char *vertexShader() const override { return m_vertex_code.constData(); }
+ const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const {
+ QList<QByteArray> attributes() const override {
return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
<< "vColor" << "vDeformVec" << "vRotation";
};
- void initialize() {
+ void initialize() override {
QSGSimpleMaterialShader<TabledMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
@@ -138,7 +138,7 @@ public:
m_opacitytable_id = program()->uniformLocation("opacitytable");
}
- void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
+ void updateState(const TabledMaterialData* d, const TabledMaterialData*) override {
glFuncs->glActiveTexture(GL_TEXTURE1);
d->colorTable->bind();
@@ -192,15 +192,15 @@ public:
Q_ASSERT(!m_fragment_code.isNull());
}
- const char *vertexShader() const { return m_vertex_code.constData(); }
- const char *fragmentShader() const { return m_fragment_code.constData(); }
+ const char *vertexShader() const override { return m_vertex_code.constData(); }
+ const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const {
+ QList<QByteArray> attributes() const override {
return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
<< "vColor" << "vDeformVec" << "vRotation";
};
- void initialize() {
+ void initialize() override {
QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
@@ -209,7 +209,7 @@ public:
m_entry_id = program()->uniformLocation("entry");
}
- void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
+ void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override {
d->texture->bind();
program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
@@ -259,15 +259,15 @@ public:
Q_ASSERT(!m_fragment_code.isNull());
}
- const char *vertexShader() const { return m_vertex_code.constData(); }
- const char *fragmentShader() const { return m_fragment_code.constData(); }
+ const char *vertexShader() const override { return m_vertex_code.constData(); }
+ const char *fragmentShader() const override { return m_fragment_code.constData(); }
- QList<QByteArray> attributes() const {
+ QList<QByteArray> attributes() const override {
return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
<< "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
}
- void initialize() {
+ void initialize() override {
QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
@@ -280,7 +280,7 @@ public:
m_opacitytable_id = program()->uniformLocation("opacitytable");
}
- void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
+ void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override {
glFuncs->glActiveTexture(GL_TEXTURE1);
d->colorTable->bind();
@@ -333,10 +333,10 @@ public:
Q_ASSERT(!m_fragment_code.isNull());
}
- const char *vertexShader() const { return m_vertex_code.constData(); }
- const char *fragmentShader() const { return m_fragment_code.constData(); }
+ const char *vertexShader() const override { return m_vertex_code.constData(); }
+ const char *fragmentShader() const override { return m_fragment_code.constData(); }
- void activate() {
+ void activate() override {
QSGSimpleMaterialShader<ColoredMaterialData>::activate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glEnable(GL_POINT_SPRITE);
@@ -344,7 +344,7 @@ public:
#endif
}
- void deactivate() {
+ void deactivate() override {
QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glDisable(GL_POINT_SPRITE);
@@ -352,11 +352,11 @@ public:
#endif
}
- QList<QByteArray> attributes() const {
+ QList<QByteArray> attributes() const override {
return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
}
- void initialize() {
+ void initialize() override {
QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
@@ -365,7 +365,7 @@ public:
m_entry_id = program()->uniformLocation("entry");
}
- void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
+ void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override {
d->texture->bind();
program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
@@ -407,10 +407,10 @@ public:
Q_ASSERT(!m_fragment_code.isNull());
}
- const char *vertexShader() const { return m_vertex_code.constData(); }
- const char *fragmentShader() const { return m_fragment_code.constData(); }
+ const char *vertexShader() const override { return m_vertex_code.constData(); }
+ const char *fragmentShader() const override { return m_fragment_code.constData(); }
- void activate() {
+ void activate() override {
QSGSimpleMaterialShader<SimpleMaterialData>::activate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glEnable(GL_POINT_SPRITE);
@@ -418,7 +418,7 @@ public:
#endif
}
- void deactivate() {
+ void deactivate() override {
QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
glDisable(GL_POINT_SPRITE);
@@ -426,11 +426,11 @@ public:
#endif
}
- QList<QByteArray> attributes() const {
+ QList<QByteArray> attributes() const override {
return QList<QByteArray>() << "vPos" << "vData" << "vVec";
}
- void initialize() {
+ void initialize() override {
QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
program()->bind();
program()->setUniformValue("_qt_texture", 0);
@@ -439,7 +439,7 @@ public:
m_entry_id = program()->uniformLocation("entry");
}
- void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
+ void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override {
d->texture->bind();
program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp
index b60180b2ed..99e278238b 100644
--- a/src/particles/qquickparticlesystem.cpp
+++ b/src/particles/qquickparticlesystem.cpp
@@ -575,9 +575,6 @@ QQuickParticleSystem::QQuickParticleSystem(QQuickItem *parent) :
m_paused(false),
m_empty(true)
{
- connect(&m_painterMapper, SIGNAL(mapped(QObject*)),
- this, SLOT(loadPainter(QObject*)));
-
m_debugMode = qmlParticlesDebug();
}
@@ -615,8 +612,8 @@ void QQuickParticleSystem::registerParticlePainter(QQuickParticlePainter* p)
qDebug() << "Registering Painter" << p << "to" << this;
//TODO: a way to Unregister emitters, painters and affectors
m_painters << QPointer<QQuickParticlePainter>(p);//###Set or uniqueness checking?
- connect(p, SIGNAL(groupsChanged(QStringList)),
- &m_painterMapper, SLOT(map()));
+
+ connect(p, &QQuickParticlePainter::groupsChanged, this, [this, p] { this->loadPainter(p); }, Qt::QueuedConnection);
loadPainter(p);
}
@@ -802,13 +799,11 @@ void QQuickParticleSystem::reset()
}
-void QQuickParticleSystem::loadPainter(QObject *p)
+void QQuickParticleSystem::loadPainter(QQuickParticlePainter *painter)
{
- if (!m_componentComplete || !p)
+ if (!m_componentComplete || !painter)
return;
- QQuickParticlePainter* painter = qobject_cast<QQuickParticlePainter*>(p);
- Q_ASSERT(painter);//XXX
for (QQuickParticleGroupData* sg : groupData) {
sg->painters.removeOne(painter);
}
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index de39b436e2..92dca40419 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -56,7 +56,6 @@
#include <QVector>
#include <QHash>
#include <QPointer>
-#include <QSignalMapper>
#include <private/qquicksprite_p.h>
#include <QAbstractAnimation>
#include <QtQml/qqml.h>
@@ -393,7 +392,7 @@ protected:
private Q_SLOTS:
void emittersChanged();
- void loadPainter(QObject* p);
+ void loadPainter(QQuickParticlePainter *p);
void createEngine(); //Not invoked by sprite engine, unlike Sprite uses
void particleStateChange(int idx);
@@ -461,8 +460,6 @@ private:
QSet<int> m_reusableIndexes;
bool m_componentComplete;
- QSignalMapper m_painterMapper;
- QSignalMapper m_emitterMapper;
bool m_paused;
bool m_allDead;
bool m_empty;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index aed2759383..a4bad5618b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -273,9 +273,11 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
QV4::ScopedObject scopeObject(scope, engine()->newObject());
Q_ASSERT(names.size() == m_collectedRefs.size());
- for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i)
- scopeObject->put(engine(), names.at(i),
- QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i))));
+ QV4::ScopedString propName(scope);
+ for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
+ propName = engine()->newString(names.at(i));
+ scopeObject->put(propName, QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i))));
+ }
Ref scopeObjectRef = addRef(scopeObject);
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index df316c1ae6..d5fadad50a 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -90,12 +90,15 @@ void JavaScriptJob::run()
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext);
QV4::ScopedObject withContext(scope, engine->newObject());
+ QV4::ScopedString k(scope);
+ QV4::ScopedValue v(scope);
for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) {
QObject *object = ctxtPriv->instances.at(ii);
if (QQmlContext *context = qmlContext(object)) {
if (QQmlContextData *cdata = QQmlContextData::get(context)) {
- QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object));
- withContext->put(engine, cdata->findObjectId(object), v);
+ v = QV4::QObjectWrapper::wrap(engine, object);
+ k = engine->newString(cdata->findObjectId(object));
+ withContext->put(k, v);
}
}
}
diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
index 6152853917..97e4b4e3e4 100644
--- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
@@ -57,15 +57,15 @@ public:
QLocalClientConnection();
~QLocalClientConnection();
- void setServer(QQmlDebugServer *server);
- bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress);
- bool setFileName(const QString &filename, bool block);
+ void setServer(QQmlDebugServer *server) override;
+ bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) override;
+ bool setFileName(const QString &filename, bool block) override;
- bool isConnected() const;
- void disconnect();
+ bool isConnected() const override;
+ void disconnect() override;
- void waitForConnection();
- void flush();
+ void waitForConnection() override;
+ void flush() override;
private:
void connectionEstablished();
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
index f6f48e43a4..bcfb3b8a75 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
@@ -114,7 +114,7 @@ public:
return m_pluginName;
}
- void run();
+ void run() override;
private:
QQmlDebugServerImpl *m_server;
diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
index b305c3f535..af4f5292ba 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp
@@ -55,15 +55,15 @@ public:
QTcpServerConnection();
~QTcpServerConnection();
- void setServer(QQmlDebugServer *server);
- bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress);
- bool setFileName(const QString &fileName, bool block);
+ void setServer(QQmlDebugServer *server) override;
+ bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) override;
+ bool setFileName(const QString &fileName, bool block) override;
- bool isConnected() const;
- void disconnect();
+ bool isConnected() const override;
+ void disconnect() override;
- void waitForConnection();
- void flush();
+ void waitForConnection() override;
+ void flush() override;
private:
void newConnection();
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h
index f1ab580a84..f828843227 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h
@@ -86,6 +86,7 @@ public:
void setDevicePixelRatio(qreal ratio) override;
void setMirrorHorizontal(bool mirror) override;
void setMirrorVertical(bool mirror) override;
+ void setSamples(int) override { }
public Q_SLOTS:
void markDirtyTexture() override;
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
index 8be2a97034..9cf4184c20 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
@@ -43,6 +43,7 @@
#include "qsgopenvghelpers.h"
#include "qsgopenvgfontglyphcache.h"
#include "qopenvgoffscreensurface.h"
+#include <cmath>
QT_BEGIN_NAMESPACE
@@ -143,7 +144,7 @@ void QSGOpenVGGlyphNode::render()
vgLoadMatrix(transform().constData());
} else {
vgLoadIdentity();
- offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_bounding_rect.width()), ceil(m_bounding_rect.height())));
+ offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_bounding_rect.width()), std::ceil(m_bounding_rect.height())));
offscreenSurface->makeCurrent();
}
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
index be437303bc..0bd51cbf46 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
@@ -39,7 +39,7 @@
#include "qsgopenvginternalrectanglenode.h"
#include "qsgopenvghelpers.h"
-
+#include <cmath>
#include <VG/vgu.h>
QSGOpenVGInternalRectangleNode::QSGOpenVGInternalRectangleNode()
@@ -207,9 +207,9 @@ void QSGOpenVGInternalRectangleNode::render()
vgLoadIdentity();
if (m_radius > 0) {
// Fallback to rendering to an image for rounded rects with perspective transforms
- if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(ceil(m_rect.width()), ceil(m_rect.height()))) {
+ if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) {
delete m_offscreenSurface;
- m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_rect.width()), ceil(m_rect.height())));
+ m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height())));
}
m_offscreenSurface->makeCurrent();
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 1de5dfa6fa..fa66d3a6e3 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -39,7 +39,10 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(qml-interpreter) {
+qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+}
+
+qmldevtools_build|qtConfig(qml-interpreter) {
HEADERS += \
$$PWD/qv4instr_moth_p.h \
$$PWD/qv4isel_moth_p.h
@@ -48,6 +51,3 @@ qtConfig(qml-interpreter) {
$$PWD/qv4isel_moth.cpp
}
-
-qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
-}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 54d0cb4f46..030f485504 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1605,7 +1605,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
scan.leaveEnvironment();
- _env = 0;
+ _variableEnvironment = 0;
_function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
@@ -2061,4 +2061,156 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
return 0;
}
+IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
+ : unit(qmlData)
+ , output(output)
+{
+ pool = output->jsParserEngine.pool();
+}
+
+void IRLoader::load()
+{
+ output->jsGenerator.stringTable.clear();
+ for (uint i = 0; i < unit->stringTableSize; ++i)
+ output->jsGenerator.stringTable.registerString(unit->stringAt(i));
+
+ for (quint32 i = 0; i < unit->nImports; ++i)
+ output->imports << unit->importAt(i);
+
+ if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
+ QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ p->location = QV4::CompiledData::Location();
+ p->type = QmlIR::Pragma::PragmaSingleton;
+ output->pragmas << p;
+ }
+
+ output->indexOfRootObject = unit->indexOfRootObject;
+
+ for (uint i = 0; i < unit->nObjects; ++i) {
+ const QV4::CompiledData::Object *serializedObject = unit->objectAt(i);
+ QmlIR::Object *object = loadObject(serializedObject);
+ output->objects.append(object);
+ }
+}
+
+struct FakeExpression : public QQmlJS::AST::NullExpression
+{
+ FakeExpression(int start, int length)
+ : location(start, length)
+ {}
+
+ virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ { return location; }
+
+ virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ { return location; }
+
+private:
+ QQmlJS::AST::SourceLocation location;
+};
+
+QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+{
+ QmlIR::Object *object = pool->New<QmlIR::Object>();
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+
+ object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
+ object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
+
+ object->location = serializedObject->location;
+ object->locationOfIdProperty = serializedObject->locationOfIdProperty;
+
+ QVector<int> functionIndices;
+ functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
+
+ for (uint i = 0; i < serializedObject->nBindings; ++i) {
+ QmlIR::Binding *b = pool->New<QmlIR::Binding>();
+ *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
+ object->bindings->append(b);
+ if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ functionIndices.append(b->value.compiledScriptIndex);
+ b->value.compiledScriptIndex = functionIndices.count() - 1;
+
+ QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
+ foe->disableAcceleratedLookups = true;
+ foe->nameIndex = 0;
+
+ QQmlJS::AST::ExpressionNode *expr;
+
+ if (b->stringIndex != quint32(0)) {
+ const int start = output->code.length();
+ const QString script = output->stringAt(b->stringIndex);
+ const int length = script.length();
+ output->code.append(script);
+ expr = new (pool) FakeExpression(start, length);
+ } else
+ expr = new (pool) QQmlJS::AST::NullExpression();
+ foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
+ object->functionsAndExpressions->append(foe);
+ }
+ }
+
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+
+ for (uint i = 0; i < serializedObject->nSignals; ++i) {
+ const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
+ QmlIR::Signal *s = pool->New<QmlIR::Signal>();
+ s->nameIndex = serializedSignal->nameIndex;
+ s->location = serializedSignal->location;
+ s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
+
+ for (uint i = 0; i < serializedSignal->nParameters; ++i) {
+ QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
+ *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
+ s->parameters->append(p);
+ }
+
+ object->qmlSignals->append(s);
+ }
+
+ const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
+ for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
+ QmlIR::Property *p = pool->New<QmlIR::Property>();
+ *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
+ object->properties->append(p);
+ }
+
+ QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
+
+ const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
+ for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
+ QmlIR::Function *f = pool->New<QmlIR::Function>();
+ const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
+
+ functionIndices.append(*functionIdx);
+ f->index = functionIndices.count() - 1;
+ f->location = compiledFunction->location;
+ f->nameIndex = compiledFunction->nameIndex;
+
+ QQmlJS::AST::FormalParameterList *paramList = 0;
+ const QV4::CompiledData::LEUInt32 *formalNameIdx = compiledFunction->formalsTable();
+ for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) {
+ const QString formal = unit->stringAt(*formalNameIdx);
+ QStringRef paramNameRef = jsParserEngine->newStringRef(formal);
+
+ if (paramList)
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ const QString name = unit->stringAt(compiledFunction->nameIndex);
+ f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0);
+
+ object->functions->append(f);
+ }
+
+ object->runtimeFunctionIndices.allocate(pool, functionIndices);
+
+ return object;
+}
+
#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 95756845c3..2022112e07 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -622,6 +622,21 @@ private:
int _importedScriptsTemp;
};
+struct IRLoader {
+ IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
+
+ void load();
+
+private:
+ QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
+
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
+
+ const QV4::CompiledData::Unit *unit;
+ QmlIR::Document *output;
+ QQmlJS::MemoryPool *pool;
+};
+
} // namespace QmlIR
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index ab2b0553a9..85267225be 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -57,12 +57,12 @@
QT_BEGIN_NAMESPACE
QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, typeData(typeData)
- , importCache(importCache)
+ , typeNameCache(typeNameCache)
, document(parsedQML)
{
}
@@ -138,7 +138,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
sss.scan();
}
- QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
+ QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
@@ -164,7 +164,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
compilationUnit = document->javaScriptCompilationUnit;
- compilationUnit->importCache = importCache;
+ compilationUnit->typeNameCache = typeNameCache;
compilationUnit->resolvedTypes = resolvedTypes;
compilationUnit->propertyCaches = std::move(m_propertyCaches);
Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects));
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index de6abb4ced..2b59e7e42f 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -89,7 +89,7 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
@@ -139,7 +139,7 @@ private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
QQmlTypeData *typeData;
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 46c27fc735..0afc97e4bf 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -73,10 +73,29 @@ static inline void setLocation(IR::Stmt *s, const SourceLocation &loc)
s->location = loc;
}
+static bool cjumpCanHandle(IR::AluOp op)
+{
+ switch (op) {
+ case IR::OpIn:
+ case IR::OpInstanceof:
+ case IR::OpEqual:
+ case IR::OpNotEqual:
+ case IR::OpGe:
+ case IR::OpGt:
+ case IR::OpLe:
+ case IR::OpLt:
+ case IR::OpStrictEqual:
+ case IR::OpStrictNotEqual:
+ return true;
+ default:
+ return false;
+ }
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
- , _env(0)
+ , _variableEnvironment(0)
, _allowFuncDecls(true)
, defaultProgramMode(defaultProgramMode)
{
@@ -90,17 +109,17 @@ void Codegen::ScanFunctions::operator()(Node *node)
void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Environment *e = _cg->newEnvironment(node, _env, compilationMode);
+ Environment *e = _cg->newEnvironment(node, _variableEnvironment, compilationMode);
if (!e->isStrict)
e->isStrict = _cg->_strictMode;
_envStack.append(e);
- _env = e;
+ _variableEnvironment = e;
}
void Codegen::ScanFunctions::leaveEnvironment()
{
_envStack.pop();
- _env = _envStack.isEmpty() ? 0 : _envStack.top();
+ _variableEnvironment = _envStack.isEmpty() ? 0 : _envStack.top();
}
void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
@@ -116,7 +135,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
continue;
QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
if (str == QLatin1String("use strict")) {
- _env->isStrict = true;
+ _variableEnvironment->isStrict = true;
} else {
// TODO: give a warning.
}
@@ -131,7 +150,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
if (name == QLatin1String("implements")
|| name == QLatin1String("interface")
|| name == QLatin1String("let")
@@ -149,7 +168,7 @@ void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *paramet
{
while (parameters) {
if (parameters->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
parameters = parameters->next;
}
}
@@ -168,19 +187,19 @@ void Codegen::ScanFunctions::endVisit(Program *)
bool Codegen::ScanFunctions::visit(CallExpression *ast)
{
- if (! _env->hasDirectEval) {
+ if (! _variableEnvironment->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
- _env->hasDirectEval = true;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ _variableEnvironment->hasDirectEval = true;
}
}
}
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -189,7 +208,7 @@ bool Codegen::ScanFunctions::visit(NewMemberExpression *ast)
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -205,26 +224,38 @@ bool Codegen::ScanFunctions::visit(ArrayLiteral *ast)
for (Elision *elision = ast->elision->next; elision; elision = elision->next)
++index;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, index);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, index);
return true;
}
bool Codegen::ScanFunctions::visit(VariableDeclaration *ast)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
checkName(ast->name, ast->identifierToken);
if (ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration);
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ if (ast->scope == AST::VariableDeclaration::VariableScope::ReadOnlyBlockScope && !ast->expression) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
+ return false;
+ }
+ QString name = ast->name.toString();
+ const Environment::Member *m = 0;
+ if (_variableEnvironment->memberInfo(name, &m)) {
+ if (m->isLexicallyScoped() || ast->isLexicallyScoped()) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
+ }
+ }
+ _variableEnvironment->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration, ast->scope);
return true;
}
bool Codegen::ScanFunctions::visit(IdentifierExpression *ast)
{
checkName(ast->name, ast->identifierToken);
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
return true;
}
@@ -256,7 +287,7 @@ bool Codegen::ScanFunctions::visit(FunctionExpression *ast)
void Codegen::ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName, bool isExpression)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression);
}
@@ -277,7 +308,7 @@ bool Codegen::ScanFunctions::visit(ObjectLiteral *ast)
if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
++argc;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
Node::accept(ast->properties, this);
@@ -309,7 +340,7 @@ void Codegen::ScanFunctions::endVisit(FunctionDeclaration *)
bool Codegen::ScanFunctions::visit(WithStatement *ast)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
_cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
return false;
}
@@ -319,7 +350,7 @@ bool Codegen::ScanFunctions::visit(WithStatement *ast)
bool Codegen::ScanFunctions::visit(DoWhileStatement *ast) {
{
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
}
Node::accept(ast->expression, this);
@@ -331,7 +362,7 @@ bool Codegen::ScanFunctions::visit(ForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -342,7 +373,7 @@ bool Codegen::ScanFunctions::visit(LocalForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -352,7 +383,7 @@ bool Codegen::ScanFunctions::visit(ForEachStatement *ast) {
Node::accept(ast->initialiser, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -362,7 +393,7 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
Node::accept(ast->declaration, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -370,12 +401,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
bool Codegen::ScanFunctions::visit(ThisExpression *)
{
- _env->usesThis = true;
+ _variableEnvironment->usesThis = true;
return false;
}
bool Codegen::ScanFunctions::visit(Block *ast) {
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _variableEnvironment->isStrict ? false : _allowFuncDecls);
Node::accept(ast->statements, this);
return false;
}
@@ -383,26 +414,26 @@ bool Codegen::ScanFunctions::visit(Block *ast) {
void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression)
{
bool wasStrict = false;
- if (_env) {
- _env->hasNestedFunctions = true;
+ if (_variableEnvironment) {
+ _variableEnvironment->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
if (expr)
- _env->enter(name, Environment::FunctionDefinition, expr);
+ _variableEnvironment->enter(name, Environment::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
if (name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- wasStrict = _env->isStrict;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ wasStrict = _variableEnvironment->isStrict;
}
enterEnvironment(ast, FunctionCode);
checkForArguments(formals);
- _env->isNamedFunctionExpression = isExpression && !name.isEmpty();
- _env->formals = formals;
+ _variableEnvironment->isNamedFunctionExpression = isExpression && !name.isEmpty();
+ _variableEnvironment->formals = formals;
if (body)
checkDirectivePrologue(body->elements);
- if (wasStrict || _env->isStrict) {
+ if (wasStrict || _variableEnvironment->isStrict) {
QStringList args;
for (FormalParameterList *it = formals; it; it = it->next) {
QString arg = it->name.toString();
@@ -426,7 +457,7 @@ Codegen::Codegen(bool strict)
, _block(0)
, _exitBlock(0)
, _returnAddress(0)
- , _env(0)
+ , _variableEnvironment(0)
, _loop(0)
, _labelledStatement(0)
, _scopeAndFinally(0)
@@ -446,7 +477,7 @@ void Codegen::generateFromProgram(const QString &fileName,
Q_ASSERT(node);
_module = module;
- _env = 0;
+ _variableEnvironment = 0;
_module->setFileName(fileName);
@@ -465,7 +496,7 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
{
_module = module;
_module->setFileName(fileName);
- _env = 0;
+ _variableEnvironment = 0;
ScanFunctions scan(this, sourceCode, GlobalCode);
// fake a global environment
@@ -482,14 +513,14 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
void Codegen::enterEnvironment(Node *node)
{
- _env = _envMap.value(node);
- Q_ASSERT(_env);
+ _variableEnvironment = _envMap.value(node);
+ Q_ASSERT(_variableEnvironment);
}
void Codegen::leaveEnvironment()
{
- Q_ASSERT(_env);
- _env = _env->parent;
+ Q_ASSERT(_variableEnvironment);
+ _variableEnvironment = _variableEnvironment->parent;
}
void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock)
@@ -611,7 +642,7 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
if (IR::Const *c1 = left->asConst()) {
if (IR::Const *c2 = right->asConst()) {
- if (c1->type == IR::NumberType && c2->type == IR::NumberType) {
+ if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) {
switch (op) {
case IR::OpAdd: return _block->CONST(IR::NumberType, c1->value + c2->value);
case IR::OpAnd: return _block->CONST(IR::BoolType, c1->value ? c2->value : 0);
@@ -659,20 +690,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
}
}
- if (!left->asTemp() && !left->asArgLocal()) {
+ if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), left), loc);
left = _block->TEMP(t);
}
- if (!right->asTemp() && !right->asArgLocal()) {
+ if (!right->asTemp() && !right->asArgLocal() && !right->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), right), loc);
right = _block->TEMP(t);
}
- Q_ASSERT(left->asTemp() || left->asArgLocal());
- Q_ASSERT(right->asTemp() || right->asArgLocal());
+ Q_ASSERT(left->asTemp() || left->asArgLocal() || left->asConst());
+ Q_ASSERT(right->asTemp() || right->asArgLocal() || right->asConst());
return _block->BINOP(op, left, right);
}
@@ -715,7 +746,7 @@ IR::Stmt *Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock
if (hasError)
return 0;
- if (! (cond->asTemp() || cond->asBinop())) {
+ if (! (cond->asTemp() || (cond->asBinop() && cjumpCanHandle(cond->asBinop()->op)) )) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), cond);
cond = _block->TEMP(t);
@@ -842,9 +873,16 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
Q_ASSERT(expr.code);
initializer = *expr;
- int initialized = _block->newTemp();
- move(_block->TEMP(initialized), initializer);
- move(identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), _block->TEMP(initialized));
+ IR::Expr *lhs = identifier(ast->name.toString(), ast->identifierToken.startLine,
+ ast->identifierToken.startColumn);
+
+ if (lhs->asArgLocal()) {
+ move(lhs, initializer);
+ } else {
+ int initialized = _block->newTemp();
+ move(_block->TEMP(initialized), initializer);
+ move(lhs, _block->TEMP(initialized));
+ }
}
void Codegen::variableDeclarationList(VariableDeclarationList *ast)
@@ -1274,14 +1312,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (_expr.accept(cx)) {
setLocation(cjump(binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken);
} else {
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
- if (e->asConst() || e->asString())
- _expr.code = e;
- else {
- const unsigned t = _block->newTemp();
- setLocation(move(_block->TEMP(t), e), ast->operatorToken);
- _expr.code = _block->TEMP(t);
- }
+ _expr.code = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
}
break;
}
@@ -1307,14 +1338,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (hasError)
return false;
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
- if (e->asConst() || e->asString())
- _expr.code = e;
- else {
- const unsigned t = _block->newTemp();
- setLocation(move(_block->TEMP(t), e), ast->operatorToken);
- _expr.code = _block->TEMP(t);
- }
+ _expr.code = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken);
break;
}
@@ -1389,7 +1413,7 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
// Temporaries cannot be deleted
IR::ArgLocal *al = expr->asArgLocal();
- if (al && al->index < static_cast<unsigned>(_env->members.size())) {
+ if (al && al->index < static_cast<unsigned>(_variableEnvironment->members.size())) {
// Trying to delete a function argument might throw.
if (_function->isStrict) {
throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
@@ -1418,7 +1442,7 @@ bool Codegen::visit(DeleteExpression *ast)
}
if (expr->asTemp() ||
(expr->asArgLocal() &&
- expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) {
+ expr->asArgLocal()->index >= static_cast<unsigned>(_variableEnvironment->members.size()))) {
_expr.code = _block->CONST(IR::BoolType, 1);
return false;
}
@@ -1469,7 +1493,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
return 0;
uint scope = 0;
- Environment *e = _env;
+ Environment *e = _variableEnvironment;
IR::Function *f = _function;
while (f && e->parent) {
@@ -1500,7 +1524,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
if (IR::Expr *fallback = fallbackNameLookup(name, line, col))
return fallback;
- if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
+ if (!e->parent && (!f || !f->insideWithOrCatch) && _variableEnvironment->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
// global context or with. Lookup by name
@@ -1995,7 +2019,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
if (hasError)
return false;
- if (_env->compilationMode == QmlBinding)
+ if (_variableEnvironment->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
return false;
@@ -2019,26 +2043,26 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::BasicBlock *entryBlock = function->newBasicBlock(0);
IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock);
- function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode
+ function->hasDirectEval = _variableEnvironment->hasDirectEval || _variableEnvironment->compilationMode == EvalCode
|| _module->debugMode; // Conditional breakpoints are like eval in the function
- function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
- function->usesThis = _env->usesThis;
- function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
- function->isStrict = _env->isStrict;
- function->isNamedExpression = _env->isNamedFunctionExpression;
- function->isQmlBinding = _env->compilationMode == QmlBinding;
+ function->usesArgumentsObject = _variableEnvironment->parent && (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+ function->usesThis = _variableEnvironment->usesThis;
+ function->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
+ function->isStrict = _variableEnvironment->isStrict;
+ function->isNamedExpression = _variableEnvironment->isNamedFunctionExpression;
+ function->isQmlBinding = _variableEnvironment->compilationMode == QmlBinding;
AST::SourceLocation loc = ast->firstSourceLocation();
function->line = loc.startLine;
function->column = loc.startColumn;
if (function->usesArgumentsObject)
- _env->enter(QStringLiteral("arguments"), Environment::VariableDeclaration);
+ _variableEnvironment->enter(QStringLiteral("arguments"), Environment::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
// variables in global code are properties of the global context object, not locals as with other functions.
- if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == FunctionCode || _variableEnvironment->compilationMode == QmlBinding) {
unsigned t = 0;
- for (Environment::MemberMap::iterator it = _env->members.begin(), end = _env->members.end(); it != end; ++it) {
+ for (Environment::MemberMap::iterator it = _variableEnvironment->members.begin(), end = _variableEnvironment->members.end(); it != end; ++it) {
const QString &local = it.key();
function->LOCAL(local);
(*it).index = t;
@@ -2046,18 +2070,19 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
++t;
}
} else {
- if (!_env->isStrict) {
+ if (!_variableEnvironment->isStrict) {
for (const QString &inheritedLocal : qAsConst(inheritedLocals)) {
function->LOCAL(inheritedLocal);
unsigned tempIndex = entryBlock->newTemp();
Environment::Member member = { Environment::UndefinedMember,
- static_cast<int>(tempIndex), 0 };
- _env->members.insert(inheritedLocal, member);
+ static_cast<int>(tempIndex), 0,
+ AST::VariableDeclaration::VariableScope::FunctionScope };
+ _variableEnvironment->members.insert(inheritedLocal, member);
}
}
IR::ExprList *args = 0;
- for (Environment::MemberMap::const_iterator it = _env->members.constBegin(), cend = _env->members.constEnd(); it != cend; ++it) {
+ for (Environment::MemberMap::const_iterator it = _variableEnvironment->members.constBegin(), cend = _variableEnvironment->members.constEnd(); it != cend; ++it) {
const QString &local = it.key();
IR::ExprList *next = function->New<IR::ExprList>();
next->expr = entryBlock->NAME(local, 0, 0);
@@ -2089,11 +2114,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- for (const Environment::Member &member : qAsConst(_env->members)) {
+ for (const Environment::Member &member : qAsConst(_variableEnvironment->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
- if (! _env->parent) {
+ if (! _variableEnvironment->parent) {
move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
_block->CLOSURE(function));
} else {
@@ -2269,7 +2294,7 @@ bool Codegen::visit(ExpressionStatement *ast)
if (hasError)
return true;
- if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == EvalCode || _variableEnvironment->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
move(_block->TEMP(_returnAddress), *e);
@@ -2505,7 +2530,7 @@ bool Codegen::visit(ReturnStatement *ast)
if (hasError)
return true;
- if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding) {
+ if (_variableEnvironment->compilationMode != FunctionCode && _variableEnvironment->compilationMode != QmlBinding) {
throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
return false;
}
@@ -2883,7 +2908,7 @@ bool Codegen::visit(UiSourceElement *)
bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, const SourceLocation& loc)
{
- if (!_env->isStrict)
+ if (!_variableEnvironment->isStrict)
return false;
if (IR::Name *n = expr->asName()) {
if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments"))
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 742ee79648..239ed5c4b9 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -141,10 +141,14 @@ protected:
VariableDeclaration,
FunctionDefinition
};
+
struct Member {
MemberType type;
int index;
AST::FunctionExpression *function;
+ AST::VariableDeclaration::VariableScope scope;
+
+ bool isLexicallyScoped() const { return this->scope != AST::VariableDeclaration::FunctionScope; }
};
typedef QMap<QString, Member> MemberMap;
@@ -191,6 +195,18 @@ protected:
return (*it).index;
}
+ bool memberInfo(const QString &name, const Member **m) const
+ {
+ Q_ASSERT(m);
+ MemberMap::const_iterator it = members.find(name);
+ if (it == members.end()) {
+ *m = 0;
+ return false;
+ }
+ *m = &(*it);
+ return true;
+ }
+
bool lookupMember(const QString &name, Environment **scope, int *index, int *distance)
{
Environment *it = this;
@@ -206,7 +222,7 @@ protected:
return false;
}
- void enter(const QString &name, MemberType type, AST::FunctionExpression *function = 0)
+ void enter(const QString &name, MemberType type, AST::VariableDeclaration::VariableScope scope, AST::FunctionExpression *function = 0)
{
if (! name.isEmpty()) {
if (type != FunctionDefinition) {
@@ -220,8 +236,10 @@ protected:
m.index = -1;
m.type = type;
m.function = function;
+ m.scope = scope;
members.insert(name, m);
} else {
+ Q_ASSERT(scope == (*it).scope);
if ((*it).type <= type) {
(*it).type = type;
(*it).function = function;
@@ -448,7 +466,7 @@ protected:
QV4::IR::BasicBlock *_block;
QV4::IR::BasicBlock *_exitBlock;
unsigned _returnAddress;
- Environment *_env;
+ Environment *_variableEnvironment;
Loop *_loop;
AST::LabelledStatement *_labelledStatement;
ScopeAndFinally *_scopeAndFinally;
@@ -526,7 +544,7 @@ protected:
// fields:
Codegen *_cg;
const QString _sourceCode;
- Environment *_env;
+ Environment *_variableEnvironment;
QStack<Environment *> _envStack;
bool _allowFuncDecls;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 6aac111897..8f8d374e24 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -52,7 +52,6 @@
#include "qv4compilationunitmapper_p.h"
#include <QQmlPropertyMap>
#include <QDateTime>
-#include <QSaveFile>
#include <QFile>
#include <QFileInfo>
#include <QScopedValueRollback>
@@ -62,6 +61,7 @@
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
+#include <QSaveFile>
#include <algorithm>
@@ -77,6 +77,27 @@ namespace QV4 {
namespace CompiledData {
+#ifdef V4_BOOTSTRAP
+static QString cacheFilePath(const QString &localSourcePath)
+{
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ return localCachePath;
+}
+#else
+static QString cacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ return localCachePath;
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+}
+#endif
+
#ifndef V4_BOOTSTRAP
CompilationUnit::CompilationUnit()
: data(0)
@@ -207,7 +228,7 @@ void CompilationUnit::unlink()
dependentScripts.at(ii)->release();
dependentScripts.clear();
- importCache = nullptr;
+ typeNameCache = nullptr;
qDeleteAll(resolvedTypes);
resolvedTypes.clear();
@@ -329,20 +350,68 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
-static QString cacheFilePath(const QUrl &url)
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString localCachePath = localSourcePath + QLatin1Char('c');
- if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
- return localCachePath;
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ if (!mappedUnit)
+ return false;
+
+ const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
+ QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+
+ if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ *errorString = QStringLiteral("QML source file has moved to a different location.");
+ return false;
+ }
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
}
+#endif // V4_BOOTSTRAP
+
+#if defined(V4_BOOTSTRAP)
+bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
+#else
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+#endif
{
errorString->clear();
@@ -351,10 +420,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return false;
}
+#if !defined(V4_BOOTSTRAP)
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
+#endif
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(cacheFilePath(unitUrl));
@@ -390,78 +461,105 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
+ Q_UNUSED(unit);
+}
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
- if (!mappedUnit)
- return false;
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+ if (!irDocument->javaScriptCompilationUnit->data)
+ return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
+ QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
- if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- return false;
- }
+ QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
- {
- const QString foundArchitecture = stringAt(data->architectureIndex);
- const QString expectedArchitecture = QSysInfo::buildAbi();
- if (foundArchitecture != expectedArchitecture) {
- *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
- return false;
+ // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
+ // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
+ // the string table.
+ QVector<quint32> changedSignals;
+ QVector<QQmlJS::AST::FormalParameterList*> changedSignalParameters;
+ for (QmlIR::Object *o: qAsConst(irDocument->objects)) {
+ for (QmlIR::Binding *binding = o->firstBinding(); binding; binding = binding->next) {
+ if (!(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression))
+ continue;
+
+ quint32 functionIndex = binding->value.compiledScriptIndex;
+ QmlIR::CompiledFunctionOrExpression *foe = o->functionsAndExpressions->slowAt(functionIndex);
+ if (!foe)
+ continue;
+
+ // save absolute index
+ changedSignals << o->runtimeFunctionIndices.at(functionIndex);
+
+ Q_ASSERT(foe->node);
+ Q_ASSERT(QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node));
+
+ QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals;
+ changedSignalParameters << parameters;
+
+ for (; parameters; parameters = parameters->next)
+ stringTable.registerString(parameters->name.toString());
}
}
- {
- const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
- const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
- if (foundCodeGenerator != expectedCodeGenerator) {
- *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
- return false;
+ QVector<quint32> signalParameterNameTable;
+ quint32 signalParameterNameTableOffset = jsUnit->unitSize;
+
+ // Update signal signatures
+ if (!changedSignals.isEmpty()) {
+ if (jsUnit == compilationUnit->data) {
+ char *unitCopy = (char*)malloc(jsUnit->unitSize);
+ memcpy(unitCopy, jsUnit, jsUnit->unitSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
}
- }
- if (!memoryMapCode(errorString))
- return false;
+ for (int i = 0; i < changedSignals.count(); ++i) {
+ const uint functionIndex = changedSignals.at(i);
+ // The data is now read-write due to the copy above, so the const_cast is ok.
+ QV4::CompiledData::Function *function = const_cast<QV4::CompiledData::Function *>(jsUnit->functionAt(functionIndex));
+ Q_ASSERT(function->nFormals == quint32(0));
- dataPtrChange.commit();
- free(const_cast<Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
-}
+ function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex];
-void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
-{
- Q_UNUSED(unit);
-}
+ for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i);
+ parameters; parameters = parameters->next) {
+ signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString()));
+ function->nFormals = function->nFormals + 1;
+ }
-bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
-{
- Q_UNUSED(device);
- Q_UNUSED(unit);
- *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
- return false;
-}
+ // Hack to ensure an activation is created.
+ function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval;
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- *errorString = QStringLiteral("Missing code mapping backend");
- return false;
-}
-#endif // V4_BOOTSTRAP
+ signalParameterNameTableOffset += function->nFormals * sizeof(quint32);
+ }
+ }
-Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
-{
- return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
+ if (!signalParameterNameTable.isEmpty()) {
+ Q_ASSERT(jsUnit != compilationUnit->data);
+ const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
+ uint newSize = jsUnit->unitSize + signalParameterTableSize;
+ const uint oldSize = jsUnit->unitSize;
+ char *unitWithSignalParameters = (char*)realloc(jsUnit, newSize);
+ memcpy(unitWithSignalParameters + oldSize, signalParameterNameTable.constData(), signalParameterTableSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitWithSignalParameters);
+ jsUnit->unitSize = newSize;
+ }
+
+ if (jsUnit != compilationUnit->data)
+ jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
+
+ return jsUnit;
}
QString Binding::valueAsString(const Unit *unit) const
@@ -624,7 +722,7 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
Dl_info libInfo;
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2682365182..13a0c4b075 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x08
+#define QV4_DATA_STRUCTURE_VERSION 0x09
class QIODevice;
class QQmlPropertyCache;
@@ -133,7 +133,7 @@ struct Location
QJsonPrivate::qle_bitfield<20, 12> column;
};
- Location() { line = 0; column = 0; }
+ Location() { line.val = 0; column.val = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -153,7 +153,7 @@ struct RegExp
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
- RegExp() { flags = 0; stringIndex = 0; }
+ RegExp() { flags.val = 0; stringIndex.val = 0; }
};
struct Lookup
@@ -171,7 +171,7 @@ struct Lookup
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
- Lookup() { type_and_flags = 0; nameIndex = 0; }
+ Lookup() { type_and_flags.val = 0; nameIndex.val = 0; }
};
struct JSClassMember
@@ -625,7 +625,8 @@ struct Unit
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10, // .pragma shared?
- ContainsMachineCode = 0x20 // used to determine if we need to mmap with execute permissions
+ ContainsMachineCode = 0x20, // used to determine if we need to mmap with execute permissions
+ PendingTypeCompilation = 0x40 // the QML data structures present are incomplete and require type compilation
};
LEUInt32 flags;
LEUInt32 stringTableSize;
@@ -777,31 +778,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
};
#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : type(0)
- , majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType *type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
+struct ResolvedTypeReference;
// map from name index
// While this could be a hash, a map is chosen here to provide a stable
// order, which is used to calculating a check-sum on dependent meta-objects.
@@ -841,10 +818,14 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
#ifndef V4_BOOTSTRAP
ExecutionEngine *engine;
+#endif
+
+ QV4::Heap::String **runtimeStrings; // Array
+
+#ifndef V4_BOOTSTRAP
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QV4::Heap::String **runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
@@ -855,7 +836,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QQmlPropertyCacheVector propertyCaches;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
// index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive
@@ -918,17 +899,53 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
void destroy() Q_DECL_OVERRIDE;
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
- virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
- virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
virtual bool memoryMapCode(QString *errorString);
#endif // V4_BOOTSTRAP
+
+public:
+#if defined(V4_BOOTSTRAP)
+ bool saveToDisk(const QString &unitUrl, QString *errorString);
+#else
+ bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+#endif
+
+protected:
+ virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
+ virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
};
+#ifndef V4_BOOTSTRAP
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : type(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType *type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
+
+ void doDynamicTypeCheck();
+};
+#endif
+
}
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index cd822a2614..9cfac4a676 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -220,7 +220,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
- CompiledData::LEUInt32 *functionOffsets = reinterpret_cast<CompiledData::LEUInt32*>(alloca(irModule->functions.size() * sizeof(CompiledData::LEUInt32)));
+ Q_ALLOCA_VAR(CompiledData::LEUInt32, functionOffsets, irModule->functions.size() * sizeof(CompiledData::LEUInt32));
uint jsClassDataOffset = 0;
char *dataPtr;
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index ca4e0b73d4..53d9956315 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -52,10 +52,11 @@
//
#include <private/qv4global_p.h>
#include <private/qv4value_p.h>
-#include <private/qv4function_p.h>
#include <private/qv4runtime_p.h>
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 9dbebd1128..04844302d9 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -39,15 +39,15 @@
#include "qv4isel_util_p.h"
#include "qv4isel_moth_p.h"
-#include "qv4vme_moth_p.h"
#include "qv4ssa_p.h"
-#include <private/qv4debugging_p.h>
-#include <private/qv4function_p.h>
-#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmlengine_p.h>
#include <wtf/MathExtras.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4vme_moth_p.h"
+#include <private/qv4function_p.h>
+#endif
+
#undef USE_TYPE_INFO
using namespace QV4;
@@ -1185,8 +1185,11 @@ void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
void InstructionSelection::callBuiltinPopScope()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinPopScope call;
addInstruction(call);
+ QT_WARNING_POP
}
void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
@@ -1335,8 +1338,11 @@ void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
void QV4::Moth::InstructionSelection::callBuiltinConvertThisToObject()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinConvertThisToObject call;
addInstruction(call);
+ QT_WARNING_POP
}
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
@@ -1425,6 +1431,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
#ifdef MOTH_THREADED_INTERPRETER
@@ -1461,6 +1469,31 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
+#ifdef MOTH_THREADED_INTERPRETER
+ // for the threaded interpreter we need to make a copy of the data because it needs to be
+ // modified for the instruction handler addresses.
+ QByteArray code(codePtr, compiledFunction->codeSize);
+#else
+ QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
+#endif
+ codeRefs[i] = code;
+ }
+
+ return true;
+}
+
+#endif // V4_BOOTSTRAP
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -1482,7 +1515,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray padding;
-#ifdef MOTH_THREADED_INTERPRETER
+#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
// Map from instruction label back to instruction type. Only needed when persisting
// already linked compilation units;
QHash<void*, int> reverseInstructionMapping;
@@ -1511,7 +1544,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray code = codeRefs.at(i);
-#ifdef MOTH_THREADED_INTERPRETER
+#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
if (!reverseInstructionMapping.isEmpty()) {
char *codePtr = code.data(); // detaches
int index = 0;
@@ -1541,29 +1574,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
-#ifdef MOTH_THREADED_INTERPRETER
- // for the threaded interpreter we need to make a copy of the data because it needs to be
- // modified for the instruction handler addresses.
- QByteArray code(codePtr, compiledFunction->codeSize);
-#else
- QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
-#endif
- codeRefs[i] = code;
- }
-
- return true;
-}
-
QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index afe5fe342e..41469f1985 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -59,7 +59,9 @@
#include <private/qv4value_p.h>
#include "qv4instr_moth_p.h"
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
@@ -69,10 +71,12 @@ namespace Moth {
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
QVector<QByteArray> codeRefs;
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 73aa6c4975..04bc3d86e5 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -315,20 +315,20 @@ struct Q_AUTOTEST_EXPORT Expr {
Expr(ExprKind exprKind): type(UnknownType), exprKind(exprKind) {}
bool isLValue() const;
- Const *asConst() { return as<Const>(); }
- String *asString() { return as<String>(); }
- RegExp *asRegExp() { return as<RegExp>(); }
- Name *asName() { return as<Name>(); }
- Temp *asTemp() { return as<Temp>(); }
- ArgLocal *asArgLocal() { return as<ArgLocal>(); }
- Closure *asClosure() { return as<Closure>(); }
- Convert *asConvert() { return as<Convert>(); }
- Unop *asUnop() { return as<Unop>(); }
- Binop *asBinop() { return as<Binop>(); }
- Call *asCall() { return as<Call>(); }
- New *asNew() { return as<New>(); }
- Subscript *asSubscript() { return as<Subscript>(); }
- Member *asMember() { return as<Member>(); }
+ Const *asConst();
+ String *asString();
+ RegExp *asRegExp();
+ Name *asName();
+ Temp *asTemp();
+ ArgLocal *asArgLocal();
+ Closure *asClosure();
+ Convert *asConvert();
+ Unop *asUnop();
+ Binop *asBinop();
+ Call *asCall();
+ New *asNew();
+ Subscript *asSubscript();
+ Member *asMember();
};
#define EXPR_VISIT_ALL_KINDS(e) \
@@ -773,12 +773,12 @@ struct Stmt {
Stmt *asTerminator();
- Exp *asExp() { return as<Exp>(); }
- Move *asMove() { return as<Move>(); }
- Jump *asJump() { return as<Jump>(); }
- CJump *asCJump() { return as<CJump>(); }
- Ret *asRet() { return as<Ret>(); }
- Phi *asPhi() { return as<Phi>(); }
+ Exp *asExp();
+ Move *asMove();
+ Jump *asJump();
+ CJump *asCJump();
+ Ret *asRet();
+ Phi *asPhi();
int id() const { return _id; }
@@ -1720,6 +1720,28 @@ inline Stmt *BasicBlock::RET(Expr *expr)
return s;
}
+inline Const *Expr::asConst() { return as<Const>(); }
+inline String *Expr::asString() { return as<String>(); }
+inline RegExp *Expr::asRegExp() { return as<RegExp>(); }
+inline Name *Expr::asName() { return as<Name>(); }
+inline Temp *Expr::asTemp() { return as<Temp>(); }
+inline ArgLocal *Expr::asArgLocal() { return as<ArgLocal>(); }
+inline Closure *Expr::asClosure() { return as<Closure>(); }
+inline Convert *Expr::asConvert() { return as<Convert>(); }
+inline Unop *Expr::asUnop() { return as<Unop>(); }
+inline Binop *Expr::asBinop() { return as<Binop>(); }
+inline Call *Expr::asCall() { return as<Call>(); }
+inline New *Expr::asNew() { return as<New>(); }
+inline Subscript *Expr::asSubscript() { return as<Subscript>(); }
+inline Member *Expr::asMember() { return as<Member>(); }
+
+inline Exp *Stmt::asExp() { return as<Exp>(); }
+inline Move *Stmt::asMove() { return as<Move>(); }
+inline Jump *Stmt::asJump() { return as<Jump>(); }
+inline CJump *Stmt::asCJump() { return as<CJump>(); }
+inline Ret *Stmt::asRet() { return as<Ret>(); }
+inline Phi *Stmt::asPhi() { return as<Phi>(); }
+
} // end of namespace IR
} // end of namespace QV4
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 1d512711b8..10f0bbcf8f 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -5123,7 +5123,7 @@ void LifeTimeInterval::setFrom(int from) {
Q_ASSERT(from > 0);
if (_ranges.isEmpty()) { // this is the case where there is no use, only a define
- _ranges.prepend(Range(from, from));
+ _ranges.prepend(LifeTimeIntervalRange(from, from));
if (_end == InvalidPosition)
_end = from;
} else {
@@ -5137,17 +5137,17 @@ void LifeTimeInterval::addRange(int from, int to) {
Q_ASSERT(to >= from);
if (_ranges.isEmpty()) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
_end = to;
return;
}
- Range *p = &_ranges.first();
+ LifeTimeIntervalRange *p = &_ranges.first();
if (to + 1 >= p->start && p->end + 1 >= from) {
p->start = qMin(p->start, from);
p->end = qMax(p->end, to);
while (_ranges.count() > 1) {
- Range *p1 = p + 1;
+ LifeTimeIntervalRange *p1 = p + 1;
if (p->end + 1 < p1->start || p1->end + 1 < p->start)
break;
p1->start = qMin(p->start, p1->start);
@@ -5157,10 +5157,10 @@ void LifeTimeInterval::addRange(int from, int to) {
}
} else {
if (to < p->start) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
} else {
Q_ASSERT(from > _ranges.last().end);
- _ranges.push_back(Range(from, to));
+ _ranges.push_back(LifeTimeIntervalRange(from, to));
}
}
@@ -5206,7 +5206,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
} else {
// find the first range where the temp will get active again:
while (!newInterval._ranges.isEmpty()) {
- const Range &range = newInterval._ranges.first();
+ const LifeTimeIntervalRange &range = newInterval._ranges.first();
if (range.start > newStart) {
// The split position is before the start of the range. Either we managed to skip
// over the correct range, or we got an invalid split request. Either way, this
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index db8b6edd1a..c07abd04c4 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -63,20 +63,28 @@ class QQmlEnginePrivate;
namespace QV4 {
namespace IR {
-class Q_AUTOTEST_EXPORT LifeTimeInterval {
-public:
- struct Range {
- int start;
- int end;
+struct LifeTimeIntervalRange {
+ int start;
+ int end;
- Range(int start = InvalidPosition, int end = InvalidPosition)
- : start(start)
- , end(end)
- {}
+ LifeTimeIntervalRange(int start = -1, int end = -1)
+ : start(start)
+ , end(end)
+ {}
- bool covers(int position) const { return start <= position && position <= end; }
- };
- typedef QVarLengthArray<Range, 4> Ranges;
+ bool covers(int position) const { return start <= position && position <= end; }
+};
+} // IR namespace
+} // QV4 namespace
+
+Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeIntervalRange, Q_PRIMITIVE_TYPE);
+
+namespace QV4 {
+namespace IR {
+
+class Q_AUTOTEST_EXPORT LifeTimeInterval {
+public:
+ typedef QVarLengthArray<LifeTimeIntervalRange, 4> Ranges;
private:
Temp _temp;
@@ -137,7 +145,7 @@ public:
// Validate the new range
if (_end != InvalidPosition) {
Q_ASSERT(!_ranges.isEmpty());
- for (const Range &range : qAsConst(_ranges)) {
+ for (const LifeTimeIntervalRange &range : qAsConst(_ranges)) {
Q_ASSERT(range.start >= 0);
Q_ASSERT(range.end >= 0);
Q_ASSERT(range.start <= range.end);
@@ -457,7 +465,6 @@ protected:
Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval::Range, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 3a507bef74..41fb2c5b7b 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -73,7 +73,7 @@ struct QQmlProfiler {};
struct QQmlBindingProfiler
{
- QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {}
+ QQmlBindingProfiler(quintptr, QV4::Function *) {}
};
struct QQmlHandlingSignalProfiler
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index ac6600f38c..4523ee39d8 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -167,9 +167,9 @@ additional features. See the \l {qtqml-javascript-hostenvironment.html}
The QML engine provides automatic type conversion between QVariantList and
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
-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
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
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
-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
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
@@ -215,7 +215,7 @@ is received in C++:
\table
\header
\row
-
+\li QML
\li
\qml
// MyItem.qml
@@ -227,6 +227,7 @@ Item {
}
\endqml
\row
+\li C++
\li
\code
// C++
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index e06451b2bc..7d4a543089 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -282,6 +282,9 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
template<typename T, int metaObjectRevision>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+
+template<typename T, typename E, int metaObjectRevision>
+int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
\endcode
For example, if \c BaseType is changed and now has a revision 1, you can
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index ed0d049564..3bffd2eb6f 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -390,8 +390,8 @@ that is a public slot:
\endcode
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
-methods, as shown below right:
+MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
+examples below:
\table
\row
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index a349fd0713..1aa3bb6ab5 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -30,7 +30,7 @@
\brief Description of how to integrate QML and C++ code
QML is designed to be easily extensible through C++ code. The classes in the \l {Qt QML} module
-enables QML objects to be loaded and manipulated from C++, and the nature of QML engine's
+enable QML objects to be loaded and manipulated from C++, and the nature of QML engine's
integration with Qt's \l{Meta Object System}{meta object system} enables C++ functionality to be
invoked directly from QML. This allows the development of hybrid applications which are implemented
with a mixture of QML, JavaScript and C++ code.
diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc
index f5b1ed3cf1..fd916e1e24 100644
--- a/src/qml/doc/src/javascript/functionlist.qdoc
+++ b/src/qml/doc/src/javascript/functionlist.qdoc
@@ -182,6 +182,7 @@
\li lastIndexOf(searchString, position)
\li localeCompare(that)
\li match(regexp)
+ \li repeat(count) // ECMAScript 6: Added in Qt 5.9
\li replace(searchValue, replaceValue)
\li search(regexp)
\li slice(start, end)
diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc
index d4ce25c92b..489da08ada 100644
--- a/src/qml/doc/src/javascript/imports.qdoc
+++ b/src/qml/doc/src/javascript/imports.qdoc
@@ -56,10 +56,10 @@ import "jsfile.js" as Logic
\endcode
Imported JavaScript resources are always qualified using the "as" keyword. The
-qualifier for JavaScript resources must be unique, so there is always a
-one-to-one mapping between qualifiers and JavaScript files. (This also means
-qualifiers cannot be named the same as built-in JavaScript objects such as
-\c Date and \c Math).
+qualifier for JavaScript resources must start with an uppercase letter, and must
+be unique, so there is always a one-to-one mapping between qualifiers and JavaScript
+files. (This also means qualifiers cannot be named the same as built-in JavaScript
+objects such as \c Date and \c Math).
The functions defined in an imported JavaScript file are available to objects
defined in the importing QML document, via the
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 030eb72b5f..33f58dc1b9 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -630,7 +630,7 @@ a \l {MouseArea::}{clicked} signal that is emitted when the user clicks
within the mouse area.
An object can be notified through a \l{Signal handler attributes}
-{signal handler} whenever it a particular signal is emitted. A signal handler
+{signal handler} whenever a particular signal is emitted. A signal handler
is declared with the syntax \e on<Signal> where \e <Signal> is the name of the
signal, with the first letter capitalized. The signal handler must be declared
within the definition of the object that emits the signal, and the handler
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
index ffbf2282a6..a486b47f03 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
@@ -324,6 +324,9 @@ property is only invoked when the property is reassigned to a different object v
\li Values in the list are accessed using the \c [index] syntax
\endlist
+ Values can be dynamically added to the list by using the \c push method,
+ as if it were a JavaScript Array
+
A \c list can only store QML objects, and cannot contain any
\l {QML Basic Types}{basic type} values. (To store basic types within a
list, use the \l var type instead.)
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index f32574fcc1..b2bb9ebd18 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -89,7 +89,7 @@ provided:
\ingroup qtquickbasictypes
\brief a date value.
-The \c date type refers to a date value.
+The \c date type refers to a date value, including the time of the day.
To create a \c date value, specify it as a "YYYY-MM-DD" string:
@@ -100,7 +100,7 @@ MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" }
To read a date value returned from a C++ extension class, use
\l{QtQml::Qt::formatDate()}{Qt.formatDate()} and \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
-When integrating with C++, note that any QDate value
+When integrating with C++, note that any QDate or QDateTime value
\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
converted into a \c date value, and vice-versa.
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 018396318e..ca270a0648 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -39,11 +39,6 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
-#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -51,6 +46,10 @@
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4function_p.h"
+#endif
+
#include <iostream>
#include <QBuffer>
#include <QCoreApplication>
@@ -68,6 +67,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
{
runtimeFunctions.resize(data->functionTableSize);
@@ -81,6 +82,26 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
+ JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
+ JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
+ codeRefs[i] = codeRef;
+ }
+
+ return true;
+}
+
+#endif // !defined(V4_BOOTSTRAP)
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -128,27 +149,11 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
+template <typename TargetConfiguration>
+const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
- JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
- JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
- codeRefs[i] = codeRef;
- }
-
- return true;
-}
-
-const Assembler::VoidType Assembler::Void;
-
-Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
+template <typename TargetConfiguration>
+Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
: _function(function)
, _nextBlock(0)
, _executableAllocator(executableAllocator)
@@ -159,14 +164,16 @@ Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function*
_labelPatches.resize(_function->basicBlockCount());
}
-void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
{
_addrs[block->index()] = label();
catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
-void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
{
Q_UNUSED(current);
@@ -174,12 +181,14 @@ void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
_patches[target->index()].push_back(jump());
}
-void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
{
_patches[targetBlock->index()].push_back(targetJump);
}
-void Assembler::addPatch(DataLabelPtr patch, Label target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, Label target)
{
DataLabelPatch p;
p.dataLabel = patch;
@@ -187,37 +196,21 @@ void Assembler::addPatch(DataLabelPtr patch, Label target)
_dataLabelPatches.push_back(p);
}
-void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
{
_labelPatches[target->index()].push_back(patch);
}
-void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
-}
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
- RegisterID left,
- TrustedImm64 right,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- if (trueBlock == _nextBlock) {
- Jump target = branch64(invert(cond), left, right);
- addPatch(falseBlock, target);
- } else {
- Jump target = branch64(cond, left, right);
- addPatch(trueBlock, target);
- jumpToBlock(currentBlock, falseBlock);
- }
+ generateCJumpOnCompare(RelationalCondition::NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
}
-#endif
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
TrustedImm32 right,
IR::BasicBlock *currentBlock,
@@ -234,7 +227,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
RegisterID right,
IR::BasicBlock *currentBlock,
@@ -251,7 +245,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e)
{
IR::Temp *t = e->asTemp();
if (t)
@@ -260,7 +255,8 @@ Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
return loadArgLocalAddress(tmp, e->asArgLocal());
}
-Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadTempAddress(IR::Temp *t)
{
if (t->kind == IR::Temp::StackSlot)
return stackSlotPointer(t);
@@ -268,7 +264,8 @@ Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
Q_UNREACHABLE();
}
-Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
{
int32_t offset = 0;
int scope = al->scope;
@@ -298,7 +295,8 @@ Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLoc
return Pointer(baseReg, offset);
}
-Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
@@ -307,12 +305,14 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
return Pointer(reg, id * sizeof(QV4::String*));
}
-Assembler::Address Assembler::loadConstant(IR::Const *c, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
{
return loadConstant(convertToValue(c), baseReg);
}
-Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
@@ -320,33 +320,36 @@ Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseRe
return Address(baseReg, index * sizeof(QV4::Value));
}
-void Assembler::loadStringRef(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString &string)
{
const int id = _jsGenerator->registerString(string);
move(TrustedImm32(id), reg);
}
-void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
{
Address addr = loadAddress(ScratchRegister, destination);
storeValue(value, addr);
}
-void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
platformEnterStandardStackFrame(this);
- move(StackPointerRegister, FramePointerRegister);
+ move(StackPointerRegister, JITTargetPlatform::FramePointerRegister);
const int frameSize = _stackLayout->calculateStackFrameSize();
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- Address slotAddr(FramePointerRegister, 0);
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, 0);
for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
slotAddr.offset -= sizeof(double);
- JSC::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
+ TargetConfiguration::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
}
for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister());
@@ -355,10 +358,11 @@ void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegist
}
}
-void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
- Address slotAddr(FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
// restore the callee saved registers
for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) {
@@ -368,23 +372,14 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
}
for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
- JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
+ TargetConfiguration::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
slotAddr.offset += sizeof(double);
}
Q_ASSERT(slotAddr.offset == 0);
const int frameSize = _stackLayout->calculateStackFrameSize();
- // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
- // 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);
+ platformLeaveStandardStackFrame(this, frameSize);
}
@@ -393,7 +388,8 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
// Try to load the source expression into the destination FP register. This assumes that two
// general purpose (integer) registers are available: the ScratchRegister and the
// ReturnValueRegister. It returns a Jump if no conversion can be performed.
-Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::genTryDoubleConversion(IR::Expr *src, FPRegisterID dest)
{
switch (src->type) {
case IR::DoubleType:
@@ -436,11 +432,10 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
isNoInt.link(this);
#ifdef QV4_USE_64_BIT_VALUE_ENCODING
rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Equal, ScratchRegister, TrustedImm32(0));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0));
#else
and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask));
#endif
toDoubleRegister(src, dest);
intDone.link(this);
@@ -448,10 +443,11 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
return isNoDbl;
}
-Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchDouble(bool invertCondition, IR::AluOp op,
IR::Expr *left, IR::Expr *right)
{
- Assembler::DoubleCondition cond;
+ DoubleCondition cond;
switch (op) {
case IR::OpGt: cond = Assembler::DoubleGreaterThan; break;
case IR::OpLt: cond = Assembler::DoubleLessThan; break;
@@ -465,12 +461,13 @@ Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, FPGpr1));
+ return TargetConfiguration::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, JITTargetPlatform::FPGpr1));
}
-Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
{
Assembler::RelationalCondition cond;
switch (op) {
@@ -486,18 +483,51 @@ Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::E
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branch32(cond,
- toInt32Register(left, Assembler::ScratchRegister),
- toInt32Register(right, Assembler::ReturnValueRegister));
+ return TargetConfiguration::MacroAssembler::branch32(cond,
+ toInt32Register(left, Assembler::ScratchRegister),
+ toInt32Register(right, Assembler::ReturnValueRegister));
}
-void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
{
_stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave));
}
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave)
+{
+ if (!s) {
+ // this only happens if the method doesn't have a return statement and can
+ // only exit through an exception
+ } else if (IR::Temp *t = s->expr->asTemp()) {
+ RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
+ } else if (IR::Const *c = s->expr->asConst()) {
+ QV4::Primitive retVal = convertToValue(c);
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ } else {
+ Q_UNREACHABLE();
+ Q_UNUSED(s);
+ }
+
+ Label leaveStackFrame = label();
+
+ const int locals = stackLayout().calculateJSStackFrameSize();
+ subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
+ loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister);
+ storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+
+ leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
+ ret();
+
+ exceptionReturnLabel = label();
+ QV4::Primitive retVal = Primitive::undefinedValue();
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ jump(leaveStackFrame);
+}
namespace {
class QIODevicePrintStream: public FilePrintStream
@@ -516,7 +546,7 @@ public:
~QIODevicePrintStream()
{}
- void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
+ void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0)
{
const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
if (written > 0)
@@ -524,7 +554,7 @@ public:
memset(buf.data(), 0, qMin(written, buf.size()));
}
- void flush()
+ void flush() override
{}
private:
@@ -563,7 +593,8 @@ static void qt_closePmap()
#endif
-JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
+template <typename TargetConfiguration>
+JSC::MacroAssemblerCodeRef Assembler<TargetConfiguration>::link(int *codeSize)
{
Label endOfCode = label();
@@ -577,7 +608,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
}
JSC::JSGlobalData dummy(_executableAllocator);
- JSC::LinkBuffer linkBuffer(dummy, this, 0);
+ JSC::LinkBuffer<typename TargetConfiguration::MacroAssembler> linkBuffer(dummy, this, 0);
for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
@@ -668,4 +699,14 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
+template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
+#if defined(V4_BOOTSTRAP)
+#if !CPU(ARM_THUMB2)
+template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+#endif
+#if !CPU(ARM64)
+template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
+#endif
+#endif
+
#endif
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index de9c246ed6..fd65c9b3d2 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -55,7 +55,8 @@
#include "private/qv4isel_p.h"
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
-#include "private/qv4lookup_p.h"
+#include "private/qv4context_p.h"
+#include "private/qv4engine_p.h"
#include "qv4targetplatform_p.h"
#include <config.h>
@@ -73,46 +74,671 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class InstructionSelection;
-
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
// Coderef + execution engine
QVector<JSC::MacroAssemblerCodeRef> codeRefs;
};
-struct LookupCall {
- JSC::MacroAssembler::Address addr;
- uint getterSetterOffset;
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization Specialization>
+struct AssemblerTargetConfiguration
+{
+ typedef JSC::MacroAssembler<PlatformAssembler> MacroAssembler;
+ typedef TargetPlatform<PlatformAssembler, Specialization> Platform;
+ // More things coming here in the future, such as Target OS
+};
+
+#if CPU(ARM_THUMB2)
+typedef JSC::MacroAssemblerARMv7 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM64)
+typedef JSC::MacroAssemblerARM64 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM_TRADITIONAL)
+typedef JSC::MacroAssemblerARM DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(MIPS)
+typedef JSC::MacroAssemblerMIPS DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86)
+typedef JSC::MacroAssemblerX86 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86_64)
+typedef JSC::MacroAssemblerX86_64 DefaultPlatformMacroAssembler;
+
+#if OS(WINDOWS)
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, WindowsSpecialization> DefaultAssemblerTargetConfiguration;
+#else
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
- LookupCall(const JSC::MacroAssembler::Address &addr, uint getterSetterOffset)
- : addr(addr)
- , getterSetterOffset(getterSetterOffset)
- {}
+#elif CPU(SH4)
+typedef JSC::MacroAssemblerSH4 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
+
+#define isel_stringIfyx(s) #s
+#define isel_stringIfy(s) isel_stringIfyx(s)
+
+#define generateRuntimeCall(as, t, function, ...) \
+ as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
+
+
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform, int RegisterSize>
+struct RegisterSizeDependentAssembler
+{
};
-struct RuntimeCall {
- JSC::MacroAssembler::Address addr;
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 4>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Jump = typename JITAssembler::Jump;
+ using Label = typename JITAssembler::Label;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->MacroAssembler::loadDouble(addr, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->MacroAssembler::storeDouble(source, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->storeDouble(source, ptr);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store32(TrustedImm32(value.int_32()), destination);
+ destination.offset += 4;
+ as->store32(TrustedImm32(value.tag()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ as->loadDouble(source, TargetPlatform::FPGpr0);
+ as->storeDouble(TargetPlatform::FPGpr0, destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ as->MacroAssembler::loadDouble(as->loadConstant(c, TargetPlatform::ScratchRegister), target);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ Address destination = dest;
+ as->store32(TargetPlatform::LowReturnValueRegister, destination);
+ destination.offset += 4;
+ as->store32(TargetPlatform::HighReturnValueRegister, destination);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ const auto lowReg = TargetPlatform::LowReturnValueRegister;
+ const auto highReg = TargetPlatform::HighReturnValueRegister;
+
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ switch (t->type) {
+ case IR::DoubleType:
+ as->moveDoubleToInts((FPRegisterID) t->index, lowReg, highReg);
+ break;
+ case IR::UInt32Type: {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(JITAssembler::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleToInts(TargetPlatform::FPGpr0, lowReg, highReg);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->move(srcReg, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ done.link(as);
+ } break;
+ case IR::SInt32Type:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ break;
+ case IR::BoolType:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ } else {
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t);
+ as->load32(addr, lowReg);
+ addr.offset += 4;
+ as->load32(addr, highReg);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister);
+ as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(temp);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(al);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(c);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(expr);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm32(0), reg);
+ }
+
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->poke(TrustedImm32(0), slot);
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer tagAddr = as->loadAddress(scratchRegister, right);
+ as->load32(tagAddr, tagRegister);
+ Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
+ as->addPatch(falseBlock, j);
+
+ tagAddr.offset += 4;
+ as->load32(tagAddr, tagRegister);
+ const TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
+ Q_ASSERT(nextBlock == as->nextBlock());
+ Q_UNUSED(nextBlock);
+ as->generateCJumpOnCompare(cond, tagRegister, tag, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ // load the tag:
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
+ tagAddr.offset += 4;
+ as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
+
+ // check if it's an int32:
+ Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ as->load32(addr, TargetPlatform::ReturnValueRegister);
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->load32(addr, (RegisterID) targetTemp->index);
+ }
+ Jump intDone = as->jump();
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+
+ intDone.link(as);
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store32(registerWithPtr, destAddr);
+ destAddr.offset += 4;
+ as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->and32(TrustedImm32(Value::NotDouble_Mask), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ TrustedImm32(Value::NotDouble_Mask));
+ }
- inline RuntimeCall(uint offset = uint(INT_MIN));
- bool isValid() const { return addr.offset >= 0; }
+ 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);
+ }
};
-class Assembler : public JSC::MacroAssembler, public TargetPlatform
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 8>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using Address = typename JITAssembler::Address;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Pointer = typename JITAssembler::Pointer;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using Jump = typename JITAssembler::Jump;
+ using Label = typename JITAssembler::Label;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->load64(addr, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->store64(TargetPlatform::ReturnValueRegister, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store64(TargetPlatform::ReturnValueRegister, ptr);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ as->store64(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ if (t->type == IR::DoubleType) {
+ as->moveDoubleTo64((FPRegisterID) t->index,
+ TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask),
+ TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ } else if (t->type == IR::UInt32Type) {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
+ quint64 tag = QV4::Value::Integer_Type_Internal;
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ done.link(as);
+ } else {
+ as->zeroExtend32ToPtr((RegisterID) t->index, TargetPlatform::ReturnValueRegister);
+ quint64 tag;
+ switch (t->type) {
+ case IR::SInt32Type:
+ tag = QV4::Value::Integer_Type_Internal;
+ break;
+ case IR::BoolType:
+ tag = QV4::Value::Boolean_Type_Internal;
+ break;
+ default:
+ tag = 31337; // bogus value
+ Q_UNREACHABLE();
+ }
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ }
+ } else {
+ as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store64(TrustedImm64(value.rawValue()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ // Use ReturnValueRegister as "scratch" register because loadArgument
+ // and storeArgument are functions that may need a scratch register themselves.
+ loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0);
+ as->storeReturnValue(destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
+ int64_t i;
+ memcpy(&i, &c->value, sizeof(double));
+ as->move(TrustedImm64(i), TargetPlatform::ReturnValueRegister);
+ 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)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (temp) {
+ Pointer addr = as->loadTempAddress(temp);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (al) {
+ Pointer addr = as->loadArgLocalAddress(dest, al);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ QV4::Value v = convertToValue(c);
+ as->move(TrustedImm64(v.rawValue()), dest);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (!expr) {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ } else if (IR::Temp *t = expr->asTemp()){
+ loadArgumentInRegister(as, t, dest, argumentNumber);
+ } else if (IR::ArgLocal *al = expr->asArgLocal()) {
+ loadArgumentInRegister(as, al, dest, argumentNumber);
+ } else if (IR::Const *c = expr->asConst()) {
+ loadArgumentInRegister(as, c, dest, argumentNumber);
+ } else {
+ Q_ASSERT(!"unimplemented expression type in loadArgument");
+ }
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm64(0), reg);
+ }
+
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->store64(TrustedImm64(0), as->addressForPoke(slot));
+ }
+
+ static void generateCJumpOnCompare(JITAssembler *as,
+ RelationalCondition cond,
+ RegisterID left,
+ TrustedImm64 right,
+ IR::BasicBlock *nextBlock,
+ IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ if (trueBlock == nextBlock) {
+ Jump target = as->branch64(as->invert(cond), left, right);
+ as->addPatch(falseBlock, target);
+ } else {
+ Jump target = as->branch64(cond, left, right);
+ as->addPatch(trueBlock, target);
+ as->jumpToBlock(currentBlock, falseBlock);
+ }
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer addr = as->loadAddress(scratchRegister, right);
+ as->load64(addr, tagRegister);
+ const TrustedImm64 tag(0);
+ generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ as->load64(addr, TargetPlatform::ScratchRegister);
+ as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+
+ // check if it's integer convertible
+ as->urshift64(TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), TargetPlatform::ScratchRegister);
+ Jump isIntConvertible = as->branch32(RelationalCondition::Equal, TargetPlatform::ScratchRegister, TrustedImm32(3));
+
+ // nope, not integer convertible, so check for a double:
+ as->urshift64(TrustedImm32(
+ QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
+ TargetPlatform::ScratchRegister);
+ Jump fallback = as->branch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0));
+
+ // it's a double
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0);
+ Jump success =
+ as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+
+
+ isIntConvertible.link(as);
+ success.link(as);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+ }
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store64(registerWithPtr, destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ 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>
+class Assembler : public TargetConfiguration::MacroAssembler, public TargetConfiguration::Platform
{
Q_DISABLE_COPY(Assembler)
public:
Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
+ using MacroAssembler = typename TargetConfiguration::MacroAssembler;
+ using RegisterID = typename MacroAssembler::RegisterID;
+ using FPRegisterID = typename MacroAssembler::FPRegisterID;
+ using Address = typename MacroAssembler::Address;
+ using Label = typename MacroAssembler::Label;
+ using Jump = typename MacroAssembler::Jump;
+ using DataLabelPtr = typename MacroAssembler::DataLabelPtr;
+ using TrustedImm32 = typename MacroAssembler::TrustedImm32;
+ using TrustedImm64 = typename MacroAssembler::TrustedImm64;
+ using TrustedImmPtr = typename MacroAssembler::TrustedImmPtr;
+ using RelationalCondition = typename MacroAssembler::RelationalCondition;
+ using typename MacroAssembler::DoubleCondition;
+ using MacroAssembler::label;
+ using MacroAssembler::move;
+ using MacroAssembler::jump;
+ using MacroAssembler::add32;
+ using MacroAssembler::and32;
+ using MacroAssembler::store32;
+ using MacroAssembler::loadPtr;
+ using MacroAssembler::load32;
+ using MacroAssembler::branch32;
+ using MacroAssembler::subDouble;
+ using MacroAssembler::subPtr;
+ using MacroAssembler::addPtr;
+ using MacroAssembler::call;
+ using MacroAssembler::poke;
+ using MacroAssembler::branchTruncateDoubleToUint32;
+ using MacroAssembler::or32;
+ using MacroAssembler::moveDouble;
+ using MacroAssembler::convertUInt32ToDouble;
+ using MacroAssembler::invert;
+ using MacroAssembler::convertInt32ToDouble;
+ using MacroAssembler::rshift32;
+ using MacroAssembler::storePtr;
+ using MacroAssembler::ret;
+
+ using JITTargetPlatform = typename TargetConfiguration::Platform;
+ using JITTargetPlatform::RegisterArgumentCount;
+ using JITTargetPlatform::StackSpaceAllocatedUponFunctionEntry;
+ using JITTargetPlatform::RegisterSize;
+ using JITTargetPlatform::StackAlignment;
+ using JITTargetPlatform::ReturnValueRegister;
+ using JITTargetPlatform::StackPointerRegister;
+ using JITTargetPlatform::ScratchRegister;
+ using JITTargetPlatform::EngineRegister;
+ using JITTargetPlatform::StackShadowSpace;
+ using JITTargetPlatform::registerForArgument;
+ using JITTargetPlatform::FPGpr0;
+ using JITTargetPlatform::platformEnterStandardStackFrame;
+ using JITTargetPlatform::platformLeaveStandardStackFrame;
+
+ using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+
+ struct LookupCall {
+ Address addr;
+ uint getterSetterOffset;
+
+ LookupCall(const Address &addr, uint getterSetterOffset)
+ : addr(addr)
+ , getterSetterOffset(getterSetterOffset)
+ {}
+ };
+
+ struct RuntimeCall {
+ Address addr;
+
+ inline RuntimeCall(uint offset = uint(INT_MIN));
+ bool isValid() const { return addr.offset >= 0; }
+ };
+
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
// to onto the stack when calling functions.
@@ -319,20 +945,29 @@ public:
void addPatch(DataLabelPtr patch, IR::BasicBlock *target);
void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm64 right,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock);
-#endif
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
- Jump genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest);
- Assembler::Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Assembler::Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ void generateCJumpOnUndefined(RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ RegisterSizeDependentOps::generateCJumpOnUndefined(this, cond, right, scratchRegister, tagRegister,
+ _nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ Jump generateIsDoubleCheck(RegisterID tagOrValueRegister)
+ {
+ return RegisterSizeDependentOps::generateIsDoubleCheck(this, tagOrValueRegister);
+ }
+
+ Jump genTryDoubleConversion(IR::Expr *src, FPRegisterID dest);
+ Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
Pointer loadAddress(RegisterID tmp, IR::Expr *t);
Pointer loadTempAddress(IR::Temp *t);
@@ -396,7 +1031,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- move(TrustedImmPtr(0), dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@@ -415,70 +1050,31 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
-#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (temp) {
- Pointer addr = loadTempAddress(temp);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, temp, dest, argumentNumber);
}
void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (al) {
- Pointer addr = loadArgLocalAddress(dest, al);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, al, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Const* c, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- QV4::Value v = convertToValue(c);
- move(TrustedImm64(v.rawValue()), dest);
+ RegisterSizeDependentOps::loadArgumentInRegister(this, c, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Expr* expr, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (!expr) {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- } else if (IR::Temp *t = expr->asTemp()){
- loadArgumentInRegister(t, dest, argumentNumber);
- } else if (IR::ArgLocal *al = expr->asArgLocal()) {
- loadArgumentInRegister(al, dest, argumentNumber);
- } else if (IR::Const *c = expr->asConst()) {
- loadArgumentInRegister(c, dest, argumentNumber);
- } else {
- Q_ASSERT(!"unimplemented expression type in loadArgument");
- }
- }
-#else
- void loadArgumentInRegister(IR::Expr*, RegisterID)
- {
- Q_ASSERT(!"unimplemented: expression in loadArgument");
+ RegisterSizeDependentOps::loadArgumentInRegister(this, expr, dest, argumentNumber);
}
-#endif
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
- xorPtr(dest, dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
if (imm32.m_value)
move(imm32, dest);
}
@@ -499,55 +1095,13 @@ public:
void storeReturnValue(FPRegisterID dest)
{
-#ifdef VALUE_FITS_IN_REGISTER
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
-#elif defined(Q_PROCESSOR_ARM)
- moveIntsToDouble(JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_X86)
- moveIntsToDouble(JSC::X86Registers::eax, JSC::X86Registers::edx, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_MIPS)
- moveIntsToDouble(JSC::MIPSRegisters::v0, JSC::MIPSRegisters::v1, dest, FPGpr0);
-#else
- subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
- Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp);
- loadDouble(tmp, dest);
- addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
-#endif
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#ifdef VALUE_FITS_IN_REGISTER
- void storeReturnValue(const Pointer &dest)
- {
- store64(ReturnValueRegister, dest);
- }
-#elif defined(Q_PROCESSOR_X86)
void storeReturnValue(const Pointer &dest)
{
- Pointer destination = dest;
- store32(JSC::X86Registers::eax, destination);
- destination.offset += 4;
- store32(JSC::X86Registers::edx, destination);
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#elif defined(Q_PROCESSOR_ARM)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::ARMRegisters::r0, destination);
- destination.offset += 4;
- store32(JSC::ARMRegisters::r1, destination);
- }
-#elif defined(Q_PROCESSOR_MIPS)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::MIPSRegisters::v0, destination);
- destination.offset += 4;
- store32(JSC::MIPSRegisters::v1, destination);
- }
-#endif
void storeReturnValue(IR::Expr *target)
{
@@ -609,7 +1163,7 @@ public:
Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
- poke(TrustedImmPtr(0), StackSlot);
+ RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
}
}
@@ -648,38 +1202,18 @@ public:
moveDouble(source, (FPRegisterID) targetTemp->index);
return;
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- Pointer ptr = loadAddress(ScratchRegister, target);
- store64(ReturnValueRegister, ptr);
-#else
- Pointer ptr = loadAddress(ScratchRegister, target);
- storeDouble(source, ptr);
-#endif
+ RegisterSizeDependentOps::storeDouble(this, source, target);
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- // We need to (de)mangle the double
+
void loadDouble(Address addr, FPRegisterID dest)
{
- load64(addr, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
+ RegisterSizeDependentOps::loadDouble(this, addr, dest);
}
void storeDouble(FPRegisterID source, Address addr)
{
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- store64(ReturnValueRegister, addr);
+ RegisterSizeDependentOps::storeDouble(this, source, addr);
}
-#else
- using JSC::MacroAssembler::loadDouble;
- using JSC::MacroAssembler::storeDouble;
-#endif
template <typename Result, typename Source>
void copyValue(Result result, Source source);
@@ -691,8 +1225,15 @@ public:
{
Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- JSC::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
- JSC::MacroAssembler::storeDouble(FPGpr0, target);
+ TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
+ TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target);
+ }
+
+ // The scratch register is used to calculate the temp address for the source.
+ void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
+ {
+ TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister);
+ TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target));
}
void storeValue(QV4::Primitive value, RegisterID destination)
@@ -704,13 +1245,7 @@ public:
void storeValue(QV4::Primitive value, Address destination)
{
-#ifdef VALUE_FITS_IN_REGISTER
- store64(TrustedImm64(value.rawValue()), destination);
-#else
- store32(TrustedImm32(value.int_32()), destination);
- destination.offset += 4;
- store32(TrustedImm32(value.tag()), destination);
-#endif
+ RegisterSizeDependentOps::storeValue(this, value, destination);
}
void storeValue(QV4::Primitive value, IR::Expr* temp);
@@ -722,7 +1257,7 @@ public:
void checkException() {
load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
- Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
addPatch(catchBlock, exceptionThrown);
else
@@ -781,6 +1316,27 @@ public:
enum { Size = 0 };
};
+ template <typename T> bool prepareCall(T &)
+ { return true; }
+
+ bool prepareCall(LookupCall &lookupCall)
+ {
+ // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
+
+ // load the table from the context
+ loadPtr(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), ScratchRegister);
+ loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
+ lookupCall.addr.base);
+ // pre-calculate the indirect address for the lookupCall table:
+ if (lookupCall.addr.offset)
+ addPtr(TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
+ // store it as the first argument
+ loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
+ // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
+ lookupCall.addr.offset = lookupCall.getterSetterOffset;
+ return false;
+ }
+
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
@@ -813,12 +1369,11 @@ public:
loadArgumentOnStackOrRegister<2>(arg3);
loadArgumentOnStackOrRegister<1>(arg2);
- if (prepareCall(function, this))
+ if (prepareCall(function))
loadArgumentOnStackOrRegister<0>(arg1);
-#ifdef RESTORE_EBX_ON_CALL
- load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
-#endif
+ if (JITTargetPlatform::gotRegister != -1)
+ load32(Address(JITTargetPlatform::FramePointerRegister, JITTargetPlatform::savedGOTRegisterSlotOnStack()), static_cast<RegisterID>(JITTargetPlatform::gotRegister)); // restore the GOT ptr
callAbsolute(functionName, function);
@@ -957,7 +1512,7 @@ public:
void storeUInt32(RegisterID reg, Pointer addr)
{
// The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
- Jump intRange = branch32(GreaterThanOrEqual, reg, TrustedImm32(0));
+ Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
storeDouble(FPGpr0, addr);
Jump done = jump();
@@ -980,15 +1535,7 @@ public:
FPRegisterID toDoubleRegister(IR::Expr *e, FPRegisterID target = FPGpr0)
{
if (IR::Const *c = e->asConst()) {
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
- int64_t i;
- memcpy(&i, &c->value, sizeof(double));
- move(TrustedImm64(i), ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, target);
-#else
- JSC::MacroAssembler::loadDouble(loadConstant(c, ScratchRegister), target);
-#endif
+ RegisterSizeDependentOps::loadDoubleConstant(this, c, target);
return target;
}
@@ -1047,7 +1594,7 @@ public:
Pointer tagAddr = addr;
tagAddr.offset += 4;
load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
+ Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
@@ -1065,10 +1612,21 @@ public:
return scratchReg;
}
+ void returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave);
+
JSC::MacroAssemblerCodeRef link(int *codeSize);
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
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;
IR::BasicBlock * catchBlock;
@@ -1095,22 +1653,16 @@ private:
QV4::Compiler::JSUnitGenerator *_jsGenerator;
};
+template <typename TargetConfiguration>
template <typename Result, typename Source>
-void Assembler::copyValue(Result result, Source source)
+void Assembler<TargetConfiguration>::copyValue(Result result, Source source)
{
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
}
+template <typename TargetConfiguration>
template <typename Result>
-void Assembler::copyValue(Result result, IR::Expr* source)
+void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source)
{
if (source->type == IR::BoolType) {
RegisterID reg = toInt32Register(source, ScratchRegister);
@@ -1124,15 +1676,7 @@ void Assembler::copyValue(Result result, IR::Expr* source)
} else if (source->type == IR::DoubleType) {
storeDouble(toDoubleRegister(source), result);
} else if (source->asTemp() || source->asArgLocal()) {
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
} else if (IR::Const *c = source->asConst()) {
QV4::Primitive v = convertToValue(c);
storeValue(v, result);
@@ -1141,34 +1685,12 @@ void Assembler::copyValue(Result result, IR::Expr* source)
}
}
-inline RuntimeCall::RuntimeCall(uint offset)
+template <typename TargetConfiguration>
+inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(uint offset)
: addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime))
{
}
-
-
-template <typename T> inline bool prepareCall(T &, Assembler *)
-{ return true; }
-
-template <> inline bool prepareCall(LookupCall &lookupCall, Assembler *as)
-{
- // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
-
- // load the table from the context
- as->loadPtr(Assembler::Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- as->loadPtr(Assembler::Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
- lookupCall.addr.base);
- // pre-calculate the indirect address for the lookupCall table:
- if (lookupCall.addr.offset)
- as->addPtr(Assembler::TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
- // store it as the first argument
- as->loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
- // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
- lookupCall.addr.offset = lookupCall.getterSetterOffset;
- return false;
-}
-
} // end of namespace JIT
} // end of namespace QV4
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index d2758c4a47..22067bbb13 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -41,8 +41,128 @@
#if ENABLE(ASSEMBLER)
-using namespace QV4;
-using namespace JIT;
+QT_BEGIN_NAMESPACE
+
+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) \
{ "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
@@ -57,7 +177,8 @@ using namespace JIT;
#define NULL_OP \
{ 0, 0, 0, 0, 0, false }
-const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
+template <typename JITAssembler>
+const typename Binop<JITAssembler>::OpInfo Binop<JITAssembler>::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpInvalid
NULL_OP, // OpIfTrue
NULL_OP, // OpNot
@@ -67,20 +188,20 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpIncrement
NULL_OP, // OpDecrement
- INLINE_OP(bitAnd, &Binop::inline_and32, &Binop::inline_and32), // OpBitAnd
- INLINE_OP(bitOr, &Binop::inline_or32, &Binop::inline_or32), // OpBitOr
- INLINE_OP(bitXor, &Binop::inline_xor32, &Binop::inline_xor32), // OpBitXor
+ INLINE_OP(bitAnd, &Binop<JITAssembler>::inline_and32, &Binop<JITAssembler>::inline_and32), // OpBitAnd
+ INLINE_OP(bitOr, &Binop<JITAssembler>::inline_or32, &Binop<JITAssembler>::inline_or32), // OpBitOr
+ INLINE_OP(bitXor, &Binop<JITAssembler>::inline_xor32, &Binop<JITAssembler>::inline_xor32), // OpBitXor
- INLINE_OPCONTEXT(add, &Binop::inline_add32, &Binop::inline_add32), // OpAdd
- INLINE_OP(sub, &Binop::inline_sub32, &Binop::inline_sub32), // OpSub
- INLINE_OP(mul, &Binop::inline_mul32, &Binop::inline_mul32), // OpMul
+ INLINE_OPCONTEXT(add, &Binop<JITAssembler>::inline_add32, &Binop<JITAssembler>::inline_add32), // OpAdd
+ INLINE_OP(sub, &Binop<JITAssembler>::inline_sub32, &Binop<JITAssembler>::inline_sub32), // OpSub
+ INLINE_OP(mul, &Binop<JITAssembler>::inline_mul32, &Binop<JITAssembler>::inline_mul32), // OpMul
OP(div), // OpDiv
OP(mod), // OpMod
- INLINE_OP(shl, &Binop::inline_shl32, &Binop::inline_shl32), // OpLShift
- INLINE_OP(shr, &Binop::inline_shr32, &Binop::inline_shr32), // OpRShift
- INLINE_OP(ushr, &Binop::inline_ushr32, &Binop::inline_ushr32), // OpURShift
+ INLINE_OP(shl, &Binop<JITAssembler>::inline_shl32, &Binop<JITAssembler>::inline_shl32), // OpLShift
+ INLINE_OP(shr, &Binop<JITAssembler>::inline_shr32, &Binop<JITAssembler>::inline_shr32), // OpRShift
+ INLINE_OP(ushr, &Binop<JITAssembler>::inline_ushr32, &Binop<JITAssembler>::inline_ushr32), // OpURShift
OP(greaterThan), // OpGt
OP(lessThan), // OpLt
@@ -100,7 +221,8 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
-void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
if (op != IR::OpMod
&& lhs->type == IR::DoubleType && rhs->type == IR::DoubleType) {
@@ -125,15 +247,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
info = stringAdd;
}
- RuntimeCall fallBack(info.fallbackImplementation);
- RuntimeCall context(info.contextImplementation);
+ typename JITAssembler::RuntimeCall fallBack(info.fallbackImplementation);
+ typename JITAssembler::RuntimeCall context(info.contextImplementation);
if (fallBack.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack,
PointerToValue(lhs),
PointerToValue(rhs));
} else if (context.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context,
- Assembler::EngineRegister,
+ JITAssembler::EngineRegister,
PointerToValue(lhs),
PointerToValue(rhs));
} else {
@@ -145,119 +267,70 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
-void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
FPRegisterID targetReg;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
targetReg = (FPRegisterID) targetTemp->index;
else
- targetReg = Assembler::FPGpr0;
+ targetReg = JITAssembler::FPGpr0;
switch (op) {
case IR::OpAdd:
if (lhs->asConst())
std::swap(lhs, rhs); // Y = constant + X -> Y = X + constant
-#if CPU(X86)
- 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, Assembler::ScratchRegister);
- as->addDouble(addr, targetReg);
+ if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleAdd(as, lhs, rhs, targetReg))
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, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+
+ as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpMul:
if (lhs->asConst())
std::swap(lhs, rhs); // Y = constant * X -> Y = X * constant
-#if CPU(X86)
- 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, Assembler::ScratchRegister);
- as->mulDouble(addr, targetReg);
+ if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleMul(as, lhs, rhs, targetReg))
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, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+
+ as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpSub:
-#if CPU(X86)
- 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, Assembler::ScratchRegister);
- as->subDouble(addr, targetReg);
+ if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleSub(as, lhs, rhs, targetReg))
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
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X - Y -> Tmp = Y; Y = X - Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpDiv:
-#if CPU(X86)
- 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, Assembler::ScratchRegister);
- as->divDouble(addr, targetReg);
+ if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleDiv(as, lhs, rhs, targetReg))
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
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X / Y -> Tmp = Y; Y = X / Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
default: {
- Q_ASSERT(target->type == IR::BoolType);
Jump trueCase = as->branchDouble(false, op, lhs, rhs);
as->storeBool(false, target);
Jump done = as->jump();
@@ -271,8 +344,8 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
as->storeDouble(targetReg, target);
}
-
-bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Q_ASSERT(leftSource->type == IR::SInt32Type);
Q_ASSERT(rightSource->type == IR::SInt32Type);
@@ -305,7 +378,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
bool inplaceOpWithAddress = false;
IR::Temp *targetTemp = target->asTemp();
- RegisterID targetReg = Assembler::ReturnValueRegister;
+ RegisterID targetReg = JITAssembler::ReturnValueRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
IR::Temp *rhs = rightSource->asTemp();
if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) {
@@ -369,12 +442,12 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
&& targetTemp->index == rightSource->asTemp()->index) {
// X = Y - X -> Tmp = X; X = Y; X -= Tmp
targetReg = (RegisterID) targetTemp->index;
- as->move(targetReg, Assembler::ScratchRegister);
+ as->move(targetReg, JITAssembler::ScratchRegister);
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(Assembler::ScratchRegister, targetReg);
+ as->sub32(JITAssembler::ScratchRegister, targetReg);
} else {
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
+ as->sub32(as->toInt32Register(rightSource, JITAssembler::ScratchRegister), targetReg);
}
as->storeInt32(targetReg, target);
return true;
@@ -419,7 +492,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource);
+ Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource);
switch (op) {
case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
@@ -433,7 +506,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else { // All cases of Z = X op Y
- RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister);
+ RegisterID r = as->toInt32Register(rightSource, JITAssembler::ScratchRegister);
switch (op) {
case IR::OpBitAnd: as->and32(l, r, targetReg); break;
case IR::OpBitOr: as->or32 (l, r, targetReg); break;
@@ -452,18 +525,18 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
// Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do
// surprising stuff when shifting over 0 bits.
#define CHECK_RHS(op) { \
- as->and32(TrustedImm32(0x1f), r, Assembler::ScratchRegister); \
- Jump notZero = as->branch32(RelationalCondition::NotEqual, Assembler::ScratchRegister, TrustedImm32(0)); \
+ as->and32(TrustedImm32(0x1f), r, JITAssembler::ScratchRegister); \
+ Jump notZero = as->branch32(RelationalCondition::NotEqual, JITAssembler::ScratchRegister, TrustedImm32(0)); \
as->move(l, targetReg); \
Jump done = as->jump(); \
notZero.link(as); \
op; \
done.link(as); \
}
- case IR::OpLShift: CHECK_RHS(as->lshift32(l, Assembler::ScratchRegister, targetReg)); break;
- case IR::OpRShift: CHECK_RHS(as->rshift32(l, Assembler::ScratchRegister, targetReg)); break;
+ case IR::OpLShift: CHECK_RHS(as->lshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
+ case IR::OpRShift: CHECK_RHS(as->rshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
case IR::OpURShift:
- CHECK_RHS(as->urshift32(l, Assembler::ScratchRegister, targetReg));
+ CHECK_RHS(as->urshift32(l, JITAssembler::ScratchRegister, targetReg));
as->storeUInt32(targetReg, target);
// IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
return true;
@@ -481,17 +554,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return true;
}
-static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
+template <typename JITAssembler>
+inline typename JITAssembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
{
if (IR::Temp *t = shouldNotOverlap->asTemp())
if (t->type == IR::DoubleType)
if (t->kind == IR::Temp::PhysicalRegister)
if (t->index == hint)
- return Assembler::FPRegisterID(hint + 1);
- return Assembler::FPRegisterID(hint);
+ return typename JITAssembler::FPRegisterID(hint + 1);
+ return typename JITAssembler::FPRegisterID(hint);
}
-Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+typename JITAssembler::Jump Binop<JITAssembler>::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Jump done;
@@ -505,8 +580,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
// register.
switch (op) {
case IR::OpAdd: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -520,8 +595,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpMul: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -535,8 +610,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpSub: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -550,8 +625,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpDiv: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -571,4 +646,20 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
return done;
}
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP)
+#if !CPU(ARM_THUMB2)
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#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
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index 3742e99e5a..d2d9ba7753 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -61,21 +61,22 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler>
struct Binop {
- Binop(Assembler *assembler, IR::AluOp operation)
+ Binop(JITAssembler *assembler, IR::AluOp operation)
: as(assembler)
, op(operation)
{}
- using Jump = Assembler::Jump;
- using Address = Assembler::Address;
- using RegisterID = Assembler::RegisterID;
- using FPRegisterID = Assembler::FPRegisterID;
- using TrustedImm32 = Assembler::TrustedImm32;
- using ResultCondition = Assembler::ResultCondition;
- using RelationalCondition = Assembler::RelationalCondition;
- using Pointer = Assembler::Pointer;
- using PointerToValue = Assembler::PointerToValue;
+ using Jump = typename JITAssembler::Jump;
+ using Address = typename JITAssembler::Address;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
@@ -103,8 +104,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchAdd32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchAdd32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchAdd32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -118,8 +119,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchSub32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchSub32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchSub32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -131,10 +132,10 @@ struct Binop {
Jump inline_mul32(Address addr, RegisterID reg)
{
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchMul32(Assembler::Overflow, addr, reg);
+ return as->branchMul32(JITAssembler::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchMul32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchMul32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -145,9 +146,9 @@ struct Binop {
Jump inline_shl32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->lshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->lshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -160,9 +161,9 @@ struct Binop {
Jump inline_shr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->rshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->rshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -175,9 +176,9 @@ struct Binop {
Jump inline_ushr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->urshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->urshift32(JITAssembler::ScratchRegister, reg);
return as->branchTest32(ResultCondition::Signed, reg, reg);
}
@@ -193,8 +194,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->and32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -210,8 +211,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->or32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->or32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->or32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -227,8 +228,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->xor32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->xor32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->xor32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -241,7 +242,7 @@ struct Binop {
- Assembler *as;
+ JITAssembler *as;
IR::AluOp op;
};
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 20752b5c34..69d6951bb9 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -39,11 +39,7 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -68,7 +64,8 @@ using namespace QV4;
using namespace QV4::JIT;
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)
, _as(0)
@@ -79,12 +76,14 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex
module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode;
}
-InstructionSelection::~InstructionSelection()
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::~InstructionSelection()
{
delete _as;
}
-void InstructionSelection::run(int functionIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::run(int functionIndex)
{
IR::Function *function = irModule->functions[functionIndex];
qSwap(_function, function);
@@ -93,8 +92,8 @@ void InstructionSelection::run(int functionIndex)
opt.run(qmlEngine);
static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC");
- if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator regalloc(Assembler::getRegisterInfo());
+ if (JITTargetPlatform::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
+ RegisterAllocator regalloc(JITTargetPlatform::getRegisterInfo());
regalloc.run(_function, opt);
calculateRegistersToSave(regalloc.usedRegisters());
} else {
@@ -103,49 +102,24 @@ void InstructionSelection::run(int functionIndex)
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
IR::Optimizer::showMeTheCode(_function, "After stack slot allocation");
- calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
+ calculateRegistersToSave(JITTargetPlatform::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
}
BitVector removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
- Assembler* oldAssembler = _as;
- _as = new Assembler(jsGenerator, _function, executableAllocator);
+ JITAssembler* oldAssembler = _as;
+ _as = new JITAssembler(jsGenerator, _function, executableAllocator);
_as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array
regularRegistersToSave.size(),
fpRegistersToSave.size());
_as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
-#ifdef ARGUMENTS_IN_REGISTERS
- _as->move(_as->registerForArgument(0), Assembler::EngineRegister);
-#else
- _as->loadPtr(addressForArgument(0), Assembler::EngineRegister);
-#endif
-
- const int locals = _as->stackLayout().calculateJSStackFrameSize();
- if (locals > 0) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister);
-#ifdef VALUE_FITS_IN_REGISTER
- _as->move(Assembler::TrustedImm64(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store64(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add64(Assembler::TrustedImm32(8), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
- jump.linkTo(loop, _as);
-#else
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
- jump.linkTo(loop, _as);
-#endif
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
- }
+ if (JITTargetPlatform::RegisterArgumentCount > 0)
+ _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
+ else
+ _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
+ _as->initializeLocalVariables();
int lastLine = 0;
for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
@@ -158,9 +132,9 @@ void InstructionSelection::run(int functionIndex)
for (IR::Stmt *s : _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- Assembler::Address lineAddr(Assembler::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
- _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
+ _as->store32(TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
}
@@ -181,165 +155,187 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep()
+template <typename JITAssembler>
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection<JITAssembler>::backendCompileStep()
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
result.adopt(compilationUnit.take());
return result;
}
-void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, callGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, callActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
}
-void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
IR::Member::MemberKind kind,
int propertyIndex, IR::Expr *result)
{
if (kind == IR::Member::MemberOfQmlScopeObject) {
- generateRuntimeCall(result, typeofScopeObjectProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofScopeObjectProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else if (kind == IR::Member::MemberOfQmlContextObject) {
- generateRuntimeCall(result, typeofContextObjectProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofContextObjectProperty,
+ JITTargetPlatform::EngineRegister, PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else {
Q_UNREACHABLE();
}
}
-void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofMember, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofMember, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofElement,
- Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, typeofElement,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, typeofName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
- generateRuntimeCall(result, typeofValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value));
+ generateRuntimeCall(_as, result, typeofValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value));
}
-void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteMember, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteMember, JITTargetPlatform::EngineRegister,
+ Reference(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, deleteElement, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, deleteElement, JITTargetPlatform::EngineRegister,
+ Reference(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
{
_as->storeValue(Primitive::fromBoolean(false), result);
}
-void InstructionSelection::callBuiltinThrow(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinThrow(IR::Expr *arg)
{
- generateRuntimeCall(Assembler::ReturnValueRegister, throwException, Assembler::EngineRegister,
- Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, throwException, JITTargetPlatform::EngineRegister,
+ PointerToValue(arg));
}
-void InstructionSelection::callBuiltinReThrow()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinReThrow()
{
_as->jumpToExceptionHandler();
}
-void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinUnwindException(IR::Expr *result)
{
- generateRuntimeCall(result, unwindException, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, unwindException, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushCatchScope(const QString &exceptionName)
{
- generateRuntimeCall(Assembler::Void, pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName));
+ generateRuntimeCall(_as, JITAssembler::Void, pushCatchScope, JITTargetPlatform::EngineRegister, StringToIndex(exceptionName));
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, result, foreachIterator, JITTargetPlatform::EngineRegister, PointerToValue(arg));
}
-void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachNextPropertyName, Assembler::Reference(arg));
+ generateRuntimeCall(_as, result, foreachNextPropertyName, Reference(arg));
}
-void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushWithScope(IR::Expr *arg)
{
Q_ASSERT(arg);
- generateRuntimeCall(Assembler::Void, pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, pushWithScope, Reference(arg), JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPopScope()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPopScope()
{
- generateRuntimeCall(Assembler::Void, popScope, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, popScope, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeclareVar(bool deletable, const QString &name)
{
- generateRuntimeCall(Assembler::Void, declareVar, Assembler::EngineRegister,
- Assembler::TrustedImm32(deletable), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, JITAssembler::Void, declareVar, JITTargetPlatform::EngineRegister,
+ TrustedImm32(deletable), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
{
Q_ASSERT(result);
int length = prepareVariableArguments(args);
- generateRuntimeCall(result, arrayLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(length));
+ generateRuntimeCall(_as, result, arrayLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(length));
}
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
{
Q_ASSERT(result);
@@ -415,81 +411,83 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
it = it->next;
}
- generateRuntimeCall(result, objectLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
- Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
+ generateRuntimeCall(_as, result, objectLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(classId),
+ TrustedImm32(arrayValueCount), TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
}
-void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinSetupArgumentObject(IR::Expr *result)
{
- generateRuntimeCall(result, setupArgumentsObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, setupArgumentsObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinConvertThisToObject()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinConvertThisToObject()
{
- generateRuntimeCall(Assembler::Void, convertThisToObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, convertThisToObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value);
prepareCallData(args, 0);
if (value->asConst())
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value),
baseAddressForCallData());
else
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::loadThisObject(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister);
-#if defined(VALUE_FITS_IN_REGISTER)
- _as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)),
- Assembler::ReturnValueRegister);
- _as->storeReturnValue(temp);
-#else
- _as->copyValue(temp, Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)));
-#endif
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
+ _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
}
-void InstructionSelection::loadQmlContext(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlContext(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlContext, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlContext, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlImportedScripts(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlImportedScripts, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlImportedScripts, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlSingleton(const QString &name, IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, temp, getQmlSingleton, JITTargetPlatform::EngineRegister, StringToIndex(name));
}
-void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::Expr *target)
{
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp->type == IR::DoubleType) {
Q_ASSERT(sourceConst->type == IR::DoubleType);
- _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(sourceConst, (FPRegisterID) targetTemp->index);
} else if (targetTemp->type == IR::SInt32Type) {
Q_ASSERT(sourceConst->type == IR::SInt32Type);
- _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::UInt32Type) {
Q_ASSERT(sourceConst->type == IR::UInt32Type);
- _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::BoolType) {
Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()),
- (Assembler::RegisterID) targetTemp->index);
+ _as->move(TrustedImm32(convertToValue(sourceConst).int_32()),
+ (RegisterID) targetTemp->index);
} else {
Q_UNREACHABLE();
}
@@ -500,147 +498,155 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
_as->storeValue(convertToValue(sourceConst), target);
}
-void InstructionSelection::loadString(const QString &str, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr *target)
{
- Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str);
- _as->loadPtr(srcAddr, Assembler::ReturnValueRegister);
- Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->store64(Assembler::ReturnValueRegister, destAddr);
-#else
- _as->store32(Assembler::ReturnValueRegister, destAddr);
- destAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr);
-#endif
+ Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
+ _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
+ Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target);
+ JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr);
}
-void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
int id = registerRegExp(sourceRegexp);
- generateRuntimeCall(target, regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, regexpLiteral, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getActivationProperty(const IR::Name *name, IR::Expr *target)
{
if (useFastLookups && name->global) {
uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::EngineRegister, Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
return;
}
- generateRuntimeCall(target, getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id));
+ generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id));
}
-void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setActivationProperty(IR::Expr *source, const QString &targetName)
{
// ### should use a lookup call here
- generateRuntimeCall(Assembler::Void, setActivationProperty,
- Assembler::EngineRegister, Assembler::StringToIndex(targetName), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setActivationProperty,
+ JITTargetPlatform::EngineRegister, StringToIndex(targetName), PointerToValue(source));
}
-void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
- generateRuntimeCall(target, closure, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, closure, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
} else {
- generateRuntimeCall(target, getProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
}
-void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfIdObjectsArray)
- generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(_as, target, getQmlIdObject, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index));
else
Q_ASSERT(false);
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0)
- generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, target, getQmlAttachedProperty, JITTargetPlatform::EngineRegister, TrustedImm32(attachedPropertiesId), TrustedImm32(propertyIndex));
else if (isSingleton)
- generateRuntimeCall(target, getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlSingletonQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
else
- generateRuntimeCall(target, getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
}
-void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr *targetBase,
const QString &targetName)
{
if (useFastLookups) {
uint index = registerSetterLookup(targetName);
- generateLookupCall(Assembler::Void, index, qOffsetOf(QV4::Lookup, setter),
- Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter),
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase),
+ PointerToValue(source));
} else {
- generateRuntimeCall(Assembler::Void, setProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::StringToIndex(targetName),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), StringToIndex(targetName),
+ PointerToValue(source));
}
}
-void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(Assembler::Void, setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(Assembler::Void, setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else
Q_ASSERT(false);
}
-void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
{
- generateRuntimeCall(Assembler::Void, setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
}
-void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
if (useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter),
- Assembler::PointerToValue(base),
- Assembler::PointerToValue(index));
+ PointerToValue(base),
+ PointerToValue(index));
return;
}
- generateRuntimeCall(target, getElement, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, target, getElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
{
if (useFastLookups) {
uint lookup = registerIndexedSetterLookup();
- generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
return;
}
- generateRuntimeCall(Assembler::Void, setElement, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
}
-void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -655,25 +661,25 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
if (sourceTemp->type == IR::DoubleType)
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
else
- _as->move((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->move((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
return;
} else {
switch (sourceTemp->type) {
case IR::DoubleType:
- _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target);
+ _as->storeDouble((FPRegisterID) sourceTemp->index, target);
break;
case IR::SInt32Type:
- _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeInt32((RegisterID) sourceTemp->index, target);
break;
case IR::UInt32Type:
- _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeUInt32((RegisterID) sourceTemp->index, target);
break;
case IR::BoolType:
- _as->storeBool((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeBool((RegisterID) sourceTemp->index, target);
break;
default:
Q_ASSERT(!"Unreachable");
@@ -685,19 +691,19 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
switch (targetTemp->type) {
case IR::DoubleType:
Q_ASSERT(source->type == IR::DoubleType);
- _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(source, (FPRegisterID) targetTemp->index);
return;
case IR::BoolType:
Q_ASSERT(source->type == IR::BoolType);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::SInt32Type:
Q_ASSERT(source->type == IR::SInt32Type);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::UInt32Type:
Q_ASSERT(source->type == IR::UInt32Type);
- _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(source, (RegisterID) targetTemp->index);
return;
default:
Q_ASSERT(!"Unreachable");
@@ -706,10 +712,11 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
}
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister);
+ _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister);
}
-void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -719,26 +726,27 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(sourceTemp->type == targetTemp->type);
if (sourceTemp->type == IR::DoubleType) {
- _as->moveDouble((Assembler::FPRegisterID) targetTemp->index, Assembler::FPGpr0);
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) sourceTemp->index);
+ _as->moveDouble((FPRegisterID) targetTemp->index, JITTargetPlatform::FPGpr0);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) sourceTemp->index);
} else {
- _as->swap((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->swap((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
}
return;
}
} else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target);
+ Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target);
// use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
- _as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0);
- _as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr1, sAddr);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr0, tAddr);
+ auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as);
+ platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0);
+ platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr);
return;
}
}
@@ -749,18 +757,18 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(memExpr);
Q_ASSERT(regTemp);
- Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr);
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr);
if (regTemp->type == IR::DoubleType) {
- _as->loadDouble(addr, Assembler::FPGpr0);
- _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index);
+ _as->loadDouble(addr, JITTargetPlatform::FPGpr0);
+ _as->storeDouble((FPRegisterID) regTemp->index, addr);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
} else if (regTemp->type == IR::UInt32Type) {
- _as->toUInt32Register(addr, Assembler::ScratchRegister);
- _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr);
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
+ _as->storeUInt32((RegisterID) regTemp->index, addr);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
} else {
- _as->load32(addr, Assembler::ScratchRegister);
- _as->store32((Assembler::RegisterID) regTemp->index, addr);
+ _as->load32(addr, JITTargetPlatform::ScratchRegister);
+ _as->store32((RegisterID) regTemp->index, addr);
if (regTemp->type != memExpr->type) {
addr.offset += 4;
quint32 tag;
@@ -775,55 +783,59 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
tag = 31337; // bogus value
Q_UNREACHABLE();
}
- _as->store32(Assembler::TrustedImm32(tag), addr);
+ _as->store32(TrustedImm32(tag), addr);
}
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
}
}
#define setOp(op, opName, operation) \
do { \
- op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
#define setOpContext(op, opName, operation) \
do { \
- opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
- QV4::JIT::Unop unop(_as, oper);
+ QV4::JIT::Unop<JITAssembler> unop(_as, oper);
unop.generate(source, target);
}
-void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
- QV4::JIT::Binop binop(_as, oper);
+ QV4::JIT::Binop<JITAssembler> binop(_as, oper);
binop.generate(leftSource, rightSource, target);
}
-void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(result, callQmlScopeObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlScopeObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(result, callQmlContextObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlContextObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else
Q_ASSERT(false);
}
-void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
@@ -832,29 +844,31 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, callPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, callProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
}
-void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
prepareCallData(args, base);
- generateRuntimeCall(result, callElement, Assembler::EngineRegister,
- Assembler::PointerToValue(index),
+ generateRuntimeCall(_as, result, callElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(index),
baseAddressForCallData());
}
-void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertType(IR::Expr *source, IR::Expr *target)
{
switch (target->type) {
case IR::DoubleType:
@@ -875,7 +889,8 @@ void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
}
}
-void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(target->type != IR::BoolType);
@@ -885,7 +900,8 @@ void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *targe
copyValue(source, target);
}
-void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::SInt32Type:
@@ -897,51 +913,37 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, target);
+ _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
convertIntToDouble(source, target);
- Assembler::Jump intDone = _as->jump();
+ Jump intDone = _as->jump();
// not an int, check if it's NOT a double:
isNoInt.link(_as);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(0));
-#else
- _as->and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
-#endif
+ Jump isDbl = _as->generateIsDoubleCheck(JITTargetPlatform::ScratchRegister);
- generateRuntimeCall(target, toDouble, Assembler::PointerToValue(source));
- Assembler::Jump noDoubleDone = _as->jump();
+ generateRuntimeCall(_as, target, toDouble, PointerToValue(source));
+ Jump noDoubleDone = _as->jump();
// it is a double:
isDbl.link(_as);
- Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
-#if Q_PROCESSOR_WORDSIZE == 8
- _as->load64(addr2, Assembler::ScratchRegister);
- _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#else
- _as->loadDouble(addr2, Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#endif
+ _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
} else {
- _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index);
+ _as->loadDouble(addr2, (FPRegisterID) targetTemp->index);
}
noDoubleDone.link(_as);
@@ -953,7 +955,8 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
}
}
-void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
switch (source->type) {
@@ -965,16 +968,16 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
// The source is in a register if the register allocator is used. If the register
// allocator was not used, then that means that we can use any register for to
// load the double into.
- Assembler::FPRegisterID reg;
+ FPRegisterID reg;
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::FPRegisterID) sourceTemp->index;
+ reg = (FPRegisterID) sourceTemp->index;
else
- reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1);
- Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0);
+ reg = _as->toDoubleRegister(source, (FPRegisterID) 1);
+ Jump nonZero = _as->branchDoubleNonZero(reg, JITTargetPlatform::FPGpr0);
// it's 0, so false:
_as->storeBool(false, target);
- Assembler::Jump done = _as->jump();
+ Jump done = _as->jump();
// it's non-zero, so true:
nonZero.link(_as);
@@ -988,283 +991,220 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
_as->storeBool(false, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
case IR::VarType:
default:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
// checkif it's a bool:
- Assembler::Jump notBool = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Boolean_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump boolDone = _as->jump();
+ Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Boolean_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump boolDone = _as->jump();
// check if it's an int32:
notBool.link(_as);
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump isZero = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(0));
- _as->move(Assembler::TrustedImm32(1), Assembler::ReturnValueRegister);
- Assembler::Jump intDone = _as->jump();
+ Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(0));
+ _as->move(TrustedImm32(1), JITTargetPlatform::ReturnValueRegister);
+ Jump intDone = _as->jump();
// not an int:
fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
isZero.link(_as);
intDone.link(_as);
boolDone.link(_as);
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
break;
}
}
-void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->load64(addr, Assembler::ScratchRegister);
- _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
-
- // check if it's integer convertible
- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister);
- Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3));
-
- // nope, not integer convertible, so check for a double:
- _as->urshift64(Assembler::TrustedImm32(
- QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
- Assembler::ScratchRegister);
- Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
-
- // it's a double
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
- Assembler::Jump success =
- _as->branchTruncateDoubleToInt32(Assembler::FPGpr0, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
-
- isIntConvertible.link(_as);
- success.link(_as);
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->storeInt32(Assembler::ReturnValueRegister, target);
- }
-#else
- // load the tag:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
- tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
-
- // check if it's an int32:
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->load32(addr, (Assembler::RegisterID) targetTemp->index);
- }
- Assembler::Jump intDone = _as->jump();
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
-
- intDone.link(_as);
-#endif
-
+ JITAssembler::RegisterSizeDependentOps::convertVarToSInt32(_as, source, target);
} break;
case IR::DoubleType: {
- Assembler::Jump success =
+ Jump success =
_as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
- Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToInt,
- Assembler::PointerToValue(source));
+ JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::UInt32Type:
- _as->storeInt32(_as->toUInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toUInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::BoolType:
- _as->storeInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::StringType:
default:
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
} // switch (source->type)
}
-void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target);
- Assembler::Jump intDone = _as->jump();
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
+ Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
intDone.link(_as);
} break;
case IR::DoubleType: {
- Assembler::FPRegisterID reg = _as->toDoubleRegister(source);
- Assembler::Jump success =
- _as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToUInt,
- Assembler::PointerToValue(source));
+ FPRegisterID reg = _as->toDoubleRegister(source);
+ Jump success =
+ _as->branchTruncateDoubleToUint32(reg, JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToUInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- Assembler::PointerToValue(source));
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ PointerToValue(source));
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::SInt32Type:
case IR::BoolType:
- _as->storeUInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeUInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
default:
break;
} // switch (source->type)
}
-void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(func != 0);
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, constructGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index), baseAddressForCallData());
+ generateRuntimeCall(_as, result, constructGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index), baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, constructActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
-void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, constructPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, constructPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, constructProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
-void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value != 0);
prepareCallData(args, 0);
- generateRuntimeCall(result, constructValue,
- Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, constructValue,
+ JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::visitJump(IR::Jump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitJump(IR::Jump *s)
{
if (!_removableJumps.at(_block->index()))
_as->jumpToBlock(_block, s->target);
}
-void InstructionSelection::visitCJump(IR::CJump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
{
IR::Temp *t = s->cond->asTemp();
if (t || s->cond->asArgLocal()) {
- Assembler::RegisterID reg;
+ RegisterID reg;
if (t && t->kind == IR::Temp::PhysicalRegister) {
Q_ASSERT(t->type == IR::BoolType);
- reg = (Assembler::RegisterID) t->index;
+ reg = (RegisterID) t->index;
} else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
- reg = Assembler::ReturnValueRegister;
+ reg = JITTargetPlatform::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond);
+ Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
- Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal));
Address data = temp;
data.offset += QV4::Value::valueOffset();
- _as->load32(data, Assembler::ReturnValueRegister);
- Assembler::Jump testBoolean = _as->jump();
+ _as->load32(data, JITTargetPlatform::ReturnValueRegister);
+ Jump testBoolean = _as->jump();
booleanConversion.link(_as);
- reg = Assembler::ReturnValueRegister;
- generateRuntimeCall(reg, toBoolean, Assembler::Reference(s->cond));
+ reg = JITTargetPlatform::ReturnValueRegister;
+ generateRuntimeCall(_as, reg, toBoolean, Reference(s->cond));
testBoolean.link(_as);
}
@@ -1274,9 +1214,9 @@ void InstructionSelection::visitCJump(IR::CJump *s)
} else if (IR::Const *c = s->cond->asConst()) {
// TODO: SSA optimization for constant condition evaluation should remove this.
// See also visitCJump() in RegAllocInfo.
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(c));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(c));
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
} else if (IR::Binop *b = s->cond->asBinop()) {
if (b->left->type == IR::DoubleType && b->right->type == IR::DoubleType
@@ -1296,8 +1236,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
return;
}
- RuntimeCall op;
- RuntimeCall opContext;
+ typename JITAssembler::RuntimeCall op;
+ typename JITAssembler::RuntimeCall opContext;
const char *opName = 0;
bool needsExceptionCheck;
switch (b->op) {
@@ -1321,165 +1261,30 @@ void InstructionSelection::visitCJump(IR::CJump *s)
// elimination (which isn't there either) would remove the whole else block.
if (opContext.isValid())
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, opContext,
- Assembler::EngineRegister,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, opContext,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
else
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, op,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, op,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
}
Q_UNREACHABLE();
}
-void InstructionSelection::visitRet(IR::Ret *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitRet(IR::Ret *s)
{
- if (!s) {
- // this only happens if the method doesn't have a return statement and can
- // only exit through an exception
- } else if (IR::Temp *t = s->expr->asTemp()) {
-#if CPU(X86) || CPU(ARM) || CPU(MIPS)
-
-# if CPU(X86)
- Assembler::RegisterID lowReg = JSC::X86Registers::eax;
- Assembler::RegisterID highReg = JSC::X86Registers::edx;
-# elif CPU(MIPS)
- Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0;
- Assembler::RegisterID highReg = JSC::MIPSRegisters::v1;
-# else // CPU(ARM)
- Assembler::RegisterID lowReg = JSC::ARMRegisters::r0;
- Assembler::RegisterID highReg = JSC::ARMRegisters::r1;
-# endif
-
- if (t->kind == IR::Temp::PhysicalRegister) {
- switch (t->type) {
- case IR::DoubleType:
- _as->moveDoubleToInts((Assembler::FPRegisterID) t->index, lowReg, highReg);
- break;
- case IR::UInt32Type: {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleToInts(Assembler::FPGpr0, lowReg, highReg);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->move(srcReg, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- done.link(_as);
- } break;
- case IR::SInt32Type:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- break;
- case IR::BoolType:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
- break;
- default:
- Q_UNREACHABLE();
- }
- } else {
- Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t);
- _as->load32(addr, lowReg);
- addr.offset += 4;
- _as->load32(addr, highReg);
- }
-#else
- if (t->kind == IR::Temp::PhysicalRegister) {
- if (t->type == IR::DoubleType) {
- _as->moveDoubleTo64((Assembler::FPRegisterID) t->index,
- Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask),
- Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- } else if (t->type == IR::UInt32Type) {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister);
- quint64 tag = QV4::Value::Integer_Type_Internal;
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- done.link(_as);
- } else {
- _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister);
- quint64 tag;
- switch (t->type) {
- case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
- break;
- case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
- break;
- default:
- tag = 31337; // bogus value
- Q_UNREACHABLE();
- }
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- }
- } else {
- _as->copyValue(Assembler::ReturnValueRegister, t);
- }
-#endif
- } else if (IR::Const *c = s->expr->asConst()) {
- QV4::Primitive retVal = convertToValue(c);
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- } else {
- Q_UNREACHABLE();
- Q_UNUSED(s);
- }
-
- Assembler::Label leaveStackFrame = _as->label();
-
- const int locals = _as->stackLayout().calculateJSStackFrameSize();
- _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
-
- _as->leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
- _as->ret();
-
- _as->exceptionReturnLabel = _as->label();
- QV4::Primitive retVal = Primitive::undefinedValue();
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- _as->jump(leaveStackFrame);
+ _as->returnFromFunction(s, regularRegistersToSave, fpRegistersToSave);
}
-int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* args)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1492,7 +1297,7 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
@@ -1500,7 +1305,8 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
return argc;
}
-int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1508,9 +1314,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
}
Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag));
- _as->store32(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), p);
+ _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc));
- _as->store32(Assembler::TrustedImm32(argc), p);
+ _as->store32(TrustedImm32(argc), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject));
if (!thisObject)
_as->storeValue(QV4::Primitive::undefinedValue(), p);
@@ -1523,25 +1329,24 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
return argc;
}
-void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::calculateRegistersToSave(const RegisterInformation &used)
{
regularRegistersToSave.clear();
fpRegistersToSave.clear();
- for (const RegisterInfo &ri : Assembler::getRegisterInfo()) {
-#if defined(RESTORE_EBX_ON_CALL)
- if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
+ for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
+ if (JITTargetPlatform::gotRegister != -1 && ri.isRegularRegister() && ri.reg<RegisterID>() == JITTargetPlatform::gotRegister) {
regularRegistersToSave.append(ri);
continue;
}
-#endif // RESTORE_EBX_ON_CALL
if (ri.isCallerSaved())
continue;
if (ri.isRegularRegister()) {
@@ -1564,35 +1369,38 @@ bool operator==(const Primitive &v1, const Primitive &v2)
} // QV4 namespace
QT_END_NAMESPACE
-bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchDouble(true, op, left, right);
+ Jump target = _as->branchDouble(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchDouble(false, op, left, right);
+ Jump target = _as->branchDouble(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-bool InstructionSelection::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchInt32(true, op, left, right);
+ Jump target = _as->branchInt32(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchInt32(false, op, left, right);
+ Jump target = _as->branchInt32(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual);
@@ -1607,15 +1415,16 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareStrictEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareStrictEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
// Only load the non-null temp.
-bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1640,19 +1449,20 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
+ const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
_as->load32(tagAddr, tagReg);
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const TrustedImm32 tag(QV4::Value::Null_Type_Internal);
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictUndefined(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1677,28 +1487,15 @@ bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
return true;
}
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load64(addr, tagReg);
- const Assembler::TrustedImm64 tag(0);
-#else // !QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load32(tagAddr, tagReg);
- Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0));
- _as->addPatch(falseBlock, j);
-
- tagAddr.offset += 4;
- _as->load32(tagAddr, tagReg);
- const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
-#endif
- _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
+ _as->generateCJumpOnUndefined(cond, varSrc, JITTargetPlatform::ScratchRegister, tagReg, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
IR::Expr *boolSrc = 0, *otherSrc = 0;
@@ -1712,13 +1509,20 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// neither operands are statically typed as bool, so bail out.
return false;
}
+ if (otherSrc->type == IR::UnknownType) {
+ // Ok, we really need to call into the runtime.
+ // (This case doesn't happen when the optimizer ran, because everything will be typed (yes,
+ // possibly as "var" meaning anything), but it does happen for $0===true, which is generated
+ // for things where the optimizer didn't run (like functions with a try block).)
+ return false;
+ }
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
if (otherSrc->type == IR::BoolType) { // both are boolean
- Assembler::RegisterID one = _as->toBoolRegister(boolSrc, Assembler::ReturnValueRegister);
- Assembler::RegisterID two = _as->toBoolRegister(otherSrc, Assembler::ScratchRegister);
+ RegisterID one = _as->toBoolRegister(boolSrc, JITTargetPlatform::ReturnValueRegister);
+ RegisterID two = _as->toBoolRegister(otherSrc, JITTargetPlatform::ScratchRegister);
_as->generateCJumpOnCompare(cond, one, two, _block, trueBlock, falseBlock);
return true;
}
@@ -1728,13 +1532,13 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
return true;
}
- Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc);
+ Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
- _as->load32(otherAddr, Assembler::ScratchRegister);
- Assembler::Jump noBool = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ _as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
+ Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(QV4::Value::Boolean_Type_Internal));
if (binop->op == IR::OpStrictEqual)
_as->addPatch(falseBlock, noBool);
else
@@ -1742,14 +1546,15 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// ok, both are boolean, so let's load them and compare them.
otherAddr.offset -= 4; // int_32 address
- _as->load32(otherAddr, Assembler::ReturnValueRegister);
- Assembler::RegisterID boolReg = _as->toBoolRegister(boolSrc, Assembler::ScratchRegister);
- _as->generateCJumpOnCompare(cond, boolReg, Assembler::ReturnValueRegister, _block, trueBlock,
+ _as->load32(otherAddr, JITTargetPlatform::ReturnValueRegister);
+ RegisterID boolReg = _as->toBoolRegister(boolSrc, JITTargetPlatform::ScratchRegister);
+ _as->generateCJumpOnCompare(cond, boolReg, JITTargetPlatform::ReturnValueRegister, _block, trueBlock,
falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1776,18 +1581,18 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
_as->load32(tagAddr, tagReg);
if (binop->op == IR::OpNotEqual)
qSwap(trueBlock, falseBlock);
- Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal)));
- Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
+ Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal)));
+ Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
tagAddr.offset -= 4;
_as->load32(tagAddr, tagReg);
- Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0));
+ Jump isNotUndefinedValue = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(0));
_as->addPatch(trueBlock, isNull);
_as->addPatch(falseBlock, isNotUndefinedTag);
_as->addPatch(falseBlock, isNotUndefinedValue);
@@ -1797,7 +1602,8 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
}
-void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpEqual || binop->op == IR::OpNotEqual);
@@ -1808,18 +1614,55 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
-QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+template <typename JITAssembler>
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
result.adopt(new JIT::CompilationUnit);
return result;
}
+QT_BEGIN_NAMESPACE
+namespace QV4 { namespace JIT {
+template class Q_QML_EXPORT InstructionSelection<>;
+template class Q_QML_EXPORT ISelFactory<>;
+#if defined(V4_BOOTSTRAP)
+
+Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
+{
+ using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+ using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
+
+ if (architecture == QLatin1String("armv7"))
+ return new ISelFactory<ARMv7CrossAssembler>;
+ else if (architecture == QLatin1String("armv8"))
+ return new ISelFactory<ARM64CrossAssembler>;
+
+ QString hostArch;
+#if CPU(ARM_THUMB2)
+ hostArch = QStringLiteral("armv7");
+#elif CPU(MIPS)
+ hostArch = QStringLiteral("mips");
+#elif CPU(X86)
+ hostArch = QStringLiteral("x86");
+#elif CPU(X86_64)
+ hostArch = QStringLiteral("x86_64");
+#endif
+ if (!hostArch.isEmpty() && architecture == hostArch)
+ return new ISelFactory<>;
+
+ return nullptr;
+}
+
+#endif
+} }
+QT_END_NAMESPACE
+
#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 012745c5f2..5c046cb397 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -72,6 +72,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT InstructionSelection:
protected IR::IRDecoder,
public EvalInstructionSelection
@@ -136,18 +137,31 @@ protected:
void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target) override;
void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) override;
- typedef Assembler::Address Address;
- typedef Assembler::Pointer Pointer;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Label = typename JITAssembler::Label;
+ using Jump = typename JITAssembler::Jump;
+ using StringToIndex = typename JITAssembler::StringToIndex;
+ using Reference = typename JITAssembler::Reference;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+
+ using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
-#if !defined(ARGUMENTS_IN_REGISTERS)
Address addressForArgument(int index) const
{
// FramePointerRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
- return Address(Assembler::FramePointerRegister, (index + 2) * sizeof(void*));
+ return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
}
-#endif
Pointer baseAddressForCallArguments()
{
@@ -192,61 +206,55 @@ private:
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (IR::Temp *sourceTemp = source->asTemp()) {
if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertInt32ToDouble((Assembler::RegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble((RegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
} else {
- _as->convertInt32ToDouble(_as->loadAddress(Assembler::ReturnValueRegister, sourceTemp),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp),
+ (FPRegisterID) targetTemp->index);
}
} else {
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ (FPRegisterID) targetTemp->index);
}
return;
}
}
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target));
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
- Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
+ RegisterID tmpReg = JITTargetPlatform::ScratchRegister;
+ RegisterID reg = _as->toInt32Register(source, tmpReg);
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg);
+ _as->convertUInt32ToDouble(reg, (FPRegisterID) targetTemp->index, tmpReg);
return;
}
}
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
- Assembler::FPGpr0, tmpReg);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target));
+ JITTargetPlatform::FPGpr0, tmpReg);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target));
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID reg = Assembler::ScratchRegister;
+ RegisterID reg = JITTargetPlatform::ScratchRegister;
if (IR::Temp *targetTemp = target->asTemp())
if (targetTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::RegisterID) targetTemp->index;
+ reg = (RegisterID) targetTemp->index;
_as->move(_as->toInt32Register(source, reg), reg);
- _as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
+ _as->compare32(RelationalCondition::NotEqual, reg, TrustedImm32(0), reg);
_as->storeBool(reg, target);
}
- #define isel_stringIfyx(s) #s
- #define isel_stringIfy(s) isel_stringIfyx(s)
-
- #define generateRuntimeCall(t, function, ...) \
- _as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
-
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
@@ -259,22 +267,22 @@ private:
// goes into the same register as the return value (currently only ARM), the prepareCall
// will combine loading the looupAddr into the register and calculating the indirect call
// address.
- Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
+ Pointer lookupAddr(JITTargetPlatform::ReturnValueRegister, index * sizeof(QV4::Lookup));
_as->generateFunctionCallImp(true, retval, "lookup getter/setter",
- LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
+ typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
arg1, arg2, arg3);
}
template <typename Retval, typename Arg1, typename Arg2>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
- generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType());
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
}
IR::BasicBlock *_block;
BitVector _removableJumps;
- Assembler* _as;
+ JITAssembler* _as;
QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
@@ -282,13 +290,14 @@ private:
RegisterInformation fpRegistersToSave;
};
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
virtual ~ISelFactory() {}
EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ { return new InstructionSelection<JITAssembler>(qmlEngine, execAllocator, module, jsGenerator, this); }
bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return true; }
QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 3fb0815299..e5abaa7458 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -973,7 +973,15 @@ private:
break;
Q_ASSERT(!i->isFixedInterval());
- _liveIntervals.push_back(i);
+ auto it = _liveIntervals.begin();
+ for (; it != _liveIntervals.end(); ++it) {
+ if ((*it)->temp() == i->temp()) {
+ *it = i;
+ break;
+ }
+ }
+ if (it == _liveIntervals.end())
+ _liveIntervals.push_back(i);
// qDebug() << "-- Activating interval for temp" << i->temp().index;
_unprocessedReverseOrder.removeLast();
@@ -1521,7 +1529,7 @@ static inline int indexOfRangeCoveringPosition(const LifeTimeInterval::Ranges &r
return -1;
}
-static inline int intersectionPosition(const LifeTimeInterval::Range &one, const LifeTimeInterval::Range &two)
+static inline int intersectionPosition(const LifeTimeIntervalRange &one, const LifeTimeIntervalRange &two)
{
if (one.covers(two.start))
return two.start;
@@ -1567,7 +1575,7 @@ static void longestAvailableReg(int *nextUses, int nextUseCount, int &reg, int &
#define CALLOC_ON_STACK(ty, ptr, sz, val) \
Q_ASSERT(sz > 0); \
- ty *ptr = reinterpret_cast<ty *>(alloca(sizeof(ty) * (sz))); \
+ Q_ALLOCA_VAR(ty, ptr, sizeof(ty) * (sz)); \
for (ty *it = ptr, *eit = ptr + (sz); it != eit; ++it) \
*it = val;
@@ -1779,9 +1787,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
return -1;
for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) {
- const LifeTimeInterval::Range currentRange = currentRanges.at(currentIt);
+ const LifeTimeIntervalRange currentRange = currentRanges.at(currentIt);
for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) {
- const LifeTimeInterval::Range anotherRange = anotherRanges.at(anotherIt);
+ const LifeTimeIntervalRange anotherRange = anotherRanges.at(anotherIt);
if (anotherRange.start > currentRange.end)
break;
int intersectPos = intersectionPosition(currentRange, anotherRange);
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index 7e265258d5..fcc600eb2e 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+enum TargetOperatingSystemSpecialization {
+ NoOperatingSystemSpecialization,
+ WindowsSpecialization
+};
+
// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
//
// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
@@ -79,25 +84,38 @@ namespace JIT {
// a call, we add a load it right before emitting the call instruction.
//
// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h!
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization specialization = NoOperatingSystemSpecialization>
class TargetPlatform
{
-public:
+};
+
#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD) || defined(Q_OS_IOS))
- enum { RegAllocIsSupported = 1 };
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::esi;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ enum { RegAllocIsSupported = 1 };
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const RegisterID EngineRegister = JSC::X86Registers::esi;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID LowReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID HighReturnValueRegister = JSC::X86Registers::edx;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -109,28 +127,31 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-# undef VALUE_FITS_IN_REGISTER
static const int RegisterSize = 4;
-# undef ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 0;
- static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
+ static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
+ {
+ if (frameSize > 0)
+ as->add32(TrustedImm32(frameSize), StackPointerRegister);
+ as->pop(FramePointerRegister);
+ }
#if OS(WINDOWS) || OS(QNX) || \
((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
-#define RESTORE_EBX_ON_CALL
- static JSC::MacroAssembler::Address ebxAddressOnStack()
- {
+ static const int gotRegister = JSC::X86Registers::ebx;
+ static int savedGOTRegisterSlotOnStack() {
static int ebxIdx = -1;
if (ebxIdx == -1) {
int calleeSaves = 0;
@@ -146,34 +167,47 @@ public:
Q_ASSERT(ebxIdx >= 0);
ebxIdx += 1;
}
- return JSC::MacroAssembler::Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
+ return ebxIdx * -int(sizeof(void*));
}
+#else
+ static const int gotRegister = -1;
+ static int savedGOTRegisterSlotOnStack() { return -1; }
#endif
-
-#endif // Windows on x86
+};
+#endif // x86
#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || OS(QNX) || defined(Q_OS_IOS))
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ // r11 is used as scratch register by the macro assembler
<< RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -185,17 +219,16 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-#define VALUE_FITS_IN_REGISTER
static const int RegisterSize = 8;
-#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 6;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::edi,
JSC::X86Registers::esi,
JSC::X86Registers::edx,
@@ -210,51 +243,72 @@ public:
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(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
#if CPU(X86_64) && OS(WINDOWS)
- // 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
- // incoming function parameters to the shadow space is missing.
- enum { RegAllocIsSupported = 0 };
-
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static RegisterInformation getPlatformRegisterInfo()
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, WindowsSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
+
+ enum { RegAllocIsSupported = 1 };
+
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
- << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
- << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
- << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ static RegisterInformation info = RegisterInformation()
+ << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ // r11 is used as scratch register by the macro assembler
<< RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-#define VALUE_FITS_IN_REGISTER
static const int RegisterSize = 8;
-#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::ecx,
JSC::X86Registers::edx,
JSC::X86Registers::r8,
@@ -262,16 +316,34 @@ public:
};
Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
return regs[index];
- };
+ }
static const int StackAlignment = 16;
static const int StackShadowSpace = 32;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(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
-#if CPU(ARM)
+#if CPU(ARM) || defined(V4_BOOTSTRAP)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARMv7;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
+
enum { RegAllocIsSupported = 1 };
// The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
@@ -287,23 +359,25 @@ public:
// is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
// accordingly, and assign the locals-register to the "other" register.
#if CPU(ARM_THUMB2)
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
#endif
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r5;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARMRegisters::r10;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r5;
+ static const RegisterID EngineRegister = JSC::ARMRegisters::r10;
+ static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+ static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
+ static const RegisterID LowReturnValueRegister = JSC::ARMRegisters::r0;
+ static const RegisterID HighReturnValueRegister = JSC::ARMRegisters::r1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -336,17 +410,16 @@ public:
<< RI(JSC::ARMRegisters::d14, QStringLiteral("d14"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::d15, QStringLiteral("d15"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
-#undef VALUE_FITS_IN_REGISTER
static const int RegisterSize = 4;
-#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARMRegisters::r0,
JSC::ARMRegisters::r1,
JSC::ARMRegisters::r2,
@@ -361,35 +434,54 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::ARMRegisters::lr);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *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(JSC::ARMRegisters::lr);
}
+
+ static const int gotRegister = -1;
+ static int savedGOTRegisterSlotOnStack() { return -1; }
+};
#endif // ARM (32 bit)
-#if CPU(ARM64)
+#if CPU(ARM64) || defined(V4_BOOTSTRAP)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARM64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARM64Registers::x28;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARM64Registers::x9;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARM64Registers::x27;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
+ static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
+ static const RegisterID LocalsRegister = JSC::ARM64Registers::x28;
+ static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
+ static const RegisterID ScratchRegister = JSC::ARM64Registers::x9;
+ static const RegisterID EngineRegister = JSC::ARM64Registers::x27;
+ static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
+ static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
+ static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARM64Registers::x0, QStringLiteral("x0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARM64Registers::x1, QStringLiteral("x1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::x2, QStringLiteral("x2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -447,17 +539,16 @@ public:
<< RI(JSC::ARM64Registers::q30, QStringLiteral("q30"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::q31, QStringLiteral("q31"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
-#define VALUE_FITS_IN_REGISTER
static const int RegisterSize = 8;
-#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 8;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARM64Registers::x0,
JSC::ARM64Registers::x1,
JSC::ARM64Registers::x2,
@@ -476,33 +567,49 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
+ if (frameSize > 0)
+ as->add64(TrustedImm32(frameSize), StackPointerRegister);
as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
+
+ static const int gotRegister = -1;
+ static int savedGOTRegisterSlotOnStack() { return -1; }
+};
#endif // ARM64
#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
+template <>
+class TargetPlatform<JSC::MacroAssemblerMIPS, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerMIPS;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+ using TrustedImm32 = PlatformAssembler::TrustedImm32;
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::MIPSRegisters::s1;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
+ static const RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
+ static const RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
+ static const RegisterID EngineRegister = JSC::MIPSRegisters::s1;
+ static const RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
+ static const FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
+ static const FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
+ static const RegisterID LowReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID HighReturnValueRegister = JSC::MIPSRegisters::v1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
// Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS.
<< RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -524,17 +631,16 @@ public:
<< RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
-#undef VALUE_FITS_IN_REGISTER
static const int RegisterSize = 4;
-#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::MIPSRegisters::a0,
JSC::MIPSRegisters::a1,
JSC::MIPSRegisters::a2,
@@ -549,27 +655,25 @@ public:
static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers.
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::MIPSRegisters::ra);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
+ if (frameSize > 0)
+ as->add32(TrustedImm32(frameSize), StackPointerRegister);
as->pop(FramePointerRegister);
as->pop(JSC::MIPSRegisters::ra);
}
-#endif // Linux on MIPS (32 bit)
-public: // utility functions
- static const RegisterInformation getRegisterInfo()
- {
- static const RegisterInformation info = getPlatformRegisterInfo();
- return info;
- }
+ static const int gotRegister = -1;
+ static int savedGOTRegisterSlotOnStack() { return -1; }
};
+#endif // Linux on MIPS (32 bit)
} // JIT namespace
} // QV4 namespace
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 799103849b..76c6457d67 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -48,14 +48,15 @@ using namespace JIT;
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
do { \
- call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
+ call = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void Unop::generate(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generate(IR::Expr *source, IR::Expr *target)
{
bool needsExceptionCheck;
- RuntimeCall call;
+ typename JITAssembler::RuntimeCall call;
const char *name = 0;
switch (op) {
case IR::OpNot:
@@ -75,17 +76,18 @@ void Unop::generate(IR::Expr *source, IR::Expr *target)
} // switch
Q_ASSERT(call.isValid());
- _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, Assembler::PointerToValue(source));
+ _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, PointerToValue(source));
}
-void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateUMinus(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- Assembler::RegisterID sReg = _as->toInt32Register(source, tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ typename JITAssembler::RegisterID sReg = _as->toInt32Register(source, tReg);
_as->move(sReg, tReg);
_as->neg32(tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
@@ -93,26 +95,27 @@ void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
return;
}
- generateRuntimeCall(target, uMinus, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
}
-void Unop::generateNot(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateNot(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::BoolType) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
return;
} else if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->compare32(Assembler::Equal,
- _as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->compare32(RelationalCondition::Equal,
+ _as->toInt32Register(source, JITAssembler::ScratchRegister), TrustedImm32(0),
tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
@@ -122,22 +125,33 @@ void Unop::generateNot(IR::Expr *source, IR::Expr *target)
}
// ## generic implementation testing for int/bool
- generateRuntimeCall(target, uNot, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uNot, PointerToValue(source));
}
-void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateCompl(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeInt32(tReg, target);
return;
}
- generateRuntimeCall(target, complement, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, complement, PointerToValue(source));
}
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP)
+#if !CPU(ARM_THUMB2)
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#endif
+#if !CPU(ARM64)
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>>;
+#endif
+#endif
+
#endif
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
index 1141a84913..fb68f80eec 100644
--- a/src/qml/jit/qv4unop_p.h
+++ b/src/qml/jit/qv4unop_p.h
@@ -60,21 +60,25 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class Assembler;
-
+template <typename JITAssembler>
struct Unop {
- Unop(Assembler *assembler, IR::AluOp operation)
+ Unop(JITAssembler *assembler, IR::AluOp operation)
: _as(assembler)
, op(operation)
{}
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+
void generate(IR::Expr *source, IR::Expr *target);
void generateUMinus(IR::Expr *source, IR::Expr *target);
void generateNot(IR::Expr *source, IR::Expr *target);
void generateCompl(IR::Expr *source, IR::Expr *target);
- Assembler *_as;
+ JITAssembler *_as;
IR::AluOp op;
};
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 919524d1ed..955cf585e4 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -35,7 +35,6 @@ SOURCES += \
$$PWD/qv4regexp.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4executableallocator.cpp \
$$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
@@ -113,7 +112,8 @@ HEADERS += \
SOURCES += \
$$PWD/qv4runtime.cpp \
$$PWD/qv4string.cpp \
- $$PWD/qv4value.cpp
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4executableallocator.cpp
valgrind {
DEFINES += V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 5a190d6690..7c1cc92a13 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -88,10 +88,12 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
- d()->mappedArguments = md->allocate(engine(), numAccessors);
- for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
- arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ if (numAccessors) {
+ d()->mappedArguments = md->allocate(engine(), numAccessors);
+ for (uint i = 0; i < numAccessors; ++i) {
+ d()->mappedArguments->data[i] = context()->callData->args[i];
+ arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ }
}
arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
@@ -164,18 +166,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
return Encode::undefined();
}
-void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
+bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
args->fullyCreate();
- if (args->fullyCreated()) {
- Object::putIndexed(m, index, value);
- return;
- }
+ if (args->fullyCreated())
+ return Object::putIndexed(m, index, value);
args->context()->callData->args[index] = value;
+ return true;
}
bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 0a2ea3b42a..f80ade9611 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -128,7 +128,7 @@ struct ArgumentsObject: Object {
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 60b90e4bf0..740ebbe359 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -155,7 +155,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
ctx = ctx->d()->outer;
}
- if (activation->hasProperty(name))
+ if (activation->hasOwnProperty(name))
return;
ScopedProperty desc(scope);
PropertyAttributes attrs(Attr_Data);
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b90c335b1c..c56d007028 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -340,7 +340,9 @@ static inline double TimeClip(double t)
{
if (! qt_is_finite(t) || fabs(t) > 8.64e15)
return qt_qnan();
- return Primitive::toInteger(t);
+
+ // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0.
+ return Primitive::toInteger(t) + 0;
}
static inline double ParseString(const QString &s)
@@ -724,7 +726,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7));
LocalTZA = getLocalTZA();
ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
@@ -774,8 +776,21 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1);
defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3);
defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
- defineDefaultProperty(QStringLiteral("toUTCString"), method_toUTCString, 0);
- defineDefaultProperty(QStringLiteral("toGMTString"), method_toUTCString, 0);
+
+ // ES6: B.2.4.3 & 20.3.4.43:
+ // We have to use the *same object* for toUTCString and toGMTString
+ {
+ QString toUtcString(QStringLiteral("toUTCString"));
+ QString toGmtString(QStringLiteral("toGMTString"));
+ ScopedString us(scope, engine->newIdentifier(toUtcString));
+ ScopedString gs(scope, engine->newIdentifier(toGmtString));
+ ExecutionContext *global = engine->rootContext();
+ ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString));
+ toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineDefaultProperty(us, toUtcGmtStringFn);
+ defineDefaultProperty(gs, toUtcGmtStringFn);
+ }
+
defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
@@ -1025,6 +1040,7 @@ void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(t));
scope.result = Encode(self->date());
}
@@ -1036,7 +1052,9 @@ void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
scope.result = Encode(self->date());
}
@@ -1048,7 +1066,9 @@ void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &sc
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
scope.result = Encode(self->date());
}
@@ -1060,8 +1080,11 @@ void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1088,9 +1111,13 @@ void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1118,10 +1145,15 @@ void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1150,7 +1182,9 @@ void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1163,7 +1197,9 @@ void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1176,8 +1212,11 @@ void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1245,11 +1284,15 @@ void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, Ca
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
if (std::isnan(t))
t = 0;
double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index a56d17f9b1..b32b2c3f66 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -112,7 +112,7 @@ struct DateCtor: FunctionObject
static void call(const Managed *that, Scope &scope, CallData *);
};
-struct DatePrototype: DateObject
+struct DatePrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a11f7f0875..39b433e5f9 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -91,7 +91,9 @@
#if USE(PTHREADS)
# include <pthread.h>
+#if !defined(Q_OS_INTEGRITY)
# include <sys/resource.h>
+#endif
#if HAVE(PTHREAD_NP_H)
# include <pthread_np.h>
#endif
@@ -168,7 +170,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
if (forceMoth) {
factory = new Moth::ISelFactory;
} else {
- factory = new JIT::ISelFactory;
+ factory = new JIT::ISelFactory<>;
jitDisabled = false;
}
#else // !V4_ENABLE_JIT
@@ -256,6 +258,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(arrayClass, objectPrototype());
+ jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
@@ -358,6 +361,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
+ static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
@@ -400,7 +404,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
- globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor());
+ FunctionObject *numberObject = numberCtor();
+ globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
@@ -430,8 +435,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
- globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
- globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
+ // ES6: 20.1.2.12 & 20.1.2.13:
+ // parseInt and parseFloat must be the same FunctionObject on the global &
+ // Number object.
+ {
+ QString piString(QStringLiteral("parseInt"));
+ QString pfString(QStringLiteral("parseFloat"));
+ Scope scope(this);
+ ScopedString pi(scope, newIdentifier(piString));
+ ScopedString pf(scope, newIdentifier(pfString));
+ ExecutionContext *global = rootContext();
+ ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt));
+ ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat));
+ parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
+ parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
+ globalObject->defineDefaultProperty(piString, parseIntFn);
+ globalObject->defineDefaultProperty(pfString, parseFloatFn);
+ numberObject->defineDefaultProperty(piString, parseIntFn);
+ numberObject->defineDefaultProperty(pfString, parseFloatFn);
+ }
+
globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
@@ -1109,7 +1132,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (typeHint == qMetaTypeId<QJSValue>())
return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
- if (value.as<Object>()) {
+ if (value.as<QV4::Object>()) {
QV4::ScopedObject object(scope, value);
if (typeHint == QMetaType::QJsonObject
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
@@ -1755,7 +1778,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
@@ -1770,7 +1793,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value,
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value)
+static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (!value.isObject())
return 0;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 1c20ad30aa..69aa389c44 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -157,6 +157,7 @@ public:
IntegerNull, // Has to come after the RootContext to make the context stack safe
ObjectProto,
ArrayProto,
+ PropertyListProto,
StringProto,
NumberProto,
BooleanProto,
@@ -225,6 +226,7 @@ public:
Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
+ Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index b2d89220ea..e9431ed25e 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -131,7 +131,7 @@ void FunctionObject::init(String *n, bool createProto)
}
if (n)
- defineReadonlyProperty(s.engine->id_name(), *n);
+ defineReadonlyConfigurableProperty(s.engine->id_name(), *n);
}
ReturnedValue FunctionObject::name() const
@@ -258,10 +258,10 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
@@ -557,7 +557,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(s.engine->id_length(), Primitive::fromInt32(len));
ScopedProperty pd(s);
pd->value = s.engine->thrower();
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 66861bf697..b0d14fc2b4 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -258,6 +258,7 @@ enum PropertyFlag {
Attr_NotEnumerable = 0x4,
Attr_NotConfigurable = 0x8,
Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable,
+ Attr_ReadOnly_ButConfigurable = Attr_NotWritable|Attr_NotEnumerable,
Attr_Invalid = 0xff
};
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index dcda949c97..1d8ef4b0fb 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -234,7 +234,7 @@ struct InternalClassTransition
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id; }
+ { return id < other.id || (id == other.id && flags < other.flags); }
};
struct InternalClass : public QQmlJS::Managed {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 1d571f53f3..0f021c8bd0 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -705,7 +705,7 @@ QString Stringify::Str(const QString &key, const Value &v)
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), scope.result);
+ holder->put(scope.engine->id_empty(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
callData->args[1] = scope.result;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 52f54e25f5..c5ee92fedd 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -54,8 +54,11 @@
#include "qv4runtime_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+
+#if !defined(V4_BOOTSTRAP)
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index f2a24f8179..db45c77472 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -55,6 +55,7 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(n);
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 09644c161d..8cfa930888 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -102,6 +102,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
+ ctor->defineReadonlyProperty(QStringLiteral("MAX_SAFE_INTEGER"), Primitive::fromDouble(9007199254740991));
+ ctor->defineReadonlyProperty(QStringLiteral("MIN_SAFE_INTEGER"), Primitive::fromDouble(-9007199254740991));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
@@ -109,15 +111,17 @@ QT_WARNING_DISABLE_INTEL(239)
QT_WARNING_POP
ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isInteger"), method_isInteger, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isSafeInteger"), method_isSafeInteger, 1);
ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
- defineDefaultProperty(engine->id_toString(), method_toString);
+ defineDefaultProperty(engine->id_toString(), method_toString, 1);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1);
- defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential);
- defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
+ defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1);
+ defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1);
}
inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
@@ -155,6 +159,52 @@ void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, Cal
scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
+void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv);
+}
+
+void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+}
+
void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (!callData->argc) {
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 364b866a16..e18267c50c 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -88,6 +88,8 @@ struct NumberPrototype: NumberObject
void init(ExecutionEngine *engine, Object *ctor);
static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 5d6c479477..dd3bbccde3 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,7 +61,8 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
- if (!d()->memberData || (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);
}
@@ -92,13 +93,6 @@ bool Object::setPrototype(Object *proto)
return true;
}
-void Object::put(ExecutionEngine *engine, const QString &name, const Value &value)
-{
- Scope scope(engine);
- ScopedString n(scope, engine->newString(name));
- put(n, value);
-}
-
ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs)
{
if (!attrs.isAccessor())
@@ -114,11 +108,11 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
return scope.result.asReturnedValue();
}
-void Object::putValue(uint memberIndex, const Value &value)
+bool Object::putValue(uint memberIndex, const Value &value)
{
QV4::InternalClass *ic = internalClass();
if (ic->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs = ic->propertyData[memberIndex];
@@ -131,7 +125,7 @@ void Object::putValue(uint memberIndex, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !ic->engine->hasException;
}
goto reject;
}
@@ -140,11 +134,12 @@ void Object::putValue(uint memberIndex, const Value &value)
goto reject;
*propertyData(memberIndex) = value;
- return;
+ return true;
reject:
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
void Object::defineDefaultProperty(const QString &name, const Value &value)
@@ -162,7 +157,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -173,7 +168,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -183,7 +178,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -193,7 +188,7 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -250,6 +245,19 @@ void Object::defineReadonlyProperty(String *name, const Value &value)
insertMember(name, value, Attr_ReadOnly);
}
+void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value)
+{
+ QV4::ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineReadonlyConfigurableProperty(s, value);
+}
+
+void Object::defineReadonlyConfigurableProperty(String *name, const Value &value)
+{
+ insertMember(name, value, Attr_ReadOnly_ButConfigurable);
+}
+
void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
{
Heap::Object *o = static_cast<Heap::Object *>(that);
@@ -440,14 +448,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty
return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
}
-void Object::put(Managed *m, String *name, const Value &value)
+bool Object::put(Managed *m, String *name, const Value &value)
{
- static_cast<Object *>(m)->internalPut(name, value);
+ return static_cast<Object *>(m)->internalPut(name, value);
}
-void Object::putIndexed(Managed *m, uint index, const Value &value)
+bool Object::putIndexed(Managed *m, uint index, const Value &value)
{
- static_cast<Object *>(m)->internalPutIndexed(index, value);
+ return static_cast<Object *>(m)->internalPutIndexed(index, value);
}
PropertyAttributes Object::query(const Managed *m, String *name)
@@ -705,10 +713,10 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
-void Object::internalPut(String *name, const Value &value)
+bool Object::internalPut(String *name, const Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -737,7 +745,7 @@ void Object::internalPut(String *name, const Value &value)
uint l = value.asArrayLength(&ok);
if (!ok) {
engine()->throwRangeError(value);
- return;
+ return false;
}
ok = setArrayLength(l);
if (!ok)
@@ -745,7 +753,7 @@ void Object::internalPut(String *name, const Value &value)
} else {
*v = value;
}
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
@@ -776,24 +784,26 @@ void Object::internalPut(String *name, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
insertMember(name, value);
- return;
+ return true;
reject:
+ // ### this should be removed once everything is ported to use Object::set()
if (engine()->current->strictMode) {
QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
engine()->throwTypeError(message);
}
+ return false;
}
-void Object::internalPutIndexed(uint index, const Value &value)
+bool Object::internalPutIndexed(uint index, const Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs;
@@ -815,7 +825,7 @@ void Object::internalPutIndexed(uint index, const Value &value)
goto reject;
else
*v = value;
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
@@ -846,15 +856,17 @@ void Object::internalPutIndexed(uint index, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
arraySet(index, value);
- return;
+ return true;
reject:
+ // ### this should be removed once everything is ported to use Object::setIndexed()
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
// Section 8.12.7
@@ -1155,6 +1167,49 @@ uint Object::getLength(const Managed *m)
return v->toUInt32();
}
+// 'var' is 'V' in 15.3.5.3.
+ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var)
+{
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+
+ // 15.3.5.3, Assume F is a Function object.
+ const FunctionObject *function = typeObject->as<FunctionObject>();
+ if (!function)
+ return engine->throwTypeError();
+
+ Heap::FunctionObject *f = function->d();
+ if (function->isBoundFunction())
+ f = function->cast<BoundFunction>()->target();
+
+ // 15.3.5.3, 1: HasInstance can only be used on an object
+ const Object *lhs = var.as<Object>();
+ if (!lhs)
+ return Encode(false);
+
+ // 15.3.5.3, 2
+ const Object *o = f->protoProperty();
+ if (!o) // 15.3.5.3, 3
+ return engine->throwTypeError();
+
+ Heap::Object *v = lhs->d();
+
+ // 15.3.5.3, 4
+ while (v) {
+ // 15.3.5.3, 4, a
+ v = v->prototype;
+
+ // 15.3.5.3, 4, b
+ if (!v)
+ break; // will return false
+
+ // 15.3.5.3, 4, c
+ else if (o->d() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
bool Object::setArrayLength(uint newLen)
{
Q_ASSERT(isArrayObject());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 4a78690f47..0d17afbf41 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -130,8 +130,8 @@ struct ObjectVTable
void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
- void (*put)(Managed *, String *name, const Value &value);
- void (*putIndexed)(Managed *, uint index, const Value &value);
+ bool (*put)(Managed *, String *name, const Value &value);
+ bool (*putIndexed)(Managed *, uint index, const Value &value);
PropertyAttributes (*query)(const Managed *, String *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
bool (*deleteProperty)(Managed *m, String *name);
@@ -140,6 +140,7 @@ struct ObjectVTable
void (*setLookup)(Managed *m, Lookup *l, const Value &v);
uint (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
+ ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
};
#define DEFINE_OBJECT_VTABLE_BASE(classname) \
@@ -159,7 +160,8 @@ const QV4::ObjectVTable classname::static_vtbl = \
getLookup, \
setLookup, \
getLength, \
- advanceIterator \
+ advanceIterator, \
+ instanceOf \
}
#define DEFINE_OBJECT_VTABLE(classname) \
@@ -221,8 +223,6 @@ struct Q_QML_EXPORT Object: Managed {
//
// helpers
//
- void put(ExecutionEngine *engine, const QString &name, const Value &value);
-
static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs);
ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const {
Scope scope(this->engine());
@@ -230,7 +230,7 @@ struct Q_QML_EXPORT Object: Managed {
return getValue(t, v, attrs);
}
- void putValue(uint memberIndex, const Value &value);
+ bool putValue(uint memberIndex, const Value &value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
void defineDefaultProperty(String *name, const Value &value) {
@@ -251,6 +251,10 @@ struct Q_QML_EXPORT Object: Managed {
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
+ /* Fixed: Writable: false, Enumerable: false, Configurable: true */
+ void defineReadonlyConfigurableProperty(const QString &name, const Value &value);
+ void defineReadonlyConfigurableProperty(String *name, const Value &value);
+
void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
Scope scope(engine());
ScopedProperty p(scope);
@@ -332,10 +336,47 @@ public:
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const
{ return vtable()->getIndexed(this, idx, hasProperty); }
- inline void put(String *name, const Value &v)
- { vtable()->put(this, name, v); }
- inline void putIndexed(uint idx, const Value &v)
- { vtable()->putIndexed(this, idx, v); }
+
+ // use the set variants instead, to customize throw behavior
+ inline bool put(String *name, const Value &v)
+ { return vtable()->put(this, name, v); }
+ inline bool putIndexed(uint idx, const Value &v)
+ { return vtable()->putIndexed(this, idx, v); }
+
+ enum ThrowOnFailure {
+ DoThrowOnRejection,
+ DoNotThrow
+ };
+
+ // ES6: 7.3.3 Set (O, P, V, Throw)
+ inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->put(this, name, v);
+ // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
+ e->throwTypeError(message);
+ }
+ }
+ return ret;
+ }
+
+ inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->putIndexed(this, idx, v);
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ e->throwTypeError();
+ }
+ }
+ return ret;
+ }
+
+
PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
@@ -351,6 +392,8 @@ public:
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
+ ReturnedValue instanceOf(const Value &var) const
+ { return vtable()->instanceOf(this, var); }
inline void construct(Scope &scope, CallData *d) const
{ return vtable()->construct(this, scope, d); }
@@ -362,8 +405,8 @@ protected:
static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static bool deleteProperty(Managed *m, String *name);
@@ -372,12 +415,13 @@ protected:
static void setLookup(Managed *m, Lookup *l, const Value &v);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
+ static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
- void internalPut(String *name, const Value &value);
- void internalPutIndexed(uint index, const Value &value);
+ bool internalPut(String *name, const Value &value);
+ bool internalPutIndexed(uint index, const Value &value);
bool internalDeleteProperty(String *name);
bool internalDeleteIndexedProperty(uint index);
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 97dbe24339..f650ffc7b1 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -89,10 +90,11 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ScopedObject o(scope, this);
ctor->defineReadonlyProperty(v4->id_prototype(), o);
- ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(v4->id_length(), Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2);
@@ -123,9 +125,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedObject p(scope, o->prototype());
scope.result = !!p ? p->asReturnedValue() : Encode::null();
@@ -133,11 +134,8 @@ void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scop
void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
@@ -154,13 +152,54 @@ void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, S
void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+}
+
+// 19.1.2.1
+void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject to(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ if (callData->argc == 1) {
+ scope.result = to;
return;
}
- scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+ for (int i = 1; i < callData->argc; ++i) {
+ if (callData->args[i].isUndefined() || callData->args[i].isNull())
+ continue;
+
+ ScopedObject from(scope, callData->args[i].toObject(scope.engine));
+ CHECK_EXCEPTION();
+ QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
+ quint32 length = keys->getLength();
+
+ ScopedString nextKey(scope);
+ ScopedValue propValue(scope);
+ for (quint32 i = 0; i < length; ++i) {
+ nextKey = Value::fromReturnedValue(keys->getIndexed(i)).toString(scope.engine);
+
+ PropertyAttributes attrs;
+ ScopedProperty prop(scope);
+ from->getOwnProperty(nextKey, &attrs, prop);
+
+ if (attrs == PropertyFlag::Attr_Invalid)
+ continue;
+
+ if (!attrs.isEnumerable())
+ continue;
+
+ propValue = from->get(nextKey);
+ to->set(nextKey, propValue, Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ }
+
+ scope.result = to;
}
void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
@@ -246,8 +285,11 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.17, 1
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->sealed());
@@ -265,8 +307,11 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.5, 1
+ scope.result = callData->argument(0);
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -287,9 +332,11 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->nonExtensible());
scope.result = o;
@@ -297,9 +344,11 @@ void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &s
void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -335,9 +384,11 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -373,18 +424,19 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(false);
+ return;
+ }
scope.result = Encode((bool)o->isExtensible());
}
void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -670,12 +722,12 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c
return o.asReturnedValue();
}
-
+// es6: GetOwnPropertyKeys
Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
{
Scope scope(v4);
ScopedArrayObject array(scope, v4->newArrayObject());
- ScopedObject O(scope, o);
+ ScopedObject O(scope, o.toObject(v4));
if (O) {
ObjectIterator it(scope, O, ObjectIterator::NoFlags);
ScopedValue name(scope);
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 1db8615511..44b54267f3 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -81,6 +81,7 @@ struct ObjectPrototype: Object
static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assign(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 889f4ea288..cdc29c8b9c 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -225,21 +225,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
return Encode::undefined();
}
-void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlContextWrapper::put(Managed *m, String *name, const Value &value)
{
Q_ASSERT(m->as<QmlContextWrapper>());
QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
if (scope.hasException())
- return;
+ return false;
QV4::Scoped<QmlContextWrapper> wrapper(scope, resource);
uint member = wrapper->internalClass()->find(name);
- if (member < UINT_MAX) {
- wrapper->putValue(member, value);
- return;
- }
+ if (member < UINT_MAX)
+ return wrapper->putValue(member, value);
if (wrapper->d()->isNullWrapper) {
if (wrapper && wrapper->d()->readOnly) {
@@ -247,11 +245,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QLatin1Char('"');
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
- Object::put(m, name, value);
- return;
+ return Object::put(m, name, value);
}
// Its possible we could delay the calculation of the "actual" context (in the case
@@ -260,7 +257,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QQmlContextData *expressionContext = context;
if (!context)
- return;
+ return false;
// See QV8ContextWrapper::Getter for resolution order
@@ -270,18 +267,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
const QV4::IdentifierHash<int> &properties = context->propertyNames();
// Search context properties
if (properties.count() && properties.value(name) != -1)
- return;
+ return false;
// Search scope object
if (scopeObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
scopeObject = 0;
// Search context object
if (context->contextObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
context = context->parent;
}
@@ -292,10 +289,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->throwError(error);
- return;
+ return false;
}
- Object::put(m, name, value);
+ return Object::put(m, name, value);
}
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 9aec7467da..6e5e743609 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -100,7 +100,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
void setReadOnly(bool b) { d()->readOnly = b; }
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 7260e71fab..c9b4b433bd 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -625,13 +625,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has
return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-void QObjectWrapper::put(Managed *m, String *name, const Value &value)
+bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
if (v4->hasException || QQmlData::wasDeleted(that->d()->object()))
- return;
+ return false;
QQmlContextData *qmlContext = v4->callingQmlContext();
if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
@@ -642,10 +642,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
v4->throwError(error);
+ return false;
} else {
- QV4::Object::put(m, name, value);
+ return QV4::Object::put(m, name, value);
}
}
+
+ return true;
}
PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
@@ -673,18 +676,24 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
- if (that->d()->object()) {
- const QMetaObject *mo = that->d()->object()->metaObject();
+ QObject *thatObject = that->d()->object();
+ if (thatObject && !QQmlData::wasDeleted(thatObject)) {
+ const QMetaObject *mo = thatObject->metaObject();
// These indices don't apply to gadgets, so don't block them.
const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject;
const int propertyCount = mo->propertyCount();
if (it->arrayIndex < static_cast<uint>(propertyCount)) {
- Scope scope(that->engine());
- ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())));
+ ExecutionEngine *thatEngine = that->engine();
+ Scope scope(thatEngine);
+ const QMetaProperty property = mo->property(it->arrayIndex);
+ ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name())));
name->setM(propName->d());
++it->arrayIndex;
*attributes = QV4::Attr_Data;
- p->value = that->get(propName);
+
+ QQmlPropertyData local;
+ local.load(property);
+ p->value = that->getProperty(thatEngine, thatObject, &local);
return;
}
const int methodCount = mo->methodCount();
@@ -694,11 +703,15 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
++it->arrayIndex;
if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2)))
continue;
- Scope scope(that->engine());
- ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name())));
+ ExecutionEngine *thatEngine = that->engine();
+ Scope scope(thatEngine);
+ ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name())));
name->setM(methodName->d());
*attributes = QV4::Attr_Data;
- p->value = that->get(methodName);
+
+ QQmlPropertyData local;
+ local.load(method);
+ p->value = that->getProperty(thatEngine, thatObject, &local);
return;
}
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index b09e06cec5..d81ef2a680 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -192,7 +192,7 @@ protected:
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 40682aaa4b..0894d0c25b 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -367,7 +367,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
RETURN_RESULT(Encode::null());
}
- uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 023a739e33..6590054bf3 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -343,35 +343,15 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
return Encode(engine->currentContext->deleteProperty(name));
}
-QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
- const FunctionObject *function = right.as<FunctionObject>();
- if (!function)
- return engine->throwTypeError();
-
- Heap::FunctionObject *f = function->d();
- if (function->isBoundFunction())
- f = function->cast<BoundFunction>()->target();
-
- const Object *o = left.as<Object>();
- if (!o)
- return Encode(false);
- Heap::Object *v = o->d();
-
- o = f->protoProperty();
- if (!o)
- return engine->throwTypeError();
-
- while (v) {
- v = v->prototype;
-
- if (!v)
- break;
- else if (o->d() == v)
- return Encode(true);
- }
+ // 11.8.6, 5: rval must be an Object
+ const Object *rhs = rval.as<Object>();
+ if (!rhs)
+ return engine->throwTypeError();
- return Encode(false);
+ // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
+ return rhs->instanceOf(lval);
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1284,12 +1264,16 @@ ReturnedValue Runtime::method_unwindException(ExecutionEngine *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);
}
void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
{
+ engine->jsAlloca(1); // keep this symmetric with pushWithScope
ExecutionContext *c = engine->currentContext;
engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
@@ -1299,7 +1283,7 @@ void Runtime::method_popScope(NoThrowEngine *engine)
{
Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
engine->popContext();
- engine->jsStackTop -= 2;
+ engine->jsStackTop -= 3;
}
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8ce10e326d..6d3110771e 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -274,20 +274,20 @@ public:
return Encode::undefined();
}
- void containerPutIndexed(uint index, const QV4::Value &value)
+ bool containerPutIndexed(uint index, const QV4::Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return;
+ return false;
}
if (d()->isReference) {
if (!d()->object)
- return;
+ return false;
loadReference();
}
@@ -313,6 +313,7 @@ public:
if (d()->isReference)
storeReference();
+ return true;
}
QV4::PropertyAttributes containerQueryIndexed(uint index) const
@@ -540,8 +541,8 @@ public:
static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
- static void putIndexed(Managed *that, uint index, const QV4::Value &value)
- { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
+ static bool putIndexed(Managed *that, uint index, const QV4::Value &value)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
static bool deleteIndexedProperty(QV4::Managed *that, uint index)
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 3c6a24e035..72be11eca0 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -200,6 +200,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1);
defineDefaultProperty(QStringLiteral("replace"), method_replace, 2);
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
@@ -458,6 +459,21 @@ void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallDa
scope.result = a;
}
+void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ double repeats = callData->args[0].toInteger();
+
+ if (repeats < 0 || qIsInf(repeats)) {
+ scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value"));
+ return;
+ }
+
+ scope.result = scope.engine->newString(value.repeated(int(repeats)));
+}
+
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
result->reserve(result->length() + replaceValue.length());
@@ -634,7 +650,7 @@ void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallD
Q_ASSERT(regExp);
}
Scoped<RegExp> re(scope, regExp->value());
- uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, regExp->value()->captureCount() * 2 * sizeof(uint));
uint result = re->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
scope.result = Encode(-1);
@@ -705,7 +721,7 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
ScopedString s(scope);
if (re) {
uint offset = 0;
- uint* matchOffsets = (uint*)alloca(re->value()->captureCount() * 2 * sizeof(uint));
+ Q_ALLOCA_VAR(uint, matchOffsets, re->value()->captureCount() * 2 * sizeof(uint));
while (true) {
Scoped<RegExp> regexp(scope, re->value());
uint result = regexp->match(text, offset, matchOffsets);
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 0ee7a6ece9..aed3bc1e28 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -121,6 +121,7 @@ struct StringPrototype: StringObject
static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index cecd1e6958..5573a2e57f 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -398,11 +398,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp
return a->d()->type->read(a->d()->buffer->data->data(), byteOffset);
}
-void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
+bool TypedArray::putIndexed(Managed *m, uint index, const Value &value)
{
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
- return;
+ return false;
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
@@ -413,11 +413,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
goto reject;
a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
- return;
+ return true;
reject:
if (scope.engine->current->strictMode)
scope.engine->throwTypeError();
+ return false;
}
void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index eefed2db4b..fbf13c9815 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -133,7 +133,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
static void markObjects(Heap::Base *that, ExecutionEngine *e);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 816b8fb11b..4ff0565f9b 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -254,34 +254,47 @@ public:
Q_ASSERT(isDouble()); return Double_Type;
}
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-16,
+ IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
+ Managed_Type_Internal_64 = 0
+ };
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ // Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
- NaN_Mask = 0x7ff80000,
NotDouble_Mask = 0x7ffa0000,
- Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit,
- Tag_Shift = 32
};
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
enum {
- Managed_Type_Internal = NotDouble_Mask
+ Managed_Type_Internal_32 = NotDouble_Mask
};
-#else
- static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
- static const quint64 Immediate_Mask = 0x00020000u; // bit 49
- enum Masks {
- NaN_Mask = 0x7ff80000,
+#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+ enum {
+ Managed_Type_Internal = Managed_Type_Internal_64
};
+ static const quint64 Immediate_Mask = Immediate_Mask_64;
+#else
enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-16,
- Tag_Shift = 32,
- IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
- Managed_Type_Internal = 0
+ Managed_Type_Internal = Managed_Type_Internal_32
};
+ static const quint64 Immediate_Mask = Immediate_Mask_32;
#endif
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
enum ValueTypeInternal {
Empty_Type_Internal = Immediate_Mask | 0,
ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
@@ -544,7 +557,7 @@ inline bool Value::asArrayIndex(uint &idx) const
}
double d = doubleValue();
idx = (uint)d;
- return (idx == d);
+ return (idx == d && idx != UINT_MAX);
}
#endif
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index b9183313cd..be2772c23f 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -402,7 +402,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
}
}
- QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth)));
+ Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
{
scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->constants);
// stack gets setup in push instruction
@@ -957,8 +957,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
return QV4::Encode::undefined();
code = exceptionHandler;
}
-
-
}
#ifdef MOTH_THREADED_INTERPRETER
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 6330ef6038..a829e902fb 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -328,40 +328,65 @@ void Chunk::freeAll()
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
+// qDebug() << "sortIntoBins:";
HeapItem *base = realBase();
#if QT_POINTER_SIZE == 8
const int start = 0;
#else
const int start = 1;
#endif
+#ifndef QT_NO_DEBUG
+ uint freeSlots = 0;
+ uint allocatedSlots = 0;
+#endif
for (int i = start; i < EntriesInBitmap; ++i) {
quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]);
#if QT_POINTER_SIZE == 8
if (!i)
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
- uint index = qCountTrailingZeroBits(usedSlots + 1);
- if (index == Bits)
- continue;
- uint freeStart = i*Bits + index;
- usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
- while (i < EntriesInBitmap && !usedSlots) {
- ++i;
- usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+#ifndef QT_NO_DEBUG
+ allocatedSlots += qPopulationCount(usedSlots);
+// qDebug() << hex << " i=" << i << "used=" << usedSlots;
+#endif
+ while (1) {
+ uint index = qCountTrailingZeroBits(usedSlots + 1);
+ if (index == Bits)
+ break;
+ uint freeStart = i*Bits + index;
+ usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
+ while (!usedSlots) {
+ ++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;
+
+ index = qCountTrailingZeroBits(usedSlots);
+ usedSlots |= (quintptr(1) << index) - 1;
+ uint freeEnd = i*Bits + index;
+ uint nSlots = freeEnd - freeStart;
+#ifndef QT_NO_DEBUG
+// qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots;
+ freeSlots += nSlots;
+#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;
}
- if (i == EntriesInBitmap)
- usedSlots = 1;
- HeapItem *freeItem = base + freeStart;
-
- uint freeEnd = i*Bits + qCountTrailingZeroBits(usedSlots);
- uint nSlots = freeEnd - freeStart;
- Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
- freeItem->freeData.availableSlots = nSlots;
- uint bin = qMin(nBins - 1, nSlots);
- freeItem->freeData.next = bins[bin];
- bins[bin] = freeItem;
- // DEBUG << "binnig item" << freeItem << nSlots << bin << freeItem->freeData.availableSlots;
}
+#ifndef QT_NO_DEBUG
+ Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr));
+#endif
}
@@ -427,28 +452,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
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) {
// use bump allocation
Q_ASSERT(nextFree);
@@ -467,13 +471,11 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
size_t remainingSlots = m->freeData.availableSlots - slotsRequired;
// DEBUG << "found large 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;
+ if (remainingSlots == 0)
goto done;
- }
+
HeapItem *remainder = m + slotsRequired;
- if (remainingSlots >= 2*NumBins) {
+ if (remainingSlots > nFree) {
if (nFree) {
size_t bin = binForSlots(nFree);
nextFree->freeData.next = freeBins[bin];
@@ -493,6 +495,24 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
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 (!forceAllocation)
return 0;
@@ -622,14 +642,24 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
#endif
}
+#ifndef QT_NO_DEBUG
+static size_t lastAllocRequestedSlots = 0;
+#endif
+
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
- if (aggressiveGC)
+ const size_t stringSize = align(sizeof(Heap::String));
+#ifndef QT_NO_DEBUG
+ lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift;
+#endif
+
+ bool didGCRun = false;
+ if (aggressiveGC) {
runGC();
+ didGCRun = true;
+ }
- const size_t stringSize = align(sizeof(Heap::String));
unmanagedHeapSize += unmanagedSize;
- bool didGCRun = false;
if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
runGC();
@@ -655,8 +685,15 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
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();
+ didRunGC = true;
+ }
#ifdef DETAILED_MM_STATS
willAllocate(size);
#endif // DETAILED_MM_STATS
@@ -671,7 +708,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
HeapItem *m = blockAllocator.allocate(size);
if (!m) {
- if (shouldRunGC())
+ if (!didRunGC && shouldRunGC())
runGC();
m = blockAllocator.allocate(size, true);
}
@@ -817,6 +854,26 @@ bool MemoryManager::shouldRunGC() const
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()
{
@@ -833,31 +890,56 @@ void MemoryManager::runGC()
sweep();
// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
} else {
+ bool triggeredByUnmanagedHeap = (unmanagedHeapSize > unmanagedHeapSizeGCLimit);
+ size_t oldUnmanagedSize = unmanagedHeapSize;
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;
t.start();
mark();
qint64 markTime = t.restart();
- const size_t usedBefore = getUsedMem();
- const size_t largeItemsBefore = getLargeItemsMem();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
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() << "Sweeped object in" << sweepTime << "ms.";
- qDebug() << "Allocated" << totalMem << "bytes";
qDebug() << "Used memory before GC:" << usedBefore;
qDebug() << "Used memory after GC:" << usedAfter;
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
- qDebug() << "Large item memory before GC:" << largeItemsBefore;
- qDebug() << "Large item memory after GC:" << largeItemsAfter;
- qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
+ size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
+ if (lost)
+ 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 ========";
}
+
+ if (aggressiveGC) {
+ // ensure we don't 'loose' any memory
+ Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
+ }
}
size_t MemoryManager::getUsedMem() const
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 9cd212015e..ca84e0c157 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -71,7 +71,7 @@
%token T_VAR "var" T_VOID "void" T_WHILE "while"
%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
%token T_NULL "null" T_TRUE "true" T_FALSE "false"
-%token T_CONST "const"
+%token T_CONST "const" T_LET "let"
%token T_DEBUGGER "debugger"
%token T_RESERVED_WORD "reserved word"
%token T_MULTILINE_STRING_LITERAL "multiline string literal"
@@ -1622,6 +1622,7 @@ ReservedIdentifier: T_VAR ;
ReservedIdentifier: T_VOID ;
ReservedIdentifier: T_WHILE ;
ReservedIdentifier: T_CONST ;
+ReservedIdentifier: T_LET ;
ReservedIdentifier: T_DEBUGGER ;
ReservedIdentifier: T_RESERVED_WORD ;
ReservedIdentifier: T_WITH ;
@@ -2486,14 +2487,26 @@ VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_S
VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
/.
case $rule_number: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(
- sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ if (sym(1).ival == T_LET)
+ s = AST::VariableDeclaration::BlockScope;
+ else if (sym(1).ival == T_CONST)
+ s = AST::VariableDeclaration::ReadOnlyBlockScope;
+
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
node->declarationKindToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
./
+VariableDeclarationKind: T_LET ;
+/.
+case $rule_number: {
+ sym(1).ival = T_LET;
+} break;
+./
+
VariableDeclarationKind: T_CONST ;
/.
case $rule_number: {
@@ -2542,7 +2555,8 @@ case $rule_number: {
VariableDeclaration: JsIdentifier InitialiserOpt ;
/.
case $rule_number: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
@@ -2551,7 +2565,8 @@ case $rule_number: {
VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
/.
case $rule_number: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
@@ -2677,8 +2692,9 @@ case $rule_number: {
IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
/.
case $rule_number: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
sym(8).Expression, sym(10).Statement);
node->forToken = loc(1);
node->lparenToken = loc(2);
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 9b06bf3d31..0de419d697 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -1315,10 +1315,18 @@ class QML_PARSER_EXPORT VariableDeclaration: public Node
public:
QQMLJS_DECLARE_AST_NODE(VariableDeclaration)
- VariableDeclaration(const QStringRef &n, ExpressionNode *e):
- name (n), expression (e), readOnly(false)
+ enum VariableScope {
+ FunctionScope,
+ BlockScope, // let
+ ReadOnlyBlockScope // const
+ };
+
+ VariableDeclaration(const QStringRef &n, ExpressionNode *e, VariableScope s):
+ name (n), expression (e), scope(s)
{ kind = K; }
+ bool isLexicallyScoped() const { return scope != FunctionScope; }
+
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
@@ -1330,8 +1338,8 @@ public:
// attributes
QStringRef name;
ExpressionNode *expression;
- bool readOnly;
SourceLocation identifierToken;
+ VariableScope scope;
};
class QML_PARSER_EXPORT VariableDeclarationList: public Node
@@ -1363,14 +1371,13 @@ public:
return declaration->lastSourceLocation();
}
- inline VariableDeclarationList *finish (bool readOnly)
+ inline VariableDeclarationList *finish(VariableDeclaration::VariableScope s)
{
VariableDeclarationList *front = next;
next = 0;
- if (readOnly) {
- VariableDeclarationList *vdl;
- for (vdl = front; vdl != 0; vdl = vdl->next)
- vdl->declaration->readOnly = true;
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next) {
+ vdl->declaration->scope = s;
}
return front;
}
diff --git a/src/qml/parser/qqmljsgrammar.cpp b/src/qml/parser/qqmljsgrammar.cpp
index b27f4af080..ca5a4bbd85 100644
--- a/src/qml/parser/qqmljsgrammar.cpp
+++ b/src/qml/parser/qqmljsgrammar.cpp
@@ -51,48 +51,48 @@ const char *const QQmlJSGrammar::spell [] = {
"||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
"this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
- "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", 0,
- "public", "import", "pragma", "as", "on", "get", "set", 0, 0, 0,
- 0, 0, 0, 0, 0, 0};
+ "^=", "null", "true", "false", "const", "let", "debugger", "reserved word", "multiline string literal", "comment",
+ 0, "public", "import", "pragma", "as", "on", "get", "set", 0, 0,
+ 0, 0, 0, 0, 0, 0, 0};
const short QQmlJSGrammar::lhs [] = {
- 106, 106, 106, 106, 106, 106, 107, 113, 113, 116,
- 116, 116, 116, 119, 121, 117, 117, 118, 118, 118,
- 118, 118, 118, 118, 118, 122, 123, 115, 114, 126,
- 126, 127, 127, 128, 128, 125, 111, 111, 111, 111,
- 130, 130, 130, 130, 130, 130, 130, 111, 138, 138,
- 138, 138, 139, 139, 140, 140, 111, 111, 111, 111,
- 111, 111, 111, 111, 111, 111, 111, 111, 111, 111,
- 111, 111, 111, 111, 111, 111, 124, 124, 124, 124,
- 124, 124, 124, 143, 143, 143, 143, 143, 143, 143,
- 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
- 143, 129, 145, 145, 145, 145, 144, 144, 149, 149,
- 149, 147, 147, 150, 150, 150, 150, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 154, 154,
- 120, 120, 120, 120, 120, 157, 157, 158, 158, 158,
- 158, 156, 156, 159, 159, 160, 160, 161, 161, 161,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 163, 163, 163, 163, 164, 164, 164, 165, 165, 165,
- 165, 166, 166, 166, 166, 166, 166, 166, 167, 167,
- 167, 167, 167, 167, 168, 168, 168, 168, 168, 169,
- 169, 169, 169, 169, 170, 170, 171, 171, 172, 172,
- 173, 173, 174, 174, 175, 175, 176, 176, 177, 177,
- 178, 178, 179, 179, 180, 180, 181, 181, 148, 148,
- 182, 182, 183, 183, 183, 183, 183, 183, 183, 183,
- 183, 183, 183, 183, 109, 109, 184, 184, 185, 185,
- 186, 186, 108, 108, 108, 108, 108, 108, 108, 108,
- 108, 108, 108, 108, 108, 108, 108, 131, 195, 195,
- 194, 194, 142, 142, 196, 196, 197, 197, 199, 199,
- 198, 200, 203, 201, 201, 204, 202, 202, 132, 133,
- 133, 134, 134, 187, 187, 187, 187, 187, 187, 187,
- 187, 188, 188, 188, 188, 189, 189, 189, 189, 190,
- 190, 135, 136, 205, 205, 208, 208, 206, 206, 209,
- 207, 191, 192, 192, 137, 137, 137, 210, 211, 193,
- 193, 212, 141, 155, 155, 213, 213, 152, 152, 151,
- 151, 214, 112, 112, 215, 215, 110, 110, 146, 146,
- 216};
+ 107, 107, 107, 107, 107, 107, 108, 114, 114, 117,
+ 117, 117, 117, 120, 122, 118, 118, 119, 119, 119,
+ 119, 119, 119, 119, 119, 123, 124, 116, 115, 127,
+ 127, 128, 128, 129, 129, 126, 112, 112, 112, 112,
+ 131, 131, 131, 131, 131, 131, 131, 112, 139, 139,
+ 139, 139, 140, 140, 141, 141, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 125, 125, 125, 125,
+ 125, 125, 125, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 130, 146, 146, 146, 146, 145, 145, 150, 150,
+ 150, 148, 148, 151, 151, 151, 151, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 155,
+ 155, 121, 121, 121, 121, 121, 158, 158, 159, 159,
+ 159, 159, 157, 157, 160, 160, 161, 161, 162, 162,
+ 162, 163, 163, 163, 163, 163, 163, 163, 163, 163,
+ 163, 164, 164, 164, 164, 165, 165, 165, 166, 166,
+ 166, 166, 167, 167, 167, 167, 167, 167, 167, 168,
+ 168, 168, 168, 168, 168, 169, 169, 169, 169, 169,
+ 170, 170, 170, 170, 170, 171, 171, 172, 172, 173,
+ 173, 174, 174, 175, 175, 176, 176, 177, 177, 178,
+ 178, 179, 179, 180, 180, 181, 181, 182, 182, 149,
+ 149, 183, 183, 184, 184, 184, 184, 184, 184, 184,
+ 184, 184, 184, 184, 184, 110, 110, 185, 185, 186,
+ 186, 187, 187, 109, 109, 109, 109, 109, 109, 109,
+ 109, 109, 109, 109, 109, 109, 109, 109, 132, 196,
+ 196, 195, 195, 143, 143, 197, 197, 197, 198, 198,
+ 200, 200, 199, 201, 204, 202, 202, 205, 203, 203,
+ 133, 134, 134, 135, 135, 188, 188, 188, 188, 188,
+ 188, 188, 188, 189, 189, 189, 189, 190, 190, 190,
+ 190, 191, 191, 136, 137, 206, 206, 209, 209, 207,
+ 207, 210, 208, 192, 193, 193, 138, 138, 138, 211,
+ 212, 194, 194, 213, 142, 156, 156, 214, 214, 153,
+ 153, 152, 152, 215, 113, 113, 216, 216, 111, 111,
+ 147, 147, 217};
const short QQmlJSGrammar::rhs [] = {
2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
@@ -110,777 +110,798 @@ const short QQmlJSGrammar::rhs [] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 4, 3, 5, 1, 2, 4, 4, 4,
- 3, 0, 1, 1, 3, 1, 1, 1, 2, 2,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 3, 3, 3, 1, 3, 3, 1, 3, 3,
- 3, 1, 3, 3, 3, 3, 3, 3, 1, 3,
- 3, 3, 3, 3, 1, 3, 3, 3, 3, 1,
- 3, 3, 3, 3, 1, 3, 1, 3, 1, 3,
- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
- 1, 3, 1, 3, 1, 5, 1, 5, 1, 3,
- 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 3, 0, 1, 1, 3,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 3, 1, 2,
- 0, 1, 3, 3, 1, 1, 1, 3, 1, 3,
- 2, 2, 2, 0, 1, 2, 0, 1, 1, 2,
- 2, 7, 5, 7, 7, 7, 5, 9, 10, 7,
- 8, 2, 2, 3, 3, 2, 2, 3, 3, 3,
- 3, 5, 5, 3, 5, 1, 2, 0, 1, 4,
- 3, 3, 3, 3, 3, 3, 4, 5, 2, 2,
- 2, 1, 8, 8, 7, 1, 3, 0, 1, 0,
- 1, 1, 1, 1, 1, 2, 1, 1, 0, 1,
- 2};
+ 1, 1, 1, 4, 3, 5, 1, 2, 4, 4,
+ 4, 3, 0, 1, 1, 3, 1, 1, 1, 2,
+ 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 3, 3, 3, 1, 3, 3, 1, 3,
+ 3, 3, 1, 3, 3, 3, 3, 3, 3, 1,
+ 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
+ 1, 3, 3, 3, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 3, 1, 5, 1, 5, 1,
+ 3, 1, 3, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 3, 0, 1, 1,
+ 3, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 1,
+ 2, 0, 1, 3, 3, 1, 1, 1, 1, 3,
+ 1, 3, 2, 2, 2, 0, 1, 2, 0, 1,
+ 1, 2, 2, 7, 5, 7, 7, 7, 5, 9,
+ 10, 7, 8, 2, 2, 3, 3, 2, 2, 3,
+ 3, 3, 3, 5, 5, 3, 5, 1, 2, 0,
+ 1, 4, 3, 3, 3, 3, 3, 3, 4, 5,
+ 2, 2, 2, 1, 8, 8, 7, 1, 3, 0,
+ 1, 0, 1, 1, 1, 1, 1, 2, 1, 1,
+ 0, 1, 2};
const short QQmlJSGrammar::action_default [] = {
- 0, 0, 28, 0, 0, 0, 28, 0, 188, 255,
- 219, 227, 223, 167, 239, 215, 3, 152, 85, 168,
- 231, 235, 156, 185, 166, 171, 151, 205, 192, 0,
- 92, 93, 88, 0, 82, 77, 359, 0, 0, 0,
+ 0, 0, 28, 0, 0, 0, 28, 0, 189, 256,
+ 220, 228, 224, 168, 240, 216, 3, 153, 85, 169,
+ 232, 236, 157, 186, 167, 172, 152, 206, 193, 0,
+ 92, 93, 88, 0, 82, 77, 361, 0, 0, 0,
0, 90, 0, 0, 86, 89, 81, 0, 0, 78,
- 80, 83, 79, 91, 84, 0, 87, 0, 0, 181,
- 0, 0, 168, 187, 170, 169, 0, 0, 0, 183,
- 184, 182, 186, 0, 216, 0, 0, 0, 0, 206,
- 0, 0, 0, 0, 0, 0, 196, 0, 0, 0,
- 190, 191, 189, 194, 198, 197, 195, 193, 208, 207,
- 209, 0, 224, 0, 220, 0, 0, 162, 149, 161,
- 150, 118, 119, 120, 145, 121, 146, 122, 123, 124,
- 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
- 147, 135, 136, 137, 138, 139, 140, 141, 142, 143,
- 144, 148, 0, 0, 160, 256, 163, 0, 164, 0,
- 165, 159, 0, 252, 245, 243, 250, 251, 249, 248,
- 254, 247, 246, 244, 253, 240, 0, 228, 0, 0,
- 232, 0, 0, 236, 0, 0, 162, 154, 0, 153,
- 0, 158, 172, 0, 348, 348, 349, 0, 346, 0,
- 347, 0, 350, 263, 270, 269, 277, 265, 0, 266,
- 0, 351, 0, 358, 267, 268, 85, 273, 271, 355,
- 352, 357, 274, 0, 285, 0, 0, 0, 0, 342,
- 0, 359, 257, 299, 0, 0, 0, 286, 0, 0,
- 275, 276, 0, 264, 272, 300, 301, 0, 348, 0,
- 0, 350, 0, 343, 344, 0, 332, 356, 0, 316,
- 317, 318, 319, 0, 312, 313, 314, 315, 340, 341,
- 0, 0, 0, 0, 0, 304, 305, 306, 261, 259,
- 221, 229, 225, 241, 217, 262, 0, 168, 233, 237,
- 210, 199, 0, 0, 218, 0, 0, 0, 0, 211,
- 0, 0, 0, 0, 0, 203, 201, 204, 202, 200,
- 213, 212, 214, 0, 226, 0, 222, 0, 260, 168,
- 0, 242, 257, 258, 0, 257, 0, 0, 308, 0,
- 0, 0, 310, 0, 230, 0, 0, 234, 0, 0,
- 238, 297, 0, 289, 298, 292, 0, 296, 0, 257,
- 290, 0, 257, 0, 0, 309, 0, 0, 0, 311,
- 0, 0, 0, 303, 0, 302, 85, 112, 360, 0,
- 0, 117, 279, 282, 0, 118, 285, 121, 146, 123,
- 124, 88, 128, 129, 82, 130, 133, 86, 89, 257,
- 83, 91, 136, 84, 138, 87, 140, 141, 286, 143,
- 144, 148, 0, 114, 113, 116, 100, 115, 99, 0,
- 109, 280, 278, 0, 0, 0, 350, 0, 110, 156,
- 157, 162, 0, 155, 0, 320, 321, 0, 348, 0,
- 0, 350, 0, 111, 0, 0, 0, 323, 328, 326,
- 329, 0, 0, 327, 328, 0, 324, 0, 325, 281,
- 331, 0, 281, 330, 0, 333, 334, 0, 281, 335,
- 336, 0, 0, 337, 0, 0, 0, 338, 339, 174,
- 173, 0, 0, 0, 307, 0, 0, 0, 322, 294,
- 287, 0, 295, 291, 0, 293, 283, 0, 284, 288,
- 0, 0, 350, 0, 345, 103, 0, 0, 107, 94,
- 0, 96, 105, 0, 97, 106, 108, 98, 104, 95,
- 0, 101, 178, 176, 180, 177, 175, 179, 353, 6,
- 354, 4, 2, 75, 102, 0, 0, 78, 80, 79,
- 37, 5, 0, 76, 0, 51, 50, 49, 0, 0,
- 51, 0, 0, 0, 52, 0, 67, 68, 0, 65,
- 0, 66, 41, 42, 43, 44, 46, 47, 71, 45,
- 0, 51, 0, 0, 0, 0, 0, 61, 0, 62,
- 0, 0, 32, 0, 0, 72, 33, 0, 36, 34,
- 30, 0, 35, 31, 0, 63, 0, 64, 156, 0,
- 69, 73, 0, 0, 0, 0, 156, 281, 0, 70,
- 85, 118, 285, 121, 146, 123, 124, 88, 128, 129,
- 130, 133, 86, 89, 257, 91, 136, 84, 138, 87,
- 140, 141, 286, 143, 144, 148, 74, 0, 59, 53,
- 60, 54, 0, 0, 0, 0, 56, 0, 57, 58,
- 55, 0, 0, 0, 0, 48, 0, 38, 39, 0,
- 40, 8, 0, 0, 9, 0, 11, 0, 10, 0,
- 1, 27, 15, 14, 26, 13, 12, 29, 7, 0,
- 18, 0, 19, 0, 24, 25, 0, 20, 21, 0,
- 22, 23, 16, 17, 361};
+ 80, 83, 79, 91, 84, 0, 87, 0, 0, 182,
+ 0, 0, 169, 188, 171, 170, 0, 0, 0, 184,
+ 185, 183, 187, 0, 217, 0, 0, 0, 0, 207,
+ 0, 0, 0, 0, 0, 0, 197, 0, 0, 0,
+ 191, 192, 190, 195, 199, 198, 196, 194, 209, 208,
+ 210, 0, 225, 0, 221, 0, 0, 163, 150, 162,
+ 151, 118, 119, 120, 145, 121, 147, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 146, 133,
+ 134, 148, 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 149, 0, 0, 161, 257, 164, 0, 165,
+ 0, 166, 160, 0, 253, 246, 244, 251, 252, 250,
+ 249, 255, 248, 247, 245, 254, 241, 0, 229, 0,
+ 0, 233, 0, 0, 237, 0, 0, 163, 155, 0,
+ 154, 0, 159, 173, 0, 350, 350, 351, 0, 348,
+ 0, 349, 0, 352, 264, 271, 270, 278, 266, 0,
+ 267, 0, 353, 0, 360, 268, 269, 85, 274, 272,
+ 357, 354, 359, 275, 0, 287, 0, 0, 0, 0,
+ 344, 0, 361, 286, 258, 301, 0, 0, 0, 288,
+ 0, 0, 276, 277, 0, 265, 273, 302, 303, 0,
+ 350, 0, 0, 352, 0, 345, 346, 0, 334, 358,
+ 0, 318, 319, 320, 321, 0, 314, 315, 316, 317,
+ 342, 343, 0, 0, 0, 0, 0, 306, 307, 308,
+ 262, 260, 222, 230, 226, 242, 218, 263, 0, 169,
+ 234, 238, 211, 200, 0, 0, 219, 0, 0, 0,
+ 0, 212, 0, 0, 0, 0, 0, 204, 202, 205,
+ 203, 201, 214, 213, 215, 0, 227, 0, 223, 0,
+ 261, 169, 0, 243, 258, 259, 0, 258, 0, 0,
+ 310, 0, 0, 0, 312, 0, 231, 0, 0, 235,
+ 0, 0, 239, 299, 0, 291, 300, 294, 0, 298,
+ 0, 258, 292, 0, 258, 0, 0, 311, 0, 0,
+ 0, 313, 0, 0, 0, 305, 0, 304, 85, 112,
+ 362, 0, 0, 117, 280, 283, 0, 118, 287, 121,
+ 147, 123, 124, 88, 128, 129, 82, 130, 286, 133,
+ 86, 89, 258, 83, 91, 136, 84, 138, 87, 140,
+ 141, 288, 143, 144, 149, 0, 114, 113, 116, 100,
+ 115, 99, 0, 109, 281, 279, 0, 0, 0, 352,
+ 0, 110, 157, 158, 163, 0, 156, 0, 322, 323,
+ 0, 350, 0, 0, 352, 0, 111, 0, 0, 0,
+ 325, 330, 328, 331, 0, 0, 329, 330, 0, 326,
+ 0, 327, 282, 333, 0, 282, 332, 0, 335, 336,
+ 0, 282, 337, 338, 0, 0, 339, 0, 0, 0,
+ 340, 341, 175, 174, 0, 0, 0, 309, 0, 0,
+ 0, 324, 296, 289, 0, 297, 293, 0, 295, 284,
+ 0, 285, 290, 0, 0, 352, 0, 347, 103, 0,
+ 0, 107, 94, 0, 96, 105, 0, 97, 106, 108,
+ 98, 104, 95, 0, 101, 179, 177, 181, 178, 176,
+ 180, 355, 6, 356, 4, 2, 75, 102, 0, 0,
+ 78, 80, 79, 37, 5, 0, 76, 0, 51, 50,
+ 49, 0, 0, 51, 0, 0, 0, 52, 0, 67,
+ 68, 0, 65, 0, 66, 41, 42, 43, 44, 46,
+ 47, 71, 45, 0, 51, 0, 0, 0, 0, 0,
+ 61, 0, 62, 0, 0, 32, 0, 0, 72, 33,
+ 0, 36, 34, 30, 0, 35, 31, 0, 63, 0,
+ 64, 157, 0, 69, 73, 0, 0, 0, 0, 157,
+ 282, 0, 70, 85, 118, 287, 121, 147, 123, 124,
+ 88, 128, 129, 130, 286, 133, 86, 89, 258, 91,
+ 136, 84, 138, 87, 140, 141, 288, 143, 144, 149,
+ 74, 0, 59, 53, 60, 54, 0, 0, 0, 0,
+ 56, 0, 57, 58, 55, 0, 0, 0, 0, 48,
+ 0, 38, 39, 0, 40, 8, 0, 0, 9, 0,
+ 11, 0, 10, 0, 1, 27, 15, 14, 26, 13,
+ 12, 29, 7, 0, 18, 0, 19, 0, 24, 25,
+ 0, 20, 21, 0, 22, 23, 16, 17, 363};
const short QQmlJSGrammar::goto_default [] = {
- 7, 650, 211, 198, 209, 521, 509, 645, 658, 508,
- 644, 648, 646, 654, 22, 651, 649, 647, 18, 520,
- 571, 561, 568, 563, 548, 193, 197, 199, 204, 234,
- 212, 231, 552, 622, 621, 203, 233, 26, 487, 486,
- 359, 358, 9, 357, 360, 202, 480, 361, 109, 17,
- 147, 24, 13, 146, 19, 25, 59, 23, 8, 28,
- 27, 280, 15, 274, 10, 270, 12, 272, 11, 271,
- 20, 278, 21, 279, 14, 273, 269, 310, 414, 275,
- 276, 205, 195, 194, 208, 207, 230, 196, 364, 363,
- 232, 471, 470, 332, 333, 473, 335, 472, 334, 427,
- 431, 434, 430, 429, 449, 450, 200, 186, 201, 210,
+ 7, 654, 212, 199, 210, 524, 512, 649, 662, 511,
+ 648, 652, 650, 658, 22, 655, 653, 651, 18, 523,
+ 574, 564, 571, 566, 551, 194, 198, 200, 205, 236,
+ 213, 233, 555, 626, 625, 204, 235, 26, 490, 489,
+ 361, 360, 9, 359, 362, 203, 483, 363, 109, 17,
+ 148, 24, 13, 147, 19, 25, 59, 23, 8, 28,
+ 27, 282, 15, 276, 10, 272, 12, 274, 11, 273,
+ 20, 280, 21, 281, 14, 275, 271, 312, 417, 277,
+ 278, 206, 196, 195, 209, 208, 232, 197, 366, 365,
+ 234, 474, 473, 334, 335, 476, 337, 475, 336, 430,
+ 434, 437, 433, 432, 452, 453, 201, 187, 202, 211,
0};
const short QQmlJSGrammar::action_index [] = {
- 246, 1285, 2768, 2768, 2666, 998, 98, 198, 86, -106,
- 26, -15, -39, 234, -106, 314, 54, -106, -106, 714,
- 89, 151, 212, 219, -106, -106, -106, 412, 279, 1285,
- -106, -106, -106, 525, -106, -106, 2360, 1675, 1285, 1285,
- 1285, -106, 902, 1285, -106, -106, -106, 1285, 1285, -106,
- -106, -106, -106, -106, -106, 1285, -106, 1285, 1285, -106,
- 1285, 1285, 103, 197, -106, -106, 1285, 1285, 1285, -106,
- -106, -106, 214, 1285, 297, 1285, 1285, 1285, 1285, 392,
- 1285, 1285, 1285, 1285, 1285, 1285, 213, 1285, 1285, 1285,
- 96, 100, 101, 279, 279, 195, 190, 181, 402, 372,
- 382, 1285, -10, 1285, 106, 2258, 1285, 1285, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, 136, 1285, -106, -106, 65, 29, -106, 1285,
- -106, -106, 1285, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, 1285, -46, 1285, 1285,
- 30, 27, 1285, -106, 2258, 1285, 1285, -106, 130, -106,
- -31, -106, -106, -16, 520, 520, 71, 21, -106, 421,
- -106, 38, 2768, -106, -106, -106, -106, -106, 237, -106,
- 520, -106, -52, -106, -106, -106, 23, -106, -106, -106,
- 2768, -106, -106, 596, -106, 588, 141, 2666, 2, 1,
- -1, 2972, 1285, -106, 13, 1285, 28, -106, -28, -30,
- -106, -106, 435, -106, -106, -106, -106, 60, 520, 52,
- 67, 2768, 64, -106, -106, 2666, -106, -106, 126, -106,
- -106, -106, -106, 73, -106, -106, -106, -106, -106, -106,
- -18, 34, 1285, 156, 168, -106, -106, -106, 1479, -106,
- 79, 40, 48, -106, 312, 75, 42, 672, 80, 143,
- 331, 279, 442, 1285, 316, 1285, 1285, 1285, 1285, 341,
- 1285, 1285, 1285, 1285, 1285, 279, 360, 360, 196, 225,
- 443, 357, 351, 1285, -4, 1285, 63, 1285, -106, 714,
- 1285, -106, 1285, 102, 68, 1285, 62, 2666, -106, 1285,
- 147, 2666, -106, 1285, 56, 1285, 1285, 91, 87, 1285,
- -106, 81, 149, 74, -106, -106, 1285, -106, 439, 1285,
- -106, -44, 1285, -42, 2666, -106, 1285, 153, 2666, -106,
- 1285, 154, 2666, 10, 2666, -106, 0, -106, 15, -54,
- 92, -106, -106, 2666, -50, 539, -7, 536, 121, 1285,
- 2666, 5, -8, 445, 2462, 24, 902, 51, 50, 1384,
- 2462, 47, 20, 46, 1285, 44, 19, 1285, 41, 1285,
- 3, -5, 2564, -106, -106, -106, -106, -106, -106, 1285,
- -106, -106, -106, 6, -17, 11, 2768, -9, -106, 249,
- -106, 1285, -13, -106, 105, -106, -106, -12, 520, -41,
- -20, 2768, -45, -106, 1285, 115, 12, -106, 36, -106,
- 31, 122, 1285, -106, 58, 4, -106, -51, -106, 2666,
- -106, 146, 2666, -106, 235, -106, -106, 140, 2666, 93,
- -106, 84, 76, -106, 520, 17, 33, -106, -106, -106,
- -106, 1285, 134, 2666, -106, 1285, 125, 2666, -106, 55,
- -106, 163, -106, -106, 1285, -106, -106, 520, -106, -106,
- 7, 45, 2768, 32, -106, -106, 120, 1773, -106, -106,
- 1577, -106, -106, 1871, -106, -106, -106, -106, -106, -106,
- 113, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- 2768, -106, -106, -106, 109, 35, 808, 206, 49, 61,
- -106, -106, 229, -106, 203, 37, -106, -106, 611, 183,
- -106, 124, 39, 389, -106, 97, -106, -106, 252, -106,
- 2061, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- 269, -23, 611, 243, 180, 424, 232, -106, 16, -106,
- 808, 162, -106, 22, 808, -106, -106, 1190, -106, -106,
- -106, 1094, -106, -106, 248, -106, 2061, -106, 305, -24,
- -106, -106, 215, 457, 18, 2156, 292, 2870, -11, -106,
- 14, 599, 9, 528, 119, 1285, 2666, 8, 70, 514,
- 72, 902, 95, 90, 1384, 85, 59, 77, 1285, 110,
- 83, 1285, 104, 1285, 82, 78, -106, 205, -106, 236,
- -106, 57, 25, 611, 167, 517, -106, 107, -106, -106,
- -106, 1966, 808, 1675, 43, -106, 155, -106, -106, 53,
- -106, -106, 808, 808, 108, 808, -106, 289, -106, 117,
- -106, -106, 150, 157, -106, -106, -106, -106, -106, 364,
- -106, 226, -106, 69, -106, -106, 432, -106, -106, 88,
- -106, -106, -106, -106, -106,
+ 308, 1392, 2787, 2787, 2890, 1102, 71, 6, 103, -107,
+ 10, -35, -64, 287, -107, 310, 11, -107, -107, 815,
+ 30, 112, 183, 214, -107, -107, -107, 463, 203, 1392,
+ -107, -107, -107, 536, -107, -107, 2478, 1786, 1392, 1392,
+ 1392, -107, 1005, 1392, -107, -107, -107, 1392, 1392, -107,
+ -107, -107, -107, -107, -107, 1392, -107, 1392, 1392, -107,
+ 1392, 1392, 75, 204, -107, -107, 1392, 1392, 1392, -107,
+ -107, -107, 221, 1392, 306, 1392, 1392, 1392, 1392, 463,
+ 1392, 1392, 1392, 1392, 1392, 1392, 200, 1392, 1392, 1392,
+ 149, 145, 108, 231, 241, 295, 379, 379, 463, 463,
+ 463, 1392, -70, 1392, 4, 2375, 1392, 1392, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, 105, 1392, -107, -107, -5, -58, -107,
+ 1392, -107, -107, 1392, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, 1392, -44, 1392,
+ 1392, 5, 7, 1392, -107, 2375, 1392, 1392, -107, 134,
+ -107, -43, -107, -107, -16, 541, 541, 15, -36, -107,
+ 462, -107, -4, 2787, -107, -107, -107, -107, -107, 213,
+ -107, 449, -107, -20, -107, -107, -107, 31, -107, -107,
+ -107, 2787, -107, -107, 616, -107, 711, 144, 2890, 21,
+ 42, 43, 3096, -107, 1392, -107, 62, 1392, 101, -107,
+ 102, 99, -107, -107, 417, -107, -107, -107, -107, 93,
+ 441, 56, 92, 2787, 34, -107, -107, 2890, -107, -107,
+ 118, -107, -107, -107, -107, 125, -107, -107, -107, -107,
+ -107, -107, -14, 33, 1392, 137, 193, -107, -107, -107,
+ 1488, -107, 44, -1, -42, -107, 316, -8, -60, 718,
+ 97, 87, 368, 222, 359, 1392, 313, 1392, 1392, 1392,
+ 1392, 342, 1392, 1392, 1392, 1392, 1392, 271, 270, 263,
+ 262, 225, 346, 352, 362, 1392, -51, 1392, 29, 1392,
+ -107, 815, 1392, -107, 1392, 28, -22, 1392, -19, 2890,
+ -107, 1392, 160, 2890, -107, 1392, 0, 1392, 1392, 97,
+ 45, 1392, -107, 37, 142, 25, -107, -107, 1392, -107,
+ 541, 1392, -107, 9, 1392, 12, 2890, -107, 1392, 128,
+ 2890, -107, 1392, 124, 2890, 61, 2890, -107, 60, -107,
+ 67, 26, 73, -107, -107, 2890, 49, 544, 80, 556,
+ 114, 1392, 2890, 85, 58, 482, 2581, 64, 88, 1005,
+ 90, 94, 1588, 2581, 96, 70, 197, 1392, 100, 76,
+ 1392, 104, 1392, 82, 84, 2684, -107, -107, -107, -107,
+ -107, -107, 1392, -107, -107, -107, 95, 63, 91, 2787,
+ 53, -107, 217, -107, 1392, 50, -107, 120, -107, -107,
+ 40, 372, 8, 27, 2787, 3, -107, 1392, 141, 20,
+ -107, 46, -107, 41, 147, 1392, -107, 39, 36, -107,
+ -15, -107, 2890, -107, 297, 2890, -107, 175, -107, -107,
+ 187, 2890, 14, -107, -3, -2, -107, 459, -34, -6,
+ -107, -107, -107, -107, 1392, 139, 2890, -107, 1392, 132,
+ 2890, -107, 1, -107, 251, -107, -107, 1392, -107, -107,
+ 541, -107, -107, -48, -23, 2787, -47, -107, -107, 113,
+ 1984, -107, -107, 1885, -107, -107, 1687, -107, -107, -107,
+ -107, -107, -107, 107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, 2787, -107, -107, -107, 131, -50, 910,
+ 243, -45, -7, -107, -107, 232, -107, 206, -12, -107,
+ -107, 633, 189, -107, 198, 13, 385, -107, 153, -107,
+ -107, 184, -107, 2080, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, 208, 18, 633, 219, 129, 353, 292,
+ -107, 48, -107, 910, 122, -107, 81, 910, -107, -107,
+ 1296, -107, -107, -107, 1199, -107, -107, 224, -107, 2080,
+ -107, 311, 81, -107, -107, 205, 633, 98, 2176, 304,
+ 2993, 69, -107, 89, 613, 86, 597, 109, 1392, 2890,
+ 83, 55, 467, 52, 79, 804, 78, 77, 1588, 66,
+ 47, 59, 1392, 57, 32, 1392, 54, 1392, 38, 35,
+ -107, 255, -107, 228, -107, 51, 2, 524, 195, 532,
+ -107, 133, -107, -107, -107, 2272, 910, 1786, 17, -107,
+ 152, -107, -107, 16, -107, -107, 910, 910, 119, 910,
+ -107, 302, -107, 148, -107, -107, 143, 140, -107, -107,
+ -107, -107, -107, 369, -107, 249, -107, 111, -107, -107,
+ 364, -107, -107, 65, -107, -107, -107, -107, -107,
- -111, 8, 65, 83, 84, 317, 1, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -77,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, 96,
- -111, -111, -111, 2, -111, -111, -5, -28, 12, 106,
- 95, -111, 61, 55, -111, -111, -111, 63, 70, -111,
- -111, -111, -111, -111, -111, 54, -111, 172, 177, -111,
- 180, 191, -111, -111, -111, -111, 197, 202, 203, -111,
- -111, -111, -111, 210, -111, 209, 195, 109, 116, -111,
- 146, 125, 126, 127, 135, 138, -111, 141, 144, 110,
+ -111, 55, 62, 77, 71, 279, -7, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, -74,
+ -111, -111, -111, -111, -111, -111, -111, -111, -111, 70,
+ -111, -111, -111, -8, -111, -111, -6, -28, 12, 84,
+ 85, -111, 93, 100, -111, -111, -111, 101, 104, -111,
+ -111, -111, -111, -111, -111, 107, -111, 112, 118, -111,
+ 182, 184, -111, -111, -111, -111, 218, 215, 209, -111,
+ -111, -111, -111, 202, -111, 195, 193, 192, 191, -111,
+ 189, 183, 181, 175, 168, 155, -111, 170, 153, 150,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, 150, -111, 155, -111, 192, 4, -33, -111, -111,
+ -111, 151, -111, 142, -111, 172, 30, -4, -111, -111,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -9, -111, -111, -111, -111, -111, 7,
- -111, -111, 40, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, 99, -111, 52, 31,
- -111, -111, 30, -111, 253, 44, 87, -111, -111, -111,
- -111, -111, -111, -111, 45, 86, -111, -111, -111, 41,
- -111, -111, 5, -111, -111, -111, -111, -111, -111, -111,
- 50, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- 154, -111, -111, 26, -111, 49, -111, 330, -111, 28,
- -111, 248, 27, -111, -111, 124, 51, -111, -111, -111,
- -111, -111, 46, -111, -111, -111, -111, -111, 196, -111,
- -111, 185, -111, -111, -111, 194, -111, -111, -111, -111,
+ -111, -111, -111, -111, -2, -111, -111, -111, -111, -111,
+ 0, -111, -111, 9, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, -111, -111, 125, -111, 122,
+ 10, -111, -111, 22, -111, 236, 46, 127, -111, -111,
+ -111, -111, -111, -111, -111, 37, 124, -111, -111, -111,
+ 39, -111, -111, 42, -111, -111, -111, -111, -111, -111,
+ -111, 44, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, 94, -111, -111, 47, -111, 48, -111, 128, -111,
+ 50, -111, 91, -111, -3, -111, -111, 66, 53, -111,
+ -111, -111, -111, -111, 57, -111, -111, -111, -111, -111,
+ 79, -111, -111, 78, -111, -111, -111, 82, -111, -111,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, 15, -111, -111, -111, -111, -111, 74, -111,
+ -111, -111, -111, -111, 67, -111, -111, -111, -111, -111,
+ 61, -111, -111, -111, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, 59, 258, -111, 259, 268, 269,
+ 272, -111, 60, 63, 73, 74, 75, -111, -111, -111,
+ -111, -111, -111, -111, -111, 252, -111, 242, -111, 233,
+ -111, -111, 232, -111, 87, -111, -111, 89, -111, 133,
+ -111, 51, -111, 135, -111, 231, -111, 223, 222, -111,
+ -111, 221, -111, -111, -111, -111, -111, -111, 219, -111,
+ 92, 102, -111, -111, 110, -111, 171, -111, 40, -111,
+ 173, -111, 38, -111, 176, -111, 179, -111, -111, -111,
+ -111, -111, -111, -111, -111, 180, -111, 19, -111, 18,
+ -111, 145, 185, -111, -111, 17, 166, -111, -111, 65,
+ -111, -111, 29, 177, -111, -111, -111, 25, -111, 5,
+ 159, -111, 164, -111, -111, 207, -111, -111, -111, -111,
+ -111, -111, -18, -111, -111, -111, -111, -111, -111, 212,
+ -111, -111, -111, -111, 216, -111, -111, -111, -111, -111,
+ -111, 213, -111, -111, 86, -111, -111, 16, -111, -111,
+ -111, -111, -111, -85, -111, 14, -111, -84, -111, -111,
+ -111, -111, 286, -111, -111, 287, -111, -111, -111, -111,
+ -111, 214, -94, -111, -111, -16, -111, -10, -111, -19,
+ -111, -111, -111, -111, 2, -111, 83, -111, 105, -111,
+ 81, -111, -111, -111, -111, -111, -111, -41, -111, -111,
+ 131, -111, -111, -111, -111, 76, -111, -111, -111, -111,
+ -35, -111, -111, 64, -111, -111, -29, -111, -111, -111,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -16, 230, -111, 233, 269, 251, 265, -111,
- 80, 81, 82, 88, 89, -111, -111, -111, -111, -111,
- -111, -111, -111, 216, -111, 255, -111, 259, -111, -111,
- 223, -111, 68, -111, -111, 217, -111, 236, -111, 24,
- -111, 244, -111, 227, -111, 226, 257, -111, -111, 263,
- -111, -111, -111, -111, -111, -111, 249, -111, 113, 163,
- -111, -111, 212, -111, 173, -111, 48, -111, 211, -111,
- 53, -111, 206, -111, 204, -111, -111, -111, -111, -111,
- -111, -111, -111, 199, -111, 23, -111, 25, -111, 134,
- 175, -111, -111, 37, 200, -111, 222, -111, -111, 57,
- 56, -111, -111, -111, 124, -111, 32, 43, -111, 105,
- -111, -111, 139, -111, -111, -111, -111, -111, -111, 38,
- -111, -111, -111, -111, -111, -111, 75, -111, -111, -111,
- -111, 71, -111, -111, -111, -111, -111, -111, 72, -111,
- -111, 85, -111, -111, 59, -111, -111, -111, -111, -111,
- -37, -111, 62, -111, -58, -111, -111, -111, -111, 286,
- -111, -111, 250, -111, -111, -111, -111, -111, 153, -57,
- -111, -111, 33, -111, 34, -111, 36, -111, -111, -111,
- -111, 47, -111, 77, -111, 29, -111, 67, -111, -111,
- -111, -111, -111, -111, 42, -111, -111, 214, -111, -111,
- -111, -111, 229, -111, -111, -111, -111, 35, -111, -111,
- 145, -111, -111, 3, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, 208, -111, -111, -111, -111, -111, 20,
+ -111, -111, -111, -111, -111, -111, -111, 13, -111, -111,
+ -111, 26, 15, -111, -111, -111, 32, -111, -111, -111,
+ -111, -111, -111, 329, -111, -111, -111, -111, -111, -111,
+ -111, -111, -111, -111, -111, 54, 56, -111, 58, -111,
+ -111, -111, -111, 68, -111, -111, -111, 72, -111, -111,
+ 330, -111, -111, -111, 327, -111, -111, -111, -111, 389,
+ -111, -111, 52, -111, -111, 31, 49, -111, 371, -111,
+ 134, 34, -111, -111, 43, -111, 41, -111, 108, 141,
+ -111, -111, 35, -111, -111, 97, -111, -111, 45, -111,
+ -111, -111, 36, -111, 21, 129, -111, 146, -111, -111,
+ -111, -111, -111, -1, -111, -111, -111, 11, -5, 7,
+ -111, -111, -111, -111, -111, 353, 311, 408, 4, -111,
+ -111, -111, -111, 1, -111, -111, 8, 6, 249, 248,
-111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- 207, -111, -111, -111, -111, -111, 39, -111, -111, -111,
- -111, -111, -111, -111, -24, -111, -111, -111, -12, -27,
- -111, -111, -111, -14, -111, -111, -111, -111, -111, -111,
- 333, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, 6, 22, -111, 20, -111, -111, -111, -111,
- 159, -111, -111, -111, 246, -111, -111, 332, -111, -111,
- -111, 436, -111, -111, -111, -111, 388, -111, -111, 18,
- -111, -111, -6, 19, -111, 352, -111, 225, 14, -111,
- -111, 13, -111, 11, -111, 167, 136, -111, -111, 10,
- -111, 64, -111, -111, 9, -111, -111, -111, 124, -111,
- 0, 69, -111, 60, -111, -111, -111, -111, -111, -10,
- -111, -111, -111, -1, -11, -2, -111, -111, -111, -111,
- -111, 370, 142, 315, -3, -111, -111, -111, -111, 17,
- -111, -111, -13, 21, 133, 221, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, 16,
- -111, -111, -111, -111, -111, -111, -15, -111, -111, -111,
- -111, -111, -111, -111, -111};
+ -111, -111, -111, 3, -111, -111, -111, -111, -111, -111,
+ -14, -111, -111, -111, -111, -111, -111, -111, -111};
const short QQmlJSGrammar::action_info [] = {
- -145, 398, 101, 244, 438, 402, 465, 245, 461, 567,
- 423, 439, -126, 421, 553, -126, -145, 342, 344, 420,
- 185, 245, 567, 392, 418, 585, 354, 73, 268, 181,
- 245, 465, 166, 101, 172, 350, 432, 184, 268, 461,
- 103, 432, 404, 405, 406, 428, 408, 413, -142, 424,
- 560, -139, 448, -137, -115, 567, 424, -116, -134, 261,
- 350, 448, 143, 432, 283, 624, 448, 481, 534, 103,
- 262, 192, 474, 149, 529, 305, 567, 456, 482, 189,
- 283, 191, 323, 307, -137, 627, 567, 484, 303, 151,
- 617, 166, -115, 323, 329, 424, 238, -116, 336, 399,
- 241, 524, -134, 312, 303, 346, 268, 73, 350, 448,
- 143, -142, 240, 452, 465, 582, 448, -139, 461, 243,
- 454, 143, 317, 143, 174, 0, 60, 305, 490, 315,
- 665, 664, 435, 143, 257, 256, 60, 61, 143, 532,
- 60, 60, 143, 175, 143, 64, 451, 61, 533, 671,
- 670, 61, 61, 442, 143, 143, 65, 338, 537, 536,
- 452, 143, 143, 564, 143, 174, 416, 415, 629, 628,
- 564, 477, 174, 501, 0, 426, 491, 436, 673, 672,
- 259, 258, 259, 258, 175, 467, 179, 252, 251, 642,
- 643, 175, 144, 325, 463, 532, 530, 326, 674, 642,
- 643, 168, 259, 258, 555, 169, 87, 321, 88, 66,
- 339, 637, 530, 348, 352, 87, 264, 88, 565, 89,
- 87, 87, 88, 88, 478, 476, 66, 174, 89, 267,
- 265, 66, 525, 89, 89, 551, 631, 0, 87, 558,
- 88, 619, 527, 143, 530, 143, 175, 0, 176, 105,
- 87, 89, 88, 526, 67, 576, 0, 266, 527, 540,
- 68, 0, 567, 89, 174, 530, 620, 618, 106, 526,
- 107, 67, 530, 0, 0, 0, 67, 68, 527, 0,
- 0, 527, 68, 175, 174, 411, 0, 668, 667, 526,
- 527, 0, 526, 559, 557, 0, 446, 445, 236, 235,
- 0, 526, 0, 175, 87, 411, 88, 174, 0, 577,
- 575, 527, 0, 541, 539, 75, 76, 89, 527, 666,
- 174, 0, 526, 632, 0, -102, 175, 0, 176, 526,
- 285, 286, 75, 76, 285, 286, 661, 0, -102, 175,
- 0, 176, 77, 78, 6, 5, 4, 1, 3, 2,
- 662, 660, 0, 0, 290, 291, 0, 287, 288, 77,
- 78, 287, 288, 292, 290, 291, 293, 0, 294, 0,
- 0, 0, 0, 292, 290, 291, 293, 0, 294, 0,
- 290, 291, 659, 292, 0, 87, 293, 88, 294, 292,
- 0, 0, 293, 35, 294, 80, 81, 0, 89, 0,
- 0, 0, 0, 82, 83, 80, 81, 84, 0, 85,
- 0, 0, 0, 82, 83, 80, 81, 84, 35, 85,
- 0, 0, 0, 82, 83, 80, 81, 84, 0, 85,
- 49, 52, 50, 82, 83, 80, 81, 84, 0, 85,
- 0, 0, 0, 82, 83, 0, 0, 84, 0, 85,
- 35, 0, 0, 35, 0, 49, 52, 50, 46, 34,
- 51, 35, 0, 0, 35, 0, 290, 291, 35, 0,
- 0, 35, 532, 0, 35, 292, 0, 0, 293, 0,
- 294, 184, 0, 46, 34, 51, 35, 49, 52, 50,
+ 309, 314, 152, 150, 101, 73, 678, 167, 487, 103,
+ 485, 73, 484, 101, 173, 103, 527, 182, 477, 144,
+ 186, 585, 621, 190, 192, 532, 459, 451, 307, 193,
+ 285, 451, 167, 457, 455, 246, 144, 307, 247, 317,
+ 441, 319, 537, 442, 435, 285, 435, 305, 305, 570,
+ 570, 435, 331, 431, 338, 556, 348, 270, 426, 628,
+ 424, -142, 631, 263, -139, 451, -137, 247, 423, 264,
+ 344, 468, 346, -115, 464, 395, 421, 356, 185, 352,
+ 402, 401, 563, 427, -116, -134, -146, -145, 352, 245,
+ -126, 270, -126, -145, 270, -146, 247, -134, 427, 325,
+ 352, -116, 570, -115, 405, 588, 427, -139, 411, 451,
+ 416, -142, 0, 144, 570, 144, 242, 64, 464, 0,
+ 468, 493, 0, 408, 409, 243, 675, 674, 65, 240,
+ 567, 407, 144, 0, 451, 468, 144, 327, 464, 0,
+ 144, 328, 144, 60, 535, 144, 175, 144, 60, 144,
+ 340, 0, 0, 558, 61, 175, 0, 438, 175, 61,
+ 567, 145, 169, 646, 647, 176, 170, 504, 144, 494,
+ 261, 260, 669, 668, 176, 261, 260, 176, 568, 254,
+ 253, 419, 418, 144, 354, 60, 259, 258, 350, 60,
+ 180, 543, 470, 454, 633, 632, 61, 266, 175, 466,
+ 61, 429, 439, 341, -137, 261, 260, 455, 641, 677,
+ 676, 646, 647, 535, 540, 539, 66, 176, 533, 177,
+ 323, 144, 536, 175, 533, 87, 66, 88, 87, 0,
+ 88, 579, 175, 66, 533, 528, 449, 448, 89, 635,
+ 0, 89, 176, 0, 414, 544, 542, 87, 533, 88,
+ 87, 176, 88, 414, 269, 267, 87, 533, 88, 480,
+ 89, 67, 0, 89, 530, 570, 87, 68, 88, 89,
+ 530, 67, 554, 0, 238, 237, 529, 68, 67, 89,
+ 530, 530, 529, 268, 68, 580, 578, 87, 87, 88,
+ 88, 623, 529, 529, 530, 87, 87, 88, 88, 561,
+ 89, 89, 105, 530, 445, 144, 529, 0, 89, 89,
+ 672, 671, 481, 479, 0, 529, 624, 622, 530, 175,
+ 87, 106, 88, 107, 75, 76, 175, 636, 75, 76,
+ 529, 287, 288, 89, 287, 288, 0, -102, 176, 0,
+ 177, 0, 0, 670, -102, 176, 0, 177, 0, 665,
+ 0, 77, 78, 562, 560, 77, 78, 0, 289, 290,
+ 0, 289, 290, 666, 664, 292, 293, 0, 0, 292,
+ 293, 0, 0, 0, 294, 292, 293, 295, 294, 296,
+ 0, 295, 35, 296, 294, 292, 293, 295, 35, 296,
+ 0, 292, 293, 35, 294, 0, 663, 295, 35, 296,
+ 294, 35, 0, 295, 87, 296, 88, 6, 5, 4,
+ 1, 3, 2, 0, 35, 0, 0, 89, 0, 49,
+ 52, 50, 0, 0, 0, 49, 52, 50, 0, 0,
+ 49, 52, 50, 0, 0, 49, 52, 50, 49, 52,
+ 50, 0, 0, 0, 0, 0, 35, 0, 46, 34,
+ 51, 49, 52, 50, 46, 34, 51, 0, 0, 46,
+ 34, 51, 0, 0, 46, 34, 51, 46, 34, 51,
+ 35, 0, 0, 0, 0, 0, 0, 0, 35, 0,
+ 46, 34, 51, 49, 52, 50, 80, 81, 35, 0,
+ 0, 35, 0, 0, 82, 83, 35, 0, 84, 0,
+ 85, 0, 0, 185, 0, 0, 0, 49, 52, 50,
+ 0, 35, 46, 34, 51, 49, 52, 50, 185, 0,
+ 0, 0, 0, 0, 0, 49, 52, 50, 49, 52,
+ 50, 0, 0, 49, 52, 50, 46, 34, 51, 535,
+ 0, 0, 0, 0, 46, 34, 51, 535, 49, 52,
+ 50, 0, 0, 35, 46, 34, 51, 46, 34, 51,
+ 0, 35, 46, 34, 51, 35, 0, 0, 0, 0,
+ 35, 0, 185, 35, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 0,
49, 52, 50, 0, 0, 0, 0, 0, 49, 52,
- 50, 49, 52, 50, 0, 49, 52, 50, 49, 52,
- 50, 49, 52, 50, 0, 46, 34, 51, 46, 34,
- 51, 0, 0, 49, 52, 50, 46, 34, 51, 46,
- 34, 51, 532, 46, 34, 51, 46, 34, 51, 46,
- 34, 51, 0, 35, 0, 0, 35, 0, 0, 35,
- 184, 46, 34, 51, 35, 0, 0, 35, 0, 0,
- 0, 184, 0, 0, 0, 35, 0, 0, 35, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 49, 52, 50, 49, 52, 50, 49, 52, 50, 255,
- 254, 49, 52, 50, 49, 52, 50, 255, 254, 0,
- 250, 249, 49, 52, 50, 49, 52, 50, 46, 34,
- 51, 46, 34, 51, 46, 34, 51, 35, 0, 46,
- 34, 51, 46, 34, 51, 35, 532, 0, 35, 0,
- 46, 34, 51, 46, 34, 51, 0, 0, 0, 0,
- 35, 0, 0, 0, 0, 0, 0, 0, 0, 255,
- 254, 0, 0, 0, 49, 52, 50, 250, 249, 0,
- 250, 249, 49, 52, 50, 49, 52, 50, 0, 0,
- 0, 0, 0, 0, 0, 153, 0, 49, 52, 50,
- 0, 0, 46, 34, 51, 154, 0, 0, 0, 155,
- 46, 34, 51, 46, 34, 51, 0, 0, 156, 0,
- 157, 0, 0, 319, 0, 46, 34, 51, 0, 0,
- 0, 158, 0, 159, 64, 0, 0, 153, 0, 0,
- 0, 160, 0, 0, 161, 65, 0, 154, 0, 0,
- 162, 155, 0, 0, 0, 0, 163, 0, 0, 0,
- 156, 0, 157, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 164, 158, 0, 159, 64, 0, 0, 0,
- 0, 0, 0, 160, 0, 0, 161, 65, 0, 0,
- 0, 0, 162, 0, 0, 0, 0, 0, 163, 0,
+ 50, 0, 49, 52, 50, 252, 251, 49, 52, 50,
+ 49, 52, 50, 0, 0, 0, 0, 257, 256, 46,
+ 34, 51, 49, 52, 50, 0, 35, 46, 34, 51,
+ 0, 46, 34, 51, 0, 0, 46, 34, 51, 46,
+ 34, 51, 35, 0, 0, 35, 0, 0, 535, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 257, 256,
+ 0, 0, 35, 49, 52, 50, 0, 0, 0, 0,
+ 0, 0, 0, 0, 252, 251, 0, 252, 251, 49,
+ 52, 50, 49, 52, 50, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 49,
+ 52, 50, 0, 0, 0, 0, 0, 0, 46, 34,
+ 51, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 154, 0, 0, 0, 0, 0, 0, 46, 34,
+ 51, 155, 0, 0, 0, 156, 0, 0, 0, 0,
+ 35, 0, 0, 0, 157, 0, 158, 0, 0, 321,
+ 0, 0, 0, 0, 0, 0, 0, 159, 0, 160,
+ 64, 0, 0, 0, 0, 0, 0, 161, 0, 0,
+ 162, 65, 257, 256, 0, 0, 163, 49, 52, 50,
+ 0, 0, 164, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 165, 0,
+ 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
+ 0, 0, 0, 0, 0, 0, 30, 31, 154, 0,
+ 0, 0, 0, 0, 0, 0, 33, 0, 155, 0,
+ 0, 0, 156, 35, 0, 0, 0, 36, 37, 0,
+ 38, 157, 0, 158, 0, 0, 0, 42, 0, 0,
+ 0, 45, 0, 0, 159, 0, 160, 64, 0, 0,
+ 0, 0, 0, 0, 161, 0, 0, 162, 65, 53,
+ 49, 52, 50, 163, 54, 0, 0, 0, 0, 164,
+ 0, 0, 0, 0, 0, 44, 56, 32, 0, 0,
+ 0, 0, 41, 0, 0, 165, 0, 0, 0, 46,
+ 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 164, 0, 0, 0, 0, 0,
+ 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 35,
+ 0, 0, 0, 36, 37, 0, 38, 0, 0, 0,
+ 0, 0, 0, 519, 0, 0, 0, 45, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 53, 49, 52, 50, 0,
+ 54, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 44, 56, 32, 0, 0, 0, 0, 41, 0,
+ 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
+ 0, 38, 0, 0, 0, 0, 0, 0, 42, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
- 0, 36, 37, 0, 38, 0, 0, 0, 0, 0,
- 0, 516, 0, 0, 0, 45, 0, 0, 0, 0,
+ 53, 49, 52, 50, 0, 54, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 44, 56, 32, 0,
+ 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
+ 46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 518, 0, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 220, 0, 0, 0, 0, 0,
+ 0, 35, 0, 0, 0, 36, 37, 0, 38, 0,
+ 0, 0, 0, 0, 0, 519, 0, 0, 0, 45,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 44,
- 56, 32, 0, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 53, 520, 522,
+ 521, 0, 54, 0, 0, 0, 0, 229, 0, 0,
+ 0, 0, 0, 44, 56, 32, 215, 223, 0, 0,
+ 41, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 518,
+ 0, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 220, 0, 0, 0, 0, 0, 0, 35, 0,
+ 0, 0, 36, 37, 0, 38, 0, 0, 0, 0,
+ 0, 0, 519, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 575, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 53, 520, 522, 521, 0, 54,
+ 0, 0, 0, 0, 229, 0, 0, 0, 0, 0,
+ 44, 56, 32, 215, 223, 0, 0, 41, 0, 0,
+ 0, 0, 0, 0, 46, 34, 51, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 518, 0, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 220, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 0, 0, 0, 519,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 572, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 520, 522, 521, 0, 54, 0, 0, 0,
+ 0, 229, 0, 0, 0, 0, 0, 44, 56, 32,
+ 215, 223, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 29, 30, 31, 0, 0, 0, 0,
0, 0, 0, 0, 33, 0, 0, 0, 0, 0,
0, 35, 0, 0, 0, 36, 37, 0, 38, 0,
- 0, 0, 0, 0, 0, 42, 0, 0, 0, 45,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 39, 0, 40, 42, 43, 0, 0, 45,
+ 0, 0, 0, 47, 0, 48, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 53, 49, 52,
- 50, 0, 54, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 44, 56, 32, 0, 0, 0, 41,
- 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 515, 0,
+ 50, 0, 54, 0, 55, 0, 57, 0, 58, 0,
+ 0, 0, 0, 44, 56, 32, 0, 0, 0, 0,
+ 41, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 219, 0, 0, 0, 0, 0, 0, 35, 0, 0,
- 0, 36, 37, 0, 38, 0, 0, 0, 0, 0,
- 0, 516, 0, 0, 0, 45, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 53, 517, 519, 518, 0, 54, 0,
- 0, 0, 0, 227, 0, 0, 0, 0, 0, 44,
- 56, 32, 214, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 515, 0, 30, 31, 0, 0,
- 0, 0, 0, 0, 0, 0, 219, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 0, 36, 37, 0,
- 38, 0, 0, 0, 0, 0, 0, 516, 0, 0,
- 0, 45, 0, 0, 0, 0, 0, 0, 0, 572,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 53,
- 517, 519, 518, 0, 54, 0, 0, 0, 0, 227,
- 0, 0, 0, 0, 0, 44, 56, 32, 214, 0,
- 0, 41, 0, 0, 0, 0, 0, 0, 46, 34,
- 51, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 515, 0, 30, 31, 0, 0, 0, 0, 0, 0,
- 0, 0, 219, 0, 0, 0, 0, 0, 0, 35,
- 0, 0, 0, 36, 37, 0, 38, 0, 0, 0,
- 0, 0, 0, 516, 0, 0, 0, 45, 0, 0,
- 0, 0, 0, 0, 0, 569, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 53, 517, 519, 518, 0,
- 54, 0, 0, 0, 0, 227, 0, 0, 0, 0,
- 0, 44, 56, 32, 214, 0, 0, 41, 0, 0,
- 0, 0, 0, 0, 46, 34, 51, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
- 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
- 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
- 0, 38, 0, 0, 0, 39, 0, 40, 42, 43,
- 0, 0, 45, 0, 0, 0, 47, 0, 48, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 53, 49, 52, 50, 0, 54, 0, 55, 0, 57,
- 0, 58, 0, 0, 0, 0, 44, 56, 32, 0,
- 0, 0, 41, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, -135, 0, 0, 0, 29, 30, 31, 0, 0,
- 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 0, 36, 37, 0,
- 38, 0, 0, 0, 39, 0, 40, 42, 43, 0,
- 0, 45, 0, 0, 0, 47, 0, 48, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 53,
- 49, 52, 50, 0, 54, 0, 55, 0, 57, 0,
- 58, 0, 0, 0, 0, 44, 56, 32, 0, 0,
- 0, 41, 0, 0, 0, 0, 0, 0, 46, 34,
- 51, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
- 0, 33, 0, 0, 0, 0, 0, 0, 35, 0,
- 0, 0, 36, 37, 0, 38, 0, 0, 0, 39,
- 0, 40, 42, 43, 0, 0, 45, 0, 0, 0,
- 47, 0, 48, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 53, 49, 52, 50, 0, 54,
- 0, 55, 0, 57, 282, 58, 0, 0, 0, 0,
- 44, 56, 32, 0, 0, 0, 41, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
+ 0, 36, 37, 0, 38, 0, 0, 0, 39, 0,
+ 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
+ 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
+ 55, 0, 57, 284, 58, 0, 0, 0, 0, 44,
+ 56, 32, 0, 0, 0, 0, 41, 0, 0, 0,
+ 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -135, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
+ 0, 36, 37, 0, 38, 0, 0, 0, 39, 0,
+ 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
+ 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
+ 55, 0, 57, 0, 58, 0, 0, 0, 0, 44,
+ 56, 32, 0, 0, 0, 0, 41, 0, 0, 0,
0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 488, 0, 0, 29, 30,
+ 0, 0, 0, 0, 0, 499, 0, 0, 29, 30,
31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
0, 0, 0, 0, 0, 0, 35, 0, 0, 0,
36, 37, 0, 38, 0, 0, 0, 39, 0, 40,
42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
- 48, 0, 0, 494, 0, 0, 0, 0, 0, 0,
+ 48, 0, 0, 500, 0, 0, 0, 0, 0, 0,
0, 0, 53, 49, 52, 50, 0, 54, 0, 55,
0, 57, 0, 58, 0, 0, 0, 0, 44, 56,
- 32, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 32, 0, 0, 0, 0, 41, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 491, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 492, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 488, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 491, 0, 0, 29, 30, 31, 0,
0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
0, 38, 0, 0, 0, 39, 0, 40, 42, 43,
0, 0, 45, 0, 0, 0, 47, 0, 48, 0,
- 0, 489, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 497, 0, 0, 0, 0, 0, 0, 0, 0,
53, 49, 52, 50, 0, 54, 0, 55, 0, 57,
0, 58, 0, 0, 0, 0, 44, 56, 32, 0,
- 0, 0, 41, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 496, 0, 0, 29, 30, 31, 0, 0, 0,
- 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
- 0, 0, 0, 39, 0, 40, 42, 43, 0, 0,
- 45, 0, 0, 0, 47, 0, 48, 0, 0, 499,
- 0, 0, 0, 0, 0, 0, 0, 0, 53, 49,
- 52, 50, 0, 54, 0, 55, 0, 57, 0, 58,
- 0, 0, 0, 0, 44, 56, 32, 0, 0, 0,
- 41, 0, 0, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 496,
- 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
- 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
- 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
- 0, 0, 47, 0, 48, 0, 0, 497, 0, 0,
- 0, 0, 0, 0, 0, 0, 53, 49, 52, 50,
- 0, 54, 0, 55, 0, 57, 0, 58, 0, 0,
- 0, 0, 44, 56, 32, 0, 0, 0, 41, 0,
- 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 587,
- 633, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 0, 55, 226,
- 57, 0, 58, 0, 229, 0, 0, 44, 56, 32,
0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
- 35, 220, 0, 0, 221, 37, 0, 38, 0, 0,
- 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
- 0, 0, 47, 0, 48, 0, 0, 0, 0, 0,
- 0, 0, 223, 0, 0, 0, 53, 49, 52, 50,
- 224, 54, 0, 55, 226, 57, 0, 58, 0, 229,
- 0, 0, 44, 56, 32, 0, 0, 0, 41, 0,
+ 0, 0, 499, 0, 0, 29, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
+ 0, 0, 0, 35, 0, 0, 0, 36, 37, 0,
+ 38, 0, 0, 0, 39, 0, 40, 42, 43, 0,
+ 0, 45, 0, 0, 0, 47, 0, 48, 0, 0,
+ 502, 0, 0, 0, 0, 0, 0, 0, 0, 53,
+ 49, 52, 50, 0, 54, 0, 55, 0, 57, 0,
+ 58, 0, 0, 0, 0, 44, 56, 32, 0, 0,
+ 0, 0, 41, 0, 0, 0, 0, 0, 0, 46,
+ 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 29, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 35,
+ 221, 0, 0, 222, 37, 0, 38, 0, 0, 0,
+ 39, 0, 40, 42, 43, 0, 0, 45, 0, 0,
+ 0, 47, 0, 48, 0, 0, 0, 0, 0, 0,
+ 0, 225, 0, 0, 0, 53, 49, 52, 50, 226,
+ 54, 0, 55, 228, 57, 0, 58, 0, 231, 0,
+ 0, 44, 56, 32, 0, 0, 0, 0, 41, 0,
0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 587,
+ 0, 0, 0, 0, 0, 35, 221, 0, 0, 590,
37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 0, 55, 226,
- 57, 0, 58, 0, 229, 0, 0, 44, 56, 32,
- 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 225, 0, 0,
+ 0, 53, 49, 52, 50, 226, 54, 0, 55, 228,
+ 57, 0, 58, 0, 231, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 29, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 0,
+ 0, 35, 221, 0, 0, 590, 637, 0, 38, 0,
+ 0, 0, 39, 0, 40, 42, 43, 0, 0, 45,
+ 0, 0, 0, 47, 0, 48, 0, 0, 0, 0,
+ 0, 0, 0, 225, 0, 0, 0, 53, 49, 52,
+ 50, 226, 54, 0, 55, 228, 57, 0, 58, 0,
+ 231, 0, 0, 44, 56, 32, 0, 0, 0, 0,
+ 41, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 111,
+ 112, 113, 0, 0, 115, 117, 118, 0, 0, 119,
+ 0, 120, 0, 0, 0, 122, 123, 124, 0, 0,
+ 0, 0, 0, 0, 35, 125, 126, 127, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 129, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 132, 0, 0, 0, 0, 0,
+ 0, 49, 52, 50, 133, 134, 135, 0, 137, 138,
+ 139, 140, 141, 142, 0, 0, 130, 136, 121, 114,
+ 128, 116, 131, 0, 0, 0, 0, 0, 0, 0,
46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
0, 0, 111, 112, 113, 0, 0, 115, 117, 118,
0, 0, 119, 0, 120, 0, 0, 0, 122, 123,
124, 0, 0, 0, 0, 0, 0, 35, 125, 126,
127, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 128, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 131, 0, 0,
- 0, 0, 0, 0, 49, 52, 50, 132, 133, 134,
- 0, 136, 137, 138, 139, 140, 141, 0, 0, 129,
- 135, 121, 114, 116, 130, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 111, 112, 113, 0, 0, 115,
- 117, 118, 0, 0, 119, 0, 120, 0, 0, 0,
- 122, 123, 124, 0, 0, 0, 0, 0, 0, 35,
- 125, 126, 127, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 128, 0, 0, 0, 395, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 131,
- 0, 0, 0, 0, 0, 397, 49, 52, 50, 132,
- 133, 134, 0, 136, 137, 138, 139, 140, 141, 0,
- 0, 129, 135, 121, 114, 116, 130, 0, 0, 0,
- 0, 0, 0, 0, 46, 374, 380, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 111, 112, 113, 0,
- 0, 115, 117, 118, 0, 0, 119, 0, 120, 0,
- 0, 0, 122, 123, 124, 0, 0, 0, 0, 0,
- 0, 35, 125, 126, 127, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 128, 0, 0, 0, 395,
+ 0, 129, 0, 0, 0, 398, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 132, 0, 0,
+ 0, 0, 0, 400, 49, 52, 50, 133, 134, 135,
+ 0, 137, 138, 139, 140, 141, 142, 0, 0, 130,
+ 136, 121, 114, 128, 116, 131, 0, 0, 0, 0,
+ 0, 0, 0, 46, 376, 383, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 111, 112, 113, 0, 0,
+ 115, 117, 118, 0, 0, 119, 0, 120, 0, 0,
+ 0, 122, 123, 124, 0, 0, 0, 0, 0, 0,
+ 35, 125, 126, 127, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 129, 0, 0, 0, 398, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 131, 0, 0, 0, 0, 0, 397, 49, 52,
- 50, 132, 133, 134, 0, 136, 137, 138, 139, 140,
- 141, 0, 0, 129, 135, 121, 114, 116, 130, 0,
+ 132, 0, 0, 0, 0, 0, 400, 49, 52, 50,
+ 133, 134, 135, 0, 137, 138, 139, 140, 141, 142,
+ 0, 0, 130, 136, 121, 114, 128, 116, 131, 0,
0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
0, 0, 0, 0, 0, 0, 0, 0, 111, 112,
113, 0, 0, 115, 117, 118, 0, 0, 119, 0,
120, 0, 0, 0, 122, 123, 124, 0, 0, 0,
0, 0, 0, 35, 125, 126, 127, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 128, 0, 0,
- 0, 395, 0, 0, 0, 0, 0, 0, 0, 396,
- 0, 0, 0, 131, 0, 0, 0, 0, 0, 397,
- 49, 52, 50, 132, 133, 134, 0, 136, 137, 138,
- 139, 140, 141, 0, 0, 129, 135, 121, 114, 116,
- 130, 0, 0, 0, 0, 0, 0, 0, 46, 374,
- 380, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 213, 0, 0, 0, 0, 215, 0, 29, 30, 31,
- 217, 0, 0, 0, 0, 0, 0, 218, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 221,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 222, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 225, 55, 226,
- 57, 227, 58, 228, 229, 0, 0, 44, 56, 32,
- 214, 216, 0, 41, 0, 0, 0, 0, 0, 0,
- 46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 213, 0, 0, 0, 0, 215, 0, 29,
- 30, 31, 217, 0, 0, 0, 0, 0, 0, 218,
- 219, 0, 0, 0, 0, 0, 0, 35, 220, 0,
- 0, 221, 37, 0, 38, 0, 0, 0, 39, 0,
- 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
- 0, 48, 0, 0, 0, 0, 0, 222, 0, 223,
- 0, 0, 0, 53, 49, 52, 50, 224, 54, 225,
- 55, 226, 57, 227, 58, 228, 229, 0, 0, 44,
- 56, 32, 214, 216, 0, 41, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 129, 0, 0,
+ 0, 398, 0, 0, 0, 0, 0, 0, 0, 399,
+ 0, 0, 0, 132, 0, 0, 0, 0, 0, 400,
+ 49, 52, 50, 133, 134, 135, 0, 137, 138, 139,
+ 140, 141, 142, 0, 0, 130, 136, 121, 114, 128,
+ 116, 131, 0, 0, 0, 0, 0, 0, 0, 46,
+ 376, 383, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 214, 0, 0, 0, 0, 216, 0, 29, 30,
+ 31, 218, 0, 0, 0, 0, 0, 0, 219, 220,
+ 0, 0, 0, 0, 0, 0, 35, 221, 0, 0,
+ 222, 37, 0, 38, 0, 0, 0, 39, 0, 40,
+ 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
+ 48, 0, 0, 0, 0, 0, 224, 0, 225, 0,
+ 0, 0, 53, 49, 52, 50, 226, 54, 227, 55,
+ 228, 57, 229, 58, 230, 231, 0, 0, 44, 56,
+ 32, 215, 223, 217, 0, 41, 0, 0, 0, 0,
0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 591, 112, 113, 0, 0, 593,
- 117, 595, 30, 31, 596, 0, 120, 0, 0, 0,
- 122, 598, 599, 0, 0, 0, 0, 0, 0, 35,
- 600, 126, 127, 221, 37, 0, 38, 0, 0, 0,
- 39, 0, 40, 601, 43, 0, 0, 603, 0, 0,
- 0, 47, 0, 48, 0, 0, 0, 0, 0, 604,
- 0, 223, 0, 0, 0, 605, 49, 52, 50, 606,
- 607, 608, 55, 610, 611, 612, 613, 614, 615, 0,
- 0, 602, 609, 597, 592, 594, 130, 41, 0, 0,
- 0, 0, 0, 0, 46, 374, 380, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 365, 112, 113, 0,
- 0, 367, 117, 369, 30, 31, 370, 0, 120, 0,
- 0, 0, 122, 372, 373, 0, 0, 0, 0, 0,
- 0, 35, 375, 126, 127, 221, 37, 0, 38, 0,
- 0, 0, 39, 0, 40, 376, 43, 0, 0, 378,
- 0, 0, 0, 47, 0, 48, 0, -281, 0, 0,
- 0, 379, 0, 223, 0, 0, 0, 381, 49, 52,
- 50, 382, 383, 384, 55, 386, 387, 388, 389, 390,
- 391, 0, 0, 377, 385, 371, 366, 368, 130, 41,
- 0, 0, 0, 0, 0, 0, 46, 374, 380, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 214, 0, 0, 0, 0, 216,
+ 0, 29, 30, 31, 218, 0, 0, 0, 0, 0,
+ 0, 219, 33, 0, 0, 0, 0, 0, 0, 35,
+ 221, 0, 0, 222, 37, 0, 38, 0, 0, 0,
+ 39, 0, 40, 42, 43, 0, 0, 45, 0, 0,
+ 0, 47, 0, 48, 0, 0, 0, 0, 0, 224,
+ 0, 225, 0, 0, 0, 53, 49, 52, 50, 226,
+ 54, 227, 55, 228, 57, 229, 58, 230, 231, 0,
+ 0, 44, 56, 32, 215, 223, 217, 0, 41, 0,
+ 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 594, 112, 113,
+ 0, 0, 596, 117, 598, 30, 31, 599, 0, 120,
+ 0, 0, 0, 122, 601, 602, 0, 0, 0, 0,
+ 0, 0, 35, 603, 126, 127, 222, 37, 0, 38,
+ 0, 0, 0, 39, 0, 40, 605, 43, 0, 0,
+ 607, 0, 0, 0, 47, 0, 48, 0, 0, 0,
+ 0, 0, 608, 0, 225, 0, 0, 0, 609, 49,
+ 52, 50, 610, 611, 612, 55, 614, 615, 616, 617,
+ 618, 619, 0, 0, 606, 613, 600, 595, 604, 597,
+ 131, 41, 0, 0, 0, 0, 0, 0, 46, 376,
+ 383, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 367, 112, 113, 0, 0, 369, 117, 371, 30, 31,
+ 372, 0, 120, 0, 0, 0, 122, 374, 375, 0,
+ 0, 0, 0, 0, 0, 35, 377, 126, 127, 222,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 379,
+ 43, 0, 0, 381, 0, 0, 0, 47, 0, 48,
+ 0, -282, 0, 0, 0, 382, 0, 225, 0, 0,
+ 0, 384, 49, 52, 50, 385, 386, 387, 55, 389,
+ 390, 391, 392, 393, 394, 0, 0, 380, 388, 373,
+ 368, 378, 370, 131, 41, 0, 0, 0, 0, 0,
+ 0, 46, 376, 383, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,
- 152, 652, 331, 669, 535, 531, 538, 142, 528, 148,
- 641, 16, 313, 393, 485, 500, 626, 630, 263, 638,
- 183, 625, 623, 206, 574, 447, 583, 320, 183, 253,
- 313, 248, 466, 145, 663, 653, 616, 584, 556, 640,
- 581, 248, 437, 253, 248, 495, 183, 178, 453, 150,
- 462, 347, 455, 550, 554, 183, 351, 447, 458, 190,
- 313, 457, 425, 188, 469, 441, 433, 253, 237, 468,
- 0, 313, 173, 171, 393, 409, 447, 498, 409, 464,
- 400, 0, 165, 206, 475, 206, 512, 511, 0, 0,
- 188, 0, 0, 206, 0, 206, 0, 62, 0, 459,
- 417, 206, 206, 206, 188, 0, 62, 0, 62, 62,
- 507, 504, 410, 148, 62, 410, 460, 62, 419, 505,
- 407, 412, 170, 62, 62, 459, 506, 444, 277, 148,
- 422, 331, 187, 281, 62, 62, 62, 180, 260, 295,
- 296, 297, 62, 62, 656, 655, 314, 298, 299, 62,
- 62, 503, 182, 62, 206, 362, 514, 393, 247, 62,
- 62, 460, 502, 62, 62, 639, 313, 167, 92, 99,
- 62, 206, 206, 514, 510, 345, 100, 260, 562, 62,
- 62, 62, 394, 493, 93, 94, 95, 492, 62, 62,
- 182, 206, 62, 206, 96, 62, 246, 97, 62, 90,
- 62, 401, 91, 206, 62, 86, 355, 340, 353, 62,
- 108, 247, 206, 349, 188, 313, 102, 206, 393, 104,
- 313, 62, 206, 182, 206, 206, 62, 362, 459, 206,
- 242, 62, 469, 460, 62, 514, 409, 63, 318, 110,
- 657, 341, 239, 590, 403, 62, 322, 206, 72, 62,
- 362, 62, 362, 69, 206, 98, 62, 62, 70, 71,
- 514, 0, 206, 62, 62, 566, 356, 0, 206, 79,
- 62, 108, 74, 410, 483, 281, 0, 309, 0, 0,
- 62, 62, 281, 304, 62, 281, 281, 62, 362, 281,
- 343, 0, 281, 284, 289, 316, 324, 327, 0, 311,
- 110, 177, 0, 309, 206, 62, 479, 0, 281, 62,
- 281, 309, 301, 309, 281, 0, 281, 309, 281, 62,
- 306, 0, 281, 62, 281, 337, 302, 0, 281, 578,
- 300, 514, 260, 328, 562, 308, 636, 570, 443, 330,
- 522, 0, 0, 0, 0, 0, 514, 0, 206, 0,
- 0, 0, 513, 523, 0, 522, 0, 485, 542, 543,
- 544, 545, 549, 546, 547, 0, 586, 513, 523, 0,
- 0, 0, 0, 0, 440, 588, 589, 542, 543, 544,
- 545, 549, 546, 547, 586, 0, 0, 0, 0, 0,
- 0, 0, 0, 634, 635, 542, 543, 544, 545, 549,
- 546, 547, 578, 0, 0, 0, 0, 0, 0, 0,
- 0, 579, 580, 542, 543, 544, 545, 549, 546, 547,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 573, 0, 0, 0, 0, 0, 0, 0, 0,
- 514, 0, 0, 0, 0, 0, 0, 0, 0, 522,
+ 315, 478, 645, 153, 673, 465, 460, 501, 458, 461,
+ 184, 456, 396, 498, 488, 503, 440, 444, 436, 428,
+ 657, 667, 656, 644, 403, 630, 642, 629, 447, 634,
+ 450, 627, 315, 143, 553, 184, 255, 250, 149, 447,
+ 146, 353, 151, 349, 541, 531, 450, 534, 315, 179,
+ 538, 166, 172, 184, 322, 189, 620, 191, 16, 255,
+ 207, 250, 239, 586, 174, 250, 255, 587, 184, 447,
+ 265, 0, 577, 515, 584, 472, 559, 333, 450, 412,
+ 207, 514, 517, 471, 248, 467, 517, 565, 557, 207,
+ 315, 569, 315, 364, 207, 207, 207, 189, 249, 207,
+ 207, 207, 496, 0, 207, 315, 495, 412, 469, 358,
+ 333, 412, 207, 315, 62, 279, 413, 62, 0, 297,
+ 283, 486, 298, 244, 62, 241, 183, 62, 62, 62,
+ 262, 425, 299, 300, 301, 320, 364, 324, 62, 62,
+ 505, 506, 189, 262, 413, 0, 207, 0, 413, 472,
+ 0, 207, 593, 207, 62, 62, 507, 508, 62, 207,
+ 509, 62, 62, 510, 183, 316, 62, 318, 462, 149,
+ 188, 513, 62, 347, 463, 351, 62, 181, 355, 62,
+ 343, 357, 404, 62, 396, 462, 342, 262, 345, 207,
+ 108, 207, 171, 168, 207, 396, 62, 207, 207, 62,
+ 62, 183, 463, 207, 62, 62, 104, 62, 92, 62,
+ 406, 91, 249, 62, 97, 462, 364, 102, 62, 110,
+ 463, 420, 62, 482, 62, 396, 207, 96, 90, 62,
+ 207, 189, 207, 0, 95, 62, 62, 62, 62, 63,
+ 94, 72, 93, 62, 0, 62, 62, 62, 86, 62,
+ 397, 100, 99, 98, 108, 79, 62, 410, 149, 422,
+ 660, 659, 517, 62, 74, 71, 415, 661, 0, 62,
+ 0, 70, 62, 311, 69, 311, 311, 62, 283, 0,
+ 283, 283, 283, 110, 178, 62, 311, 311, 364, 364,
+ 283, 283, 283, 517, 329, 339, 62, 332, 330, 0,
+ 326, 283, 525, 0, 207, 207, 62, 308, 313, 310,
+ 0, 283, 62, 62, 516, 526, 0, 283, 283, 306,
+ 291, 286, 62, 62, 0, 517, 62, 283, 283, 302,
+ 303, 283, 576, 304, 643, 573, 0, 0, 0, 0,
+ 0, 517, 0, 0, 517, 0, 0, 0, 0, 0,
+ 525, 0, 0, 525, 545, 546, 547, 548, 552, 549,
+ 550, 0, 516, 526, 0, 516, 526, 589, 0, 0,
+ 0, 0, 0, 0, 443, 446, 638, 639, 545, 546,
+ 547, 548, 552, 549, 550, 589, 0, 0, 0, 0,
+ 0, 0, 0, 0, 591, 592, 545, 546, 547, 548,
+ 552, 549, 550, 581, 0, 0, 0, 0, 0, 0,
+ 0, 0, 582, 583, 545, 546, 547, 548, 552, 549,
+ 550, 0, 581, 0, 0, 0, 0, 565, 0, 640,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 513, 523, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 488, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0};
+ 0, 0, 0, 0, 0, 0, 0, 0, 0};
const short QQmlJSGrammar::action_check [] = {
- 7, 55, 48, 55, 55, 55, 36, 7, 36, 33,
- 55, 7, 7, 33, 37, 7, 7, 61, 60, 60,
- 36, 7, 33, 8, 36, 7, 16, 1, 36, 60,
- 7, 36, 2, 48, 7, 36, 5, 36, 36, 36,
- 79, 5, 36, 60, 33, 33, 55, 60, 7, 36,
- 34, 7, 33, 7, 7, 33, 36, 7, 7, 77,
- 36, 33, 8, 5, 1, 8, 33, 60, 29, 79,
- 36, 33, 17, 8, 37, 79, 33, 60, 33, 8,
- 1, 60, 2, 8, 7, 60, 33, 55, 48, 60,
- 29, 2, 7, 2, 7, 36, 36, 7, 17, 7,
- 33, 66, 7, 61, 48, 31, 36, 1, 36, 33,
- 8, 7, 60, 20, 36, 66, 33, 7, 36, 55,
- 36, 8, 60, 8, 15, -1, 40, 79, 8, 61,
- 61, 62, 10, 8, 61, 62, 40, 51, 8, 15,
- 40, 40, 8, 34, 8, 42, 6, 51, 24, 61,
- 62, 51, 51, 7, 8, 8, 53, 8, 61, 62,
- 20, 8, 8, 8, 8, 15, 61, 62, 61, 62,
- 8, 8, 15, 60, -1, 60, 56, 55, 61, 62,
- 61, 62, 61, 62, 34, 60, 56, 61, 62, 91,
- 92, 34, 56, 50, 60, 15, 29, 54, 0, 91,
- 92, 50, 61, 62, 24, 54, 25, 60, 27, 12,
- 61, 56, 29, 60, 60, 25, 60, 27, 56, 38,
- 25, 25, 27, 27, 61, 62, 12, 15, 38, 61,
- 62, 12, 29, 38, 38, 29, 7, -1, 25, 7,
- 27, 36, 75, 8, 29, 8, 34, -1, 36, 15,
- 25, 38, 27, 86, 57, 7, -1, 89, 75, 7,
- 63, -1, 33, 38, 15, 29, 61, 62, 34, 86,
- 36, 57, 29, -1, -1, -1, 57, 63, 75, -1,
- -1, 75, 63, 34, 15, 36, -1, 61, 62, 86,
- 75, -1, 86, 61, 62, -1, 61, 62, 61, 62,
- -1, 86, -1, 34, 25, 36, 27, 15, -1, 61,
- 62, 75, -1, 61, 62, 18, 19, 38, 75, 93,
- 15, -1, 86, 94, -1, 33, 34, -1, 36, 86,
- 18, 19, 18, 19, 18, 19, 47, -1, 33, 34,
- -1, 36, 45, 46, 98, 99, 100, 101, 102, 103,
- 61, 62, -1, -1, 23, 24, -1, 45, 46, 45,
- 46, 45, 46, 32, 23, 24, 35, -1, 37, -1,
- -1, -1, -1, 32, 23, 24, 35, -1, 37, -1,
- 23, 24, 93, 32, -1, 25, 35, 27, 37, 32,
- -1, -1, 35, 29, 37, 23, 24, -1, 38, -1,
- -1, -1, -1, 31, 32, 23, 24, 35, -1, 37,
- -1, -1, -1, 31, 32, 23, 24, 35, 29, 37,
- -1, -1, -1, 31, 32, 23, 24, 35, -1, 37,
- 66, 67, 68, 31, 32, 23, 24, 35, -1, 37,
- -1, -1, -1, 31, 32, -1, -1, 35, -1, 37,
- 29, -1, -1, 29, -1, 66, 67, 68, 94, 95,
- 96, 29, -1, -1, 29, -1, 23, 24, 29, -1,
- -1, 29, 15, -1, 29, 32, -1, -1, 35, -1,
- 37, 36, -1, 94, 95, 96, 29, 66, 67, 68,
+ 8, 61, 60, 8, 48, 1, 0, 2, 55, 79,
+ 33, 1, 60, 48, 7, 79, 66, 60, 17, 8,
+ 36, 66, 29, 8, 60, 37, 60, 33, 79, 33,
+ 1, 33, 2, 36, 20, 55, 8, 79, 7, 61,
+ 55, 60, 29, 7, 5, 1, 5, 48, 48, 33,
+ 33, 5, 7, 33, 17, 37, 31, 36, 55, 8,
+ 33, 7, 60, 77, 7, 33, 7, 7, 60, 36,
+ 61, 36, 60, 7, 36, 8, 36, 16, 36, 36,
+ 7, 55, 34, 36, 7, 7, 7, 7, 36, 55,
+ 7, 36, 7, 7, 36, 7, 7, 7, 36, 2,
+ 36, 7, 33, 7, 55, 7, 36, 7, 55, 33,
+ 60, 7, -1, 8, 33, 8, 60, 42, 36, -1,
+ 36, 8, -1, 60, 33, 33, 61, 62, 53, 36,
+ 8, 36, 8, -1, 33, 36, 8, 50, 36, -1,
+ 8, 54, 8, 40, 15, 8, 15, 8, 40, 8,
+ 8, -1, -1, 24, 51, 15, -1, 10, 15, 51,
+ 8, 56, 50, 92, 93, 34, 54, 60, 8, 56,
+ 61, 62, 61, 62, 34, 61, 62, 34, 56, 61,
+ 62, 61, 62, 8, 60, 40, 61, 62, 60, 40,
+ 56, 7, 60, 6, 61, 62, 51, 60, 15, 60,
+ 51, 60, 55, 61, 7, 61, 62, 20, 56, 61,
+ 62, 92, 93, 15, 61, 62, 12, 34, 29, 36,
+ 60, 8, 24, 15, 29, 25, 12, 27, 25, -1,
+ 27, 7, 15, 12, 29, 29, 61, 62, 38, 7,
+ -1, 38, 34, -1, 36, 61, 62, 25, 29, 27,
+ 25, 34, 27, 36, 61, 62, 25, 29, 27, 8,
+ 38, 57, -1, 38, 75, 33, 25, 63, 27, 38,
+ 75, 57, 29, -1, 61, 62, 87, 63, 57, 38,
+ 75, 75, 87, 90, 63, 61, 62, 25, 25, 27,
+ 27, 36, 87, 87, 75, 25, 25, 27, 27, 7,
+ 38, 38, 15, 75, 7, 8, 87, -1, 38, 38,
+ 61, 62, 61, 62, -1, 87, 61, 62, 75, 15,
+ 25, 34, 27, 36, 18, 19, 15, 95, 18, 19,
+ 87, 18, 19, 38, 18, 19, -1, 33, 34, -1,
+ 36, -1, -1, 94, 33, 34, -1, 36, -1, 47,
+ -1, 45, 46, 61, 62, 45, 46, -1, 45, 46,
+ -1, 45, 46, 61, 62, 23, 24, -1, -1, 23,
+ 24, -1, -1, -1, 32, 23, 24, 35, 32, 37,
+ -1, 35, 29, 37, 32, 23, 24, 35, 29, 37,
+ -1, 23, 24, 29, 32, -1, 94, 35, 29, 37,
+ 32, 29, -1, 35, 25, 37, 27, 99, 100, 101,
+ 102, 103, 104, -1, 29, -1, -1, 38, -1, 66,
+ 67, 68, -1, -1, -1, 66, 67, 68, -1, -1,
+ 66, 67, 68, -1, -1, 66, 67, 68, 66, 67,
+ 68, -1, -1, -1, -1, -1, 29, -1, 95, 96,
+ 97, 66, 67, 68, 95, 96, 97, -1, -1, 95,
+ 96, 97, -1, -1, 95, 96, 97, 95, 96, 97,
+ 29, -1, -1, -1, -1, -1, -1, -1, 29, -1,
+ 95, 96, 97, 66, 67, 68, 23, 24, 29, -1,
+ -1, 29, -1, -1, 31, 32, 29, -1, 35, -1,
+ 37, -1, -1, 36, -1, -1, -1, 66, 67, 68,
+ -1, 29, 95, 96, 97, 66, 67, 68, 36, -1,
+ -1, -1, -1, -1, -1, 66, 67, 68, 66, 67,
+ 68, -1, -1, 66, 67, 68, 95, 96, 97, 15,
+ -1, -1, -1, -1, 95, 96, 97, 15, 66, 67,
+ 68, -1, -1, 29, 95, 96, 97, 95, 96, 97,
+ -1, 29, 95, 96, 97, 29, -1, -1, -1, -1,
+ 29, -1, 36, 29, -1, -1, -1, 95, 96, 97,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, -1,
66, 67, 68, -1, -1, -1, -1, -1, 66, 67,
- 68, 66, 67, 68, -1, 66, 67, 68, 66, 67,
- 68, 66, 67, 68, -1, 94, 95, 96, 94, 95,
- 96, -1, -1, 66, 67, 68, 94, 95, 96, 94,
- 95, 96, 15, 94, 95, 96, 94, 95, 96, 94,
- 95, 96, -1, 29, -1, -1, 29, -1, -1, 29,
- 36, 94, 95, 96, 29, -1, -1, 29, -1, -1,
- -1, 36, -1, -1, -1, 29, -1, -1, 29, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 66, 67, 68, 66, 67, 68, 66, 67, 68, 61,
- 62, 66, 67, 68, 66, 67, 68, 61, 62, -1,
- 61, 62, 66, 67, 68, 66, 67, 68, 94, 95,
- 96, 94, 95, 96, 94, 95, 96, 29, -1, 94,
- 95, 96, 94, 95, 96, 29, 15, -1, 29, -1,
- 94, 95, 96, 94, 95, 96, -1, -1, -1, -1,
- 29, -1, -1, -1, -1, -1, -1, -1, -1, 61,
- 62, -1, -1, -1, 66, 67, 68, 61, 62, -1,
- 61, 62, 66, 67, 68, 66, 67, 68, -1, -1,
- -1, -1, -1, -1, -1, 3, -1, 66, 67, 68,
- -1, -1, 94, 95, 96, 13, -1, -1, -1, 17,
- 94, 95, 96, 94, 95, 96, -1, -1, 26, -1,
- 28, -1, -1, 31, -1, 94, 95, 96, -1, -1,
- -1, 39, -1, 41, 42, -1, -1, 3, -1, -1,
- -1, 49, -1, -1, 52, 53, -1, 13, -1, -1,
- 58, 17, -1, -1, -1, -1, 64, -1, -1, -1,
- 26, -1, 28, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 80, 39, -1, 41, 42, -1, -1, -1,
- -1, -1, -1, 49, -1, -1, 52, 53, -1, -1,
- -1, -1, 58, -1, -1, -1, -1, -1, 64, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 80, -1, -1, -1, -1, -1,
+ 68, -1, 66, 67, 68, 61, 62, 66, 67, 68,
+ 66, 67, 68, -1, -1, -1, -1, 61, 62, 95,
+ 96, 97, 66, 67, 68, -1, 29, 95, 96, 97,
+ -1, 95, 96, 97, -1, -1, 95, 96, 97, 95,
+ 96, 97, 29, -1, -1, 29, -1, -1, 15, -1,
+ -1, 95, 96, 97, -1, -1, -1, -1, 61, 62,
+ -1, -1, 29, 66, 67, 68, -1, -1, -1, -1,
+ -1, -1, -1, -1, 61, 62, -1, 61, 62, 66,
+ 67, 68, 66, 67, 68, -1, -1, -1, -1, -1,
+ -1, -1, 95, 96, 97, -1, -1, -1, -1, 66,
+ 67, 68, -1, -1, -1, -1, -1, -1, 95, 96,
+ 97, 95, 96, 97, -1, -1, -1, -1, -1, -1,
+ -1, 3, -1, -1, -1, -1, -1, -1, 95, 96,
+ 97, 13, -1, -1, -1, 17, -1, -1, -1, -1,
+ 29, -1, -1, -1, 26, -1, 28, -1, -1, 31,
+ -1, -1, -1, -1, -1, -1, -1, 39, -1, 41,
+ 42, -1, -1, -1, -1, -1, -1, 49, -1, -1,
+ 52, 53, 61, 62, -1, -1, 58, 66, 67, 68,
+ -1, -1, 64, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 80, -1,
+ -1, -1, -1, -1, -1, -1, 95, 96, 97, -1,
+ -1, -1, -1, -1, -1, -1, 12, 13, 3, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, 13, -1,
+ -1, -1, 17, 29, -1, -1, -1, 33, 34, -1,
+ 36, 26, -1, 28, -1, -1, -1, 43, -1, -1,
+ -1, 47, -1, -1, 39, -1, 41, 42, -1, -1,
+ -1, -1, -1, -1, 49, -1, -1, 52, 53, 65,
+ 66, 67, 68, 58, 70, -1, -1, -1, -1, 64,
+ -1, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, -1, 80, -1, -1, -1, 95,
+ 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
- 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
+ -1, -1, -1, -1, -1, 95, 96, 97, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 12, 13, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, -1, -1, -1, -1, -1,
+ 95, 96, 97, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 10, -1, 12, 13, -1, -1, -1, -1,
-1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
-1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
-1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
- 68, -1, 70, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, 87,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 10, -1,
+ 68, -1, 70, -1, -1, -1, -1, 75, -1, -1,
+ -1, -1, -1, 81, 82, 83, 84, 85, -1, -1,
+ 88, -1, -1, -1, -1, -1, -1, 95, 96, 97,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 10,
+ -1, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, -1,
+ -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, 55, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, -1, -1, -1, 75, -1, -1, -1, -1, -1,
+ 81, 82, 83, 84, 85, -1, -1, 88, -1, -1,
+ -1, -1, -1, -1, 95, 96, 97, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 10, -1, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, -1, -1, -1, 43,
+ -1, -1, -1, 47, -1, -1, -1, -1, -1, -1,
+ -1, 55, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, -1, -1,
+ -1, 75, -1, -1, -1, -1, -1, 81, 82, 83,
+ 84, 85, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, 95, 96, 97, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 11, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
+ 68, -1, 70, -1, 72, -1, 74, -1, 76, -1,
+ -1, -1, -1, 81, 82, 83, -1, -1, -1, -1,
+ 88, -1, -1, -1, -1, -1, -1, 95, 96, 97,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 11,
12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- -1, -1, -1, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, 84, -1, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 10, -1, 12, 13, -1, -1,
- -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
- -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
- 36, -1, -1, -1, -1, -1, -1, 43, -1, -1,
- -1, 47, -1, -1, -1, -1, -1, -1, -1, 55,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
- 66, 67, 68, -1, 70, -1, -1, -1, -1, 75,
- -1, -1, -1, -1, -1, 81, 82, 83, 84, -1,
- -1, 87, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 10, -1, 12, 13, -1, -1, -1, -1, -1, -1,
- -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
- -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
- -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
- -1, -1, -1, -1, -1, 55, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
- 70, -1, -1, -1, -1, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, 84, -1, -1, 87, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
- -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
- -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
- -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
- -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
- -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, 87, -1, -1, -1, -1, -1, -1, 94,
- 95, 96, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 7, -1, -1, -1, 11, 12, 13, -1, -1,
- -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
- -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
- 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
- -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
- 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
- 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
- -1, 87, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
- -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
- -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
- -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
- 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
- -1, 72, -1, 74, 75, 76, -1, -1, -1, -1,
- 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
- -1, -1, -1, 94, 95, 96, -1, -1, -1, -1,
+ 72, -1, 74, 75, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, -1, 88, -1, -1, -1,
+ -1, -1, -1, 95, 96, 97, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 7, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, -1, 88, -1, -1, -1,
+ -1, -1, -1, 95, 96, 97, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 8, -1, -1, 11, 12,
13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
-1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
@@ -889,8 +910,18 @@ const short QQmlJSGrammar::action_check [] = {
53, -1, -1, 56, -1, -1, -1, -1, -1, -1,
-1, -1, 65, 66, 67, 68, -1, 70, -1, 72,
-1, 74, -1, 76, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, -1, 87, -1, -1, -1, -1, -1,
- -1, 94, 95, 96, -1, -1, -1, -1, -1, -1,
+ 83, -1, -1, -1, -1, 88, -1, -1, -1, -1,
+ -1, -1, 95, 96, 97, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, 95, 96, 97, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 8, -1, -1, 11, 12, 13, -1,
-1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
-1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
@@ -899,46 +930,27 @@ const short QQmlJSGrammar::action_check [] = {
-1, 56, -1, -1, -1, -1, -1, -1, -1, -1,
65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
-1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, 87, -1, -1, -1, -1, -1, -1, 94,
- 95, 96, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 8, -1, -1, 11, 12, 13, -1, -1, -1,
- -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
- -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
- -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
- 47, -1, -1, -1, 51, -1, 53, -1, -1, 56,
- -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
- 67, 68, -1, 70, -1, 72, -1, 74, -1, 76,
- -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
- 87, -1, -1, -1, -1, -1, -1, 94, 95, 96,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 8,
- -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
- -1, -1, 51, -1, 53, -1, -1, 56, -1, -1,
- -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
- -1, 70, -1, 72, -1, 74, -1, 76, -1, -1,
- -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
- -1, -1, -1, -1, -1, 94, 95, 96, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, 61, -1, -1,
- -1, 65, 66, 67, 68, 69, 70, -1, 72, 73,
- 74, -1, 76, -1, 78, -1, -1, 81, 82, 83,
- -1, -1, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
- -1, -1, 61, -1, -1, -1, 65, 66, 67, 68,
- 69, 70, -1, 72, 73, 74, -1, 76, -1, 78,
- -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
- -1, -1, -1, -1, -1, 94, 95, 96, -1, -1,
+ -1, -1, -1, 88, -1, -1, -1, -1, -1, -1,
+ 95, 96, 97, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 8, -1, -1, 11, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
+ -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
+ 56, -1, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
+ 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
+ -1, -1, 88, -1, -1, -1, -1, -1, -1, 95,
+ 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ 30, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
+ -1, 51, -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, 61, -1, -1, -1, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, -1, 76, -1, 78, -1,
+ -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
+ -1, -1, -1, -1, -1, 95, 96, 97, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
-1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
-1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
@@ -947,38 +959,48 @@ const short QQmlJSGrammar::action_check [] = {
-1, -1, -1, -1, -1, -1, -1, 61, -1, -1,
-1, 65, 66, 67, 68, 69, 70, -1, 72, 73,
74, -1, 76, -1, 78, -1, -1, 81, 82, 83,
- -1, -1, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, 95, 96, 97, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 11, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, 30, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
+ -1, -1, -1, 51, -1, 53, -1, -1, -1, -1,
+ -1, -1, -1, 61, -1, -1, -1, 65, 66, 67,
+ 68, 69, 70, -1, 72, 73, 74, -1, 76, -1,
+ 78, -1, -1, 81, 82, 83, -1, -1, -1, -1,
+ 88, -1, -1, -1, -1, -1, -1, 95, 96, 97,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 59, -1, -1, -1, -1, -1,
+ -1, 66, 67, 68, 69, 70, 71, -1, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, 87, -1, -1, -1, -1, -1, -1, -1,
+ 95, 96, 97, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 4, 5, 6, -1, -1, 9, 10, 11,
-1, -1, 14, -1, 16, -1, -1, -1, 20, 21,
22, -1, -1, -1, -1, -1, -1, 29, 30, 31,
32, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 59, -1, -1,
- -1, -1, -1, -1, 66, 67, 68, 69, 70, 71,
+ -1, -1, -1, 65, 66, 67, 68, 69, 70, 71,
-1, 73, 74, 75, 76, 77, 78, -1, -1, 81,
- 82, 83, 84, 85, 86, -1, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 4, 5, 6, -1, -1, 9,
- 10, 11, -1, -1, 14, -1, 16, -1, -1, -1,
- 20, 21, 22, -1, -1, -1, -1, -1, -1, 29,
- 30, 31, 32, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 59,
- -1, -1, -1, -1, -1, 65, 66, 67, 68, 69,
- 70, 71, -1, 73, 74, 75, 76, 77, 78, -1,
- -1, 81, 82, 83, 84, 85, 86, -1, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 4, 5, 6, -1,
- -1, 9, 10, 11, -1, -1, 14, -1, 16, -1,
- -1, -1, 20, 21, 22, -1, -1, -1, -1, -1,
- -1, 29, 30, 31, 32, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
+ 82, 83, 84, 85, 86, 87, -1, -1, -1, -1,
+ -1, -1, -1, 95, 96, 97, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, 5, 6, -1, -1,
+ 9, 10, 11, -1, -1, 14, -1, 16, -1, -1,
+ -1, 20, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 59, -1, -1, -1, -1, -1, 65, 66, 67,
- 68, 69, 70, 71, -1, 73, 74, 75, 76, 77,
- 78, -1, -1, 81, 82, 83, 84, 85, 86, -1,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
+ 59, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ 69, 70, 71, -1, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, 86, 87, -1,
+ -1, -1, -1, -1, -1, -1, 95, 96, 97, -1,
-1, -1, -1, -1, -1, -1, -1, -1, 4, 5,
6, -1, -1, 9, 10, 11, -1, -1, 14, -1,
16, -1, -1, -1, 20, 21, 22, -1, -1, -1,
@@ -988,104 +1010,102 @@ const short QQmlJSGrammar::action_check [] = {
-1, -1, -1, 59, -1, -1, -1, -1, -1, 65,
66, 67, 68, 69, 70, 71, -1, 73, 74, 75,
76, 77, 78, -1, -1, 81, 82, 83, 84, 85,
- 86, -1, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 4, -1, -1, -1, -1, 9, -1, 11, 12, 13,
- 14, -1, -1, -1, -1, -1, -1, 21, 22, -1,
- -1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, 59, -1, 61, -1, -1,
- -1, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, -1, -1, 81, 82, 83,
- 84, 85, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 4, -1, -1, -1, -1, 9, -1, 11,
- 12, 13, 14, -1, -1, -1, -1, -1, -1, 21,
- 22, -1, -1, -1, -1, -1, -1, 29, 30, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
- 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
- -1, 53, -1, -1, -1, -1, -1, 59, -1, 61,
- -1, -1, -1, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, -1, -1, 81,
- 82, 83, 84, 85, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 4, 5, 6, -1, -1, 9,
- 10, 11, 12, 13, 14, -1, 16, -1, -1, -1,
- 20, 21, 22, -1, -1, -1, -1, -1, -1, 29,
- 30, 31, 32, 33, 34, -1, 36, -1, -1, -1,
+ 86, 87, -1, -1, -1, -1, -1, -1, -1, 95,
+ 96, 97, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, -1, -1, -1, -1, 9, -1, 11, 12,
+ 13, 14, -1, -1, -1, -1, -1, -1, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, 59, -1, 61, -1,
+ -1, -1, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, -1, 88, -1, -1, -1, -1,
+ -1, -1, 95, 96, 97, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 4, -1, -1, -1, -1, 9,
+ -1, 11, 12, 13, 14, -1, -1, -1, -1, -1,
+ -1, 21, 22, -1, -1, -1, -1, -1, -1, 29,
+ 30, -1, -1, 33, 34, -1, 36, -1, -1, -1,
40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
-1, 51, -1, 53, -1, -1, -1, -1, -1, 59,
-1, 61, -1, -1, -1, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, -1,
- -1, 81, 82, 83, 84, 85, 86, 87, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 4, 5, 6, -1,
- -1, 9, 10, 11, 12, 13, 14, -1, 16, -1,
- -1, -1, 20, 21, 22, -1, -1, -1, -1, -1,
- -1, 29, 30, 31, 32, 33, 34, -1, 36, -1,
- -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
- -1, -1, -1, 51, -1, 53, -1, 55, -1, -1,
- -1, 59, -1, 61, -1, -1, -1, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, -1, -1, 81, 82, 83, 84, 85, 86, 87,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 81, 82, 83, 84, 85, 86, -1, 88, -1,
+ -1, -1, -1, -1, -1, 95, 96, 97, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
+ -1, -1, 9, 10, 11, 12, 13, 14, -1, 16,
+ -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, 31, 32, 33, 34, -1, 36,
+ -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
+ 47, -1, -1, -1, 51, -1, 53, -1, -1, -1,
+ -1, -1, 59, -1, 61, -1, -1, -1, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
+ 87, 88, -1, -1, -1, -1, -1, -1, 95, 96,
+ 97, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 4, 5, 6, -1, -1, 9, 10, 11, 12, 13,
+ 14, -1, 16, -1, -1, -1, 20, 21, 22, -1,
+ -1, -1, -1, -1, -1, 29, 30, 31, 32, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, 55, -1, -1, -1, 59, -1, 61, -1, -1,
+ -1, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, -1, -1, 81, 82, 83,
+ 84, 85, 86, 87, 88, -1, -1, -1, -1, -1,
+ -1, 95, 96, 97, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,
- 77, 14, 18, 18, 18, 32, 18, 3, 32, 42,
- 9, 3, 3, 18, 42, 3, 18, 18, 3, 22,
- 18, 32, 32, 18, 18, 25, 32, 3, 18, 18,
- 3, 18, 3, 42, 18, 14, 22, 18, 18, 22,
- 22, 18, 100, 18, 18, 42, 18, 3, 105, 42,
- 3, 3, 18, 14, 32, 18, 3, 25, 25, 18,
- 3, 25, 3, 18, 18, 3, 103, 18, 18, 2,
- -1, 3, 42, 42, 18, 14, 25, 42, 14, 2,
- 42, -1, 42, 18, 42, 18, 2, 4, -1, -1,
- 18, -1, -1, 18, -1, 18, -1, 54, -1, 56,
- 44, 18, 18, 18, 18, -1, 54, -1, 54, 54,
- 56, 56, 51, 42, 54, 51, 56, 54, 46, 56,
- 45, 50, 70, 54, 54, 56, 56, 3, 54, 42,
- 45, 18, 46, 59, 54, 54, 54, 50, 2, 59,
- 59, 59, 54, 54, 11, 12, 78, 59, 59, 54,
- 54, 56, 56, 54, 18, 2, 14, 18, 4, 54,
- 54, 56, 56, 54, 54, 23, 3, 68, 58, 60,
- 54, 18, 18, 14, 109, 2, 60, 2, 19, 54,
- 54, 54, 43, 38, 59, 59, 59, 42, 54, 54,
- 56, 18, 54, 18, 59, 54, 2, 59, 54, 58,
- 54, 2, 58, 18, 54, 59, 2, 94, 2, 54,
- 18, 4, 18, 2, 18, 3, 66, 18, 18, 64,
- 3, 54, 18, 56, 18, 18, 54, 2, 56, 18,
- 45, 54, 18, 56, 54, 14, 14, 57, 2, 47,
- 19, 78, 46, 18, 44, 54, 2, 18, 57, 54,
- 2, 54, 2, 56, 18, 60, 54, 54, 56, 56,
- 14, -1, 18, 54, 54, 19, 18, -1, 18, 60,
- 54, 18, 62, 51, 45, 59, -1, 54, -1, -1,
- 54, 54, 59, 67, 54, 59, 59, 54, 2, 59,
- 78, -1, 59, 63, 61, 78, 69, 71, -1, 76,
- 47, 48, -1, 54, 18, 54, 92, -1, 59, 54,
- 59, 54, 61, 54, 59, -1, 59, 54, 59, 54,
- 65, -1, 59, 54, 59, 76, 61, -1, 59, 14,
- 61, 14, 2, 76, 19, 76, 21, 5, 88, 76,
- 23, -1, -1, -1, -1, -1, 14, -1, 18, -1,
- -1, -1, 35, 36, -1, 23, -1, 42, 25, 26,
- 27, 28, 29, 30, 31, -1, 14, 35, 36, -1,
- -1, -1, -1, -1, 88, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 14, -1, -1, -1, -1, -1,
- -1, -1, -1, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 14, -1, -1, -1, -1, -1, -1, -1,
- -1, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 5, -1, -1, -1, -1, -1, -1, -1, -1,
- 14, -1, -1, -1, -1, -1, -1, -1, -1, 23,
+ 3, 42, 9, 77, 18, 3, 25, 42, 18, 25,
+ 18, 105, 18, 42, 42, 3, 100, 3, 103, 3,
+ 14, 18, 14, 22, 42, 18, 22, 32, 3, 18,
+ 25, 32, 3, 3, 14, 18, 18, 18, 42, 3,
+ 42, 3, 42, 3, 18, 32, 25, 32, 3, 3,
+ 18, 42, 42, 18, 3, 18, 22, 18, 3, 18,
+ 18, 18, 18, 32, 42, 18, 18, 18, 18, 3,
+ 3, -1, 18, 2, 22, 18, 18, 18, 25, 14,
+ 18, 4, 14, 2, 2, 2, 14, 19, 32, 18,
+ 3, 19, 3, 2, 18, 18, 18, 18, 4, 18,
+ 18, 18, 38, -1, 18, 3, 42, 14, 3, 18,
+ 18, 14, 18, 3, 54, 54, 51, 54, -1, 59,
+ 59, 45, 59, 45, 54, 46, 56, 54, 54, 54,
+ 2, 45, 59, 59, 59, 2, 2, 2, 54, 54,
+ 56, 56, 18, 2, 51, -1, 18, -1, 51, 18,
+ -1, 18, 18, 18, 54, 54, 56, 56, 54, 18,
+ 56, 54, 54, 56, 56, 78, 54, 78, 56, 42,
+ 46, 109, 54, 2, 56, 2, 54, 50, 2, 54,
+ 78, 2, 2, 54, 18, 56, 94, 2, 78, 18,
+ 18, 18, 70, 68, 18, 18, 54, 18, 18, 54,
+ 54, 56, 56, 18, 54, 54, 64, 54, 58, 54,
+ 44, 58, 4, 54, 59, 56, 2, 66, 54, 47,
+ 56, 44, 54, 92, 54, 18, 18, 59, 58, 54,
+ 18, 18, 18, -1, 59, 54, 54, 54, 54, 57,
+ 59, 57, 59, 54, -1, 54, 54, 54, 59, 54,
+ 43, 60, 60, 60, 18, 60, 54, 45, 42, 46,
+ 11, 12, 14, 54, 62, 56, 50, 19, -1, 54,
+ -1, 56, 54, 54, 56, 54, 54, 54, 59, -1,
+ 59, 59, 59, 47, 48, 54, 54, 54, 2, 2,
+ 59, 59, 59, 14, 71, 76, 54, 76, 76, -1,
+ 69, 59, 23, -1, 18, 18, 54, 65, 76, 76,
+ -1, 59, 54, 54, 35, 36, -1, 59, 59, 67,
+ 61, 63, 54, 54, -1, 14, 54, 59, 59, 61,
+ 61, 59, 5, 61, 23, 5, -1, -1, -1, -1,
+ -1, 14, -1, -1, 14, -1, -1, -1, -1, -1,
+ 23, -1, -1, 23, 25, 26, 27, 28, 29, 30,
+ 31, -1, 35, 36, -1, 35, 36, 14, -1, -1,
+ -1, -1, -1, -1, 88, 88, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 14, -1, -1, -1, -1,
+ -1, -1, -1, -1, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 14, -1, -1, -1, -1, -1, -1,
+ -1, -1, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, -1, 14, -1, -1, -1, -1, 19, -1, 21,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 35, 36, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 42, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1};
+ -1, -1, -1, -1, -1, -1, -1, -1, -1};
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsgrammar_p.h b/src/qml/parser/qqmljsgrammar_p.h
index 050ef6c288..b4f762d28b 100644
--- a/src/qml/parser/qqmljsgrammar_p.h
+++ b/src/qml/parser/qqmljsgrammar_p.h
@@ -61,23 +61,23 @@ class QQmlJSGrammar
public:
enum VariousConstants {
EOF_SYMBOL = 0,
- REDUCE_HERE = 105,
- SHIFT_THERE = 104,
+ REDUCE_HERE = 106,
+ SHIFT_THERE = 105,
T_AND = 1,
T_AND_AND = 2,
T_AND_EQ = 3,
- T_AS = 93,
+ T_AS = 94,
T_AUTOMATIC_SEMICOLON = 62,
T_BREAK = 4,
T_CASE = 5,
T_CATCH = 6,
T_COLON = 7,
T_COMMA = 8,
- T_COMMENT = 88,
- T_COMPATIBILITY_SEMICOLON = 89,
+ T_COMMENT = 89,
+ T_COMPATIBILITY_SEMICOLON = 90,
T_CONST = 84,
T_CONTINUE = 9,
- T_DEBUGGER = 85,
+ T_DEBUGGER = 86,
T_DEFAULT = 10,
T_DELETE = 11,
T_DIVIDE_ = 12,
@@ -88,19 +88,19 @@ public:
T_EQ = 17,
T_EQ_EQ = 18,
T_EQ_EQ_EQ = 19,
- T_ERROR = 97,
+ T_ERROR = 98,
T_FALSE = 83,
- T_FEED_JS_EXPRESSION = 101,
- T_FEED_JS_PROGRAM = 103,
- T_FEED_JS_SOURCE_ELEMENT = 102,
- T_FEED_JS_STATEMENT = 100,
- T_FEED_UI_OBJECT_MEMBER = 99,
- T_FEED_UI_PROGRAM = 98,
+ T_FEED_JS_EXPRESSION = 102,
+ T_FEED_JS_PROGRAM = 104,
+ T_FEED_JS_SOURCE_ELEMENT = 103,
+ T_FEED_JS_STATEMENT = 101,
+ T_FEED_UI_OBJECT_MEMBER = 100,
+ T_FEED_UI_PROGRAM = 99,
T_FINALLY = 20,
T_FOR = 21,
T_FUNCTION = 22,
T_GE = 23,
- T_GET = 95,
+ T_GET = 96,
T_GT = 24,
T_GT_GT = 25,
T_GT_GT_EQ = 26,
@@ -108,12 +108,13 @@ public:
T_GT_GT_GT_EQ = 28,
T_IDENTIFIER = 29,
T_IF = 30,
- T_IMPORT = 91,
+ T_IMPORT = 92,
T_IN = 31,
T_INSTANCEOF = 32,
T_LBRACE = 33,
T_LBRACKET = 34,
T_LE = 35,
+ T_LET = 85,
T_LPAREN = 36,
T_LT = 37,
T_LT_LT = 38,
@@ -121,34 +122,34 @@ public:
T_MINUS = 40,
T_MINUS_EQ = 41,
T_MINUS_MINUS = 42,
- T_MULTILINE_STRING_LITERAL = 87,
+ T_MULTILINE_STRING_LITERAL = 88,
T_NEW = 43,
T_NOT = 44,
T_NOT_EQ = 45,
T_NOT_EQ_EQ = 46,
T_NULL = 81,
T_NUMERIC_LITERAL = 47,
- T_ON = 94,
+ T_ON = 95,
T_OR = 48,
T_OR_EQ = 49,
T_OR_OR = 50,
T_PLUS = 51,
T_PLUS_EQ = 52,
T_PLUS_PLUS = 53,
- T_PRAGMA = 92,
+ T_PRAGMA = 93,
T_PROPERTY = 66,
- T_PUBLIC = 90,
+ T_PUBLIC = 91,
T_QUESTION = 54,
T_RBRACE = 55,
T_RBRACKET = 56,
T_READONLY = 68,
T_REMAINDER = 57,
T_REMAINDER_EQ = 58,
- T_RESERVED_WORD = 86,
+ T_RESERVED_WORD = 87,
T_RETURN = 59,
T_RPAREN = 60,
T_SEMICOLON = 61,
- T_SET = 96,
+ T_SET = 97,
T_SIGNAL = 67,
T_STAR = 63,
T_STAR_EQ = 64,
@@ -167,15 +168,15 @@ public:
T_XOR = 79,
T_XOR_EQ = 80,
- ACCEPT_STATE = 674,
- RULE_COUNT = 361,
- STATE_COUNT = 675,
- TERMINAL_COUNT = 106,
+ ACCEPT_STATE = 678,
+ RULE_COUNT = 363,
+ STATE_COUNT = 679,
+ TERMINAL_COUNT = 107,
NON_TERMINAL_COUNT = 111,
- GOTO_INDEX_OFFSET = 675,
- GOTO_INFO_OFFSET = 3078,
- GOTO_CHECK_OFFSET = 3078
+ GOTO_INDEX_OFFSET = 679,
+ GOTO_INFO_OFFSET = 3203,
+ GOTO_CHECK_OFFSET = 3203
};
static const char *const spell [];
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 84ebe5f210..8b789526a5 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -106,6 +106,13 @@ static inline int classify3(const QChar *s, bool qmlMode) {
}
}
}
+ else if (s[0].unicode() == 'l') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 't') {
+ return int(Lexer::T_LET);
+ }
+ }
+ }
else if (s[0].unicode() == 'n') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 'w') {
@@ -278,7 +285,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 's') {
if (s[4].unicode() == 't') {
- return qmlMode ? int(Lexer::T_CONST) : int(Lexer::T_RESERVED_WORD);
+ return int(Lexer::T_CONST);
}
}
}
diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp
index 50518a92ee..636b959097 100644
--- a/src/qml/parser/qqmljsparser.cpp
+++ b/src/qml/parser/qqmljsparser.cpp
@@ -914,21 +914,21 @@ case 116: {
sym(1).Node = node;
} break;
-case 152: {
+case 153: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 153: {
+case 154: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 154: {
+case 155: {
AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
node->newToken = loc(1);
node->lparenToken = loc(3);
@@ -936,384 +936,384 @@ case 154: {
sym(1).Node = node;
} break;
-case 156: {
+case 157: {
AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
node->newToken = loc(1);
sym(1).Node = node;
} break;
-case 157: {
+case 158: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 158: {
+case 159: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 159: {
+case 160: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 160: {
+case 161: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 161: {
+case 162: {
sym(1).Node = 0;
} break;
-case 162: {
+case 163: {
sym(1).Node = sym(1).ArgumentList->finish();
} break;
-case 163: {
+case 164: {
sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
} break;
-case 164: {
+case 165: {
AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 168: {
+case 169: {
AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
node->incrementToken = loc(2);
sym(1).Node = node;
} break;
-case 169: {
+case 170: {
AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
node->decrementToken = loc(2);
sym(1).Node = node;
} break;
-case 171: {
+case 172: {
AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
node->deleteToken = loc(1);
sym(1).Node = node;
} break;
-case 172: {
+case 173: {
AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
node->voidToken = loc(1);
sym(1).Node = node;
} break;
-case 173: {
+case 174: {
AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
node->typeofToken = loc(1);
sym(1).Node = node;
} break;
-case 174: {
+case 175: {
AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
node->incrementToken = loc(1);
sym(1).Node = node;
} break;
-case 175: {
+case 176: {
AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
node->decrementToken = loc(1);
sym(1).Node = node;
} break;
-case 176: {
+case 177: {
AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
node->plusToken = loc(1);
sym(1).Node = node;
} break;
-case 177: {
+case 178: {
AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
node->minusToken = loc(1);
sym(1).Node = node;
} break;
-case 178: {
+case 179: {
AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
node->tildeToken = loc(1);
sym(1).Node = node;
} break;
-case 179: {
+case 180: {
AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
node->notToken = loc(1);
sym(1).Node = node;
} break;
-case 181: {
+case 182: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Mul, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 182: {
+case 183: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Div, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 183: {
+case 184: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Mod, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 185: {
+case 186: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Add, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 186: {
+case 187: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Sub, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 188: {
+case 189: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::LShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 189: {
+case 190: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::RShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 190: {
+case 191: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::URShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 192: {
+case 193: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 193: {
+case 194: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 194: {
+case 195: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 195: {
+case 196: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 196: {
+case 197: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 197: {
+case 198: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::In, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 199: {
+case 200: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 200: {
+case 201: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 201: {
+case 202: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 202: {
+case 203: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 203: {
+case 204: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 205: {
+case 206: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 206: {
+case 207: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 207: {
+case 208: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 208: {
+case 209: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 210: {
+case 211: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 211: {
+case 212: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 212: {
+case 213: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 213: {
+case 214: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 215: {
+case 216: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 217: {
+case 218: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 219: {
+case 220: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 221: {
+case 222: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 223: {
+case 224: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 225: {
+case 226: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 227: {
+case 228: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 229: {
+case 230: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 231: {
+case 232: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 233: {
+case 234: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 235: {
+case 236: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1321,7 +1321,7 @@ case 235: {
sym(1).Node = node;
} break;
-case 237: {
+case 238: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1329,189 +1329,200 @@ case 237: {
sym(1).Node = node;
} break;
-case 239: {
+case 240: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 241: {
+case 242: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 242: {
+case 243: {
sym(1).ival = QSOperator::Assign;
} break;
-case 243: {
+case 244: {
sym(1).ival = QSOperator::InplaceMul;
} break;
-case 244: {
+case 245: {
sym(1).ival = QSOperator::InplaceDiv;
} break;
-case 245: {
+case 246: {
sym(1).ival = QSOperator::InplaceMod;
} break;
-case 246: {
+case 247: {
sym(1).ival = QSOperator::InplaceAdd;
} break;
-case 247: {
+case 248: {
sym(1).ival = QSOperator::InplaceSub;
} break;
-case 248: {
+case 249: {
sym(1).ival = QSOperator::InplaceLeftShift;
} break;
-case 249: {
+case 250: {
sym(1).ival = QSOperator::InplaceRightShift;
} break;
-case 250: {
+case 251: {
sym(1).ival = QSOperator::InplaceURightShift;
} break;
-case 251: {
+case 252: {
sym(1).ival = QSOperator::InplaceAnd;
} break;
-case 252: {
+case 253: {
sym(1).ival = QSOperator::InplaceXor;
} break;
-case 253: {
+case 254: {
sym(1).ival = QSOperator::InplaceOr;
} break;
-case 255: {
+case 256: {
AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 256: {
+case 257: {
sym(1).Node = 0;
} break;
-case 259: {
+case 260: {
AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 260: {
+case 261: {
sym(1).Node = 0;
} break;
-case 277: {
+case 278: {
AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 278: {
+case 279: {
sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
} break;
-case 279: {
+case 280: {
sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
} break;
-case 280: {
+case 281: {
sym(1).Node = 0;
} break;
-case 281: {
+case 282: {
sym(1).Node = sym(1).StatementList->finish ();
} break;
-case 283: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(
- sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+case 284: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ if (sym(1).ival == T_LET)
+ s = AST::VariableDeclaration::BlockScope;
+ else if (sym(1).ival == T_CONST)
+ s = AST::VariableDeclaration::ReadOnlyBlockScope;
+
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
node->declarationKindToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 284: {
+case 285: {
+ sym(1).ival = T_LET;
+} break;
+
+case 286: {
sym(1).ival = T_CONST;
} break;
-case 285: {
+case 287: {
sym(1).ival = T_VAR;
} break;
-case 286: {
+case 288: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
} break;
-case 287: {
+case 289: {
AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 288: {
+case 290: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
} break;
-case 289: {
+case 291: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
} break;
-case 290: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+case 292: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 291: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+case 293: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 292: {
+case 294: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 293: {
+case 295: {
sym(1).Node = 0;
} break;
-case 295: {
+case 297: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 296: {
+case 298: {
sym(1).Node = 0;
} break;
-case 298: {
+case 300: {
AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
node->semicolonToken = loc(1);
sym(1).Node = node;
} break;
-case 300: {
+case 302: {
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 301: {
+case 303: {
AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1520,7 +1531,7 @@ case 301: {
sym(1).Node = node;
} break;
-case 302: {
+case 304: {
AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1528,7 +1539,7 @@ case 302: {
sym(1).Node = node;
} break;
-case 305: {
+case 307: {
AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
node->doToken = loc(1);
node->whileToken = loc(3);
@@ -1538,7 +1549,7 @@ case 305: {
sym(1).Node = node;
} break;
-case 306: {
+case 308: {
AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
node->whileToken = loc(1);
node->lparenToken = loc(2);
@@ -1546,7 +1557,7 @@ case 306: {
sym(1).Node = node;
} break;
-case 307: {
+case 309: {
AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
sym(5).Expression, sym(7).Expression, sym(9).Statement);
node->forToken = loc(1);
@@ -1557,9 +1568,10 @@ case 307: {
sym(1).Node = node;
} break;
-case 308: {
+case 310: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
sym(8).Expression, sym(10).Statement);
node->forToken = loc(1);
node->lparenToken = loc(2);
@@ -1570,7 +1582,7 @@ case 308: {
sym(1).Node = node;
} break;
-case 309: {
+case 311: {
AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
sym(5).Expression, sym(7).Statement);
node->forToken = loc(1);
@@ -1580,7 +1592,7 @@ case 309: {
sym(1).Node = node;
} break;
-case 310: {
+case 312: {
AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
node->forToken = loc(1);
@@ -1591,14 +1603,14 @@ case 310: {
sym(1).Node = node;
} break;
-case 312: {
+case 314: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
node->continueToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 314: {
+case 316: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
node->continueToken = loc(1);
node->identifierToken = loc(2);
@@ -1606,14 +1618,14 @@ case 314: {
sym(1).Node = node;
} break;
-case 316: {
+case 318: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
node->breakToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 318: {
+case 320: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
node->breakToken = loc(1);
node->identifierToken = loc(2);
@@ -1621,14 +1633,14 @@ case 318: {
sym(1).Node = node;
} break;
-case 320: {
+case 322: {
AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
node->returnToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 321: {
+case 323: {
AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
node->withToken = loc(1);
node->lparenToken = loc(2);
@@ -1636,7 +1648,7 @@ case 321: {
sym(1).Node = node;
} break;
-case 322: {
+case 324: {
AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
node->switchToken = loc(1);
node->lparenToken = loc(2);
@@ -1644,83 +1656,83 @@ case 322: {
sym(1).Node = node;
} break;
-case 323: {
+case 325: {
AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 324: {
+case 326: {
AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(5);
sym(1).Node = node;
} break;
-case 325: {
+case 327: {
sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
} break;
-case 326: {
+case 328: {
sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
} break;
-case 327: {
+case 329: {
sym(1).Node = 0;
} break;
-case 328: {
+case 330: {
sym(1).Node = sym(1).CaseClauses->finish ();
} break;
-case 329: {
+case 331: {
AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
node->caseToken = loc(1);
node->colonToken = loc(3);
sym(1).Node = node;
} break;
-case 330: {
+case 332: {
AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
node->defaultToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 331: {
+case 333: {
AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
node->identifierToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 333: {
+case 335: {
AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
node->throwToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 334: {
+case 336: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 335: {
+case 337: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 336: {
+case 338: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 337: {
+case 339: {
AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
node->catchToken = loc(1);
node->lparenToken = loc(2);
@@ -1729,20 +1741,20 @@ case 337: {
sym(1).Node = node;
} break;
-case 338: {
+case 340: {
AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
node->finallyToken = loc(1);
sym(1).Node = node;
} break;
-case 340: {
+case 342: {
AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
node->debuggerToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 342: {
+case 344: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
node->identifierToken = loc(2);
@@ -1753,7 +1765,7 @@ case 342: {
sym(1).Node = node;
} break;
-case 343: {
+case 345: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
if (! stringRef(2).isNull())
@@ -1765,7 +1777,7 @@ case 343: {
sym(1).Node = node;
} break;
-case 344: {
+case 346: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
node->functionToken = loc(1);
node->lparenToken = loc(2);
@@ -1775,56 +1787,56 @@ case 344: {
sym(1).Node = node;
} break;
-case 345: {
+case 347: {
AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 346: {
+case 348: {
AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
node->commaToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 347: {
+case 349: {
sym(1).Node = 0;
} break;
-case 348: {
+case 350: {
sym(1).Node = sym(1).FormalParameterList->finish ();
} break;
-case 349: {
+case 351: {
sym(1).Node = 0;
} break;
-case 351: {
+case 353: {
sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
} break;
-case 353: {
+case 355: {
sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
} break;
-case 354: {
+case 356: {
sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
} break;
-case 355: {
+case 357: {
sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
} break;
-case 356: {
+case 358: {
sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
} break;
-case 357: {
+case 359: {
sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
} break;
-case 358: {
+case 360: {
sym(1).Node = 0;
} break;
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index f0973338ea..ddb4af0b81 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -238,6 +238,44 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T, typename E, int metaObjectRevision>
+int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+ QML_GETTYPENAMES
+
+ QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
+ const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
+ if (!attached) {
+ attached = QQmlPrivate::attachedPropertiesFunc<T>();
+ attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>();
+ }
+
+ QQmlPrivate::RegisterType type = {
+ 1,
+
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0,
+ Q_NULLPTR,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ attached,
+ attachedMetaObject,
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ QQmlPrivate::createParent<E>, &E::staticMetaObject,
+
+ Q_NULLPTR,
+ metaObjectRevision
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason);
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 2a96d96302..a10dda166c 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -66,8 +66,6 @@ void QQmlApplicationEnginePrivate::cleanUp()
void QQmlApplicationEnginePrivate::init()
{
Q_Q(QQmlApplicationEngine);
- q->connect(&statusMapper, SIGNAL(mapped(QObject*)),
- q, SLOT(_q_finishLoad(QObject*)));
q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit);
#if QT_CONFIG(translation)
@@ -113,20 +111,15 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
c->loadUrl(url);
if (!c->isLoading()) {
- _q_finishLoad(c);
+ finishLoad(c);
return;
}
- statusMapper.setMapping(c, c);
- q->connect(c, SIGNAL(statusChanged(QQmlComponent::Status)),
- &statusMapper, SLOT(map()));
+ QObject::connect(c, &QQmlComponent::statusChanged, q, [this, c] { this->finishLoad(c); });
}
-void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o)
+void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
{
Q_Q(QQmlApplicationEngine);
- QQmlComponent *c = qobject_cast<QQmlComponent *>(o);
- if (!c)
- return;
switch (c->status()) {
case QQmlComponent::Error:
qWarning() << "QQmlApplicationEngine failed to load component";
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index e64d7495cd..6c57f46c72 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -74,7 +74,6 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QQmlApplicationEngine)
Q_DECLARE_PRIVATE(QQmlApplicationEngine)
- Q_PRIVATE_SLOT(d_func(), void _q_finishLoad(QObject*))
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 8c342a43a9..4795170bed 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -42,7 +42,6 @@
#include "qqmlapplicationengine.h"
#include "qqmlengine_p.h"
-#include <QSignalMapper>
#include <QCoreApplication>
#include <QFileInfo>
#include <QLibraryInfo>
@@ -73,9 +72,8 @@ public:
void startLoad(const QUrl &url, const QByteArray &data = QByteArray(), bool dataFlag = false);
void loadTranslations(const QUrl &rootFile);
- void _q_finishLoad(QObject *component);
+ void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
- QSignalMapper statusMapper;
QObject *appObj;
#if QT_CONFIG(translation)
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 4fbd828307..19ece44beb 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -199,7 +199,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1])))
+ if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &callData->args[ii]))
callData->args[ii] = *v4Value;
else
callData->args[ii] = QV4::Encode::undefined();
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e1fa97b52f..e99335a117 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -65,6 +65,7 @@
#include <QtCore/qmetaobject.h>
#include <QDebug>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
#include <QtCore/qmutex.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
list returned by QGuiApplication::screens(). In addition to examining
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
added in Qt 5.9.
@@ -585,7 +586,7 @@ The following functions are also on the Qt object.
\li application.font
\endlist
- \sa Screen, Window, Window.targetScreen
+ \sa Screen, Window, Window.screen
*/
/*!
@@ -760,7 +761,7 @@ class QQmlThreadNotifierProxyObject : public QObject
public:
QPointer<QObject> target;
- virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) {
+ int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override {
if (!target)
return -1;
@@ -2178,6 +2179,27 @@ QString QQmlEngine::offlineStoragePath() const
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)
{
QList<QQmlType *> types;
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 3102a20fac..8cada954fe 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -136,6 +136,7 @@ public:
void setOfflineStoragePath(const QString& dir);
QString offlineStoragePath() const;
+ QString offlineStorageDatabaseFilePath(const QString &databaseName) const;
QUrl baseUrl() const;
void setBaseUrl(const QUrl &);
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 916566b6c7..1bdeacd524 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -205,6 +205,7 @@ public:
inline void deleteInEngineThread(T *);
template<typename T>
inline static void deleteInEngineThread(QQmlEngine *, T *);
+ QString offlineStorageDatabaseDirectory() const;
// These methods may be called from the loader thread
inline QQmlPropertyCache *cache(QQmlType *, int);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 8712b638c5..c07d5c740a 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -130,42 +131,74 @@ bool isPathAbsolute(const QString &path)
#endif
}
-// If the type does not already exist as a file import, add the type and return the new type
-QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
+/*
+ \internal
+
+ Fetches the QQmlType instance registered for \a urlString, creating a
+ registration for it if it is not already registered, using the associated
+ \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
+ details.
+
+ Errors (if there are any) are placed into \a errors, if it is nonzero. Note
+ that errors are treated as fatal if \a errors is not set.
+*/
+QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
bool isCompositeSingleton, QList<QQmlError> *errors,
int majorVersion=-1, int minorVersion=-1)
{
- QUrl url(urlString);
+ QUrl url(urlString); // ### unfortunate (costly) conversion
QQmlType *ret = QQmlMetaType::qmlType(url);
- if (!ret) { //QQmlType not yet existing for composite or composite singleton type
- int dot = typeName.indexOf(QLatin1Char('.'));
- QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
-
- //XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy
- QByteArray buf(unqualifiedtype.toString().toUtf8());
-
- if (isCompositeSingleton) {
- QQmlPrivate::RegisterCompositeSingletonType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
- } else {
- QQmlPrivate::RegisterCompositeType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
- }
+ if (ret)
+ return ret;
+
+ int dot = typeName.indexOf(QLatin1Char('.'));
+ QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
+
+ // We need a pointer, but we were passed a string. Take a copy so we
+ // can guarentee it will live long enough to reach qmlregister.
+ QByteArray buf(unqualifiedtype.toString().toUtf8());
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ if (isCompositeSingleton) {
+ QQmlPrivate::RegisterCompositeSingletonType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
+ } else {
+ QQmlPrivate::RegisterCompositeType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
}
- if (!ret) {//Usually when a type name is "found" but invalid
- //qDebug() << ret << urlString << QQmlMetaType::qmlType(url);
+
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (!ret) {
if (!errors) // Cannot list errors properly, just quit
qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData());
QQmlError error;
@@ -204,44 +237,38 @@ void qmlClearEnginePlugins()
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
#endif
-class QQmlImportNamespace
-{
-public:
- QQmlImportNamespace() : nextNamespace(0) {}
- ~QQmlImportNamespace() { qDeleteAll(imports); }
-
- struct Import {
- QString uri;
- QString url;
- int majversion;
- int minversion;
- bool isLibrary;
- QQmlDirComponents qmlDirComponents;
- QQmlDirScripts qmlDirScripts;
-
- bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir,
- QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
-
- static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
-
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, bool *typeRecursionDetected = 0) const;
- };
- QList<Import *> imports;
+/*!
+ \internal
+ \class QQmlImportInstance
- Import *findImport(const QString &uri) const;
+ A QQmlImportType represents a single import of a document, held within a
+ namespace.
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, QList<QQmlError> *errors = 0);
+ \note The uri here may not necessarily be unique (e.g. for file imports).
- // Prefix when used as a qualified import. Otherwise empty.
- QHashedString prefix;
+ \note Version numbers may be -1 for file imports: this means that no
+ version was specified as part of the import. Type resolution will be
+ responsible for attempting to find the "best" possible version.
+*/
- // Used by QQmlImportsPrivate::qualifiedSets
- QQmlImportNamespace *nextNamespace;
-};
+/*!
+ \internal
+ \class QQmlImportNamespace
+
+ A QQmlImportNamespace is a way of seperating imports into a local namespace.
+
+ Within a QML document, there is at least one namespace (the
+ "unqualified set") where imports without a qualifier are placed, i.e:
+
+ import QtQuick 2.6
+
+ will have a single namespace (the unqualified set) containing a single import
+ for QtQuick 2.6. However, there may be others if an import statement gives
+ a qualifier, i.e the following will result in an additional new
+ QQmlImportNamespace in the qualified set:
+
+ import MyFoo 1.0 as Foo
+*/
class QQmlImportsPrivate
{
@@ -273,9 +300,12 @@ public:
QString base;
int ref;
+ // storage of data related to imports without a namespace
mutable QQmlImportNamespace unqualifiedset;
QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ // storage of data related to imports with a namespace
mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
QQmlTypeLoader *typeLoader;
@@ -284,21 +314,21 @@ public:
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
- static bool validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
bool importExtension(const QString &absoluteFilePath, const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors);
bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors);
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
- QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace,
+ QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url,
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
@@ -363,12 +393,22 @@ QUrl QQmlImports::baseUrl() const
return d->baseUrl;
}
+/*
+ \internal
+
+ This method is responsible for populating data of all types visible in this
+ document's imports into the \a cache for resolution elsewhere (e.g. in JS,
+ or when loading additional types).
+
+ \note This is for C++ types only. Composite types are handled separately,
+ as they do not have a QQmlTypeModule.
+*/
void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
@@ -379,11 +419,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
const QQmlImportNamespace &set = *ns;
+ // positioning is important; we must create the namespace even if there is no module.
+ QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
+ typeimport.m_qualifier = set.prefix;
+
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
- QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
}
}
@@ -412,7 +455,7 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
typedef QQmlDirComponents::const_iterator ConstIterator;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
const QQmlDirComponents &components = import->qmlDirComponents;
@@ -430,6 +473,15 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
}
}
+/*
+ \internal
+
+ Returns a list of all composite singletons present in this document's
+ imports.
+
+ This information is used by QQmlTypeLoader to ensure that composite singletons
+ are marked as dependencies during type loading.
+*/
QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSingletons() const
{
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
@@ -445,6 +497,12 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
return compositeSingletons;
}
+/*
+ \internal
+
+ Returns a list of scripts imported by this document. This is used by
+ QQmlTypeLoader to properly handle dependencies on imported scripts.
+*/
QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
@@ -452,7 +510,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -466,7 +524,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = *ns;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -590,7 +648,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
@@ -600,7 +658,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
const QQmlDirScripts &scripts = qmldir->scripts();
if (!scripts.isEmpty()) {
// Verify that we haven't imported these scripts already
- for (QList<QQmlImportNamespace::Import *>::const_iterator it = nameSpace->imports.constBegin();
+ for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it != this) && ((*it)->uri == uri)) {
QQmlError error;
@@ -616,7 +674,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
return true;
}
-QQmlDirScripts QQmlImportNamespace::Import::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
{
QMap<QString, QQmlDirParser::Script> versioned;
@@ -652,7 +710,7 @@ bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &t
return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return);
}
-bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
+bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader,
const QHashedStringRef& type, int *vmajor, int *vminor,
QQmlType** type_return, QString *base, bool *typeRecursionDetected) const
{
@@ -683,15 +741,17 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if ((candidate == end) ||
(c.majorVersion > candidate->majorVersion) ||
((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) {
- componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
- if (c.internal && base) {
- if (resolveLocalUrl(*base, c.fileName) != componentUrl)
- continue; // failed attempt to access an internal type
- }
- if (base && (*base == componentUrl)) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- continue; // no recursion
+ if (base) {
+ componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
+ if (c.internal) {
+ if (resolveLocalUrl(*base, c.fileName) != componentUrl)
+ continue; // failed attempt to access an internal type
+ }
+ if (*base == componentUrl) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
}
// This is our best candidate so far
@@ -702,9 +762,11 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
if (candidate != end) {
+ if (!base) // ensure we have a componentUrl
+ componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
int major = vmajor ? *vmajor : -1;
int minor = vminor ? *vminor : -1;
- QQmlType *returnType = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
+ QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
major, minor);
if (type_return)
*type_return = returnType;
@@ -732,7 +794,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
- QQmlType *returnType = getTypeForUrl(qmlUrl, type, false, 0);
+ QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0);
if (type_return)
*type_return = returnType;
return returnType != 0;
@@ -777,7 +839,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
+ *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
return (*type_return != 0);
}
}
@@ -785,9 +847,9 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return false;
}
-QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri) const
+QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
{
- for (Import *import : imports) {
+ for (QQmlImportInstance *import : imports) {
if (import->uri == uri)
return import;
}
@@ -800,13 +862,13 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
{
bool typeRecursionDetected = false;
for (int i=0; i<imports.count(); ++i) {
- const Import *import = imports.at(i);
+ const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, vmajor, vminor, type_return,
base, &typeRecursionDetected)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
- const Import *import2 = imports.at(j);
+ const QQmlImportInstance *import2 = imports.at(j);
if (import2->resolveType(typeLoader, type, vmajor, vminor, 0, base)) {
if (errors) {
QString u1 = import->url;
@@ -949,10 +1011,12 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
#endif
+#if defined(QT_SHARED) || !QT_CONFIG(library)
static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
{
return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why);
}
+#endif
/*!
Import an extension defined by a qmldir file.
@@ -963,7 +1027,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors)
{
#if QT_CONFIG(library)
@@ -1099,7 +1163,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors)
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
@@ -1224,7 +1288,7 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
return false;
}
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors)
{
int lowest_min = INT_MAX;
@@ -1307,7 +1371,7 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix)
return nameSpace;
}
-QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
+QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url, int vmaj, int vmin,
QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence)
@@ -1317,7 +1381,7 @@ QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImport
Q_UNUSED(errors);
Q_ASSERT(url.isEmpty() || url.endsWith(Slash));
- QQmlImportNamespace::Import *import = new QQmlImportNamespace::Import;
+ QQmlImportInstance *import = new QQmlImportInstance;
import->uri = uri;
import->url = url;
import->majversion = vmaj;
@@ -1343,11 +1407,11 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
Q_ASSERT(inserted);
if (!incomplete) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!qmldirIdentifier.isEmpty()) {
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
@@ -1444,11 +1508,11 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
return false;
@@ -1471,8 +1535,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- if (QQmlImportNamespace::Import *import = nameSpace->findImport(uri)) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 0e7848730f..7c691a468c 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -68,6 +68,48 @@ class QQmlImportNamespace;
class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
+class QQmlTypeLoaderQmldirContent;
+
+struct QQmlImportInstance
+{
+ QString uri; // e.g. QtQuick
+ QString url; // the base path of the import
+ int majversion; // the major version imported
+ int minversion; // the minor version imported
+ bool isLibrary; // true means that this is not a file import
+ QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
+ QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
+
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
+
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, bool *typeRecursionDetected = 0) const;
+};
+
+class QQmlImportNamespace
+{
+public:
+ QQmlImportNamespace() : nextNamespace(0) {}
+ ~QQmlImportNamespace() { qDeleteAll(imports); }
+
+ QList<QQmlImportInstance *> imports;
+
+ QQmlImportInstance *findImport(const QString &uri) const;
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, QList<QQmlError> *errors = 0);
+
+ // Prefix when used as a qualified import. Otherwise empty.
+ QHashedString prefix;
+
+ // Used by QQmlImportsPrivate::qualifiedSets
+ QQmlImportNamespace *nextNamespace;
+};
class Q_QML_PRIVATE_EXPORT QQmlImports
{
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 8aa107dc17..43677e0d78 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -140,12 +140,13 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has
return Primitive::undefinedValue().asReturnedValue();
}
-void QmlListWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlListWrapper::put(Managed *m, String *name, const Value &value)
{
// doesn't do anything. Should we throw?
Q_UNUSED(m);
Q_UNUSED(name);
Q_UNUSED(value);
+ return false;
}
void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs)
@@ -165,4 +166,29 @@ void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name
return QV4::Object::advanceIterator(m, it, name, index, p, attrs);
}
+void PropertyListPrototype::init(ExecutionEngine *)
+{
+ defineDefaultProperty(QStringLiteral("push"), method_push, 1);
+}
+
+void PropertyListPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+ if (!w->d()->property().append)
+ THROW_GENERIC_ERROR("List doesn't define an Append function");
+
+ QV4::ScopedObject so(scope);
+ for (int i = 0; i < callData->argc; ++i)
+ {
+ so = callData->args[i].toObject(scope.engine);
+ if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
+ w->d()->property().append(&w->d()->property(), wrapper->object() );
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index d01b332159..84dadba01a 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -86,6 +86,7 @@ struct Q_QML_EXPORT QmlListWrapper : Object
{
V4_OBJECT2(QmlListWrapper, Object)
V4_NEEDS_DESTROY
+ V4_PROTOTYPE(propertyListPrototype)
static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, int propType);
static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType);
@@ -94,10 +95,17 @@ struct Q_QML_EXPORT QmlListWrapper : Object
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
};
+struct PropertyListPrototype : Object
+{
+ void init(ExecutionEngine *engine);
+
+ static void method_push(const BuiltinFunction *, Scope &, CallData *callData);
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 520c44f4da..bd6b9a1599 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -79,7 +79,7 @@ struct QQmlMetaTypeData
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
// of them by url, even if it was registered as
- // a module via qmlRegisterCompositeType.
+ // a module via QQmlPrivate::RegisterCompositeType
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 38a16b8cde..85fbd86dc4 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -170,7 +170,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context = new QQmlContextData;
context->isInternal = true;
- context->imports = compilationUnit->importCache;
+ context->imports = compilationUnit->typeNameCache;
context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
context->setParent(parentContext);
@@ -1150,7 +1150,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->importCache;
+ customParser->imports = compilationUnit->typeNameCache;
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 562aa1c88a..88ce2fa1b9 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -76,7 +76,8 @@ public:
int argumentsValid:1;
QList<QByteArray> *names;
- int arguments[0];
+
+ int arguments[1];
};
// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
@@ -919,7 +920,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
{
typedef QQmlPropertyCacheMethodArguments A;
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int)));
args->arguments[0] = argc;
args->argumentsValid = false;
args->signalParameterStringForJS = 0;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5b1bba46dd..f4f04e12c0 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1362,7 +1362,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1410,7 +1410,7 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1539,57 +1539,57 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
}
-QQmlTypeLoader::QmldirContent::QmldirContent()
+QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
{
}
-bool QQmlTypeLoader::QmldirContent::hasError() const
+bool QQmlTypeLoaderQmldirContent::hasError() const
{
return m_parser.hasError();
}
-QList<QQmlError> QQmlTypeLoader::QmldirContent::errors(const QString &uri) const
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
{
return m_parser.errors(uri);
}
-QString QQmlTypeLoader::QmldirContent::typeNamespace() const
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
{
return m_parser.typeNamespace();
}
-void QQmlTypeLoader::QmldirContent::setContent(const QString &location, const QString &content)
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
m_location = location;
m_parser.parse(content);
}
-void QQmlTypeLoader::QmldirContent::setError(const QQmlError &error)
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
{
m_parser.setError(error);
}
-QQmlDirComponents QQmlTypeLoader::QmldirContent::components() const
+QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
{
return m_parser.components();
}
-QQmlDirScripts QQmlTypeLoader::QmldirContent::scripts() const
+QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
{
return m_parser.scripts();
}
-QQmlDirPlugins QQmlTypeLoader::QmldirContent::plugins() const
+QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
{
return m_parser.plugins();
}
-QString QQmlTypeLoader::QmldirContent::pluginLocation() const
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
{
return m_location;
}
-bool QQmlTypeLoader::QmldirContent::designerSupported() const
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
{
return m_parser.designerSupported();
}
@@ -1861,13 +1861,13 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
/*!
-Return a QmldirContent for absoluteFilePath. The QmldirContent may be cached.
+Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQmldirContent may be cached.
\a filePath is a local file path.
It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
+const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
{
QUrl url(filePathIn); //May already contain http scheme
if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https"))
@@ -1883,10 +1883,10 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
else
filePath = url.path();
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(filePath);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
if (!val) {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
@@ -1916,12 +1916,12 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content)
{
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(url);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(url);
if (val) {
qmldir = *val;
} else {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
m_importQmlDirCache.insert(url, qmldir);
}
@@ -2075,6 +2075,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
}
+ if (unit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(unit);
+ return true;
+ }
+
m_compiledData = unit;
for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
@@ -2127,11 +2132,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
return true;
}
-void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
- m_compiledData->importCache = importCache;
+ m_compiledData->typeNameCache = typeNameCache;
m_compiledData->resolvedTypes = resolvedTypeCache;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2217,10 +2222,10 @@ void QQmlTypeData::done()
}
}
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
{
- QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isSet()) {
setError(error);
return;
@@ -2240,9 +2245,9 @@ void QQmlTypeData::done()
if (!m_document.isNull()) {
// Compile component
- compile(importCache, resolvedTypeCache);
+ compile(typeNameCache, resolvedTypeCache);
} else {
- createTypeAndPropertyCaches(importCache, resolvedTypeCache);
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
}
if (isError())
@@ -2303,7 +2308,7 @@ void QQmlTypeData::done()
qualifier = qualifier.mid(lastDotIndex+1);
}
- m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref();
m_compiledData->dependentScripts << scriptData;
@@ -2397,6 +2402,15 @@ bool QQmlTypeData::loadFromSource()
return true;
}
+void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QmlIR::IRLoader loader(unit->data, m_document.data());
+ loader.load();
+ m_document->javaScriptCompilationUnit = unit;
+ continueLoadFromIR();
+}
+
void QQmlTypeData::continueLoadFromIR()
{
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
@@ -2489,12 +2503,12 @@ QString QQmlTypeData::stringAt(int index) const
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData.isNull());
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache);
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache);
m_compiledData = compiler.compile();
if (!m_compiledData) {
setError(compiler.compilationErrors());
@@ -2598,20 +2612,20 @@ void QQmlTypeData::resolveTypes()
}
QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const
{
- importCache->adopt(new QQmlTypeNameCache);
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
for (const QString &ns: m_namespaces)
- (*importCache)->add(ns);
+ (*typeNameCache)->add(ns);
// Add any Composite Singletons that were used to the import cache
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
- (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+ (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
- m_importCache.populateCache(*importCache);
+ m_importCache.populateCache(*typeNameCache);
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2710,7 +2724,7 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData:
}
QQmlScriptData::QQmlScriptData()
- : importCache(0)
+ : typeNameCache(0)
, m_loaded(false)
, m_program(0)
{
@@ -2767,8 +2781,8 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
// For backward compatibility, if there are no imports, we need to use the
// imports from the parent context. See QTBUG-17518.
- if (!importCache->isEmpty()) {
- ctxt->imports = importCache;
+ if (!typeNameCache->isEmpty()) {
+ ctxt->imports = typeNameCache;
} else if (effectiveCtxt) {
ctxt->imports = effectiveCtxt->imports;
ctxt->importedScripts = effectiveCtxt->importedScripts;
@@ -2823,9 +2837,9 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
void QQmlScriptData::clear()
{
- if (importCache) {
- importCache->release();
- importCache = 0;
+ if (typeNameCache) {
+ typeNameCache->release();
+ typeNameCache = 0;
}
for (int ii = 0; ii < scripts.count(); ++ii)
@@ -2946,7 +2960,7 @@ void QQmlScriptBlob::done()
}
}
- m_scriptData->importCache = new QQmlTypeNameCache();
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
QSet<QString> ns;
@@ -2958,13 +2972,13 @@ void QQmlScriptBlob::done()
if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
ns.insert(script.nameSpace);
- m_scriptData->importCache->add(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
}
}
- m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->importCache);
+ m_importCache.populateCache(m_scriptData->typeNameCache);
}
QString QQmlScriptBlob::stringAt(int index) const
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c60435a2d6..915b1bcc4c 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -218,6 +218,34 @@ private:
class QQmlTypeLoaderThread;
+class QQmlTypeLoaderQmldirContent
+{
+private:
+ friend class QQmlTypeLoader;
+ QQmlTypeLoaderQmldirContent();
+
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
+
+public:
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
+
+ QString typeNamespace() const;
+
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+
+ QString pluginLocation() const;
+
+ bool designerSupported() const;
+
+private:
+ QQmlDirParser m_parser;
+ QString m_location;
+};
+
class Q_AUTOTEST_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
@@ -256,34 +284,6 @@ public:
QList<QQmlQmldirData *> m_qmldirs;
};
- class QmldirContent
- {
- private:
- friend class QQmlTypeLoader;
- QmldirContent();
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
- public:
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
- private:
- QQmlDirParser m_parser;
- QString m_location;
- };
-
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
@@ -298,7 +298,7 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
- const QmldirContent *qmldirContent(const QString &filePath);
+ const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath);
void setQmldirContent(const QString &filePath, const QString &content);
void clearCache();
@@ -363,7 +363,7 @@ private:
typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
typedef QStringHash<bool> StringSet;
typedef QStringHash<StringSet*> ImportDirCache;
- typedef QStringHash<QmldirContent *> ImportQmlDirCache;
+ typedef QStringHash<QQmlTypeLoaderQmldirContent *> ImportQmlDirCache;
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
@@ -446,15 +446,16 @@ protected:
private:
bool tryLoadFromDiskCache();
bool loadFromSource();
+ void restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit);
void continueLoadFromIR();
void resolveTypes();
QQmlCompileError buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true);
@@ -504,7 +505,7 @@ public:
QUrl url;
QString urlString;
- QQmlTypeNameCache *importCache;
+ QQmlTypeNameCache *typeNameCache;
QList<QQmlScriptBlob *> scripts;
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index c2098bc9a1..c8e2b92c29 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -43,7 +43,8 @@
QT_BEGIN_NAMESPACE
-QQmlTypeNameCache::QQmlTypeNameCache()
+QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache)
+ : m_imports(importCache)
{
}
@@ -70,6 +71,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
{
Import import;
import.scriptIndex = importedScriptIndex;
+ import.m_qualifier = name;
if (nameSpace.length() != 0) {
Import *i = m_namedImports.value(nameSpace);
@@ -94,6 +96,18 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -109,6 +123,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
if (!result.isValid())
result = query(i->compositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return result;
}
@@ -122,6 +150,19 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QString typeName = name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -143,6 +184,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons
if (!r.isValid())
r = query(i->compositeSingletons, name);
+ if (!r.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return r;
}
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 8a387bed5f..7cdcbe91b6 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -56,6 +56,7 @@
#include "qqmlmetatype_p.h"
#include <private/qhashedstring_p.h>
+#include <private/qqmlimport_p.h>
#include <QtCore/qvector.h>
@@ -66,7 +67,7 @@ class QQmlEngine;
class QQmlTypeNameCache : public QQmlRefCount
{
public:
- QQmlTypeNameCache();
+ QQmlTypeNameCache(const QQmlImports &imports);
virtual ~QQmlTypeNameCache();
inline bool isEmpty() const;
@@ -105,6 +106,9 @@ private:
// Or, imported compositeSingletons
QStringHash<QUrl> compositeSingletons;
+
+ // The qualifier of this import
+ QString m_qualifier;
};
template<typename Key>
@@ -112,6 +116,7 @@ private:
{
Import *i = imports.value(key);
if (i) {
+ Q_ASSERT(!i->m_qualifier.isEmpty());
if (i->scriptIndex != -1) {
return Result(i->scriptIndex);
} else {
@@ -151,6 +156,7 @@ private:
QMap<const Import *, QStringHash<Import> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
QStringHash<QUrl> m_anonymousCompositeSingletons;
+ QQmlImports m_imports;
};
QQmlTypeNameCache::Result::Result()
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index fd1e9cc2be..c4422afa9c 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -275,13 +275,13 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
}
-void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
{
Q_ASSERT(m->as<QmlTypeWrapper>());
QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
if (v4->hasException)
- return;
+ return false;
QV4::Scope scope(v4);
QQmlContextData *context = v4->callingQmlContext();
@@ -292,7 +292,8 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
QQmlEngine *e = scope.engine->qmlEngine();
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(e)), object);
if (ao)
- QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return false;
} else if (type && type->isSingleton()) {
QQmlEngine *e = scope.engine->qmlEngine();
QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
@@ -300,18 +301,20 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
- QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
} else if (!siinfo->scriptApi(e).isUndefined()) {
QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
v4->throwError(error);
- return;
+ return false;
} else {
- apiprivate->put(name, value);
+ return apiprivate->put(name, value);
}
}
}
+
+ return false;
}
PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 3b0ae04cc1..cfb6cb0ec9 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -100,7 +100,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static bool isEqualTo(Managed *that, Managed *o);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 44b612e7d2..d262b230e2 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -290,9 +290,11 @@ int QQmlValueTypeWrapper::typeId() const
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
{
bool destructGadgetOnExit = false;
+ Q_ALLOCA_DECLARE(void, gadget);
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
if (!d()->gadgetPtr) {
- d()->gadgetPtr = alloca(d()->valueType->metaType.sizeOf());
+ Q_ALLOCA_ASSIGN(void, gadget, d()->valueType->metaType.sizeOf());
+ d()->gadgetPtr = gadget;
d()->valueType->metaType.construct(d()->gadgetPtr, 0);
destructGadgetOnExit = true;
}
@@ -407,13 +409,13 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
#undef VALUE_TYPE_ACCESSOR
}
-void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
{
Q_ASSERT(m->as<QQmlValueTypeWrapper>());
ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
Scope scope(v4);
if (scope.hasException())
- return;
+ return false;
Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
Scoped<QQmlValueTypeReference> reference(scope, m->d());
@@ -424,7 +426,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
if (!writebackProperty.isWritable() || !reference->readReferenceValue())
- return;
+ return false;
writeBackPropertyType = writebackProperty.userType();
}
@@ -432,7 +434,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0);
if (!pd)
- return;
+ return false;
if (reference) {
QV4::ScopedFunctionObject f(scope, value);
@@ -442,7 +444,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
QQmlContextData *context = v4->callingQmlContext();
@@ -459,7 +461,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
newBinding->setSourceLocation(bindingFunction->currentLocation());
newBinding->setTarget(reference->d()->object, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
- return;
+ return true;
} else {
QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex()));
}
@@ -493,6 +495,8 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
}
}
+
+ return true;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 87f9116056..c8aac719ab 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -106,7 +106,7 @@ public:
bool write(QObject *target, int propertyIndex) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static bool isEqualTo(Managed *m, Managed *other);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 545daa96f8..490a4e19ab 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -325,9 +325,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (compiledObject->nProperties || compiledObject->nFunctions) {
Q_ASSERT(cache && cache->engine);
QV4::ExecutionEngine *v4 = cache->engine;
- QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions);
- propertyAndMethodStorage.set(v4, data);
- std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ uint size = compiledObject->nProperties + compiledObject->nFunctions;
+ if (size) {
+ QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size);
+ propertyAndMethodStorage.set(v4, data);
+ std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ }
// Need JS wrapper to ensure properties/methods are marked.
ensureQObjectWrapper();
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 63585fd62e..026be5a703 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -55,6 +55,46 @@
#include <QtQml/private/qtqml-config_p.h>
#include <QtQml/qtqmlglobal.h>
+// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
+// the occurrences of alloca() in case it's not supported.
+// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate
+// memory allocation from the declaration and RAII.
+#define Q_ALLOCA_VAR(type, name, size) \
+ Q_ALLOCA_DECLARE(type, name); \
+ Q_ALLOCA_ASSIGN(type, name, size)
+
+#if QT_CONFIG(alloca)
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ type *name = 0
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ name = static_cast<type*>(alloca(size))
+
+#else
+QT_BEGIN_NAMESPACE
+class Qt_AllocaWrapper
+{
+public:
+ Qt_AllocaWrapper() { m_data = 0; }
+ ~Qt_AllocaWrapper() { free(m_data); }
+ void *data() { return m_data; }
+ void allocate(int size) { m_data = malloc(size); }
+private:
+ void *m_data;
+};
+QT_END_NAMESPACE
+
+#define Q_ALLOCA_DECLARE(type, name) \
+ Qt_AllocaWrapper _qt_alloca_##name; \
+ type *name = 0
+
+#define Q_ALLOCA_ASSIGN(type, name, size) \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data())
+
+#endif
+
#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
# define Q_QML_PRIVATE_EXPORT
#else
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index cc4ccbaeb1..efc2828dc5 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -1268,7 +1268,7 @@ void ModelNodeMetaObject::updateValues()
const int roleCount = m_model->m_listModel->roleCount();
if (!m_initialized) {
if (roleCount) {
- int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int)));
+ Q_ALLOCA_VAR(int, changedRoles, roleCount * sizeof(int));
for (int i = 0; i < roleCount; ++i)
changedRoles[i] = i;
emitDirectNotifies(changedRoles, roleCount);
@@ -1333,7 +1333,7 @@ void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCo
namespace QV4 {
-void ModelObject::put(Managed *m, String *name, const Value &value)
+bool ModelObject::put(Managed *m, String *name, const Value &value)
{
ModelObject *that = static_cast<ModelObject*>(m);
@@ -1347,6 +1347,7 @@ void ModelObject::put(Managed *m, String *name, const Value &value)
ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
if (mo->initialized())
mo->emitPropertyNotification(name->toQString().toUtf8());
+ return true;
}
ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty)
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index cdce78e542..44583df2a6 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -179,7 +179,7 @@ struct ModelObject : public QObjectWrapper {
struct ModelObject : public QObjectWrapper
{
- static void put(Managed *m, String *name, const Value& value);
+ static bool put(Managed *m, String *name, const Value& value);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
index 47d9f2f483..17eff5ac40 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qml/types/qquickpackage.cpp
@@ -89,7 +89,7 @@ public:
{
DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QQmlGuard<QObject>&)*this = obj; }
QList<DataGuard> *list;
- void objectDestroyed(QObject *) {
+ void objectDestroyed(QObject *) override {
// we assume priv will always be destroyed after objectDestroyed calls
list->removeOne(*this);
}
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index b9d312d41f..c77495a1a7 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -103,8 +103,8 @@ public:
virtual QVariant value(int role) const = 0;
virtual void setValue(int role, const QVariant &value) = 0;
- void setValue(const QString &role, const QVariant &value);
- bool resolveIndex(const QQmlAdaptorModel &model, int idx);
+ void setValue(const QString &role, const QVariant &value) override;
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
static QV4::ReturnedValue get_property(QV4::CallContext *ctx, uint propertyId);
static QV4::ReturnedValue set_property(QV4::CallContext *ctx, uint propertyId);
@@ -141,7 +141,7 @@ public:
const QList<QQmlDelegateModelItem *> &items,
int index,
int count,
- const QVector<int> &roles) const
+ const QVector<int> &roles) const override
{
bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
@@ -185,7 +185,7 @@ public:
void replaceWatchedRoles(
QQmlAdaptorModel &,
const QList<QByteArray> &oldRoles,
- const QList<QByteArray> &newRoles) const
+ const QList<QByteArray> &newRoles) const override
{
VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
@@ -239,12 +239,12 @@ public:
// QAbstractDynamicMetaObject
- void objectDestroyed(QObject *)
+ void objectDestroyed(QObject *) override
{
release();
}
- int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments)
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
{
return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments);
}
@@ -415,18 +415,18 @@ public:
}
}
- QVariant value(int role) const
+ QVariant value(int role) const override
{
return type->model->aim()->index(index, 0, type->model->rootIndex).data(role);
}
- void setValue(int role, const QVariant &value)
+ void setValue(int role, const QVariant &value) override
{
type->model->aim()->setData(
type->model->aim()->index(index, 0, type->model->rootIndex), value, role);
}
- QV4::ReturnedValue get()
+ QV4::ReturnedValue get() override
{
if (type->prototype.isUndefined()) {
QQmlAdaptorModelEngineData * const data = engineData(v4);
@@ -449,12 +449,12 @@ public:
{
}
- int count(const QQmlAdaptorModel &model) const
+ int count(const QQmlAdaptorModel &model) const override
{
return model.aim()->rowCount(model.rootIndex);
}
- void cleanup(QQmlAdaptorModel &model, QQmlDelegateModel *vdm) const
+ void cleanup(QQmlAdaptorModel &model, QQmlDelegateModel *vdm) const override
{
QAbstractItemModel * const aim = model.aim();
if (aim && vdm) {
@@ -477,7 +477,7 @@ public:
const_cast<VDMAbstractItemModelDataType *>(this)->release();
}
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
if (it != roleNames.end()) {
@@ -489,26 +489,26 @@ public:
}
}
- QVariant parentModelIndex(const QQmlAdaptorModel &model) const
+ QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
{
return model
? QVariant::fromValue(model.aim()->parent(model.rootIndex))
: QVariant();
}
- QVariant modelIndex(const QQmlAdaptorModel &model, int index) const
+ QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
{
return model
? QVariant::fromValue(model.aim()->index(index, 0, model.rootIndex))
: QVariant();
}
- bool canFetchMore(const QQmlAdaptorModel &model) const
+ bool canFetchMore(const QQmlAdaptorModel &model) const override
{
return model && model.aim()->canFetchMore(model.rootIndex);
}
- void fetchMore(QQmlAdaptorModel &model) const
+ void fetchMore(QQmlAdaptorModel &model) const override
{
if (model)
model.aim()->fetchMore(model.rootIndex);
@@ -518,7 +518,7 @@ public:
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
QQmlEngine *engine,
- int index) const
+ int index) const override
{
VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
if (!metaObject)
@@ -606,7 +606,7 @@ public:
return QV4::Encode::undefined();
}
- QV4::ReturnedValue get()
+ QV4::ReturnedValue get() override
{
QQmlAdaptorModelEngineData *data = engineData(v4);
QV4::Scope scope(v4);
@@ -617,13 +617,13 @@ public:
return o.asReturnedValue();
}
- void setValue(const QString &role, const QVariant &value)
+ void setValue(const QString &role, const QVariant &value) override
{
if (role == QLatin1String("modelData"))
cachedData = value;
}
- bool resolveIndex(const QQmlAdaptorModel &model, int idx)
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override
{
if (index == -1) {
index = idx;
@@ -650,12 +650,12 @@ class VDMListDelegateDataType : public QQmlAdaptorModel::Accessors
public:
inline VDMListDelegateDataType() {}
- int count(const QQmlAdaptorModel &model) const
+ int count(const QQmlAdaptorModel &model) const override
{
return model.list.count();
}
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
return role == QLatin1String("modelData")
? model.list.at(index)
@@ -666,7 +666,7 @@ public:
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
QQmlEngine *,
- int index) const
+ int index) const override
{
return new QQmlDMListAccessorData(
metaType,
@@ -693,7 +693,7 @@ public:
QObject *object);
QObject *modelData() const { return object; }
- QObject *proxiedObject() { return object; }
+ QObject *proxiedObject() override { return object; }
QPointer<QObject> object;
};
@@ -735,12 +735,12 @@ public:
free(metaObject);
}
- int count(const QQmlAdaptorModel &model) const
+ int count(const QQmlAdaptorModel &model) const override
{
return model.list.count();
}
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
if (QObject *object = model.list.at(index).value<QObject *>())
return object->property(role.toUtf8());
@@ -751,7 +751,7 @@ public:
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
QQmlEngine *,
- int index) const
+ int index) const override
{
VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
if (!metaObject)
@@ -768,7 +768,7 @@ public:
metaObject = builder.toMetaObject();
}
- void cleanup(QQmlAdaptorModel &, QQmlDelegateModel *) const
+ void cleanup(QQmlAdaptorModel &, QQmlDelegateModel *) const override
{
const_cast<VDMObjectDelegateDataType *>(this)->release();
}
@@ -792,7 +792,7 @@ public:
m_type->release();
}
- int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments)
+ int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
{
Q_ASSERT(o == m_data);
Q_UNUSED(o);
@@ -813,7 +813,7 @@ public:
}
}
- int createProperty(const char *name, const char *)
+ int createProperty(const char *name, const char *) override
{
if (!m_data->object)
return -1;
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index acd5c9729b..ec5d73044f 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -18,5 +18,6 @@ include(../qml/parser/parser.pri)
include(../qml/jsruntime/jsruntime.pri)
include(../qml/compiler/compiler.pri)
include(../qml/memory/memory.pri)
+include(../qml/jit/jit.pri)
load(qt_module)
diff --git a/src/qmldevtools/qtqmldevtoolsglobal_p.h b/src/qmldevtools/qtqmldevtoolsglobal_p.h
index 5c803a4b32..5cb8a9275a 100644
--- a/src/qmldevtools/qtqmldevtoolsglobal_p.h
+++ b/src/qmldevtools/qtqmldevtoolsglobal_p.h
@@ -53,10 +53,21 @@
#include <QtCore/qglobal.h>
+// All host systems are assumed to have alloca().
+#define Q_ALLOCA_VAR(type, name, size) \
+ type *name = static_cast<type*>(alloca(size))
+
QT_BEGIN_NAMESPACE
#define Q_QML_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
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index 4b1adf5a90..dc7b917bc4 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -129,7 +129,7 @@ namespace QtQuickTest
static void mouseEvent(MouseAction action, QWindow *window,
QObject *item, Qt::MouseButton button,
- Qt::KeyboardModifiers stateKey, QPointF _pos, int delay=-1)
+ Qt::KeyboardModifiers stateKey, const QPointF &_pos, int delay=-1)
{
QTEST_ASSERT(window);
QTEST_ASSERT(item);
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index b772ed97d2..1167f408f5 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -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()
{
Q_D(QQuickCanvasItem);
@@ -651,6 +662,12 @@ void QQuickCanvasItem::invalidateSceneGraph()
d->textureProvider = 0;
}
+void QQuickCanvasItem::schedulePolish()
+{
+ auto polishRequestEvent = new QEvent(QEvent::PolishRequest);
+ QCoreApplication::postEvent(this, polishRequestEvent);
+}
+
void QQuickCanvasItem::componentComplete()
{
QQuickItem::componentComplete();
@@ -892,8 +909,9 @@ void QQuickCanvasItem::requestAnimationFrame(QQmlV4Function *args)
d->animationCallbacks.insert(++id, QV4::PersistentValue(scope.engine, f->asReturnedValue()));
+ // QTBUG-55778: Calling polish directly here can lead to a polish loop
if (isVisible())
- polish();
+ schedulePolish();
args->setReturnValue(QV4::Encode(id));
}
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 8af84d0e7c..217ae9bb69 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -182,6 +182,7 @@ private Q_SLOTS:
void sceneGraphInitialized();
void checkAnimationCallbacks();
void invalidateSceneGraph();
+ void schedulePolish();
protected:
void componentComplete() Q_DECL_OVERRIDE;
@@ -190,6 +191,7 @@ protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
void releaseResources() Q_DECL_OVERRIDE;
+ bool event(QEvent *event) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(QQuickCanvasItem)
Q_INVOKABLE void delayedCreate();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index b0c1d50907..b9b701313e 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -901,7 +901,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
V4_NEEDS_DESTROY
static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty);
- static void putIndexed(QV4::Managed *m, uint index, const QV4::Value &value);
+ static bool putIndexed(QV4::Managed *m, uint index, const QV4::Value &value);
static void proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -1879,7 +1879,7 @@ void QQuickJSContext2D::method_get_lineWidth(const QV4::BuiltinFunction *, QV4::
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
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)
@@ -1906,7 +1906,7 @@ void QQuickJSContext2D::method_get_miterLimit(const QV4::BuiltinFunction *, QV4:
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
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)
@@ -1933,7 +1933,7 @@ void QQuickJSContext2D::method_get_shadowBlur(const QV4::BuiltinFunction *, QV4:
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
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)
@@ -1990,7 +1990,7 @@ void QQuickJSContext2D::method_get_shadowOffsetX(const QV4::BuiltinFunction *, Q
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
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)
@@ -2016,7 +2016,7 @@ void QQuickJSContext2D::method_get_shadowOffsetY(const QV4::BuiltinFunction *, Q
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
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)
@@ -3043,7 +3043,7 @@ void QQuickJSContext2DPixelData::proto_get_length(const QV4::BuiltinFunction *,
if (!r || r->d()->image->isNull())
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)
@@ -3077,13 +3077,13 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m,
return QV4::Encode::undefined();
}
-void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value)
+bool QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value)
{
Q_ASSERT(m->as<QQuickJSContext2DPixelData>());
QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine();
QV4::Scope scope(v4);
if (scope.hasException())
- return;
+ return false;
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m));
@@ -3109,7 +3109,10 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
*pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
break;
}
+ return true;
}
+
+ return false;
}
/*!
\qmlmethod CanvasImageData QtQuick::Context2D::createImageData(real sw, real sh)
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index a1833081c8..22ea4774be 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
.arg(current));
}
if (!requestedUrl.isEmpty()) {
- if (QQuickPixmap::isCached(requestedUrl, QSize()))
+ if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 7b281623fe..cf6f83e5b1 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -108,7 +108,9 @@ public:
bool isAccepted() { return event.isAccepted(); }
void setAccepted(bool accepted) { event.setAccepted(accepted); }
+#if QT_CONFIG(shortcut)
Q_REVISION(2) Q_INVOKABLE bool matches(QKeySequence::StandardKey key) const { return event.matches(key); }
+#endif
private:
QKeyEvent event;
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index f71a2fbdbd..f3d7dc4b56 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -514,37 +514,41 @@ void QQuickImage::updatePaintedGeometry()
setImplicitSize(0, 0);
return;
}
- qreal w = widthValid() ? width() : d->pix.width();
- qreal widthScale = w / qreal(d->pix.width());
- qreal h = heightValid() ? height() : d->pix.height();
- qreal heightScale = h / qreal(d->pix.height());
+ const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
+ const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ const qreal w = widthValid() ? width() : pixWidth;
+ const qreal widthScale = w / pixWidth;
+ const qreal h = heightValid() ? height() : pixHeight;
+ const qreal heightScale = h / pixHeight;
if (widthScale <= heightScale) {
d->paintedWidth = w;
- d->paintedHeight = widthScale * qreal(d->pix.height());
+ d->paintedHeight = widthScale * pixHeight;
} else if (heightScale < widthScale) {
- d->paintedWidth = heightScale * qreal(d->pix.width());
+ d->paintedWidth = heightScale * pixWidth;
d->paintedHeight = h;
}
- qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : d->pix.height();
- qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : d->pix.width();
+ const qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : pixHeight;
+ const qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : pixWidth;
setImplicitSize(iWidth, iHeight);
} else if (d->fillMode == PreserveAspectCrop) {
if (!d->pix.width() || !d->pix.height())
return;
- qreal widthScale = width() / qreal(d->pix.width());
- qreal heightScale = height() / qreal(d->pix.height());
+ const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
+ const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ qreal widthScale = width() / pixWidth;
+ qreal heightScale = height() / pixHeight;
if (widthScale < heightScale) {
widthScale = heightScale;
} else if (heightScale < widthScale) {
heightScale = widthScale;
}
- d->paintedHeight = heightScale * qreal(d->pix.height());
- d->paintedWidth = widthScale * qreal(d->pix.width());
+ d->paintedHeight = heightScale * pixHeight;
+ d->paintedWidth = widthScale * pixWidth;
} else if (d->fillMode == Pad) {
- d->paintedWidth = d->pix.width();
- d->paintedHeight = d->pix.height();
+ d->paintedWidth = d->pix.width() / d->devicePixelRatio;
+ d->paintedHeight = d->pix.height() / d->devicePixelRatio;
} else {
d->paintedWidth = width();
d->paintedHeight = height();
diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h
index 522dbca803..afc33def0f 100644
--- a/src/quick/items/qquickimage_p_p.h
+++ b/src/quick/items/qquickimage_p_p.h
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
class QQuickImageTextureProvider;
-class QQuickImagePrivate : public QQuickImageBasePrivate
+class Q_QUICK_PRIVATE_EXPORT QQuickImagePrivate : public QQuickImageBasePrivate
{
Q_DECLARE_PUBLIC(QQuickImage)
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 22d631e917..33d69f5032 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -49,6 +49,30 @@
QT_BEGIN_NAMESPACE
+// This function gives derived classes the chance set the devicePixelRatio
+// if they're not happy with our implementation of it.
+bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
+{
+ // QQuickImageProvider and SVG can generate a high resolution image when
+ // sourceSize is set (this function is only called if it's set).
+ // If sourceSize is not set then the provider default size will be used, as usual.
+ bool setDevicePixelRatio = false;
+ if (url.scheme() == QLatin1String("image")) {
+ setDevicePixelRatio = true;
+ } else {
+ QString stringUrl = url.path(QUrl::PrettyDecoded);
+ if (stringUrl.endsWith(QLatin1String("svg")) ||
+ stringUrl.endsWith(QLatin1String("svgz"))) {
+ setDevicePixelRatio = true;
+ }
+ }
+
+ if (setDevicePixelRatio)
+ devicePixelRatio = targetDevicePixelRatio;
+
+ return setDevicePixelRatio;
+}
+
QQuickImageBase::QQuickImageBase(QQuickItem *parent)
: QQuickImplicitSizeItem(*(new QQuickImageBasePrivate), parent)
{
@@ -221,26 +245,11 @@ void QQuickImageBase::load()
QUrl loadUrl = d->url;
- // QQuickImageProvider and SVG can generate a high resolution image when
- // sourceSize is set. If sourceSize is not set then the provider default size
- // will be used, as usual.
- bool setDevicePixelRatio = false;
- if (d->sourcesize.isValid()) {
- if (loadUrl.scheme() == QLatin1String("image")) {
- setDevicePixelRatio = true;
- } else {
- QString stringUrl = loadUrl.path(QUrl::PrettyDecoded);
- if (stringUrl.endsWith(QLatin1String("svg")) ||
- stringUrl.endsWith(QLatin1String("svgz"))) {
- setDevicePixelRatio = true;
- }
- }
-
- if (setDevicePixelRatio)
- d->devicePixelRatio = targetDevicePixelRatio;
- }
+ bool updatedDevicePixelRatio = false;
+ if (d->sourcesize.isValid())
+ updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
- if (!setDevicePixelRatio) {
+ if (!updatedDevicePixelRatio) {
// (possible) local file: loadUrl and d->devicePixelRatio will be modified if
// an "@2x" file is found.
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index d9b609c7fe..1b771166a2 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -59,7 +59,7 @@
QT_BEGIN_NAMESPACE
class QNetworkReply;
-class QQuickImageBasePrivate : public QQuickImplicitSizeItemPrivate
+class Q_QUICK_PRIVATE_EXPORT QQuickImageBasePrivate : public QQuickImplicitSizeItemPrivate
{
Q_DECLARE_PUBLIC(QQuickImageBase)
@@ -75,6 +75,8 @@ public:
{
}
+ virtual bool updateDevicePixelRatio(qreal targetDevicePixelRatio);
+
QQuickPixmap pix;
QQuickImageBase::Status status;
QUrl url;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index f7b9a58329..22ee3f39e4 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -7865,6 +7865,7 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item)
, m_effect(0)
, m_effectSource(0)
, m_textureMirroring(QQuickShaderEffectSource::MirrorVertically)
+ , m_samples(0)
{
}
@@ -7939,6 +7940,7 @@ void QQuickItemLayer::activate()
m_effectSource->setWrapMode(m_wrapMode);
m_effectSource->setFormat(m_format);
m_effectSource->setTextureMirroring(m_textureMirroring);
+ m_effectSource->setSamples(m_samples);
if (m_effectComponent)
activateEffect();
@@ -8232,6 +8234,44 @@ void QQuickItemLayer::setTextureMirroring(QQuickShaderEffectSource::TextureMirro
}
/*!
+ \qmlproperty enumeration QtQuick::Item::layer.samples
+ \since 5.10
+
+ This property allows requesting multisampled rendering in the layer.
+
+ By default multisampling is enabled whenever multisampling is
+ enabled for the entire window, assuming the scenegraph renderer in
+ use and the underlying graphics API supports this.
+
+ By setting the value to 2, 4, etc. multisampled rendering can be requested
+ for a part of the scene without enabling multisampling for the entire
+ scene. This way multisampling is applied only to a given subtree, which can
+ lead to significant performance gains since multisampling is not applied to
+ other parts of the scene.
+
+ \note Enabling multisampling can be potentially expensive regardless of the
+ layer's size, as it incurs a hardware and driver dependent performance and
+ memory cost.
+
+ \note This property is only functional when support for multisample
+ renderbuffers and framebuffer blits is available. Otherwise the value is
+ silently ignored.
+ */
+
+void QQuickItemLayer::setSamples(int count)
+{
+ if (m_samples == count)
+ return;
+
+ m_samples = count;
+
+ if (m_effectSource)
+ m_effectSource->setSamples(m_samples);
+
+ emit samplesChanged(count);
+}
+
+/*!
\qmlproperty string QtQuick::Item::layer.samplerName
Holds the name of the effect's source texture property.
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index c0c9bd46bd..797ba42781 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -152,6 +152,8 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener
Q_PROPERTY(QByteArray samplerName READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged)
Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged)
+ Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged)
+
public:
QQuickItemLayer(QQuickItem *item);
~QQuickItemLayer();
@@ -189,6 +191,9 @@ public:
QQuickShaderEffectSource::TextureMirroring textureMirroring() const { return m_textureMirroring; }
void setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring);
+ int samples() const { return m_samples; }
+ void setSamples(int count);
+
QQuickShaderEffectSource *effectSource() const { return m_effectSource; }
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE;
@@ -213,6 +218,7 @@ Q_SIGNALS:
void formatChanged(QQuickShaderEffectSource::Format format);
void sourceRectChanged(const QRectF &sourceRect);
void textureMirroringChanged(QQuickShaderEffectSource::TextureMirroring mirroring);
+ void samplesChanged(int count);
private:
friend class QQuickTransformAnimatorJob;
@@ -237,6 +243,7 @@ private:
QQuickItem *m_effect;
QQuickShaderEffectSource *m_effectSource;
QQuickShaderEffectSource::TextureMirroring m_textureMirroring;
+ int m_samples;
};
#endif
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index 07c2cb607c..12bcd43076 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -75,7 +75,7 @@ public:
void ensureImageInCache() const {
if (url.isEmpty() && !image.isNull()) {
- url.setScheme(QStringLiteral("ItemGrabber"));
+ url.setScheme(QQuickPixmap::itemGrabberScheme);
url.setPath(QVariant::fromValue(item.data()).toString());
static uint counter = 0;
url.setFragment(QString::number(++counter));
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 65143f3e9b..43f4b88833 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -397,6 +397,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner",
QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
#endif
+
+#if QT_CONFIG(quick_shadereffect)
+ qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
+#endif
}
static void initResources()
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index 64e79a9343..bc2e2975ee 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -70,7 +70,6 @@ QT_REQUIRE_CONFIG(quick_shadereffect);
QT_BEGIN_NAMESPACE
class QSGContext;
-class QSignalMapper;
class QFileSelector;
class QQuickOpenGLCustomMaterialShader;
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index 05d3ae0191..70fc5fa65f 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -44,15 +44,23 @@
#include <QtQml/qqmlinfo.h>
#include <QtCore/qcoreapplication.h>
-#include <QtQuick/private/qquickstate_p.h>
-#include <QtQuick/private/qquickstategroup_p.h>
-#include <private/qquickstatechangescript_p.h>
#include <QtQuick/private/qquicktransition_p.h>
QT_BEGIN_NAMESPACE
-static const QQuickItemPrivate::ChangeTypes watchedChanges
- = QQuickItemPrivate::Geometry
+// The default item change types that positioners are interested in.
+static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes =
+ QQuickItemPrivate::Geometry
+ | QQuickItemPrivate::SiblingOrder
+ | QQuickItemPrivate::Visibility
+ | QQuickItemPrivate::Destroyed;
+
+// The item change types for positioners that are only interested in the implicit
+// size of the items they manage. These are used if useImplicitSize is true.
+// useImplicitSize should be set in the constructor, before any items are added.
+static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes =
+ QQuickItemPrivate::ImplicitWidth
+ | QQuickItemPrivate::ImplicitHeight
| QQuickItemPrivate::SiblingOrder
| QQuickItemPrivate::Visibility
| QQuickItemPrivate::Destroyed;
@@ -60,13 +68,15 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges
void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->addItemChangeListener(this, watchedChanges);
+ otherPrivate->addItemChangeListener(this, useImplicitSize
+ ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
}
void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->removeItemChangeListener(this, watchedChanges);
+ otherPrivate->removeItemChangeListener(this, useImplicitSize
+ ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
}
@@ -326,7 +336,7 @@ void QQuickBasePositioner::prePositioning()
if (wIdx < 0) {
d->watchChanges(child);
posItem.isNew = true;
- if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
+ if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
posItem.isVisible = false;
posItem.index = -1;
unpositionedItems.append(posItem);
@@ -348,7 +358,7 @@ void QQuickBasePositioner::prePositioning()
PositionedItem *item = &oldItems[wIdx];
// Items are only omitted from positioning if they are explicitly hidden
// i.e. their positioning is not affected if an ancestor is hidden.
- if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
+ if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
item->isVisible = false;
item->index = -1;
unpositionedItems.append(*item);
@@ -947,6 +957,7 @@ QQuickColumn::QQuickColumn(QQuickItem *parent)
void QQuickColumn::doPositioning(QSizeF *contentSize)
{
//Precondition: All items in the positioned list have a valid item pointer and should be positioned
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
qreal voffset = topPadding();
const qreal padding = leftPadding() + rightPadding();
contentSize->setWidth(qMax(contentSize->width(), padding));
@@ -955,9 +966,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize)
PositionedItem &child = positionedItems[ii];
positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
- contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
+ contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding));
- voffset += child.item->height();
+ voffset += d->itemHeight(child.item);
voffset += spacing();
}
@@ -1137,7 +1148,7 @@ public:
: QQuickBasePositionerPrivate()
{}
- void effectiveLayoutDirectionChange()
+ void effectiveLayoutDirectionChange() override
{
Q_Q(QQuickRow);
// For RTL layout the positioning changes when the width changes.
@@ -1225,9 +1236,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
hoffsets << hoffset;
}
- contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
+ contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding));
- hoffset += child.item->width();
+ hoffset += d->itemWidth(child.item);
hoffset += spacing();
}
@@ -1248,7 +1259,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int ii = 0; ii < positionedItems.count(); ++ii) {
PositionedItem &child = positionedItems[ii];
- hoffset = end - hoffsets[acc++] - child.item->width();
+ hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
}
@@ -1436,7 +1447,7 @@ public:
: QQuickBasePositionerPrivate()
{}
- void effectiveLayoutDirectionChange()
+ void effectiveLayoutDirectionChange() override
{
Q_Q(QQuickGrid);
// For RTL layout the positioning changes when the width changes.
@@ -1749,10 +1760,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- if (child.item->width() > maxColWidth[j])
- maxColWidth[j] = child.item->width();
- if (child.item->height() > maxRowHeight[i])
- maxRowHeight[i] = child.item->height();
+ const qreal childWidth = d->itemWidth(child.item);
+ const qreal childHeight = d->itemHeight(child.item);
+ if (childWidth > maxColWidth[j])
+ maxColWidth[j] = childWidth;
+ if (childHeight > maxRowHeight[i])
+ maxRowHeight[i] = childHeight;
}
}
} else {
@@ -1767,10 +1780,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- if (child.item->width() > maxColWidth[j])
- maxColWidth[j] = child.item->width();
- if (child.item->height() > maxRowHeight[i])
- maxRowHeight[i] = child.item->height();
+ const qreal childWidth = d->itemWidth(child.item);
+ const qreal childHeight = d->itemHeight(child.item);
+ if (childWidth > maxColWidth[j])
+ maxColWidth[j] = childWidth;
+ if (childHeight > maxRowHeight[i])
+ maxRowHeight[i] = childHeight;
}
}
}
@@ -1812,20 +1827,22 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
qreal childXOffset = xoffset;
+ const qreal childWidth = d->itemWidth(child.item);
+ const qreal childHeight = d->itemHeight(child.item);
if (effectiveHAlign() == AlignRight)
- childXOffset += maxColWidth[curCol] - child.item->width();
+ childXOffset += maxColWidth[curCol] - childWidth;
else if (hItemAlign() == AlignHCenter)
- childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
+ childXOffset += (maxColWidth[curCol] - childWidth)/2.0;
if (!d->isLeftToRight())
childXOffset -= maxColWidth[curCol];
qreal alignYOffset = yoffset;
if (m_vItemAlign == AlignVCenter)
- alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
+ alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0;
else if (m_vItemAlign == AlignBottom)
- alignYOffset += maxRowHeight[curRow] - child.item->height();
+ alignYOffset += maxRowHeight[curRow] - childHeight;
positionItem(childXOffset, alignYOffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
@@ -2023,7 +2040,7 @@ public:
: QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight)
{}
- void effectiveLayoutDirectionChange()
+ void effectiveLayoutDirectionChange() override
{
Q_Q(QQuickFlow);
// Don't postpone, as it might be the only trigger for visible changes.
@@ -2143,15 +2160,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
+ const qreal childWidth = d->itemWidth(child.item);
+ const qreal childHeight = d->itemHeight(child.item);
if (d->flow == LeftToRight) {
- if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
+ if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) {
hoffset = hoffset1;
voffset += linemax + spacing();
linemax = 0;
}
} else {
- if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
+ if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) {
voffset = voffset1;
hoffset += linemax + spacing();
linemax = 0;
@@ -2168,17 +2187,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
child.bottomPadding = bottomPadding();
}
- contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
- contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding()));
if (d->flow == LeftToRight) {
- hoffset += child.item->width();
+ hoffset += childWidth;
hoffset += spacing();
- linemax = qMax(linemax, child.item->height());
+ linemax = qMax(linemax, childHeight);
} else {
- voffset += child.item->height();
+ voffset += childHeight;
voffset += spacing();
- linemax = qMax(linemax, child.item->width());
+ linemax = qMax(linemax, childWidth);
}
}
@@ -2193,7 +2212,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
- hoffset = end - hoffsets[acc++] - child.item->width();
+ hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
positionItemX(hoffset, &child);
child.leftPadding = leftPadding();
child.rightPadding = rightPadding();
@@ -2217,4 +2236,18 @@ void QQuickFlow::reportConflictingAnchors()
qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
}
+QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent)
+ : QQuickRow(parent)
+{
+ QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
+ d->useImplicitSize = true;
+}
+
+QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent)
+ : QQuickGrid(parent)
+{
+ QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
+ d->useImplicitSize = true;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index ae6e795794..8dc0d90a2f 100644
--- a/src/quick/items/qquickpositioners_p.h
+++ b/src/quick/items/qquickpositioners_p.h
@@ -58,7 +58,6 @@ QT_REQUIRE_CONFIG(quick_positioners);
#include "qquickimplicitsizeitem_p.h"
#include "qquickitemviewtransition_p.h"
-#include <QtQuick/private/qquickstate_p.h>
#include <private/qpodvector_p.h>
#include <QtCore/qobject.h>
@@ -133,6 +132,11 @@ public:
static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj);
+ static QQuickBasePositionerPrivate* get(QQuickBasePositioner *positioner)
+ {
+ return positioner->d_func();
+ }
+
void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const;
qreal padding() const;
@@ -183,7 +187,7 @@ protected:
virtual void doPositioning(QSizeF *contentSize)=0;
virtual void reportConflictingAnchors()=0;
- class PositionedItem
+ class Q_QUICK_PRIVATE_EXPORT PositionedItem
{
public :
PositionedItem(QQuickItem *i);
@@ -228,7 +232,7 @@ private:
Q_DECLARE_PRIVATE(QQuickBasePositioner)
};
-class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner
+class Q_QUICK_PRIVATE_EXPORT QQuickColumn : public QQuickBasePositioner
{
Q_OBJECT
public:
@@ -242,7 +246,7 @@ private:
};
class QQuickRowPrivate;
-class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner
+class Q_QUICK_PRIVATE_EXPORT QQuickRow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
@@ -267,7 +271,7 @@ private:
};
class QQuickGridPrivate;
-class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner
+class Q_QUICK_PRIVATE_EXPORT QQuickGrid : public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
@@ -354,7 +358,7 @@ private:
};
class QQuickFlowPrivate;
-class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner
+class Q_QUICK_PRIVATE_EXPORT QQuickFlow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
@@ -387,6 +391,22 @@ private:
Q_DECLARE_PRIVATE(QQuickFlow)
};
+class Q_QUICK_PRIVATE_EXPORT QQuickImplicitRow : public QQuickRow
+{
+ Q_OBJECT
+
+public:
+ QQuickImplicitRow(QQuickItem *parent = nullptr);
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickImplicitGrid : public QQuickGrid
+{
+ Q_OBJECT
+
+public:
+ QQuickImplicitGrid(QQuickItem *parent = nullptr);
+};
+
QT_END_NAMESPACE
@@ -394,6 +414,8 @@ QML_DECLARE_TYPE(QQuickColumn)
QML_DECLARE_TYPE(QQuickRow)
QML_DECLARE_TYPE(QQuickGrid)
QML_DECLARE_TYPE(QQuickFlow)
+QML_DECLARE_TYPE(QQuickImplicitRow)
+QML_DECLARE_TYPE(QQuickImplicitGrid)
QML_DECLARE_TYPE(QQuickBasePositioner)
QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES)
diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h
index 6dd84e6098..1a7051615c 100644
--- a/src/quick/items/qquickpositioners_p_p.h
+++ b/src/quick/items/qquickpositioners_p_p.h
@@ -58,9 +58,6 @@ QT_REQUIRE_CONFIG(quick_positioners);
#include "qquickpositioners_p.h"
#include "qquickimplicitsizeitem_p_p.h"
-#include <QtQuick/private/qquickstate_p.h>
-#include <private/qquicktransitionmanager_p_p.h>
-#include <private/qquickstatechangescript_p.h>
#include <private/qlazilyallocated_p.h>
#include <QtCore/qobject.h>
@@ -92,10 +89,14 @@ public:
QLazilyAllocated<ExtraData> extra;
QQuickBasePositionerPrivate()
- : spacing(0), type(QQuickBasePositioner::None)
- , transitioner(0), positioningDirty(false)
- , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
-
+ : spacing(0)
+ , type(QQuickBasePositioner::None)
+ , transitioner(0)
+ , positioningDirty(false)
+ , doingPositioning(false)
+ , anchorConflict(false)
+ , useImplicitSize(false)
+ , layoutDirection(Qt::LeftToRight)
{
}
@@ -122,6 +123,7 @@ public:
bool positioningDirty : 1;
bool doingPositioning : 1;
bool anchorConflict : 1;
+ bool useImplicitSize : 1;
Qt::LayoutDirection layoutDirection;
@@ -177,6 +179,34 @@ public:
{
}
+ void itemImplicitWidthChanged(QQuickItem *) override
+ {
+ Q_ASSERT(useImplicitSize);
+ setPositioningDirty();
+ }
+
+ void itemImplicitHeightChanged(QQuickItem *) override
+ {
+ Q_ASSERT(useImplicitSize);
+ setPositioningDirty();
+ }
+
+ qreal itemWidth(QQuickItem *item) const
+ {
+ if (Q_LIKELY(!useImplicitSize))
+ return item->width();
+
+ return item->implicitWidth();
+ }
+
+ qreal itemHeight(QQuickItem *item) const
+ {
+ if (Q_LIKELY(!useImplicitSize))
+ return item->height();
+
+ return item->implicitHeight();
+ }
+
inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
void setTopPadding(qreal value, bool reset = false);
void setLeftPadding(qreal value, bool reset = false);
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 9347b55c70..20c6973ee1 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -207,9 +207,9 @@ QT_BEGIN_NAMESPACE
By default it is set to the value of the QScreen that the window uses.
*/
-QQuickScreenInfo::QQuickScreenInfo(QObject *parent)
- : QObject(parent),
- m_screen(nullptr)
+QQuickScreenInfo::QQuickScreenInfo(QObject *parent, QScreen *wrappedScreen)
+ : QObject(parent)
+ , m_screen(wrappedScreen)
{
}
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 06efb3ab45..99e1466631 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -84,7 +84,7 @@ class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject
Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1)
public:
- QQuickScreenInfo(QObject *parent = nullptr);
+ QQuickScreenInfo(QObject *parent = nullptr, QScreen *wrappedScreen = nullptr);
QString name() const;
int width() const;
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 1b37a746d3..c782ddb5f7 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -189,6 +189,7 @@ QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
, m_sourceItem(0)
, m_textureSize(0, 0)
, m_format(RGBA)
+ , m_samples(0)
, m_live(true)
, m_hideSource(false)
, m_mipmap(false)
@@ -582,6 +583,44 @@ void QQuickShaderEffectSource::setTextureMirroring(TextureMirroring mirroring)
}
/*!
+ \qmlproperty int QtQuick::ShaderEffectSource::samples
+ \since 5.10
+
+ This property allows requesting multisampled rendering.
+
+ By default multisampling is enabled whenever multisampling is enabled for
+ the entire window, assuming the scenegraph renderer in use and the
+ underlying graphics API supports this.
+
+ By setting the value to 2, 4, etc. multisampled rendering can be requested
+ for a part of the scene without enabling multisampling for the entire
+ scene. This way multisampling is applied only to a given subtree, which can
+ lead to significant performance gains since multisampling is not applied to
+ other parts of the scene.
+
+ \note Enabling multisampling can be potentially expensive regardless of the
+ layer's size, as it incurs a hardware and driver dependent performance and
+ memory cost.
+
+ \note This property is only functional when support for multisample
+ renderbuffers and framebuffer blits is available. Otherwise the value is
+ silently ignored.
+ */
+int QQuickShaderEffectSource::samples() const
+{
+ return m_samples;
+}
+
+void QQuickShaderEffectSource::setSamples(int count)
+{
+ if (count == m_samples)
+ return;
+ m_samples = count;
+ update();
+ emit samplesChanged();
+}
+
+/*!
\qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate()
Schedules a re-rendering of the texture for the next frame.
@@ -683,6 +722,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
m_texture->setHasMipmaps(m_mipmap);
m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
+ m_texture->setSamples(m_samples);
if (m_grab)
m_texture->scheduleUpdate();
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 5e7e354feb..d9f9079a3d 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -88,6 +88,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi
Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1)
+ Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2)
public:
enum WrapMode {
@@ -150,6 +151,9 @@ public:
Q_INVOKABLE void scheduleUpdate();
+ int samples() const;
+ void setSamples(int count);
+
Q_SIGNALS:
void wrapModeChanged();
void sourceItemChanged();
@@ -161,6 +165,7 @@ Q_SIGNALS:
void mipmapChanged();
void recursiveChanged();
void textureMirroringChanged();
+ void samplesChanged();
void scheduledUpdateCompleted();
@@ -185,6 +190,7 @@ private:
QRectF m_sourceRect;
QSize m_textureSize;
Format m_format;
+ int m_samples;
uint m_live : 1;
uint m_hideSource : 1;
uint m_mipmap : 1;
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 965fb0102f..1720377046 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -74,7 +74,7 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
QQuickTextPrivate::QQuickTextPrivate()
- : elideLayout(0), textLine(0), lineWidth(0)
+ : fontInfo(font), elideLayout(0), textLine(0), lineWidth(0)
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
, lineCount(1), multilengthEos(-1)
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
@@ -1018,6 +1018,17 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
implicitWidthValid = true;
implicitHeightValid = true;
+ QFontInfo scaledFontInfo(scaledFont);
+ if (fontInfo.weight() != scaledFontInfo.weight()
+ || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
+ || fontInfo.italic() != scaledFontInfo.italic()
+ || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
+ || fontInfo.family() != scaledFontInfo.family()
+ || fontInfo.styleName() != scaledFontInfo.styleName()) {
+ fontInfo = scaledFontInfo;
+ emit q->fontInfoChanged();
+ }
+
if (eos != multilengthEos)
truncated = true;
@@ -2974,4 +2985,80 @@ void QQuickText::resetBottomPadding()
d->setBottomPadding(0, true);
}
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.family
+ \since 5.9
+
+ The family name of the font that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.styleName
+ \since 5.9
+
+ The style name of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::fontInfo.bold
+ \since 5.9
+
+ The bold state of the font info that has been resolved for the current font
+ and fontSizeMode. This is true if the weight of the resolved font is bold or higher.
+*/
+
+/*!
+ \qmlproperty int QtQuick::Text::fontInfo.weight
+ \since 5.9
+
+ The weight of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::fontInfo.italic
+ \since 5.9
+
+ The italic state of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty real QtQuick::Text::fontInfo.pointSize
+ \since 5.9
+
+ The pointSize of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.pixelSize
+ \since 5.9
+
+ The pixel size of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+QJSValue QQuickText::fontInfo() const
+{
+ Q_D(const QQuickText);
+
+ QJSEngine *engine = qjsEngine(this);
+ if (!engine) {
+ qmlWarning(this) << "fontInfo: item has no JS engine";
+ return QJSValue();
+ }
+
+ QJSValue value = engine->newObject();
+ value.setProperty(QStringLiteral("family"), d->fontInfo.family());
+ value.setProperty(QStringLiteral("styleName"), d->fontInfo.styleName());
+ value.setProperty(QStringLiteral("bold"), d->fontInfo.bold());
+ value.setProperty(QStringLiteral("weight"), d->fontInfo.weight());
+ value.setProperty(QStringLiteral("italic"), d->fontInfo.italic());
+ value.setProperty(QStringLiteral("pointSize"), d->fontInfo.pointSizeF());
+ value.setProperty(QStringLiteral("pixelSize"), d->fontInfo.pixelSize());
+ return value;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index c3d3906e7e..b190738cfb 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -98,6 +98,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
+ Q_PROPERTY(QJSValue fontInfo READ fontInfo NOTIFY fontInfoChanged REVISION 9)
+
public:
QQuickText(QQuickItem *parent=0);
~QQuickText();
@@ -248,6 +250,8 @@ public:
void setBottomPadding(qreal padding);
void resetBottomPadding();
+ QJSValue fontInfo() const;
+
Q_SIGNALS:
void textChanged(const QString &text);
void linkActivated(const QString &link);
@@ -280,6 +284,7 @@ Q_SIGNALS:
Q_REVISION(6) void leftPaddingChanged();
Q_REVISION(6) void rightPaddingChanged();
Q_REVISION(6) void bottomPaddingChanged();
+ Q_REVISION(9) void fontInfoChanged();
protected:
QQuickText(QQuickTextPrivate &dd, QQuickItem *parent = 0);
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index 0669bcf115..6456750359 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -122,6 +122,7 @@ public:
QString text;
QFont font;
QFont sourceFont;
+ QFontInfo fontInfo;
QTextLayout layout;
QTextLayout *elideLayout;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 660c5f8067..57810e4ec9 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -453,8 +453,13 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
fboId = renderTargetId;
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
- renderer->setDevicePixelRatio(1);
+ if (QQuickRenderControl::renderWindowFor(q)) {
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ renderer->setDevicePixelRatio(devicePixelRatio);
+ } else {
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
+ renderer->setDevicePixelRatio(1);
+ }
} else {
QRect rect(QPoint(0, 0), devicePixelRatio * size);
renderer->setDeviceRect(rect);
@@ -1798,7 +1803,7 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
QPointF p = item->mapFromScene(event->posF());
if (item->contains(p)) {
- QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
+ QWheelEvent wheel(p, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(),
event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
wheel.setTimestamp(event->timestamp());
wheel.accept();
@@ -4167,25 +4172,25 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
- \qmlproperty variant Window::targetScreen
-
- Specifies the screen the window should be placed on. Equivalent to
- QWindow::setScreen().
+ \qmlproperty variant Window::screen
- The value must be an element from the Qt.application.screens array.
+ The screen with which the window is associated.
- By default the value is null which leads to using the primary screen.
+ 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.
- \note To ensure that the window is associated with the desired screen right
- upon the underlying native window's initial creation, make sure this
- property is set as early as possible and that the setting of its value is
- not deferred. This can be particularly important on embedded platforms
- without a windowing system, where only one window per screen is allowed at a
- time.
+ \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
+ early as possible and that the setting of its value is not deferred. This
+ can be particularly important on embedded platforms without a windowing system,
+ where only one window per screen is allowed at a time. Setting the screen after
+ a window has been created does not move the window if the new screen is part of
+ the same virtual desktop as the old screen.
\since 5.9
- \sa QWindow::setScreen(), QScreen, Qt.application
+ \sa QWindow::setScreen(), QWindow::screen(), QScreen, Qt.application
*/
/*!
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 42313e4584..6211b7802f 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -59,7 +59,6 @@ public:
: complete(false)
, visible(false)
, visibility(QQuickWindow::AutomaticVisibility)
- , targetScreen(nullptr)
{
}
@@ -67,7 +66,6 @@ public:
bool visible;
QQuickWindow::Visibility visibility;
QV4::PersistentValue rootItemMarker;
- QObject *targetScreen;
};
QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
@@ -75,6 +73,7 @@ QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent)
{
connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
+ connect(this, &QWindow::screenChanged, this, &QQuickWindowQmlImpl::screenChanged);
}
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 d->targetScreen;
+ return new QQuickScreenInfo(const_cast<QQuickWindowQmlImpl *>(this), QWindow::screen());
}
-void QQuickWindowQmlImpl::setTargetScreen(QObject *screen)
+void QQuickWindowQmlImpl::setScreen(QObject *screen)
{
- Q_D(QQuickWindowQmlImpl);
- if (d->targetScreen != screen) {
- d->targetScreen = screen;
- emit targetScreenChanged();
- QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
- if (screenWrapper)
- setScreen(screenWrapper->wrappedScreen());
- else
- setScreen(nullptr);
- }
+ QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen);
+ QWindow::setScreen(screenWrapper ? screenWrapper->wrappedScreen() : nullptr);
}
void QQuickWindowModule::defineModule()
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 7ca29880ea..16130bc8a0 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -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(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:
QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR);
@@ -75,15 +75,15 @@ public:
void setVisible(bool visible);
void setVisibility(Visibility visibility);
- QObject *targetScreen() const;
- void setTargetScreen(QObject *screen);
+ QObject *screen() const;
+ void setScreen(QObject *screen);
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
- Q_REVISION(2) void targetScreenChanged();
+ Q_REVISION(2) void screenChanged();
protected:
void classBegin() Q_DECL_OVERRIDE;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h
index d3f13e40b1..9f5a22e66f 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h
@@ -93,6 +93,7 @@ public:
void setDevicePixelRatio(qreal ratio) override;
void setMirrorHorizontal(bool mirror) override;
void setMirrorVertical(bool mirror) override;
+ void setSamples(int) override { }
public slots:
void markDirtyTexture() override;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
index f8c1a3d90b..ad6cf39425 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -64,7 +64,7 @@ void QSGSoftwarePixmapRenderer::renderScene(uint)
class B : public QSGBindable
{
public:
- void bind() const { }
+ void bind() const override { }
} bindable;
QSGRenderer::renderScene(bindable);
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
index 1fa5234377..d754089ce4 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp
@@ -98,10 +98,10 @@ void QSGSoftwareImageNode::paint(QPainter *painter)
if (!m_cachedPixmap.isNull()) {
painter->drawPixmap(m_rect, m_cachedPixmap, m_sourceRect);
- } else if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
+ } else if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
const QPixmap &pm = pt->pixmap();
painter->drawPixmap(m_rect, pm, m_sourceRect);
- } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) {
+ } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(m_texture)) {
const QImage &im = pt->image();
painter->drawImage(m_rect, im, m_sourceRect);
}
@@ -113,14 +113,14 @@ void QSGSoftwareImageNode::updateCachedMirroredPixmap()
m_cachedPixmap = QPixmap();
} else {
- if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
+ if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(m_texture)) {
QTransform mirrorTransform;
if (m_transformMode.testFlag(MirrorVertically))
mirrorTransform = mirrorTransform.scale(1, -1);
if (m_transformMode.testFlag(MirrorHorizontally))
mirrorTransform = mirrorTransform.scale(-1, 1);
m_cachedPixmap = pt->pixmap().transformed(mirrorTransform);
- } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) {
+ } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(m_texture)) {
m_cachedPixmap = QPixmap::fromImage(pt->image().mirrored(m_transformMode.testFlag(MirrorHorizontally), m_transformMode.testFlag(MirrorVertically)));
} else {
m_cachedPixmap = QPixmap();
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
index 7adb39d9a8..f67e2106c8 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
@@ -296,10 +296,10 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu
case QSGSoftwareRenderableNode::SimpleTexture:
{
QSGTexture *texture = m_handle.simpleTextureNode->texture();
- if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(texture)) {
+ if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(texture)) {
const QPixmap &pm = pt->pixmap();
painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, m_handle.simpleTextureNode->sourceRect());
- } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(texture)) {
+ } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(texture)) {
const QImage &im = pt->image();
painter->drawImage(m_handle.simpleTextureNode->rect(), im, m_handle.simpleTextureNode->sourceRect());
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
index cad826fb27..85d04fe136 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
@@ -90,7 +90,7 @@ void QSGSoftwareRenderer::renderScene(uint)
class B : public QSGBindable
{
public:
- void bind() const { }
+ void bind() const override { }
} bindable;
QSGRenderer::renderScene(bindable);
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
index 8abbefdd48..682f89721e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp
@@ -188,8 +188,8 @@ public:
delete rc;
}
- bool event(QEvent *e);
- void run();
+ bool event(QEvent *e) override;
+ void run() override;
void syncAndRender();
void sync(bool inExpose);
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 322192944b..2c0f8667e8 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -440,9 +440,7 @@ struct Batch
mutable uint uploadedThisFrame : 1; // solely for debugging purposes
Buffer vbo;
-#ifdef QSG_SEPARATE_INDEX_BUFFER
Buffer ibo;
-#endif
QDataBuffer<DrawSet> drawSets;
};
@@ -744,9 +742,7 @@ private:
ClipType m_currentClipType;
QDataBuffer<char> m_vertexUploadPool;
-#ifdef QSG_SEPARATE_INDEX_BUFFER
QDataBuffer<char> m_indexUploadPool;
-#endif
// For minimal OpenGL core profile support
QOpenGLVertexArrayObject *m_vao;
@@ -766,10 +762,7 @@ Batch *Renderer::newBatch()
m_batchPool.resize(size - 1);
} else {
b = new Batch();
- memset(&b->vbo, 0, sizeof(Buffer));
-#ifdef QSG_SEPARATE_INDEX_BUFFER
- memset(&b->ibo, 0, sizeof(Buffer));
-#endif
+ memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO
}
b->init();
return b;
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index a1e1ef8c27..7ef75d4b4c 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -337,13 +337,6 @@ QSGNode::~QSGNode()
to the scene graph and will cause the preprocess() function to be called
for every frame the node is rendered.
- The preprocess function is called before the update pass that propagates
- opacity and transformations through the scene graph. That means that
- functions like QSGOpacityNode::combinedOpacity() and
- QSGTransformNode::combinedMatrix() will not contain up-to-date values.
- If such values are changed during the preprocess, these changes will be
- propagated through the scene graph before it is rendered.
-
\warning Beware of deleting nodes while they are being preprocessed. It is
possible, with a small performance hit, to delete a single node during its
own preprocess call. Deleting a subtree which has nodes that also use
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index e5d464930c..9207fdbc55 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -189,7 +189,7 @@ void QSGRenderer::renderScene(uint fboId)
class B : public QSGBindable
{
public:
- void bind() const { QOpenGLFramebufferObject::bindDefault(); }
+ void bind() const override { QOpenGLFramebufferObject::bindDefault(); }
} bindable;
renderScene(bindable);
}
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
index 3b0b2faf97..0f49e615e4 100644
--- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
@@ -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.
When successful, the returned pointer is either a direct pointer to an
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 03a1f7f281..a8e35b1ac1 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -209,6 +209,7 @@ public:
virtual void setDevicePixelRatio(qreal ratio) = 0;
virtual void setMirrorHorizontal(bool mirror) = 0;
virtual void setMirrorVertical(bool mirror) = 0;
+ virtual void setSamples(int samples) = 0;
Q_SLOT virtual void markDirtyTexture() = 0;
Q_SLOT virtual void invalidated() = 0;
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 6b9db105e7..2f5d5790ee 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -88,6 +88,7 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
class QSGSpriteNode;
+class QSGRenderContext;
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
@@ -98,6 +99,54 @@ Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP)
+class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum AntialiasingMethod {
+ UndecidedAntialiasing,
+ VertexAntialiasing,
+ MsaaAntialiasing
+ };
+
+ explicit QSGContext(QObject *parent = 0);
+ virtual ~QSGContext();
+
+ virtual void renderContextInitialized(QSGRenderContext *renderContext);
+ virtual void renderContextInvalidated(QSGRenderContext *renderContext);
+ virtual QSGRenderContext *createRenderContext() = 0;
+
+ QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c);
+ virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0;
+ virtual QSGInternalImageNode *createInternalImageNode() = 0;
+ virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
+ virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
+ virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
+ virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
+ QSGGuiThreadShaderEffectManager *mgr);
+#if QT_CONFIG(quick_sprite)
+ virtual QSGSpriteNode *createSpriteNode() = 0;
+#endif
+ virtual QAnimationDriver *createAnimationDriver(QObject *parent);
+
+ virtual QSize minimumFBOSize() const;
+ virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
+
+ virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
+
+ virtual QSGRectangleNode *createRectangleNode() = 0;
+ virtual QSGImageNode *createImageNode() = 0;
+ virtual QSGNinePatchNode *createNinePatchNode() = 0;
+
+ static QSGContext *createDefaultContext();
+ static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
+ static QSGRenderLoop *createWindowManager();
+
+ static void setBackend(const QString &backend);
+};
+
class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject
{
Q_OBJECT
@@ -150,55 +199,6 @@ protected:
QSet<QFontEngine *> m_fontEnginesToClean;
};
-
-class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
-{
- Q_OBJECT
-
-public:
- enum AntialiasingMethod {
- UndecidedAntialiasing,
- VertexAntialiasing,
- MsaaAntialiasing
- };
-
- explicit QSGContext(QObject *parent = 0);
- virtual ~QSGContext();
-
- virtual void renderContextInitialized(QSGRenderContext *renderContext);
- virtual void renderContextInvalidated(QSGRenderContext *renderContext);
- virtual QSGRenderContext *createRenderContext() = 0;
-
- QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c);
- virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0;
- virtual QSGInternalImageNode *createInternalImageNode() = 0;
- virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
- virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
- virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
- virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
- virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
- QSGGuiThreadShaderEffectManager *mgr);
-#if QT_CONFIG(quick_sprite)
- virtual QSGSpriteNode *createSpriteNode() = 0;
-#endif
- virtual QAnimationDriver *createAnimationDriver(QObject *parent);
-
- virtual QSize minimumFBOSize() const;
- virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
-
- virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
-
- virtual QSGRectangleNode *createRectangleNode() = 0;
- virtual QSGImageNode *createImageNode() = 0;
- virtual QSGNinePatchNode *createNinePatchNode() = 0;
-
- static QSGContext *createDefaultContext();
- static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
- static QSGRenderLoop *createWindowManager();
-
- static void setBackend(const QString &backend);
-};
-
QT_END_NAMESPACE
#endif // QSGCONTEXT_H
diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp
index 405f1d86a4..d31a7025e5 100644
--- a/src/quick/scenegraph/qsgdefaultcontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultcontext.cpp
@@ -68,13 +68,13 @@ QT_BEGIN_NAMESPACE
namespace QSGMultisampleAntialiasing {
class ImageNode : public QSGDefaultInternalImageNode {
public:
- void setAntialiasing(bool) { }
+ void setAntialiasing(bool) override { }
};
class RectangleNode : public QSGDefaultInternalRectangleNode {
public:
- void setAntialiasing(bool) { }
+ void setAntialiasing(bool) override { }
};
}
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index b001899915..edb6e92a0d 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -91,11 +91,11 @@ class QSGTextMaskShader : public QSGMaterialShader
public:
QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat);
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
protected:
- virtual void initialize();
+ void initialize() override;
int m_matrix_id;
int m_color_id;
@@ -181,7 +181,7 @@ public:
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/8bittextmask.frag"));
}
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
};
void QSG8BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
@@ -206,10 +206,10 @@ public:
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/24bittextmask.frag"));
}
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual void initialize();
- void activate();
- void deactivate();
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ void initialize() override;
+ void activate() override;
+ void deactivate() override;
bool useSRGB() const;
uint m_useSRGB : 1;
@@ -326,10 +326,10 @@ public:
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/styledtext.frag"));
}
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
private:
- virtual void initialize();
+ void initialize() override;
int m_shift_id;
int m_styleColor_id;
diff --git a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp
index 1d54628acd..a5a6da06a7 100644
--- a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp
@@ -50,11 +50,11 @@ class SmoothTextureMaterialShader : public QSGTextureMaterialShader
public:
SmoothTextureMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
protected:
- virtual void initialize();
+ void initialize() override;
int m_pixelSizeLoc;
};
diff --git a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp
index 94414444ba..e52dcaad52 100644
--- a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp
@@ -55,11 +55,11 @@ class SmoothColorMaterialShader : public QSGMaterialShader
public:
SmoothColorMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
private:
- virtual void initialize();
+ void initialize() override;
int m_matrixLoc;
int m_opacityLoc;
diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp
index ad5b57ff83..fc8040e67b 100644
--- a/src/quick/scenegraph/qsgdefaultlayer.cpp
+++ b/src/quick/scenegraph/qsgdefaultlayer.cpp
@@ -99,6 +99,7 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
#ifdef QSG_DEBUG_FBO_OVERLAY
, m_debugOverlay(0)
#endif
+ , m_samples(0)
, m_mipmap(false)
, m_live(true)
, m_recursive(false)
@@ -313,11 +314,20 @@ void QSGDefaultLayer::grab()
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
bool deleteFboLater = false;
- if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
- || (!m_fbo->format().mipmap() && m_mipmap))
- {
+
+ int effectiveSamples = m_samples;
+ // By default m_samples is 0. Fall back to the context's setting in this case.
+ if (effectiveSamples == 0)
+ effectiveSamples = m_context->openglContext()->format().samples();
+
+ const bool needsNewFbo = !m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format;
+ const bool mipmapGotEnabled = m_fbo && !m_fbo->format().mipmap() && m_mipmap;
+ const bool msaaGotEnabled = effectiveSamples > 1 && (!m_secondaryFbo || m_secondaryFbo->format().samples() != effectiveSamples);
+ const bool msaaGotDisabled = effectiveSamples <= 1 && m_secondaryFbo;
+
+ if (needsNewFbo || mipmapGotEnabled || msaaGotEnabled || msaaGotDisabled) {
if (!m_multisamplingChecked) {
- if (m_context->openglContext()->format().samples() <= 1) {
+ if (effectiveSamples <= 1) {
m_multisampling = false;
} else {
const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
@@ -333,7 +343,7 @@ void QSGDefaultLayer::grab()
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(m_format);
- format.setSamples(m_context->openglContext()->format().samples());
+ format.setSamples(effectiveSamples);
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h
index ae39994096..7b09293095 100644
--- a/src/quick/scenegraph/qsgdefaultlayer_p.h
+++ b/src/quick/scenegraph/qsgdefaultlayer_p.h
@@ -113,6 +113,9 @@ public:
QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE;
+ int samples() const { return m_samples; }
+ void setSamples(int samples) Q_DECL_OVERRIDE { m_samples = samples; }
+
public Q_SLOTS:
void markDirtyTexture() Q_DECL_OVERRIDE;
void invalidated() Q_DECL_OVERRIDE;
@@ -138,6 +141,7 @@ private:
#endif
QSGDefaultRenderContext *m_context;
+ int m_samples;
uint m_mipmap : 1;
uint m_live : 1;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index ca91e5d85f..fc66f2f2cc 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -52,11 +52,11 @@ class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader
public:
QSGDistanceFieldTextMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
protected:
- virtual void initialize();
+ void initialize() override;
void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc);
void updateColor(const QVector4D &c);
@@ -261,10 +261,10 @@ class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMateria
public:
DistanceFieldStyledTextMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
protected:
- virtual void initialize();
+ void initialize() override;
int m_styleColor_id;
};
@@ -329,10 +329,10 @@ class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMat
public:
DistanceFieldOutlineTextMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
protected:
- virtual void initialize();
+ void initialize() override;
void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius);
@@ -413,10 +413,10 @@ class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTe
public:
DistanceFieldShiftedStyleTextMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
protected:
- virtual void initialize();
+ void initialize() override;
void updateShift(qreal fontScale, const QPointF& shift);
@@ -492,10 +492,10 @@ class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTex
public:
QSGHiQSubPixelDistanceFieldTextMaterialShader();
- virtual void initialize();
- virtual void activate();
- virtual void deactivate();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ void initialize() override;
+ void activate() override;
+ void deactivate() override;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
private:
int m_fontScale_id;
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 48288bfc62..bb581c5e36 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -139,25 +139,25 @@ public:
QSGGuiThreadRenderLoop();
~QSGGuiThreadRenderLoop();
- void show(QQuickWindow *window);
- void hide(QQuickWindow *window);
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
- void windowDestroyed(QQuickWindow *window);
+ void windowDestroyed(QQuickWindow *window) override;
void renderWindow(QQuickWindow *window);
- void exposureChanged(QQuickWindow *window);
- QImage grab(QQuickWindow *window);
+ void exposureChanged(QQuickWindow *window) override;
+ QImage grab(QQuickWindow *window) override;
- void maybeUpdate(QQuickWindow *window);
- void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation.
- void handleUpdateRequest(QQuickWindow *);
+ void maybeUpdate(QQuickWindow *window) override;
+ void update(QQuickWindow *window) override { maybeUpdate(window); } // identical for this implementation.
+ void handleUpdateRequest(QQuickWindow *) override;
- void releaseResources(QQuickWindow *) { }
+ void releaseResources(QQuickWindow *) override { }
- QAnimationDriver *animationDriver() const { return 0; }
+ QAnimationDriver *animationDriver() const override { return 0; }
- QSGContext *sceneGraphContext() const;
- QSGRenderContext *createRenderContext(QSGContext *) const { return rc; }
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; }
struct WindowData {
bool updatePending : 1;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 5fa74027c1..17a2c62a4e 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -295,8 +295,8 @@ public:
void invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *backupSurface);
void initializeOpenGL();
- bool event(QEvent *);
- void run();
+ bool event(QEvent *) override;
+ void run() override;
void syncAndRender();
void sync(bool inExpose);
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index edf4aa08c5..38c3b8dd85 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -1,4 +1,4 @@
-# DEFINES += QSG_SEPARATE_INDEX_BUFFER
+DEFINES += QSG_SEPARATE_INDEX_BUFFER
# DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG
# Core API
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
index 63773887a0..7186ee4265 100644
--- a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
@@ -94,6 +94,21 @@ QSGTexture::Filtering QSGDefaultImageNode::mipmapFiltering() const
return m_material.mipmapFiltering();
}
+void QSGDefaultImageNode::setAnisotropyLevel(QSGTexture::AnisotropyLevel level)
+{
+ if (m_material.anisotropyLevel() == level)
+ return;
+
+ m_material.setAnisotropyLevel(level);
+ m_opaque_material.setAnisotropyLevel(level);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::AnisotropyLevel QSGDefaultImageNode::anisotropyLevel() const
+{
+ return m_material.anisotropyLevel();
+}
+
void QSGDefaultImageNode::setRect(const QRectF &r)
{
if (m_rect == r)
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
index bb9ebec885..cb23e759d3 100644
--- a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
@@ -85,6 +85,10 @@ public:
void setOwnsTexture(bool owns) override;
bool ownsTexture() const override;
+ // QSGImageNode now being a public class does not allow any additional virtual methods. Placing these here, non-virtual.
+ void setAnisotropyLevel(QSGTexture::AnisotropyLevel level);
+ QSGTexture::AnisotropyLevel anisotropyLevel() const;
+
private:
QSGGeometry m_geometry;
QSGOpaqueTextureMaterial m_opaque_material;
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 8ab7669891..a0c71b5340 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -50,13 +50,13 @@ class FlatColorMaterialShader : public QSGMaterialShader
public:
FlatColorMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
static QSGMaterialType type;
private:
- virtual void initialize();
+ void initialize() override;
#if QT_CONFIG(opengl)
int m_matrix_id;
int m_color_id;
diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h
index d25e732e4b..0e053c307f 100644
--- a/src/quick/scenegraph/util/qsgimagenode.h
+++ b/src/quick/scenegraph/util/qsgimagenode.h
@@ -67,6 +67,8 @@ public:
virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
virtual QSGTexture::Filtering mipmapFiltering() const = 0;
+ // ### Qt6: Add anisotropy support here, and possibly a virtual hook or another mean to extend this class.
+
enum TextureCoordinatesTransformFlag {
NoTransform = 0x00,
MirrorHorizontally = 0x01,
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index d761eac62f..521c5e666f 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -83,6 +83,9 @@ static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"
#define GL_BGRA 0x80E1
#endif
+#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#endif
QT_BEGIN_NAMESPACE
@@ -97,10 +100,12 @@ inline static bool isPowerOfTwo(int x)
QSGTexturePrivate::QSGTexturePrivate()
: wrapChanged(false)
, filteringChanged(false)
+ , anisotropyChanged(false)
, horizontalWrap(QSGTexture::ClampToEdge)
, verticalWrap(QSGTexture::ClampToEdge)
, mipmapMode(QSGTexture::None)
, filterMode(QSGTexture::Nearest)
+ , anisotropyLevel(QSGTexture::AnisotropyNone)
{
}
@@ -278,6 +283,23 @@ static void qt_debug_remove_texture(QSGTexture* texture)
*/
/*!
+ \enum QSGTexture::AnisotropyLevel
+
+ Specifies the anisotropic filtering level to be used when
+ the texture is not screen aligned.
+
+ \value AnisotropyNone No anisotropic filtering.
+
+ \value Anisotropy2x 2x anisotropic filtering.
+
+ \value Anisotropy4x 4x anisotropic filtering.
+
+ \value Anisotropy8x 8x anisotropic filtering.
+
+ \value Anisotropy16x 16x anisotropic filtering.
+*/
+
+/*!
\fn QSGTexture::QSGTexture(QSGTexturePrivate &dd)
\internal
*/
@@ -476,6 +498,31 @@ QSGTexture::Filtering QSGTexture::filtering() const
return (QSGTexture::Filtering) d_func()->filterMode;
}
+/*!
+ Sets the level of anisotropic filtering to be used for the upcoming bind() call to \a level.
+ The default value is QSGTexture::AnisotropyNone, which means no anisotropic filtering is enabled.
+
+ \since 5.9
+ */
+void QSGTexture::setAnisotropyLevel(AnisotropyLevel level)
+{
+ Q_D(QSGTexture);
+ if (d->anisotropyLevel != (uint) level) {
+ d->anisotropyLevel = level;
+ d->anisotropyChanged = true;
+ }
+}
+
+/*!
+ Returns the anisotropy level in use for filtering this texture.
+
+ \since 5.9
+ */
+QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const
+{
+ return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
+}
+
/*!
@@ -552,6 +599,12 @@ void QSGTexture::updateBindOptions(bool force)
d->filteringChanged = false;
}
+ if (force || d->anisotropyChanged) {
+ d->anisotropyChanged = false;
+ if (QOpenGLContext::currentContext()->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")))
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, float(1 << (d->anisotropyLevel)));
+ }
+
if (force || d->wrapChanged) {
#ifndef QT_NO_DEBUG
if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat
diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h
index 2b29525efd..032129434e 100644
--- a/src/quick/scenegraph/util/qsgtexture.h
+++ b/src/quick/scenegraph/util/qsgtexture.h
@@ -68,6 +68,14 @@ public:
Linear
};
+ enum AnisotropyLevel {
+ AnisotropyNone,
+ Anisotropy2x,
+ Anisotropy4x,
+ Anisotropy8x,
+ Anisotropy16x
+ };
+
virtual int textureId() const = 0;
virtual QSize textureSize() const = 0;
virtual bool hasAlphaChannel() const = 0;
@@ -88,6 +96,9 @@ public:
void setFiltering(Filtering filter);
QSGTexture::Filtering filtering() const;
+ void setAnisotropyLevel(AnisotropyLevel level);
+ QSGTexture::AnisotropyLevel anisotropyLevel() const;
+
void setHorizontalWrapMode(WrapMode hwrap);
QSGTexture::WrapMode horizontalWrapMode() const;
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index 3a10d85b4d..52dc6db2d0 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -69,11 +69,13 @@ public:
uint wrapChanged : 1;
uint filteringChanged : 1;
+ uint anisotropyChanged : 1;
uint horizontalWrap : 2;
uint verticalWrap : 2;
uint mipmapMode : 2;
uint filterMode : 2;
+ uint anisotropyLevel: 3;
};
class Q_QUICK_PRIVATE_EXPORT QSGPlainTexture : public QSGTexture
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index fcafbba6a2..fbc8f27a63 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -110,6 +110,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
Q_UNUSED(state)
#endif
t->setMipmapFiltering(tx->mipmapFiltering());
+ t->setAnisotropyLevel(tx->anisotropyLevel());
if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
t->bind();
@@ -173,6 +174,7 @@ QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
, m_mipmap_filtering(QSGTexture::None)
, m_horizontal_wrap(QSGTexture::ClampToEdge)
, m_vertical_wrap(QSGTexture::ClampToEdge)
+ , m_anisotropy_level(QSGTexture::AnisotropyNone)
{
}
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.h b/src/quick/scenegraph/util/qsgtexturematerial.h
index dc87131773..87d8e5fd49 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial.h
@@ -69,6 +69,9 @@ public:
void setVerticalWrapMode(QSGTexture::WrapMode mode) { m_vertical_wrap = mode; }
QSGTexture::WrapMode verticalWrapMode() const { return QSGTexture::WrapMode(m_vertical_wrap); }
+ void setAnisotropyLevel(QSGTexture::AnisotropyLevel level) { m_anisotropy_level = level; }
+ QSGTexture::AnisotropyLevel anisotropyLevel() const { return QSGTexture::AnisotropyLevel(m_anisotropy_level); }
+
protected:
QSGTexture *m_texture;
@@ -76,8 +79,8 @@ protected:
uint m_mipmap_filtering: 2;
uint m_horizontal_wrap : 1;
uint m_vertical_wrap: 1;
-
- uint m_reserved : 26;
+ uint m_anisotropy_level : 3;
+ uint m_reserved : 23;
};
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index 8c305d7fd4..42c589b14a 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -48,13 +48,13 @@ class QSGVertexColorMaterialShader : public QSGMaterialShader
public:
QSGVertexColorMaterialShader();
- virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual char const *const *attributeNames() const;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
static QSGMaterialType type;
private:
- virtual void initialize();
+ void initialize() override;
#if QT_CONFIG(opengl)
int m_matrix_id;
int m_opacity_id;
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 5a723e4432..20bb23338d 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
class QQuickColorProvider : public QQmlColorProvider
{
public:
- QVariant colorFromString(const QString &s, bool *ok)
+ QVariant colorFromString(const QString &s, bool *ok) override
{
QColor c(s);
if (c.isValid()) {
@@ -73,7 +73,7 @@ public:
return QVariant();
}
- unsigned rgbaFromString(const QString &s, bool *ok)
+ unsigned rgbaFromString(const QString &s, bool *ok) override
{
QColor c(s);
if (c.isValid()) {
@@ -95,36 +95,36 @@ public:
return QString();
}
- QVariant fromRgbF(double r, double g, double b, double a)
+ QVariant fromRgbF(double r, double g, double b, double a) override
{
return QVariant(QColor::fromRgbF(r, g, b, a));
}
- QVariant fromHslF(double h, double s, double l, double a)
+ QVariant fromHslF(double h, double s, double l, double a) override
{
return QVariant(QColor::fromHslF(h, s, l, a));
}
- QVariant fromHsvF(double h, double s, double v, double a)
+ QVariant fromHsvF(double h, double s, double v, double a) override
{
return QVariant(QColor::fromHsvF(h, s, v, a));
}
- QVariant lighter(const QVariant &var, qreal factor)
+ QVariant lighter(const QVariant &var, qreal factor) override
{
QColor color = var.value<QColor>();
color = color.lighter(int(qRound(factor*100.)));
return QVariant::fromValue(color);
}
- QVariant darker(const QVariant &var, qreal factor)
+ QVariant darker(const QVariant &var, qreal factor) override
{
QColor color = var.value<QColor>();
color = color.darker(int(qRound(factor*100.)));
return QVariant::fromValue(color);
}
- QVariant tint(const QVariant &baseVar, const QVariant &tintVar)
+ QVariant tint(const QVariant &baseVar, const QVariant &tintVar) override
{
QColor tintColor = tintVar.value<QColor>();
@@ -778,13 +778,13 @@ public:
class QQuickGuiProvider : public QQmlGuiProvider
{
public:
- QQuickApplication *application(QObject *parent)
+ QQuickApplication *application(QObject *parent) override
{
return new QQuickApplication(parent);
}
#if QT_CONFIG(im)
- QInputMethod *inputMethod()
+ QInputMethod *inputMethod() override
{
QInputMethod *im = qGuiApp->inputMethod();
QQmlEngine::setObjectOwnership(im, QQmlEngine::CppOwnership);
@@ -792,20 +792,20 @@ public:
}
#endif
- QStyleHints *styleHints()
+ QStyleHints *styleHints() override
{
QStyleHints *sh = qGuiApp->styleHints();
QQmlEngine::setObjectOwnership(sh, QQmlEngine::CppOwnership);
return sh;
}
- QStringList fontFamilies()
+ QStringList fontFamilies() override
{
QFontDatabase database;
return database.families();
}
- bool openUrlExternally(QUrl &url)
+ bool openUrlExternally(QUrl &url) override
{
#ifndef QT_NO_DESKTOPSERVICES
return QDesktopServices::openUrl(url);
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 1c6b2afb54..395b89c784 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -84,6 +84,7 @@
QT_BEGIN_NAMESPACE
+const QLatin1String QQuickPixmap::itemGrabberScheme = QLatin1String("itemgrabber");
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
@@ -160,7 +161,7 @@ Q_SIGNALS:
void downloadProgress(qint64, qint64);
protected:
- bool event(QEvent *event);
+ bool event(QEvent *event) override;
private:
Q_DISABLE_COPY(QQuickPixmapReply)
@@ -198,7 +199,7 @@ public:
static QQuickPixmapReader *existingInstance(QQmlEngine *engine);
protected:
- void run();
+ void run() override;
private:
friend class QQuickPixmapReaderThreadObject;
@@ -1462,8 +1463,15 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end();
// If Cache is disabled, the pixmap will always be loaded, even if there is an existing
- // cached version.
- if (options & QQuickPixmap::Cache)
+ // cached version. Unless it's an itemgrabber url, since the cache is used to pass
+ // the result between QQuickItemGrabResult and QQuickImage.
+ if (url.scheme() == itemGrabberScheme) {
+ QSize dummy;
+ if (requestSize != dummy)
+ qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead.";
+ const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() };
+ iter = store->m_cache.find(grabberKey);
+ } else if (options & QQuickPixmap::Cache)
iter = store->m_cache.find(key);
if (iter == store->m_cache.end()) {
@@ -1533,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();
return store->m_cache.contains(key);
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index f7cdfa7d07..93d5a1cf56 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -175,7 +175,9 @@ public:
bool connectDownloadProgress(QObject *, int);
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;
private:
Q_DISABLE_COPY(QQuickPixmap)
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index 77dae0d001..b2e5b84cf4 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -54,7 +54,9 @@
#include "qquicktextmetrics_p.h"
#include "qquicktransition_p.h"
#include "qquickanimator_p.h"
+#if QT_CONFIG(shortcut)
#include "qquickshortcut_p.h"
+#endif
#include "qquickvalidator_p.h"
#include <qqmlinfo.h>
#include <private/qqmltypenotavailable_p.h>
@@ -63,7 +65,9 @@
#include <QtGui/QInputMethod>
#include <QtGui/QKeySequence>
+#if QT_CONFIG(shortcut)
Q_DECLARE_METATYPE(QKeySequence::StandardKey)
+#endif
void QQuickUtilModule::defineModule()
{
@@ -114,15 +118,18 @@ void QQuickUtilModule::defineModule()
qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser);
+#if QT_CONFIG(shortcut)
qRegisterMetaType<QKeySequence::StandardKey>();
qmlRegisterUncreatableType<QKeySequence, 2>("QtQuick", 2, 2, "StandardKey", QStringLiteral("Cannot create an instance of StandardKey."));
+#endif
qmlRegisterType<QQuickFontMetrics>("QtQuick", 2, 4, "FontMetrics");
qmlRegisterType<QQuickTextMetrics>("QtQuick", 2, 4, "TextMetrics");
+#if QT_CONFIG(shortcut)
qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut");
-
qmlRegisterType<QQuickShortcut,1>("QtQuick", 2, 6, "Shortcut");
qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
+#endif
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index 22f23f7598..56eb8ea3b7 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -26,7 +26,6 @@ SOURCES += \
$$PWD/qquickanimatorcontroller.cpp \
$$PWD/qquickfontmetrics.cpp \
$$PWD/qquicktextmetrics.cpp \
- $$PWD/qquickshortcut.cpp \
$$PWD/qquickvalidator.cpp
!contains(QT_CONFIG, no-qml-debug): SOURCES += $$PWD/qquickprofiler.cpp
@@ -63,9 +62,15 @@ HEADERS += \
$$PWD/qquickprofiler_p.h \
$$PWD/qquickfontmetrics_p.h \
$$PWD/qquicktextmetrics_p.h \
- $$PWD/qquickshortcut_p.h \
$$PWD/qquickvalidator_p.h
+qtConfig(shortcut) {
+ SOURCES += \
+ $$PWD/qquickshortcut.cpp
+ HEADERS += \
+ $$PWD/qquickshortcut_p.h
+}
+
qtConfig(quick-path) {
SOURCES += \
$$PWD/qquickpath.cpp \
diff --git a/src/src.pro b/src/src.pro
index f585ef15ca..c2a58c3757 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,7 +1,7 @@
TEMPLATE = subdirs
CONFIG += ordered
include($$OUT_PWD/quick/qtquick-config.pri)
-QT_FOR_CONFIG += quick-private
+QT_FOR_CONFIG += network quick-private
SUBDIRS += \
qml
@@ -20,6 +20,4 @@ SUBDIRS += \
imports \
qmldevtools
-!contains(QT_CONFIG, no-qml-debug): SUBDIRS += qmldebug
-
-qmldevtools.CONFIG = host_build
+qtConfig(localserver):!contains(QT_CONFIG, no-qml-debug): SUBDIRS += qmldebug