aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerCodeRef.h6
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86.h5
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86Common.h4
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86_64.h15
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h23
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp43
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h38
-rw-r--r--src/3rdparty/masm/masm-defs.pri19
-rw-r--r--src/3rdparty/masm/masm.pri11
-rw-r--r--src/3rdparty/masm/stubs/WTFStubs.cpp3
-rw-r--r--src/3rdparty/masm/wtf/MathExtras.h2
-rw-r--r--src/3rdparty/masm/wtf/Platform.h9
-rw-r--r--src/imports/dialogs/dialogs.pro27
-rw-r--r--src/imports/dialogs/plugin.cpp57
-rw-r--r--src/imports/dialogs/qmldir1
-rw-r--r--src/imports/dialogs/qquickabstractdialog.cpp5
-rw-r--r--src/imports/folderlistmodel/qmldir1
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp8
-rw-r--r--src/imports/localstorage/plugin.cpp59
-rw-r--r--src/imports/localstorage/qmldir1
-rw-r--r--src/imports/models/qmldir1
-rw-r--r--src/imports/particles/qmldir1
-rw-r--r--src/imports/qtquick2/qmldir1
-rw-r--r--src/imports/settings/qmldir1
-rw-r--r--src/imports/testlib/qmldir1
-rw-r--r--src/imports/testlib/signalspy.qdoc1
-rw-r--r--src/imports/testlib/testcase.qdoc1
-rw-r--r--src/imports/widgets/qmldir1
-rw-r--r--src/imports/window/qmldir1
-rw-r--r--src/imports/xmllistmodel/qmldir1
-rw-r--r--src/particles/qquickimageparticle.cpp22
-rw-r--r--src/qml/compiler/compiler.pri11
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp114
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h28
-rw-r--r--src/qml/compiler/qv4codegen.cpp120
-rw-r--r--src/qml/compiler/qv4codegen_p.h33
-rw-r--r--src/qml/compiler/qv4compileddata.cpp18
-rw-r--r--src/qml/compiler/qv4compileddata_p.h10
-rw-r--r--src/qml/compiler/qv4compiler.cpp1
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp251
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h60
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp2
-rw-r--r--src/qml/compiler/qv4isel_p.cpp3
-rw-r--r--src/qml/compiler/qv4jsir.cpp12
-rw-r--r--src/qml/compiler/qv4jsir_p.h16
-rw-r--r--src/qml/compiler/qv4regalloc.cpp54
-rw-r--r--src/qml/compiler/qv4ssa.cpp6
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp1
-rw-r--r--src/qml/debugger/qv8profilerservice.cpp2
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc9
-rw-r--r--src/qml/doc/src/qtqml.qdoc6
-rw-r--r--src/qml/jsapi/qjsengine.cpp8
-rw-r--r--src/qml/jsruntime/jsruntime.pri6
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp5
-rw-r--r--src/qml/jsruntime/qv4context_p.h3
-rw-r--r--src/qml/jsruntime/qv4engine.cpp74
-rw-r--r--src/qml/jsruntime/qv4engine_cxxabi.cpp46
-rw-r--r--src/qml/jsruntime/qv4engine_p.h25
-rw-r--r--src/qml/jsruntime/qv4function.cpp4
-rw-r--r--src/qml/jsruntime/qv4function_p.h25
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp77
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4global_p.h37
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4managed.cpp1
-rw-r--r--src/qml/jsruntime/qv4managed_p.h30
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4mm.cpp65
-rw-r--r--src/qml/jsruntime/qv4mm_p.h4
-rw-r--r--src/qml/jsruntime/qv4object.cpp126
-rw-r--r--src/qml/jsruntime/qv4object_p.h13
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp8
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp15
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp11
-rw-r--r--src/qml/jsruntime/qv4script.cpp45
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4sparsearray.cpp4
-rw-r--r--src/qml/jsruntime/qv4stacktrace.cpp182
-rw-r--r--src/qml/jsruntime/qv4stacktrace_p.h75
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4value_def_p.h5
-rw-r--r--src/qml/jsruntime/qv4value_p.h7
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp2
-rw-r--r--src/qml/parser/qqmljs.g4
-rw-r--r--src/qml/parser/qqmljsengine_p.h1
-rw-r--r--src/qml/parser/qqmljsparser.cpp4
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h2
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp3
-rw-r--r--src/qml/qml/qqmlcompiler.cpp126
-rw-r--r--src/qml/qml/qqmlcompiler_p.h13
-rw-r--r--src/qml/qml/qqmlcomponent.cpp74
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlerror.cpp22
-rw-r--r--src/qml/qml/qqmlerror.h7
-rw-r--r--src/qml/qml/qqmlimport.cpp65
-rw-r--r--src/qml/qml/qqmlincubator.cpp105
-rw-r--r--src/qml/qml/qqmlincubator_p.h3
-rw-r--r--src/qml/qml/qqmlinstruction.cpp2
-rw-r--r--src/qml/qml/qqmlinstruction_p.h3
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp6
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp1
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp16
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp15
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp3
-rw-r--r--src/qml/qml/qqmlscript.cpp25
-rw-r--r--src/qml/qml/qqmlscript_p.h14
-rw-r--r--src/qml/qml/qqmltypeloader.cpp31
-rw-r--r--src/qml/qml/qqmltypeloader_p.h1
-rw-r--r--src/qml/qml/qqmlvme.cpp45
-rw-r--r--src/qml/qml/qqmlvme_p.h1
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp32
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h6
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp6
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp5
-rw-r--r--src/qml/types/qquickworkerscript.cpp4
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc16
-rw-r--r--src/quick/doc/src/qtquick.qdoc6
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp8
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp4
-rw-r--r--src/quick/items/qquickborderimage.cpp8
-rw-r--r--src/quick/items/qquickflickable.cpp13
-rw-r--r--src/quick/items/qquickimage.cpp1
-rw-r--r--src/quick/items/qquickitem.cpp52
-rw-r--r--src/quick/items/qquickitem_p.h6
-rw-r--r--src/quick/items/qquickpathview.cpp8
-rw-r--r--src/quick/items/qquickpositioners.cpp2
-rw-r--r--src/quick/items/qquickspritesequence.cpp4
-rw-r--r--src/quick/qtquick2.cpp2
-rw-r--r--src/quick/qtquickglobal_p.h6
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp36
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp8
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp78
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp8
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp3
-rw-r--r--src/quick/util/qquickglobal.cpp5
-rw-r--r--src/quick/util/qquickstyledtext.cpp2
144 files changed, 1762 insertions, 1299 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerCodeRef.h b/src/3rdparty/masm/assembler/MacroAssemblerCodeRef.h
index b699316b91..f03254aa38 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerCodeRef.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerCodeRef.h
@@ -37,16 +37,14 @@
// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid
// instruction address on the platform (for example, check any alignment requirements).
-// (Disabled checks on Android/ARM because we want to intermix thumb and arm)
-#if CPU(ARM_THUMB2) && !defined(Q_OS_ANDROID)
+#if CPU(ARM_THUMB2)
// ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded
// into the processor are decorated with the bottom bit set, indicating that this is
// thumb code (as oposed to 32-bit traditional ARM). The first test checks for both
// decorated and undectorated null, and the second test ensures that the pointer is
// decorated.
#define ASSERT_VALID_CODE_POINTER(ptr) \
- ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1); \
- ASSERT(reinterpret_cast<intptr_t>(ptr) & 1)
+ ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1);
#define ASSERT_VALID_CODE_OFFSET(offset) \
ASSERT(!(offset & 1)) // Must be multiple of 2.
#else
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
index 7a01e41e11..9a33fe870e 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
@@ -197,6 +197,11 @@ public:
return Call(m_assembler.call(), Call::Linkable);
}
+ void callToRetrieveIP()
+ {
+ m_assembler.call();
+ }
+
// Address is a memory location containing the address to jump to
void jump(AbsoluteAddress address)
{
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
index 53cb80c210..520cf915fa 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
@@ -318,7 +318,7 @@ public:
{
m_assembler.sarl_i8r(imm.m_value, dest);
}
-
+
void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
{
if (src != dest)
@@ -362,7 +362,7 @@ public:
move(src, dest);
urshift32(imm, dest);
}
-
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subl_rr(src, dest);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
index 3aaa0fd1bc..9e74f1c29f 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
@@ -136,6 +136,11 @@ public:
return result;
}
+ void callToRetrieveIP()
+ {
+ m_assembler.call();
+ }
+
// Address is a memory location containing the address to jump to
void jump(AbsoluteAddress address)
{
@@ -295,6 +300,16 @@ public:
m_assembler.xorq_ir(imm.m_value, srcDest);
}
+ void urshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.shrq_i8r(imm.m_value, dest);
+ }
+
+ void lshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.shlq_i8r(imm.m_value, dest);
+ }
+
void load64(ImplicitAddress address, RegisterID dest)
{
m_assembler.movq_mr(address.offset, address.base, dest);
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index a3a480541c..1875ebaff0 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -683,6 +683,29 @@ public:
}
}
+ void shrq_i8r(int imm, RegisterID dst)
+ {
+ // ### doesn't work when removing the "0 &&"
+ if (0 && imm == 1)
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
+ else {
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+ void shlq_i8r(int imm, RegisterID dst)
+ {
+ // ### doesn't work when removing the "0 &&"
+ if (0 && imm == 1)
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
+ else {
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
+
#endif
void sarl_i8r(int imm, RegisterID dst)
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
index 0494873738..81063e2b11 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -116,8 +116,10 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = {
OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg),
OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision),
OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision),
+ OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVLDRVSTR),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVADDVSUB),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink),
@@ -577,7 +579,7 @@ const char* ARMv7DOpcodeMiscAddSubSP::format()
appendSeparator();
appendRegisterName(RegSP);
appendSeparator();
- appendUnsignedImmediate(immediate7());
+ appendUnsignedImmediate(immediate7() << 2);
return m_formatBuffer;
}
@@ -1561,6 +1563,45 @@ const char* ARMv7DOpcodeVMSR::format()
return m_formatBuffer;
}
+const char* ARMv7DOpcodeVADDVSUB::format()
+{
+ char regPrefix = sz() ? 'd' : 's';
+ if (isSub())
+ appendInstructionName("vsub");
+ else
+ appendInstructionName("vadd");
+ appendFPRegisterName(regPrefix, vd());
+ appendSeparator();
+ appendFPRegisterName(regPrefix, vn());
+ appendSeparator();
+ appendFPRegisterName(regPrefix, vm());
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeVLDRVSTR::format()
+{
+ appendInstructionName(opName());
+
+ char regPrefix = sz() ? 'd' : 's';
+ appendFPRegisterName(regPrefix, vd());
+
+ appendSeparator();
+ appendCharacter('[');
+ appendRegisterName(rn());
+
+ if (immediate8() || !uBit()) {
+ appendSeparator();
+ if (uBit())
+ appendUnsignedImmediate(immediate8() << 2);
+ else
+ appendSignedImmediate(0 - static_cast<int>(immediate8() << 2));
+ }
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
} } // namespace JSC::ARMv7Disassembler
#endif // #if USE(ARMV7_DISASSEMBLER)
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
index 0b84842590..ca5f955ba1 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
@@ -1098,7 +1098,7 @@ protected:
unsigned op() { return (m_opcode >> 20) & 0x1; }
unsigned rt2() { return (m_opcode >> 16) & 0xf; }
- unsigned rt() { return (m_opcode >> 16) & 0xf; }
+ unsigned rt() { return (m_opcode >> 12) & 0xf; }
unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
};
@@ -1132,6 +1132,42 @@ protected:
unsigned rt() { return (m_opcode >> 12) & 0xf; }
};
+class ARMv7DOpcodeVADDVSUB : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0xffb00e50;
+ static const uint32_t s_pattern = 0xee300a00;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVADDVSUB, thisObj);
+
+protected:
+ const char* format();
+
+ unsigned sz() { return (m_opcode >> 8) & 0x1; }
+ unsigned isSub() { return (m_opcode >> 6) & 0x1; }
+ unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
+ unsigned vn() { return ((m_opcode >> 16) & 0xf) | ((m_opcode >> 3) & 0x10); }
+ unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
+};
+
+class ARMv7DOpcodeVLDRVSTR : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0xff200a00;
+ static const uint32_t s_pattern = 0xed000a00;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVLDRVSTR, thisObj);
+
+protected:
+ const char* format();
+
+ const char *opName() { return op() ? "vldr" : "vstr"; }
+
+ unsigned sz() { return (m_opcode >> 8) & 0x1; }
+ unsigned op() { return (m_opcode >> 20) & 0x1; }
+ unsigned uBit() { return (m_opcode >> 23) & 0x1; }
+ unsigned rn() { return (m_opcode >> 16) & 0xf; }
+ unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
+ unsigned immediate8() { return m_opcode & 0xff; }
+};
} } // namespace JSC::ARMv7Disassembler
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index aa6acc9094..34c2e9f8de 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -1,19 +1,5 @@
-wince*: CONFIG += disable_jit
-ios: CONFIG += disable_jit
-if(win*:isEqual(QT_ARCH, "x86_64")): CONFIG += disable_jit
-equals(ANDROID_TARGET_ARCH, armeabi): CONFIG += disable_jit
-
-disable_jit: DEFINES += ENABLE_YARR_JIT=0
-else: DEFINES += V4_ENABLE_JIT ENABLE_YARR_JIT=1
-
-# On Qt/Android/ARM release builds are thumb and debug builds arm,
-# but we'll force the JIT to always generate thumb2
-contains(DEFINES, V4_ENABLE_JIT):android:isEqual(QT_ARCH, "arm") {
- DEFINES += WTF_CPU_ARM_THUMB2
-}
-
DEFINES += WTF_EXPORT_PRIVATE="" JS_EXPORT_PRIVATE=""
win*: DEFINES += NOMINMAX
@@ -22,11 +8,8 @@ DEFINES += ENABLE_LLINT=0
DEFINES += ENABLE_DFG_JIT=0
DEFINES += ENABLE_DFG_JIT_UTILITY_METHODS=1
DEFINES += ENABLE_JIT_CONSTANT_BLINDING=0
-DEFINES += ENABLE_ASSEMBLER=1
DEFINES += BUILDING_QT__
-DEFINES += ENABLE_JIT=1
-
INCLUDEPATH += $$PWD/jit
INCLUDEPATH += $$PWD/assembler
INCLUDEPATH += $$PWD/runtime
@@ -47,3 +30,5 @@ INCLUDEPATH += $$PWD/disassembler/udis86
INCLUDEPATH += $$_OUT_PWD
win32-msvc2008|wince*: INCLUDEPATH += $$PWD/stubs/compat
+
+CONFIG(release, debug|release): DEFINES += NDEBUG
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index 63537f26d5..d7b315602e 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -1,11 +1,6 @@
-contains(DEFINES, V4_ENABLE_JIT) {
- HEADERS += $$PWD/assembler/*.h
- SOURCES += $$PWD/assembler/ARMAssembler.cpp
- SOURCES += $$PWD/assembler/ARMv7Assembler.cpp
- SOURCES += $$PWD/assembler/MacroAssemblerARM.cpp
- SOURCES += $$PWD/assembler/MacroAssemblerSH4.cpp
- SOURCES += $$PWD/assembler/LinkBuffer.cpp
-}
+HEADERS += $$PWD/assembler/*.h
+SOURCES += $$PWD/assembler/ARMv7Assembler.cpp
+SOURCES += $$PWD/assembler/LinkBuffer.cpp
HEADERS += $$PWD/wtf/*.h
SOURCES += $$PWD/wtf/PrintStream.cpp
diff --git a/src/3rdparty/masm/stubs/WTFStubs.cpp b/src/3rdparty/masm/stubs/WTFStubs.cpp
index e299a54143..dff692fd67 100644
--- a/src/3rdparty/masm/stubs/WTFStubs.cpp
+++ b/src/3rdparty/masm/stubs/WTFStubs.cpp
@@ -109,8 +109,9 @@ void dataLogFString(const char* str)
extern "C" {
-void WTFReportAssertionFailure(const char* /*file*/, int /*line*/, const char* /*function*/, const char* /*assertion*/)
+void WTFReportAssertionFailure(const char* file, int line, const char* function, const char*assertion)
{
+ fprintf(stderr, "WTF failing assertion in %s, line %d, function %s: %s\n", file, line, function, assertion);
}
void WTFReportBacktrace()
diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h
index b08ee678e7..600a9c7148 100644
--- a/src/3rdparty/masm/wtf/MathExtras.h
+++ b/src/3rdparty/masm/wtf/MathExtras.h
@@ -123,6 +123,7 @@ inline bool signbit(double x) { struct ieee_double *p = (struct ieee_double *)&x
#if COMPILER(MSVC)
+#if _MSC_VER < 1800
// We must not do 'num + 0.5' or 'num - 0.5' because they can cause precision loss.
static double round(double num)
{
@@ -138,6 +139,7 @@ static float roundf(float num)
return integer - num > 0.5f ? integer - 1.0f : integer;
return integer - num >= 0.5f ? integer - 1.0f : integer;
}
+#endif
inline long long llround(double num) { return static_cast<long long>(round(num)); }
inline long long llroundf(float num) { return static_cast<long long>(roundf(num)); }
inline long lround(double num) { return static_cast<long>(round(num)); }
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index b8402a991f..c81a9fe40f 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -28,6 +28,10 @@
#ifndef WTF_Platform_h
#define WTF_Platform_h
+#if defined(__cplusplus)
+#include <private/qv4global_p.h>
+#endif
+
/* Include compiler specific macros */
#include <wtf/Compiler.h>
@@ -767,7 +771,8 @@
#endif
/* If the jit is not available, enable the LLInt C Loop: */
-#if !ENABLE(JIT)
+/* Not for Qml. We have our own interpreter. */
+#if 0 /* !ENABLE(JIT) */
#undef ENABLE_LLINT /* Undef so that we can redefine it. */
#undef ENABLE_LLINT_C_LOOP /* Undef so that we can redefine it. */
#undef ENABLE_DFG_JIT /* Undef so that we can redefine it. */
@@ -778,7 +783,7 @@
/* Do a sanity check to make sure that we at least have one execution engine in
use: */
-#if !(ENABLE(JIT) || ENABLE(LLINT))
+#if 0 /* !(ENABLE(JIT) || ENABLE(LLINT)) */
#error You have to have at least one execution model enabled to build JSC
#endif
diff --git a/src/imports/dialogs/dialogs.pro b/src/imports/dialogs/dialogs.pro
index 8db3d9ab58..e6ca7a2147 100644
--- a/src/imports/dialogs/dialogs.pro
+++ b/src/imports/dialogs/dialogs.pro
@@ -37,7 +37,7 @@ HEADERS += \
qquickfontdialog_p.h \
qquickabstractdialog_p.h
-QML_FILES += \
+DIALOGS_QML_FILES += \
DefaultMessageDialog.qml \
WidgetMessageDialog.qml \
DefaultFileDialog.qml \
@@ -69,4 +69,29 @@ QML_FILES += \
QT += quick-private gui gui-private core core-private qml
+# Create the resource file
+GENERATED_RESOURCE_FILE = $$OUT_PWD/dialogs.qrc
+
+RESOURCE_CONTENT = \
+ "<RCC>" \
+ "<qresource prefix=\"/QtQuick/Dialogs\">"
+
+for(resourcefile, DIALOGS_QML_FILES) {
+ resourcefileabsolutepath = $$absolute_path($$resourcefile)
+ relativepath_in = $$relative_path($$resourcefileabsolutepath, $$_PRO_FILE_PWD_)
+ relativepath_out = $$relative_path($$resourcefileabsolutepath, $$OUT_PWD)
+ RESOURCE_CONTENT += "<file alias=\"$$relativepath_in\">$$relativepath_out</file>"
+}
+
+RESOURCE_CONTENT += \
+ "</qresource>" \
+ "</RCC>"
+
+write_file($$GENERATED_RESOURCE_FILE, RESOURCE_CONTENT)|error("Aborting.")
+
+RESOURCES += $$GENERATED_RESOURCE_FILE
+
+# In case of a debug build, deploy the QML files too
+CONFIG(debug, debug|release): QML_FILES += $$DIALOGS_QML_FILES
+
load(qml_plugin)
diff --git a/src/imports/dialogs/plugin.cpp b/src/imports/dialogs/plugin.cpp
index e62e4efa34..1c852abae9 100644
--- a/src/imports/dialogs/plugin.cpp
+++ b/src/imports/dialogs/plugin.cpp
@@ -58,11 +58,12 @@
#include <qpa/qplatformintegration.h>
//#define PURE_QML_ONLY
+//#define DEBUG_REGISTRATION
QT_BEGIN_NAMESPACE
/*!
- \qmlmodule QtQuick.Dialogs 1
+ \qmlmodule QtQuick.Dialogs 1.1
\title Qt Quick Dialogs QML Types
\ingroup qmlmodules
\brief Provides QML types for standard file, color picker and message dialogs
@@ -82,24 +83,39 @@ class QtQuick2DialogsPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
public:
- QtQuick2DialogsPlugin() : QQmlExtensionPlugin() { }
+ QtQuick2DialogsPlugin() : QQmlExtensionPlugin(), m_useResources(true) { }
- virtual void initializeEngine(QQmlEngine *engine, const char * /*uri*/) {
- //qDebug() << Q_FUNC_INFO << uri << m_decorationComponentUrl;
+ virtual void initializeEngine(QQmlEngine *engine, const char * uri) {
+#ifdef DEBUG_REGISTRATION
+ qDebug() << Q_FUNC_INFO << uri << m_decorationComponentUrl;
+#else
+ Q_UNUSED(uri)
+#endif
QQuickAbstractDialog::m_decorationComponent =
new QQmlComponent(engine, m_decorationComponentUrl, QQmlComponent::Asynchronous);
}
virtual void registerTypes(const char *uri) {
+#ifdef DEBUG_REGISTRATION
+ qDebug() << Q_FUNC_INFO << uri;
+#endif
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Dialogs"));
bool hasTopLevelWindows = QGuiApplicationPrivate::platformIntegration()->
hasCapability(QPlatformIntegration::MultipleWindows);
QDir qmlDir(baseUrl().toLocalFile());
- m_decorationComponentUrl = QUrl::fromLocalFile(qmlDir.filePath(QString("qml/DefaultWindowDecoration.qml")));
QDir widgetsDir(baseUrl().toLocalFile());
// TODO: find the directory by searching rather than assuming a relative path
widgetsDir.cd("../PrivateWidgets");
+ // If at least one file was actually installed, then use installed qml files instead of resources.
+ // This makes debugging and incremental development easier, whereas the "normal" installation
+ // uses resources to save space and cut down on the number of files to deploy.
+ if (qmlDir.exists(QString("DefaultFileDialog.qml")))
+ m_useResources = false;
+ m_decorationComponentUrl = m_useResources ?
+ QUrl("qrc:/QtQuick/Dialogs/qml/DefaultWindowDecoration.qml") :
+ QUrl::fromLocalFile(qmlDir.filePath(QString("qml/DefaultWindowDecoration.qml")));
+
// Prefer the QPA dialog helpers if the platform supports them.
// Else if there is a QWidget-based implementation, check whether it's
// possible to instantiate it from Qt Quick.
@@ -143,8 +159,9 @@ protected:
template <class WrapperType>
void registerWidgetOrQmlImplementation(QDir widgetsDir, QDir qmlDir,
const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor) {
- //qDebug() << Q_FUNC_INFO << qmlDir << qmlName << uri;
- bool needQml = true;
+ // qDebug() << "QtQuick2DialogsPlugin::registerWidgetOrQmlImplementation" << uri << qmlName << ": QML in" << qmlDir.absolutePath()
+ // << "using resources?" << m_useResources << "; widgets in" << widgetsDir.absolutePath();
+ bool needQmlImplementation = true;
#ifdef PURE_QML_ONLY
Q_UNUSED(widgetsDir)
@@ -154,22 +171,32 @@ protected:
// widget-free QGuiApplication), assume that the widget-based dialog will work.
if (hasTopLevelWindows && widgetsDir.exists("qmldir") &&
!qstrcmp(QCoreApplication::instance()->metaObject()->className(), "QApplication")) {
- QString dialogQmlPath = qmlDir.filePath(QString("Widget%1.qml").arg(qmlName));
- if (qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, versionMajor, versionMinor, qmlName) >= 0)
- needQml = false;
- // qDebug() << "registering" << qmlName << " as " << dialogQmlPath << "success?" << !needQml;
+ QUrl dialogQmlPath = m_useResources ?
+ QUrl(QString("qrc:/QtQuick/Dialogs/Widget%1.qml").arg(qmlName)) :
+ QUrl::fromLocalFile(qmlDir.filePath(QString("Widget%1.qml").arg(qmlName)));
+ if (qmlRegisterType(dialogQmlPath, uri, versionMajor, versionMinor, qmlName) >= 0) {
+ needQmlImplementation = false;
+#ifdef DEBUG_REGISTRATION
+ qDebug() << " registering" << qmlName << " as " << dialogQmlPath << "success?" << !needQmlImplementation;
+#endif
+ }
}
#endif
- if (needQml) {
+ if (needQmlImplementation) {
QByteArray abstractTypeName = QByteArray("Abstract") + qmlName;
qmlRegisterType<WrapperType>(uri, versionMajor, versionMinor, abstractTypeName); // implementation wrapper
- QString dialogQmlPath = qmlDir.filePath(QString("Default%1.qml").arg(qmlName));
- // qDebug() << "registering" << qmlName << " as " << dialogQmlPath << "success?" <<
- qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, versionMajor, versionMinor, qmlName);
+ QUrl dialogQmlPath = m_useResources ?
+ QUrl(QString("qrc:/QtQuick/Dialogs/Default%1.qml").arg(qmlName)) :
+ QUrl::fromLocalFile(qmlDir.filePath(QString("Default%1.qml").arg(qmlName)));
+#ifdef DEBUG_REGISTRATION
+ qDebug() << " registering" << qmlName << " as " << dialogQmlPath << "success?" <<
+#endif
+ qmlRegisterType(dialogQmlPath, uri, versionMajor, versionMinor, qmlName);
}
}
QUrl m_decorationComponentUrl;
+ bool m_useResources;
};
QT_END_NAMESPACE
diff --git a/src/imports/dialogs/qmldir b/src/imports/dialogs/qmldir
index df9a035ade..b4ae1a059c 100644
--- a/src/imports/dialogs/qmldir
+++ b/src/imports/dialogs/qmldir
@@ -1,3 +1,4 @@
module QtQuick.Dialogs
plugin dialogplugin
+classname QtQuick2DialogsPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/dialogs/qquickabstractdialog.cpp b/src/imports/dialogs/qquickabstractdialog.cpp
index 17f8d1aef2..633e5b7269 100644
--- a/src/imports/dialogs/qquickabstractdialog.cpp
+++ b/src/imports/dialogs/qquickabstractdialog.cpp
@@ -92,7 +92,8 @@ void QQuickAbstractDialog::setVisible(bool v)
if (!m_dialogWindow) {
m_contentItem = qobject_cast<QQuickItem *>(m_qmlImplementation);
if (m_contentItem) {
- m_dialogWindow = m_contentItem->window();
+ if (m_hasNativeWindows)
+ m_dialogWindow = m_contentItem->window();
// An Item-based dialog implementation doesn't come with a window, so
// we have to instantiate one iff the platform allows it.
if (!m_dialogWindow && m_hasNativeWindows) {
@@ -163,6 +164,8 @@ void QQuickAbstractDialog::decorationLoaded()
{
bool ok = false;
QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ while (parentItem->parentItem() && !parentItem->parentItem()->inherits("QQuickRootItem"))
+ parentItem = parentItem->parentItem();
if (m_decorationComponent->isError()) {
qWarning() << m_decorationComponent->errors();
} else {
diff --git a/src/imports/folderlistmodel/qmldir b/src/imports/folderlistmodel/qmldir
index b5247d75f8..1865845078 100644
--- a/src/imports/folderlistmodel/qmldir
+++ b/src/imports/folderlistmodel/qmldir
@@ -1,3 +1,4 @@
module Qt.labs.folderlistmodel
plugin qmlfolderlistmodelplugin
+classname QmlFolderListModelPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 032c32a241..7cab257d32 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -193,9 +193,11 @@ void QQuickFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &li
Q_Q(QQuickFolderListModel);
QModelIndex parent;
- q->beginRemoveRows(parent, 0, data.size()-1);
- data.clear();
- q->endRemoveRows();
+ if (data.size() > 0) {
+ q->beginRemoveRows(parent, 0, data.size()-1);
+ data.clear();
+ q->endRemoveRows();
+ }
q->beginInsertRows(parent, 0, list.size()-1);
data = list;
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 84bcb756e8..2b3ef34d4c 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -186,7 +186,9 @@ static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
{
- QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+ QString databasesPath = qmlsqldatabase_databasesPath(engine);
+ if (!QDir().mkpath(databasesPath))
+ qWarning() << "LocalStorage: can't create path - " << databasesPath;
}
static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
@@ -322,6 +324,35 @@ static ReturnedValue qmlsqldatabase_executeSql(SimpleCallContext *ctx)
return result.asReturnedValue();
}
+struct TransactionRollback {
+ QSqlDatabase *db;
+ bool *inTransactionFlag;
+
+ TransactionRollback(QSqlDatabase *database, bool *transactionFlag)
+ : db(database)
+ , inTransactionFlag(transactionFlag)
+ {
+ if (inTransactionFlag)
+ *inTransactionFlag = true;
+ }
+
+ ~TransactionRollback()
+ {
+ if (inTransactionFlag)
+ *inTransactionFlag = false;
+ if (db)
+ db->rollback();
+ }
+
+ void clear() {
+ db = 0;
+ if (inTransactionFlag)
+ *inTransactionFlag = false;
+ inTransactionFlag = 0;
+ }
+};
+
+
static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
{
if (ctx->callData->argc < 2)
@@ -349,7 +380,6 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
w->type = QQmlSqlDatabaseWrapper::Query;
w->database = db;
w->version = r->version;
- w->inTransaction = true;
bool ok = true;
if (!!callback) {
@@ -359,12 +389,10 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
ScopedCallData callData(scope, 1);
callData->thisObject = engine->global();
callData->args[0] = w;
- try {
- callback->call(callData);
- } catch (...) {
- db.rollback();
- ctx->rethrowException();
- }
+
+ TransactionRollback rollbackOnException(&db, &w->inTransaction);
+ callback->call(callData);
+ rollbackOnException.clear();
if (!db.commit()) {
db.rollback();
V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed"));
@@ -373,8 +401,6 @@ static ReturnedValue qmlsqldatabase_changeVersion(SimpleCallContext *ctx)
}
}
- w->inTransaction = false;
-
if (ok) {
w->version = to_version;
#ifndef QT_NO_SETTINGS
@@ -408,22 +434,15 @@ static ReturnedValue qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, b
w->database = db;
w->version = r->version;
w->readonly = readOnly;
- w->inTransaction = true;
db.transaction();
if (callback) {
ScopedCallData callData(scope, 1);
callData->thisObject = engine->global();
callData->args[0] = w;
- try {
- callback->call(callData);
- } catch (...) {
- w->inTransaction = false;
- db.rollback();
- ctx->rethrowException();
- }
-
- w->inTransaction = false;
+ TransactionRollback rollbackOnException(&db, &w->inTransaction);
+ callback->call(callData);
+ rollbackOnException.clear();
if (!db.commit())
db.rollback();
diff --git a/src/imports/localstorage/qmldir b/src/imports/localstorage/qmldir
index a6c43a4fe5..dd14cc6244 100644
--- a/src/imports/localstorage/qmldir
+++ b/src/imports/localstorage/qmldir
@@ -1,3 +1,4 @@
module QtQuick.LocalStorage
plugin qmllocalstorageplugin
+classname QQmlLocalStoragePlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/models/qmldir b/src/imports/models/qmldir
index 9cad5ef734..4afbe5de33 100644
--- a/src/imports/models/qmldir
+++ b/src/imports/models/qmldir
@@ -1,2 +1,3 @@
module QtQml.Models
plugin modelsplugin
+classname QtQmlModelsPlugin
diff --git a/src/imports/particles/qmldir b/src/imports/particles/qmldir
index 7ee72a5ed9..1f17baadc0 100644
--- a/src/imports/particles/qmldir
+++ b/src/imports/particles/qmldir
@@ -1,3 +1,4 @@
module QtQuick.Particles
plugin particlesplugin
+classname QtQuick2ParticlesPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/qtquick2/qmldir b/src/imports/qtquick2/qmldir
index 18bde65357..4a79c82e76 100644
--- a/src/imports/qtquick2/qmldir
+++ b/src/imports/qtquick2/qmldir
@@ -1,3 +1,4 @@
module QtQuick
plugin qtquick2plugin
+classname QtQuick2Plugin
typeinfo plugins.qmltypes
diff --git a/src/imports/settings/qmldir b/src/imports/settings/qmldir
index 0d68a0742c..93d8e6719d 100644
--- a/src/imports/settings/qmldir
+++ b/src/imports/settings/qmldir
@@ -1,3 +1,4 @@
module Qt.labs.settings
plugin qmlsettingsplugin
+classname QmlSettingsPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir
index bba0e741a3..9da8ebb4be 100644
--- a/src/imports/testlib/qmldir
+++ b/src/imports/testlib/qmldir
@@ -1,5 +1,6 @@
module QtTest
plugin qmltestplugin
+classname QTestQmlModule
typeinfo plugins.qmltypes
TestCase 1.0 TestCase.qml
SignalSpy 1.0 SignalSpy.qml
diff --git a/src/imports/testlib/signalspy.qdoc b/src/imports/testlib/signalspy.qdoc
index 0bb1569190..d6f8621c23 100644
--- a/src/imports/testlib/signalspy.qdoc
+++ b/src/imports/testlib/signalspy.qdoc
@@ -42,6 +42,7 @@
/*!
\qmltype SignalSpy
\instantiates SignalSpy
+ \inqmlmodule QtTest
\brief Enables introspection of signal emission
\ingroup qtquick-utility
\since 4.8
diff --git a/src/imports/testlib/testcase.qdoc b/src/imports/testlib/testcase.qdoc
index dd1d9e5ad3..4506209f8e 100644
--- a/src/imports/testlib/testcase.qdoc
+++ b/src/imports/testlib/testcase.qdoc
@@ -42,6 +42,7 @@
/*!
\qmltype TestCase
\instantiates TestCase
+ \inqmlmodule QtTest
\brief Represents a unit test case
\ingroup qtquick-utility
\since 4.8
diff --git a/src/imports/widgets/qmldir b/src/imports/widgets/qmldir
index 16c84424f2..da63c98e61 100644
--- a/src/imports/widgets/qmldir
+++ b/src/imports/widgets/qmldir
@@ -1,3 +1,4 @@
module QtQuick.PrivateWidgets
plugin widgetsplugin
+classname QtQuick2PrivateWidgetsPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/window/qmldir b/src/imports/window/qmldir
index 1a11cca3c2..c9d1e5ace3 100644
--- a/src/imports/window/qmldir
+++ b/src/imports/window/qmldir
@@ -1,3 +1,4 @@
module QtQuick.Window
plugin windowplugin
+classname QtQuick2WindowPlugin
typeinfo plugins.qmltypes
diff --git a/src/imports/xmllistmodel/qmldir b/src/imports/xmllistmodel/qmldir
index 390117111d..d6c10c5c2a 100644
--- a/src/imports/xmllistmodel/qmldir
+++ b/src/imports/xmllistmodel/qmldir
@@ -1,3 +1,4 @@
module QtQuick.XmlListModel
plugin qmlxmllistmodelplugin
+classname QmlXmlListModelPlugin
typeinfo plugins.qmltypes
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index c550ef8f20..fa828d7b63 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -204,7 +204,7 @@ static const char vertexShaderCode[] =
"}\n";
static const char fragmentShaderCode[] =
- "uniform sampler2D texture;\n"
+ "uniform sampler2D _qt_texture;\n"
"uniform lowp float qt_Opacity;\n"
"\n"
"#if defined(SPRITE)\n"
@@ -224,21 +224,21 @@ static const char fragmentShaderCode[] =
"\n"
"void main() {\n"
"#if defined(SPRITE)\n"
- " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
+ " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), tt.y)\n"
" * fColor\n"
" * texture2D(colortable, tt)\n"
" * qt_Opacity;\n"
"#elif defined(TABLE)\n"
- " gl_FragColor = texture2D(texture, fTex)\n"
+ " gl_FragColor = texture2D(_qt_texture, fTex)\n"
" * fColor\n"
" * texture2D(colortable, tt)\n"
" * qt_Opacity;\n"
"#elif defined(DEFORM)\n"
- " gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
+ " gl_FragColor = (texture2D(_qt_texture, fTex)) * fColor * qt_Opacity;\n"
"#elif defined(COLOR)\n"
- " gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
+ " gl_FragColor = (texture2D(_qt_texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
"#else\n"
- " gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
+ " gl_FragColor = texture2D(_qt_texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
"#endif\n"
"}\n";
@@ -296,7 +296,7 @@ public:
void initialize() {
QSGSimpleMaterialShader<TabledMaterialData>::initialize();
program()->bind();
- program()->setUniformValue("texture", 0);
+ program()->setUniformValue("_qt_texture", 0);
program()->setUniformValue("colortable", 1);
glFuncs = QOpenGLContext::currentContext()->functions();
m_timestamp_id = program()->uniformLocation("timestamp");
@@ -358,7 +358,7 @@ public:
void initialize() {
QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
program()->bind();
- program()->setUniformValue("texture", 0);
+ program()->setUniformValue("_qt_texture", 0);
glFuncs = QOpenGLContext::currentContext()->functions();
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
@@ -409,7 +409,7 @@ public:
void initialize() {
QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
program()->bind();
- program()->setUniformValue("texture", 0);
+ program()->setUniformValue("_qt_texture", 0);
program()->setUniformValue("colortable", 1);
glFuncs = QOpenGLContext::currentContext()->functions();
//Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations.
@@ -488,7 +488,7 @@ public:
void initialize() {
QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
program()->bind();
- program()->setUniformValue("texture", 0);
+ program()->setUniformValue("_qt_texture", 0);
glFuncs = QOpenGLContext::currentContext()->functions();
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
@@ -552,7 +552,7 @@ public:
void initialize() {
QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
program()->bind();
- program()->setUniformValue("texture", 0);
+ program()->setUniformValue("_qt_texture", 0);
glFuncs = QOpenGLContext::currentContext()->functions();
m_timestamp_id = program()->uniformLocation("timestamp");
m_entry_id = program()->uniformLocation("entry");
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 3a1af30b88..df4f5e8dc3 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -14,7 +14,8 @@ HEADERS += \
$$PWD/qv4isel_util_p.h \
$$PWD/qv4ssa_p.h \
$$PWD/qv4regalloc_p.h \
- $$PWD/qqmlcodegenerator_p.h
+ $$PWD/qqmlcodegenerator_p.h \
+ $$PWD/qv4isel_masm_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
@@ -26,11 +27,7 @@ SOURCES += \
$$PWD/qv4jsir.cpp \
$$PWD/qv4ssa.cpp \
$$PWD/qv4regalloc.cpp \
- $$PWD/qqmlcodegenerator.cpp
-
-contains(DEFINES, V4_ENABLE_JIT) {
- HEADERS += $$PWD/qv4isel_masm_p.h
- SOURCES += $$PWD/qv4isel_masm.cpp
-}
+ $$PWD/qqmlcodegenerator.cpp \
+ $$PWD/qv4isel_masm.cpp
include(../../3rdparty/masm/masm.pri)
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index fb2ca7c14e..2aa5aa5a3c 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -118,6 +118,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
output->program = program;
qSwap(_imports, output->imports);
+ qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
@@ -140,9 +141,6 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
return false;
}
- // Reserve space for pseudo context-scope function
- _functions << program;
-
AST::UiObjectDefinition *rootObject = AST::cast<AST::UiObjectDefinition*>(program->members->member);
Q_ASSERT(rootObject);
output->indexOfRootObject = defineQMLObject(rootObject);
@@ -150,6 +148,7 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
collectTypeReferences();
qSwap(_imports, output->imports);
+ qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
qSwap(_functions, output->functions);
qSwap(_typeReferences, output->typeReferences);
@@ -406,6 +405,11 @@ bool QQmlCodeGenerator::visit(AST::UiImport *node)
error.setColumn(node->importIdToken.startColumn);
errors << error;
return false;
+ } else {
+ // For backward compatibility in how the imports are loaded we
+ // must otherwise initialize the major and minor version to -1.
+ import->majorVersion = -1;
+ import->minorVersion = -1;
}
import->location.line = node->importToken.startLine;
@@ -418,9 +422,38 @@ bool QQmlCodeGenerator::visit(AST::UiImport *node)
return false;
}
-bool QQmlCodeGenerator::visit(AST::UiPragma *ast)
+bool QQmlCodeGenerator::visit(AST::UiPragma *node)
{
- return true;
+ Pragma *pragma = New<Pragma>();
+
+ // For now the only valid pragma is Singleton, so lets validate the input
+ if (!node->pragmaType->name.isNull())
+ {
+ if (QLatin1String("Singleton") == node->pragmaType->name)
+ {
+ pragma->type = Pragma::PragmaSingleton;
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ error.setLine(node->pragmaToken.startLine);
+ error.setColumn(node->pragmaToken.startColumn);
+ errors << error;
+ return false;
+ }
+ } else {
+ QQmlError error;
+ error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ error.setLine(node->pragmaToken.startLine);
+ error.setColumn(node->pragmaToken.startColumn);
+ errors << error;
+ return false;
+ }
+
+ pragma->location.line = node->pragmaToken.startLine;
+ pragma->location.column = node->pragmaToken.startColumn;
+ _pragmas.append(pragma);
+
+ return false;
}
static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
@@ -1028,7 +1061,7 @@ bool QQmlCodeGenerator::isStatementNodeScript(AST::Statement *statement)
return true;
}
-QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices)
{
jsUnitGenerator = &output.jsGenerator;
const QmlObject *rootObject = output.objects.at(output.indexOfRootObject);
@@ -1107,7 +1140,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
for (Function *f = o->functions->first; f; f = f->next)
- *functionsTable++ = f->index;
+ *functionsTable++ = runtimeFunctionIndices[f->index];
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
for (QmlProperty *p = o->properties->first; p; p = p->next) {
@@ -1120,6 +1153,8 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
for (Binding *b = o->bindings->first; b; b = b->next) {
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
+ if (b->type == QV4::CompiledData::Binding::Type_Script)
+ bindingToWrite->value.compiledScriptIndex = runtimeFunctionIndices[b->value.compiledScriptIndex];
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
@@ -1147,6 +1182,14 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(ParsedQML &output)
objectPtr += signalTableSize;
}
+ // enable flag if we encountered pragma Singleton
+ foreach (Pragma *p, output.pragmas) {
+ if (p->type == Pragma::PragmaSingleton) {
+ qmlUnit->header.flags |= QV4::CompiledData::Unit::IsSingleton;
+ break;
+ }
+ }
+
return qmlUnit;
}
@@ -1155,30 +1198,37 @@ int QmlUnitGenerator::getStringId(const QString &str) const
return jsUnitGenerator->getStringId(str);
}
-void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output)
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output)
+{
+ return generateJSCodeForFunctionsAndBindings(fileName, output->code, &output->jsModule, &output->jsParserEngine,
+ output->program, output->functions);
+}
+
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
+ QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions)
{
- _module = &output->jsModule;
+ QVector<int> runtimeFunctionIndices(functions.size());
+ _module = jsModule;
_module->setFileName(fileName);
- QmlScanner scan(this, output->code);
- scan.begin(output->program);
- foreach (AST::Node *node, output->functions) {
- if (node == output->program)
- continue;
+ QmlScanner scan(this, sourceCode);
+ scan.begin(qmlRoot, QmlBinding);
+ foreach (AST::Node *node, functions) {
+ Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
- scan.enterEnvironment(node);
+ scan.enterEnvironment(node, function ? FunctionCode : QmlBinding);
scan(function ? function->body : node);
scan.leaveEnvironment();
}
scan.end();
_env = 0;
- _function = defineFunction(QString("context scope"), output->program, 0, 0, QmlBinding);
+ _function = _module->functions.at(defineFunction(QString("context scope"), qmlRoot, 0, 0));
- foreach (AST::Node *node, output->functions) {
- if (node == output->program)
- continue;
+ for (int i = 0; i < functions.count(); ++i) {
+ AST::Node *node = functions.at(i);
+ Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
@@ -1193,26 +1243,34 @@ void JSCodeGen::generateJSCodeForFunctionsAndBindings(const QString &fileName, P
body = function->body ? function->body->elements : 0;
else {
// Synthesize source elements.
- QQmlJS::MemoryPool *pool = output->jsParserEngine.pool();
- AST::SourceElement *element = new (pool) AST::StatementSourceElement(static_cast<AST::Statement*>(node));
- body = new (output->jsParserEngine.pool()) AST::SourceElements(element);
+ QQmlJS::MemoryPool *pool = jsEngine->pool();
+
+ AST::Statement *stmt = node->statementCast();
+ if (!stmt) {
+ Q_ASSERT(node->expressionCast());
+ AST::ExpressionNode *expr = node->expressionCast();
+ stmt = new (pool) AST::ExpressionStatement(expr);
+ }
+ AST::SourceElement *element = new (pool) AST::StatementSourceElement(stmt);
+ body = new (pool) AST::SourceElements(element);
body = body->finish();
}
- defineFunction(name, node,
- function ? function->formals : 0,
- body, function ? FunctionCode : QmlBinding);
-
+ int idx = defineFunction(name, node,
+ function ? function->formals : 0,
+ body);
+ runtimeFunctionIndices[i] = idx;
}
qDeleteAll(_envMap);
_envMap.clear();
+ return runtimeFunctionIndices;
}
-void JSCodeGen::QmlScanner::begin(AST::Node *rootNode)
+void JSCodeGen::QmlScanner::begin(AST::Node *rootNode, CompilationMode compilationMode)
{
- enterEnvironment(0);
+ enterEnvironment(0, compilationMode);
enterFunction(rootNode, "context scope", 0, 0, 0, /*isExpression*/false);
}
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index ec75c38160..8de08a81d1 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -127,12 +127,13 @@ struct QmlProperty : public QV4::CompiledData::Property
struct Binding : public QV4::CompiledData::Binding
{
+ // Binding's compiledScriptIndex is index in parsedQML::functions
Binding *next;
};
struct Function
{
- int index;
+ int index; // index in parsedQML::functions
Function *next;
};
@@ -153,6 +154,16 @@ struct QmlObject
void dump(DebugStream &out);
};
+struct Pragma
+{
+ enum PragmaType {
+ PragmaSingleton = 0x1
+ };
+ quint32 type;
+
+ QV4::CompiledData::Location location;
+};
+
struct ParsedQML
{
ParsedQML()
@@ -162,6 +173,7 @@ struct ParsedQML
QQmlJS::Engine jsParserEngine;
V4IR::Module jsModule;
QList<QV4::CompiledData::Import*> imports;
+ QList<Pragma*> pragmas;
AST::UiProgram *program;
int indexOfRootObject;
QList<QmlObject*> objects;
@@ -252,6 +264,7 @@ public:
QList<QQmlError> errors;
QList<QV4::CompiledData::Import*> _imports;
+ QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
QList<AST::Node*> _functions;
@@ -276,7 +289,7 @@ struct Q_QML_EXPORT QmlUnitGenerator
{
}
- QV4::CompiledData::QmlUnit *generate(ParsedQML &output);
+ QV4::CompiledData::QmlUnit *generate(ParsedQML &output, const QVector<int> &runtimeFunctionIndices);
private:
int getStringId(const QString &str) const;
@@ -335,23 +348,24 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
: QQmlJS::Codegen(/*strict mode*/false)
{}
- void generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
+ // Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions
+ QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, ParsedQML *output);
+ QVector<int> generateJSCodeForFunctionsAndBindings(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
+ QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, const QList<AST::Node*> &functions);
private:
struct QmlScanner : public ScanFunctions
{
QmlScanner(JSCodeGen *cg, const QString &sourceCode)
- : ScanFunctions(cg, sourceCode)
+ : ScanFunctions(cg, sourceCode, /*default program mode*/GlobalCode)
, codeGen(cg)
{}
- void begin(AST::Node *rootNode);
+ void begin(AST::Node *rootNode, CompilationMode compilationMode);
void end();
JSCodeGen *codeGen;
};
-
- V4IR::Module jsModule;
};
} // namespace QtQml
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 43756a6f35..a68920235e 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -64,11 +64,12 @@
using namespace QQmlJS;
using namespace AST;
-Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode)
+Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
, _env(0)
, _allowFuncDecls(true)
+ , defaultProgramMode(defaultProgramMode)
{
}
@@ -78,9 +79,9 @@ void Codegen::ScanFunctions::operator()(Node *node)
node->accept(this);
}
-void Codegen::ScanFunctions::enterEnvironment(Node *node)
+void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Environment *e = _cg->newEnvironment(node, _env);
+ Environment *e = _cg->newEnvironment(node, _env, compilationMode);
if (!e->isStrict)
e->isStrict = _cg->_strictMode;
_envStack.append(e);
@@ -146,7 +147,7 @@ void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *paramet
bool Codegen::ScanFunctions::visit(Program *ast)
{
- enterEnvironment(ast);
+ enterEnvironment(ast, defaultProgramMode);
checkDirectivePrologue(ast->elements);
return true;
}
@@ -374,7 +375,7 @@ void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, Forma
wasStrict = _env->isStrict;
}
- enterEnvironment(ast);
+ enterEnvironment(ast, FunctionCode);
checkForArguments(formals);
_env->isNamedFunctionExpression = isExpression && !name.isEmpty();
@@ -404,7 +405,6 @@ Codegen::Codegen(bool strict)
, _exitBlock(0)
, _throwBlock(0)
, _returnAddress(0)
- , _mode(GlobalCode)
, _env(0)
, _loop(0)
, _labelledStatement(0)
@@ -413,11 +413,11 @@ Codegen::Codegen(bool strict)
{
}
-V4IR::Function *Codegen::generateFromProgram(const QString &fileName,
+void Codegen::generateFromProgram(const QString &fileName,
const QString &sourceCode,
Program *node,
V4IR::Module *module,
- Mode mode,
+ CompilationMode mode,
const QStringList &inheritedLocals)
{
assert(node);
@@ -427,38 +427,33 @@ V4IR::Function *Codegen::generateFromProgram(const QString &fileName,
_module->setFileName(fileName);
- ScanFunctions scan(this, sourceCode);
+ ScanFunctions scan(this, sourceCode, mode);
scan(node);
- V4IR::Function *globalCode = defineFunction(QStringLiteral("%entry"), node, 0,
- node->elements, mode, inheritedLocals);
+ defineFunction(QStringLiteral("%entry"), node, 0, node->elements, inheritedLocals);
qDeleteAll(_envMap);
_envMap.clear();
-
- return globalCode;
}
-V4IR::Function *Codegen::generateFromFunctionExpression(const QString &fileName,
- const QString &sourceCode,
- AST::FunctionExpression *ast,
- V4IR::Module *module)
+void Codegen::generateFromFunctionExpression(const QString &fileName,
+ const QString &sourceCode,
+ AST::FunctionExpression *ast,
+ V4IR::Module *module)
{
_module = module;
_module->setFileName(fileName);
_env = 0;
- ScanFunctions scan(this, sourceCode);
+ ScanFunctions scan(this, sourceCode, GlobalCode);
// fake a global environment
- scan.enterEnvironment(0);
+ scan.enterEnvironment(0, FunctionCode);
scan(ast);
scan.leaveEnvironment();
- V4IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+ defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
qDeleteAll(_envMap);
_envMap.clear();
-
- return function;
}
@@ -804,14 +799,9 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
assert(expr.code);
initializer = *expr;
- if (! _env->parent || _function->insideWithOrCatch || _mode == QmlBinding) {
- // it's global code.
- move(_block->NAME(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), initializer);
- } else {
- const int index = _env->findMember(ast->name.toString());
- assert(index != -1);
- move(_block->LOCAL(index, 0), initializer);
- }
+ int initialized = _block->newTemp();
+ move(_block->TEMP(initialized), initializer);
+ move(identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), _block->TEMP(initialized));
}
void Codegen::variableDeclarationList(VariableDeclarationList *ast)
@@ -1344,7 +1334,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
bool Codegen::visit(FunctionExpression *ast)
{
- V4IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+ int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
_expr.code = _block->CLOSURE(function);
return false;
}
@@ -1355,10 +1345,7 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
Environment *e = _env;
V4IR::Function *f = _function;
- if (_mode == QmlBinding)
- return _block->NAME(name, line, col);
-
- while (f && e->parent) {
+ while (f && e->parent && e->compilationMode != QmlBinding) {
if (f->insideWithOrCatch || (f->isNamedExpression && f->name == name))
return _block->NAME(name, line, col);
@@ -1382,7 +1369,7 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
f = f->outer;
}
- if (!e->parent && (!f || !f->insideWithOrCatch) && _mode != EvalCode && _mode != QmlBinding)
+ if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
// global context or with. Lookup by name
@@ -1468,9 +1455,18 @@ bool Codegen::visit(NumericLiteral *ast)
}
struct ObjectPropertyValue {
+ ObjectPropertyValue()
+ : value(0)
+ , getter(-1)
+ , setter(-1)
+ {}
+
V4IR::Expr *value;
- V4IR::Function *getter;
- V4IR::Function *setter;
+ int getter; // index in _module->functions or -1 if not set
+ int setter;
+
+ bool hasGetter() const { return getter >= 0; }
+ bool hasSetter() const { return setter >= 0; }
};
bool Codegen::visit(ObjectLiteral *ast)
@@ -1482,18 +1478,18 @@ bool Codegen::visit(ObjectLiteral *ast)
QString name = propertyName(nv->name);
Result value = expression(nv->value);
ObjectPropertyValue &v = valueMap[name];
- if (v.getter || v.setter || (_function->isStrict && v.value))
+ if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value))
throwSyntaxError(nv->lastSourceLocation(),
QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
valueMap[name].value = *value;
} else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
QString name = propertyName(gs->name);
- V4IR::Function *function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
+ const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
ObjectPropertyValue &v = valueMap[name];
if (v.value ||
- (gs->type == PropertyGetterSetter::Getter && v.getter) ||
- (gs->type == PropertyGetterSetter::Setter && v.setter))
+ (gs->type == PropertyGetterSetter::Getter && v.hasGetter()) ||
+ (gs->type == PropertyGetterSetter::Setter && v.hasSetter()))
throwSyntaxError(gs->lastSourceLocation(),
QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
if (gs->type == PropertyGetterSetter::Getter)
@@ -1543,8 +1539,8 @@ bool Codegen::visit(ObjectLiteral *ast)
unsigned getter = _block->newTemp();
unsigned setter = _block->newTemp();
- move(_block->TEMP(getter), it->getter ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
- move(_block->TEMP(setter), it->setter ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
current->next = _function->New<V4IR::ExprList>();
current = current->next;
@@ -1589,8 +1585,8 @@ bool Codegen::visit(ObjectLiteral *ast)
getter = _block->newTemp();
setter = _block->newTemp();
}
- move(_block->TEMP(getter), it->getter ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
- move(_block->TEMP(setter), it->setter ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
// __qmljs_builtin_define_getter_setter(Value object, String *name, Value getter, Value setter, ExecutionContext *ctx);
@@ -1752,18 +1748,17 @@ bool Codegen::visit(VoidExpression *ast)
bool Codegen::visit(FunctionDeclaration * ast)
{
- if (_mode == QmlBinding)
+ if (_env->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
return false;
}
-V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::SourceElements *body, Mode mode,
- const QStringList &inheritedLocals)
+int Codegen::defineFunction(const QString &name, AST::Node *ast,
+ AST::FormalParameterList *formals,
+ AST::SourceElements *body,
+ const QStringList &inheritedLocals)
{
- qSwap(_mode, mode); // enter function code.
Loop *loop = 0;
qSwap(_loop, loop);
@@ -1771,6 +1766,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
enterEnvironment(ast);
V4IR::Function *function = _module->newFunction(name, _function);
+ int functionIndex = _module->functions.count() - 1;
V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock());
V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
@@ -1789,7 +1785,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
_env->enter("arguments", Environment::VariableDeclaration);
// variables in global code are properties of the global context object, not locals as with other functions.
- if (_mode == FunctionCode) {
+ if (_env->compilationMode == FunctionCode) {
unsigned t = 0;
for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) {
const QString &local = it.key();
@@ -1819,7 +1815,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
}
if (args) {
V4IR::ExprList *next = function->New<V4IR::ExprList>();
- next->expr = entryBlock->CONST(V4IR::BoolType, (mode == EvalCode || mode == QmlBinding));
+ next->expr = entryBlock->CONST(V4IR::BoolType, false); // ### Investigate removal of bool deletable
next->next = args;
args = next;
@@ -1849,9 +1845,9 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
foreach (const Environment::Member &member, _env->members) {
if (member.function) {
- V4IR::Function *function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
- member.function->body ? member.function->body->elements : 0);
- if (! _env->parent) {
+ const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
+ member.function->body ? member.function->body->elements : 0);
+ if (! _env->parent || _env->compilationMode == QmlBinding) {
move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
_block->CLOSURE(function));
} else {
@@ -1882,9 +1878,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
leaveEnvironment();
- qSwap(_mode, mode);
-
- return function;
+ return functionIndex;
}
bool Codegen::visit(IdentifierPropertyName *ast)
@@ -2008,7 +2002,7 @@ bool Codegen::visit(EmptyStatement *)
bool Codegen::visit(ExpressionStatement *ast)
{
- if (_mode == EvalCode || _mode == QmlBinding) {
+ if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
move(_block->TEMP(_returnAddress), *e);
@@ -2116,7 +2110,7 @@ bool Codegen::visit(LabelledStatement *ast)
// check that no outer loop contains the label
Loop *l = _loop;
while (l) {
- if (l->labelledStatement->label == ast->label) {
+ if (l->labelledStatement && l->labelledStatement->label == ast->label) {
QString error = QString(QStringLiteral("Label '%1' has already been declared")).arg(ast->label.toString());
throwSyntaxError(ast->firstSourceLocation(), error);
}
@@ -2217,7 +2211,7 @@ bool Codegen::visit(LocalForStatement *ast)
bool Codegen::visit(ReturnStatement *ast)
{
- if (_mode != FunctionCode && _mode != QmlBinding)
+ if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding)
throwSyntaxError(ast->returnToken, QCoreApplication::translate("qv4codegen", "Return statement outside of function"));
if (ast->expression) {
Result expr = expression(ast->expression);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index ea32b5b349..66b80c377b 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -68,20 +68,20 @@ class Q_QML_EXPORT Codegen: protected AST::Visitor
public:
Codegen(bool strict);
- enum Mode {
+ enum CompilationMode {
GlobalCode,
EvalCode,
FunctionCode,
QmlBinding
};
- V4IR::Function *generateFromProgram(const QString &fileName,
+ void generateFromProgram(const QString &fileName,
const QString &sourceCode,
AST::Program *ast,
V4IR::Module *module,
- Mode mode = GlobalCode,
+ CompilationMode mode = GlobalCode,
const QStringList &inheritedLocals = QStringList());
- V4IR::Function *generateFromFunctionExpression(const QString &fileName,
+ void generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
AST::FunctionExpression *ast,
V4IR::Module *module);
@@ -153,7 +153,9 @@ protected:
UsesArgumentsObject usesArgumentsObject;
- Environment(Environment *parent)
+ CompilationMode compilationMode;
+
+ Environment(Environment *parent, CompilationMode mode)
: parent(parent)
, formals(0)
, maxNumberOfArguments(0)
@@ -162,6 +164,7 @@ protected:
, isStrict(false)
, isNamedFunctionExpression(false)
, usesArgumentsObject(ArgumentsObjectUnknown)
+ , compilationMode(mode)
{
if (parent && parent->isStrict)
isStrict = true;
@@ -216,9 +219,9 @@ protected:
}
};
- Environment *newEnvironment(AST::Node *node, Environment *parent)
+ Environment *newEnvironment(AST::Node *node, Environment *parent, CompilationMode compilationMode)
{
- Environment *env = new Environment(parent);
+ Environment *env = new Environment(parent, compilationMode);
_envMap.insert(node, env);
return env;
}
@@ -280,11 +283,11 @@ protected:
void move(V4IR::Expr *target, V4IR::Expr *source, V4IR::AluOp op = V4IR::OpInvalid);
void cjump(V4IR::Expr *cond, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse);
- V4IR::Function *defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::SourceElements *body,
- Mode mode = FunctionCode,
- const QStringList &inheritedLocals = QStringList());
+ // Returns index in _module->functions
+ int defineFunction(const QString &name, AST::Node *ast,
+ AST::FormalParameterList *formals,
+ AST::SourceElements *body,
+ const QStringList &inheritedLocals = QStringList());
void unwindException(ScopeAndFinally *outest);
@@ -427,7 +430,6 @@ protected:
V4IR::BasicBlock *_exitBlock;
V4IR::BasicBlock *_throwBlock;
unsigned _returnAddress;
- Mode _mode;
Environment *_env;
Loop *_loop;
AST::LabelledStatement *_labelledStatement;
@@ -442,10 +444,10 @@ protected:
{
typedef QV4::TemporaryAssignment<bool> TemporaryBoolAssignment;
public:
- ScanFunctions(Codegen *cg, const QString &sourceCode);
+ ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode);
void operator()(AST::Node *node);
- void enterEnvironment(AST::Node *node);
+ void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
protected:
@@ -500,6 +502,7 @@ protected:
QStack<Environment *> _envStack;
bool _allowFuncDecls;
+ CompilationMode defaultProgramMode;
};
};
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index cd467300be..b485dcc240 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -98,6 +98,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
if (data->lookupTableSize) {
runtimeLookups = new QV4::Lookup[data->lookupTableSize];
+ memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup));
const CompiledData::Lookup *compiledLookups = data->lookupTable();
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
@@ -139,7 +140,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
std::sort(runtimeFunctionsSortedByAddress.begin(), runtimeFunctionsSortedByAddress.end(), functionSortHelper);
#endif
- return runtimeFunctions[data->indexOfRootFunction];
+ if (data->indexOfRootFunction != -1)
+ return runtimeFunctions[data->indexOfRootFunction];
+ else
+ return 0;
}
void CompilationUnit::unlink()
@@ -166,13 +170,17 @@ void CompilationUnit::markObjects()
{
for (int i = 0; i < data->stringTableSize; ++i)
runtimeStrings[i].mark();
- for (int i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark();
+ if (runtimeRegularExpressions) {
+ for (int i = 0; i < data->regexpTableSize; ++i)
+ runtimeRegularExpressions[i].mark();
+ }
for (int i = 0; i < runtimeFunctions.count(); ++i)
if (runtimeFunctions[i])
runtimeFunctions[i]->mark();
- for (int i = 0; i < data->lookupTableSize; ++i)
- runtimeLookups[i].name->mark();
+ if (runtimeLookups) {
+ for (int i = 0; i < data->lookupTableSize; ++i)
+ runtimeLookups[i].name->mark();
+ }
}
QString Binding::valueAsString(const Unit *unit) const
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 6784707607..2c0a46f3c5 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -148,7 +148,8 @@ struct Unit
enum {
IsJavascript = 0x1,
IsQml = 0x2,
- StaticData = 0x4 // Unit data persistent in memory?
+ StaticData = 0x4, // Unit data persistent in memory?
+ IsSingleton = 0x8
};
quint32 flags;
uint stringTableSize;
@@ -161,7 +162,7 @@ struct Unit
uint offsetToRegexpTable;
uint jsClassTableSize;
uint offsetToJSClassTable;
- uint indexOfRootFunction;
+ qint32 indexOfRootFunction;
quint32 sourceFileIndex;
QString stringAt(int idx) const {
@@ -414,7 +415,6 @@ struct Import
Location location;
};
-
struct QmlUnit
{
Unit header;
@@ -433,6 +433,10 @@ struct QmlUnit
const uint offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
}
+
+ bool isSingleton() const {
+ return header.flags & Unit::IsSingleton;
+ }
};
// This is how this hooks into the existing structures:
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 8cd4c8e2d8..7d8c188927 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -198,6 +198,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
unit->offsetToRegexpTable = unit->offsetToLookupTable + unit->lookupTableSize * CompiledData::Lookup::calculateSize();
unit->jsClassTableSize = jsClasses.count();
unit->offsetToJSClassTable = unit->offsetToRegexpTable + unit->regexpTableSize * CompiledData::RegExp::calculateSize();
+ unit->indexOfRootFunction = -1;
unit->sourceFileIndex = getStringId(irModule->fileName);
// write strings and string table
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index 6fb8393f54..d5e67d91c3 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -56,6 +56,8 @@
#include <iostream>
#include <cassert>
+#if ENABLE(ASSEMBLER)
+
#if USE(UDIS86)
# include <udis86.h>
#endif
@@ -671,7 +673,6 @@ void InstructionSelection::run(int functionIndex)
<< JSC::X86Registers::r15;
#endif
static const QVector<int> fpRegisters = QVector<int>()
- << JSC::X86Registers::xmm1
<< JSC::X86Registers::xmm2
<< JSC::X86Registers::xmm3
<< JSC::X86Registers::xmm4
@@ -1070,7 +1071,7 @@ void InstructionSelection::setActivationProperty(V4IR::Expr *source, const QStri
void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
{
- int id = irModule->functions.indexOf(closure->value);
+ int id = closure->value;
generateFunctionCall(target, __qmljs_init_closure, Assembler::ContextRegister, Assembler::TrustedImm32(id));
}
@@ -1102,6 +1103,89 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
{
+#if QT_POINTER_SIZE == 8
+ V4IR::Temp *tbase = base->asTemp();
+ V4IR::Temp *tindex = index->asTemp();
+ if (tbase && tindex &&
+ tbase->kind != V4IR::Temp::PhysicalRegister) {
+ Assembler::Pointer addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
+ _as->load64(addr, Assembler::ScratchRegister);
+ _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsManaged_Shift), Assembler::ReturnValueRegister);
+ Assembler::Jump notManaged = _as->branch64(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm64(0));
+ // check whether we have an object with a simple array
+ Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Managed, flags));
+ _as->load8(managedType, Assembler::ReturnValueRegister);
+ _as->and32(Assembler::TrustedImm32(QV4::Managed::SimpleArray), Assembler::ReturnValueRegister);
+ Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
+
+ Assembler::Jump fallback;
+ if (tindex->kind == V4IR::Temp::PhysicalRegister) {
+ if (tindex->type == V4IR::SInt32Type) {
+ _as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister);
+ } else {
+ // double, convert and check if it's a int
+ _as->truncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister);
+ _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr0);
+ fallback = _as->branchDouble(Assembler::DoubleNotEqual, Assembler::FPGpr0, (Assembler::FPRegisterID) tindex->index);
+ }
+ } else {
+ Assembler::Pointer indexAddr = _as->loadTempAddress(Assembler::ReturnValueRegister, tindex);
+ _as->load64(indexAddr, Assembler::ScratchRegister);
+ _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ReturnValueRegister);
+ Assembler::Jump isInteger = _as->branch64(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm64(1));
+
+ // other type, convert to double and check if it's a int
+ // this check is ok to do even if the type is something else than a double, as
+ // that would result in a NaN
+ _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ReturnValueRegister);
+ _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
+ _as->truncateDoubleToUint32(Assembler::FPGpr0, Assembler::ScratchRegister);
+ _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr1);
+ fallback = _as->branchDouble(Assembler::DoubleNotEqualOrUnordered, Assembler::FPGpr0, Assembler::FPGpr1);
+
+ isInteger.link(_as);
+ _as->or32(Assembler::TrustedImm32(0), Assembler::ScratchRegister);
+ }
+
+ // get data, ScratchRegister holds index
+ addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase);
+ _as->load64(addr, Assembler::ReturnValueRegister);
+ Address arrayDataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayDataLen));
+ Assembler::Jump outOfRange = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen);
+ Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData));
+ _as->load64(arrayData, Assembler::ReturnValueRegister);
+ Q_ASSERT(sizeof(Property) == (1<<4));
+ _as->lshift64(Assembler::TrustedImm32(4), Assembler::ScratchRegister);
+ _as->add64(Assembler::ReturnValueRegister, Assembler::ScratchRegister);
+ Address value(Assembler::ScratchRegister, qOffsetOf(Property, value));
+ _as->load64(value, Assembler::ReturnValueRegister);
+
+ // check that the value is not empty
+ _as->move(Assembler::ReturnValueRegister, Assembler::ScratchRegister);
+ _as->urshift64(Assembler::TrustedImm32(32), Assembler::ScratchRegister);
+ Assembler::Jump emptyValue = _as->branch32(Assembler::Equal, Assembler::TrustedImm32(QV4::Value::Empty_Type), Assembler::ScratchRegister);
+ _as->storeReturnValue(target);
+
+ Assembler::Jump done = _as->jump();
+
+ emptyValue.link(_as);
+ outOfRange.link(_as);
+ if (fallback.isSet())
+ fallback.link(_as);
+ notSimple.link(_as);
+ notManaged.link(_as);
+
+ generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister,
+ Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+
+ done.link(_as);
+ return;
+ }
+#endif
+
generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister,
Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
@@ -1313,8 +1397,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp
// register.
switch (oper) {
case V4IR::OpAdd: {
- Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1);
- Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3);
+ Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2);
+ Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4);
Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg);
Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg);
@@ -1328,8 +1412,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp
rightIsNoDbl.link(_as);
} break;
case V4IR::OpMul: {
- Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1);
- Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3);
+ Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2);
+ Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4);
Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg);
Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg);
@@ -1343,8 +1427,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp
rightIsNoDbl.link(_as);
} break;
case V4IR::OpSub: {
- Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1);
- Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3);
+ Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2);
+ Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4);
Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg);
Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg);
@@ -1358,8 +1442,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp
rightIsNoDbl.link(_as);
} break;
case V4IR::OpDiv: {
- Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1);
- Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3);
+ Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2);
+ Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4);
Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg);
Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg);
@@ -1387,8 +1471,7 @@ void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR:
doubleBinop(oper, leftSource, rightSource, target);
return;
}
- if (leftSource->type == V4IR::SInt32Type &&
- (rightSource->type == V4IR::SInt32Type || rightSource->type == V4IR::UInt32Type)) {
+ if (leftSource->type == V4IR::SInt32Type && rightSource->type == V4IR::SInt32Type) {
if (int32Binop(oper, leftSource, rightSource, target))
return;
}
@@ -1491,6 +1574,9 @@ void InstructionSelection::convertTypeToDouble(V4IR::Temp *source, V4IR::Temp *t
convertUIntToDouble(source, target);
break;
case V4IR::UndefinedType:
+ _as->loadDouble(_as->loadTempAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
+ _as->storeDouble(Assembler::FPGpr0, target);
+ break;
case V4IR::StringType:
case V4IR::VarType: {
// load the tag:
@@ -1590,15 +1676,52 @@ void InstructionSelection::convertTypeToSInt32(V4IR::Temp *source, V4IR::Temp *t
{
switch (source->type) {
case V4IR::VarType: {
+
+#if QT_POINTER_SIZE == 8
+ Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ _as->load64(addr, Assembler::ScratchRegister);
+ _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+
+ // check if it's a number
+ _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ScratchRegister);
+ Assembler::Jump fallback = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
+ // we have a number
+ _as->urshift64(Assembler::TrustedImm32(1), Assembler::ScratchRegister);
+ Assembler::Jump isInt = _as->branch32(Assembler::Equal, 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);
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32,
+ _as->loadTempAddress(Assembler::ScratchRegister, source));
+
+ isInt.link(_as);
+ success.link(_as);
+ if (target->kind == V4IR::Temp::StackSlot) {
+ Assembler::Pointer targetAddr = _as->stackSlotPointer(target);
+ _as->store32(Assembler::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ _as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr);
+ } else {
+ _as->storeInt32(Assembler::ReturnValueRegister, target);
+ }
+#else
// load the tag:
- Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer tagAddr = addr;
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, Assembler::ReturnValueRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
+ Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
Assembler::TrustedImm32(Value::_Integer_Type));
- Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
if (target->kind == V4IR::Temp::StackSlot) {
_as->load32(addr, Assembler::ScratchRegister);
Assembler::Pointer targetAddr = _as->stackSlotPointer(target);
@@ -1611,54 +1734,96 @@ void InstructionSelection::convertTypeToSInt32(V4IR::Temp *source, V4IR::Temp *t
Assembler::Jump intDone = _as->jump();
// not an int:
- isNoInt.link(_as);
+ fallback.link(_as);
generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32,
_as->loadTempAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
intDone.link(_as);
+#endif
+
} break;
case V4IR::DoubleType: {
- Assembler::FPRegisterID reg = _as->toDoubleRegister(source);
Assembler::Jump success =
- _as->branchTruncateDoubleToInt32(reg, Assembler::ReturnValueRegister,
+ _as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
+ Assembler::ReturnValueRegister,
Assembler::BranchIfTruncateSuccessful);
generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_double_to_int32,
Assembler::PointerToValue(source));
success.link(_as);
_as->storeInt32(Assembler::ReturnValueRegister, target);
} break;
- case V4IR::UInt32Type: {
- Assembler::RegisterID reg = _as->toUInt32Register(source, Assembler::ReturnValueRegister);
- Assembler::Jump easy = _as->branch32(Assembler::GreaterThanOrEqual, reg, Assembler::TrustedImm32(0));
- generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32,
- Assembler::PointerToValue(source));
- easy.link(_as);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
- } break;
+ case V4IR::UInt32Type:
+ _as->storeInt32(_as->toUInt32Register(source, Assembler::ReturnValueRegister), target);
+ break;
case V4IR::NullType:
case V4IR::UndefinedType:
_as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
break;
- case V4IR::StringType:
- generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32,
- _as->loadTempAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
- break;
case V4IR::BoolType:
_as->storeInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
break;
+ case V4IR::StringType:
default:
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_int32,
+ _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->storeInt32(Assembler::ReturnValueRegister, target);
break;
} // switch (source->type)
}
void InstructionSelection::convertTypeToUInt32(V4IR::Temp *source, V4IR::Temp *target)
{
- generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_uint32,
- Assembler::PointerToValue(source));
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ switch (source->type) {
+ case V4IR::VarType: {
+ // load the tag:
+ Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ tagAddr.offset += 4;
+ _as->load32(tagAddr, Assembler::ScratchRegister);
+
+ // check if it's an int32:
+ Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
+ Assembler::TrustedImm32(Value::_Integer_Type));
+ Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target);
+ Assembler::Jump intDone = _as->jump();
+
+ // not an int:
+ isNoInt.link(_as);
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_uint32,
+ _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->storeInt32(Assembler::ReturnValueRegister, target);
+
+ intDone.link(_as);
+ } break;
+ case V4IR::DoubleType: {
+ Assembler::FPRegisterID reg = _as->toDoubleRegister(source);
+ Assembler::Jump success =
+ _as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister,
+ Assembler::BranchIfTruncateSuccessful);
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_double_to_uint32,
+ Assembler::PointerToValue(source));
+ success.link(_as);
+ _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ } break;
+ case V4IR::NullType:
+ case V4IR::UndefinedType:
+ _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
+ _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ break;
+ case V4IR::StringType:
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_value_to_uint32,
+ Assembler::PointerToValue(source));
+ _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ break;
+ case V4IR::SInt32Type:
+ case V4IR::BoolType:
+ _as->storeUInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ break;
+ default:
+ break;
+ } // switch (source->type)
}
void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
@@ -2239,8 +2404,8 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(V4IR::Type nullOrUndef,
Assembler::RelationalCondition cond = binop->op == V4IR::OpStrictEqual ? Assembler::Equal
: Assembler::NotEqual;
- const Assembler::TrustedImm32 tag(nullOrUndef == V4IR::NullType ? QV4::Value::_Null_Type
- : QV4::Value::Undefined_Type);
+ const Assembler::TrustedImm32 tag(nullOrUndef == V4IR::NullType ? int(QV4::Value::_Null_Type)
+ : int(QV4::Value::Undefined_Type));
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
@@ -2389,7 +2554,19 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
_as->rshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
return true;
+ case V4IR::OpURShift:
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+ _as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::ReturnValueRegister);
+ _as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ Assembler::ScratchRegister);
+ _as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); // TODO: for constants, do this in the IR
+ _as->urshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ return true;
default:
return false;
}
}
+
+#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 3dfd979654..bd4c564ab9 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -51,6 +51,9 @@
#include <QtCore/QHash>
#include <config.h>
#include <wtf/Vector.h>
+
+#if ENABLE(ASSEMBLER)
+
#include <assembler/MacroAssembler.h>
#include <assembler/MacroAssemblerCodeRef.h>
@@ -136,6 +139,7 @@ public:
static const RegisterID ScratchRegister = JSC::X86Registers::r10;
static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
static const int RegisterSize = 8;
@@ -289,7 +293,7 @@ public:
qDebug("calleeSavedRegCount.....: %d",calleeSavedRegCount);
qDebug("maxOutgoingArgumentCount: %d",maxOutgoingArgumentCount);
qDebug("localCount..............: %d",localCount);
- qDebug("savedConstCount.........: %d",savedConstCount);
+ qDebug("savedConstCount.........: %d",savedRegCount);
for (int i = 0; i < maxOutgoingArgumentCount; ++i)
qDebug("argumentAddressForCall(%d) = 0x%x / -0x%x", i,
argumentAddressForCall(i).offset, -argumentAddressForCall(i).offset);
@@ -313,7 +317,8 @@ public:
+ RegisterSize; // saved StackFrameRegister
// space for the callee saved registers
- int frameSize = RegisterSize * (calleeSavedRegisterCount + savedRegCount);
+ int frameSize = RegisterSize * calleeSavedRegisterCount;
+ frameSize += savedRegCount * sizeof(QV4::SafeValue); // these get written out as Values, not as native registers
frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
frameSize -= stackSpaceAllocatedOtherwise;
@@ -428,7 +433,25 @@ public:
V4IR::BasicBlock *block;
};
+ void saveInstructionPointer(RegisterID freeScratchRegister) {
+ Address ipAddr(ContextRegister, qOffsetOf(QV4::ExecutionContext, jitInstructionPointer));
+ RegisterID sourceRegister = freeScratchRegister;
+
+#if CPU(X86_64) || CPU(X86)
+ callToRetrieveIP();
+ peek(sourceRegister);
+ pop();
+#elif CPU(ARM)
+ move(JSC::ARMRegisters::pc, sourceRegister);
+#else
+#error "Port me!"
+#endif
+
+ storePtr(sourceRegister, ipAddr);
+ }
+
void callAbsolute(const char* functionName, FunctionPtr function) {
+ saveInstructionPointer(ScratchRegister);
CallToLink ctl;
ctl.call = call();
ctl.externalFunction = function;
@@ -437,11 +460,13 @@ public:
}
void callAbsolute(const char* /*functionName*/, Address addr) {
+ saveInstructionPointer(ScratchRegister);
call(addr);
}
void callAbsolute(const char* /*functionName*/, const RelativeCall &relativeCall)
{
+ saveInstructionPointer(ScratchRegister);
call(relativeCall.addr);
}
@@ -1294,6 +1319,8 @@ public:
RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
{
+ Q_ASSERT(addr.base != scratchReg);
+
// The UInt32 representation in QV4::Value is really convoluted. See also storeUInt32.
Pointer tagAddr = addr;
tagAddr.offset += 4;
@@ -1480,30 +1507,25 @@ private:
void convertUIntToDouble(V4IR::Temp *source, V4IR::Temp *target)
{
+ Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
+ Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
+
if (target->kind == V4IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- (Assembler::FPRegisterID) target->index,
- Assembler::ScratchRegister);
- } else if (target->kind == V4IR::Temp::StackSlot) {
- _as->convertUInt32ToDouble(_as->toUInt32Register(source, Assembler::ScratchRegister),
- Assembler::FPGpr0, Assembler::ScratchRegister);
- _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
+ _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) target->index, tmpReg);
} else {
- Q_UNIMPLEMENTED();
+ _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
+ Assembler::FPGpr0, tmpReg);
+ _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
}
}
void convertIntToBool(V4IR::Temp *source, V4IR::Temp *target)
{
- Assembler::RegisterID reg = Assembler::ScratchRegister;
- if (target->kind == V4IR::Temp::PhysicalRegister) {
- reg = _as->toInt32Register(source, reg);
- } else if (target->kind == V4IR::Temp::StackSlot) {
- _as->move(_as->toInt32Register(source, reg), reg);
- } else {
- Q_UNIMPLEMENTED();
- }
+ Assembler::RegisterID reg = target->kind == V4IR::Temp::PhysicalRegister
+ ? (Assembler::RegisterID) target->index
+ : Assembler::ScratchRegister;
+ _as->move(_as->toInt32Register(source, reg), reg);
_as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
_as->storeBool(reg, target);
}
@@ -1587,4 +1609,6 @@ public:
QT_END_NAMESPACE
+#endif // ENABLE(ASSEMBLER)
+
#endif // QV4ISEL_MASM_P_H
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 0b9473b1d3..c610ca6f02 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -449,7 +449,7 @@ void InstructionSelection::setActivationProperty(V4IR::Expr *source, const QStri
void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
{
- int id = irModule->functions.indexOf(closure->value);
+ int id = closure->value;
Instruction::LoadClosure load;
load.value = id;
load.result = getResultParam(target);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 500c2bd26f..483cb8e6f9 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -80,9 +80,6 @@ EvalISelFactory::~EvalISelFactory()
QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData)
{
- Function *rootFunction = irModule->rootFunction;
- if (!rootFunction)
- return 0;
for (int i = 0; i < irModule->functions.size(); ++i)
run(i);
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 756c076abf..50afcf29c2 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -464,7 +464,7 @@ bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
void Closure::dump(QTextStream &out) const
{
- QString name = value->name ? *value->name : QString();
+ QString name = functionName ? *functionName : QString();
if (name.isEmpty())
name.sprintf("%p", value);
out << "closure(" << name << ')';
@@ -610,8 +610,10 @@ Function *Module::newFunction(const QString &name, Function *outer)
Function *f = new Function(this, outer, name);
functions.append(f);
if (!outer) {
- assert(!rootFunction);
- rootFunction = f;
+ if (!isQmlModule) {
+ assert(!rootFunction);
+ rootFunction = f;
+ }
} else {
outer->nestedFunctions.append(f);
}
@@ -763,10 +765,10 @@ Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
return e;
}
-Closure *BasicBlock::CLOSURE(Function *function)
+Closure *BasicBlock::CLOSURE(int functionInModule)
{
Closure *clos = function->New<Closure>();
- clos->init(function);
+ clos->init(functionInModule, function->module->functions.at(functionInModule)->name);
return clos;
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index f28c47a61a..7b0ee52737 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -386,11 +386,13 @@ inline uint qHash(const Temp &t, uint seed = 0) Q_DECL_NOTHROW
bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW;
struct Closure: Expr {
- Function *value;
+ int value; // index in _module->functions
+ const QString *functionName;
- void init(Function *value)
+ void init(int functionInModule, const QString *functionName)
{
- this->value = value;
+ this->value = functionInModule;
+ this->functionName = functionName;
}
virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
@@ -680,10 +682,14 @@ struct Q_QML_EXPORT Module {
QVector<Function *> functions;
Function *rootFunction;
QString fileName;
+ bool isQmlModule; // implies rootFunction is always 0
Function *newFunction(const QString &name, Function *outer);
- Module() : rootFunction(0) {}
+ Module()
+ : rootFunction(0)
+ , isQmlModule(false)
+ {}
~Module();
void setFileName(const QString &name);
@@ -812,7 +818,7 @@ struct BasicBlock {
Name *GLOBALNAME(const QString &id, quint32 line, quint32 column);
- Closure *CLOSURE(Function *function);
+ Closure *CLOSURE(int functionInModule);
Expr *CONVERT(Expr *expr, Type type);
Expr *UNOP(AluOp op, Expr *expr);
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 210ae686c8..c35ee860f7 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -242,27 +242,27 @@ protected: // IRDecoder
switch (target->type) {
case DoubleType:
- if (source->type == UInt32Type) {
- sourceReg = Use::MustHaveRegister;
+ switch (source->type) {
+ case UInt32Type:
+ case SInt32Type:
+ case NullType:
+ case UndefinedType:
+ case BoolType:
needsCall = false;
break;
- }
- case SInt32Type:
- if (source->type == DoubleType || source->type == UInt32Type) {
- // this might need a call
+ default:
break;
}
-#if 0 // TODO: change masm to generate code
- case UInt32Type:
-#endif
+ break;
case BoolType:
switch (source->type) {
case UInt32Type:
- case BoolType:
- case DoubleType:
sourceReg = Use::MustHaveRegister;
needsCall = false;
break;
+ case DoubleType:
+ case UndefinedType:
+ case NullType:
case SInt32Type:
needsCall = false;
break;
@@ -270,6 +270,28 @@ protected: // IRDecoder
break;
}
break;
+ case SInt32Type:
+ switch (source->type) {
+ case UInt32Type:
+ case NullType:
+ case UndefinedType:
+ case BoolType:
+ needsCall = false;
+ default:
+ break;
+ }
+ break;
+ case UInt32Type:
+ switch (source->type) {
+ case SInt32Type:
+ case NullType:
+ case UndefinedType:
+ case BoolType:
+ needsCall = false;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -434,14 +456,8 @@ protected: // IRDecoder
|| (oper >= OpGt && oper <= OpStrictNotEqual)) {
needsCall = false;
}
- } else if (leftSource->type == SInt32Type && rightSource->type == SInt32Type) {
- if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor) {
- needsCall = false;
- }
- } else if (leftSource->type == SInt32Type && rightSource->type == UInt32Type) {
- if (oper == OpLShift || oper == OpRShift) {
- needsCall = false;
- }
+ } if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
+ needsCall = false;
}
addDef(target);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index ee2607a086..c9ff6ad53c 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -1722,12 +1722,8 @@ protected:
case OpLShift:
case OpRShift:
- run(e->left, SInt32Type);
- run(e->right, SInt32Type);
- break;
-
case OpURShift:
- run(e->left, UInt32Type);
+ run(e->left, SInt32Type);
run(e->right, SInt32Type);
break;
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index 53ad15775c..5286d3e694 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -141,6 +141,7 @@ private:
QQmlDebugServerPrivate::QQmlDebugServerPrivate() :
connection(0),
+ pluginsLock(QReadWriteLock::Recursive),
gotHello(false),
blockingMode(false),
thread(0)
diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp
index a94f611c27..33d6747b3b 100644
--- a/src/qml/debugger/qv8profilerservice.cpp
+++ b/src/qml/debugger/qv8profilerservice.cpp
@@ -233,12 +233,14 @@ void QV8ProfilerService::stopProfiling(const QString &title)
const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
d->printProfileTree(rootNode);
} else {
+#endif
// indicate completion, even without data
QByteArray data;
QQmlDebugStream ds(&data, QIODevice::WriteOnly);
ds << (int)QV8ProfilerService::V8Complete;
sendMessage(data);
+#if 0
}
#endif
}
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index 3bd64ac115..a63ef617c0 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -166,15 +166,6 @@ Item {
}
\endqml
-\li The \c with statement is deprecated. Using the \c with statement will issue a warning
-at loading time and we plan on removing support for it in Qt 5.2. It is generally considered
-a language feature that is not recommended for use due reducing the readability of code and disabling
-many optimizations in the engine. It is also forbidden in ECMAScript 5 strict mode.
-
-\li JavaScript binding expressions are executed in non-strict mode. However we
-plan on changing the default for bindings in Qt 5.2 to execute always in
-ECMAScript 5 strict mode.
-
\endlist
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index a260a3d785..b9c008edf1 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -31,7 +31,7 @@
\brief The Qt QML module defines and implements the QML language
The Qt QML module provides a framework for developing applications and libraries
-with the \l{QML Application Developer Resources}{QML language}. It defines and implements the
+with the \l{QML Applications}{QML language}. It defines and implements the
language and engine infrastructure, and provides an API to enable application
developers to extend the QML language with custom types and integrate QML code
with JavaScript and C++. The Qt QML module provides both a \l{Qt QML QML Types}
@@ -43,7 +43,7 @@ model-view support, an animation framework, and much more for building user
interfaces.
For those new to QML and Qt Quick, please see
-\l{qtquick-applicationdevelopers.html}{QML Application Developer Resources}
+\l{QML Applications}
for an introduction to writing QML applications.
\section1 Getting Started
@@ -131,7 +131,7 @@ the QML code to interact with C++ code.
Further information for writing QML applications:
\list
\li \l{The QML Reference}
-\li \l{QML Application Developer Resources}
+\li \l{QML Applications}
- essential information for application development with QML and Qt Quick
\li \l{Qt Quick} - a module which provides a set of QML types and C++ classes
for building user interfaces and applications with QML
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 107ac98cd1..d1bd4934cd 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -241,19 +241,19 @@ void QJSEngine::collectGarbage()
QJSValue::isError()).
\a lineNumber is used to specify a starting line number for \a
- program; line number information reported by the engine that pertain
+ program; line number information reported by the engine that pertains
to this evaluation will be based on this argument. For example, if
\a program consists of two lines of code, and the statement on the
second line causes a script exception, the exception line number
would be \a lineNumber plus one. When no starting line number is
specified, line numbers will be 1-based.
- \a fileName is used for error reporting. For example in error objects
- the file name is accessible through the "fileName" property if it's
+ \a fileName is used for error reporting. For example, in error objects
+ the file name is accessible through the "fileName" property if it is
provided with this function.
\note If an exception was thrown and the exception value is not an
- Error instance (i.e., QJSValue::isError() returns false), the
+ Error instance (i.e., QJSValue::isError() returns \c false), the
exception value will still be returned, but there is currently no
API for detecting that an exception did occur in this case.
*/
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 14701feeb5..cde26c323d 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -45,7 +45,6 @@ SOURCES += \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4qmlextensions.cpp \
- $$PWD/qv4stacktrace.cpp \
$$PWD/qv4vme_moth.cpp
HEADERS += \
@@ -96,7 +95,6 @@ HEADERS += \
$$PWD/qv4include_p.h \
$$PWD/qv4qobjectwrapper_p.h \
$$PWD/qv4qmlextensions_p.h \
- $$PWD/qv4stacktrace_p.h \
$$PWD/qv4vme_moth_p.h
# Use SSE2 floating point math on 32 bit instead of the default
@@ -137,8 +135,4 @@ valgrind {
ios: DEFINES += ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
-win32:!wince* {
- LIBS_PRIVATE += -lDbgHelp
-}
-
include(../../3rdparty/double-conversion/double-conversion.pri)
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index c815036550..47b149c9d5 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -127,12 +127,11 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
isNonStrictArgumentsObject = true;
if (isMapped && attrs.isData()) {
- if (!attrs.isGeneric()) {
- ScopedCallData callData(scope, 1);
- callData->thisObject = this->asReturnedValue();
- callData->args[0] = desc.value;
- map.setter()->call(callData);
- }
+ ScopedCallData callData(scope, 1);
+ callData->thisObject = this->asReturnedValue();
+ callData->args[0] = desc.value;
+ map.setter()->call(callData);
+
if (attrs.isWritable()) {
*pd = map;
arrayAttributes[pidx] = mapAttrs;
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 92fa196331..3913b9ffe7 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -350,7 +350,7 @@ ReturnedValue ArrayPrototype::method_shift(SimpleCallContext *ctx)
Property *front = 0;
uint pidx = instance->propertyIndexFromArrayIndex(0);
- if (pidx < UINT_MAX && (!instance->arrayAttributes || !instance->arrayAttributes[0].isGeneric()))
+ if (pidx < UINT_MAX && !instance->arrayData[pidx].value.isEmpty())
front = instance->arrayData + pidx;
ScopedValue result(scope, front ? instance->getValue(front, instance->arrayAttributes ? instance->arrayAttributes[pidx] : Attr_Data) : Encode::undefined());
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index d4d6201c01..025f98351f 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -95,7 +95,9 @@ ReturnedValue BooleanPrototype::method_toString(SimpleCallContext *ctx)
ReturnedValue BooleanPrototype::method_valueOf(SimpleCallContext *ctx)
{
- // ### Shouldn't this work for a boolean thisObject?
+ if (ctx->callData->thisObject.isBoolean())
+ return ctx->callData->thisObject.asReturnedValue();
+
Scope scope(ctx);
Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject);
if (!thisObject)
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index be6e1649cf..f3d2ab66ed 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -649,11 +649,6 @@ ReturnedValue ExecutionContext::catchException(StackTrace *trace)
return engine->catchException(this, trace);
}
-void ExecutionContext::rethrowException()
-{
- engine->rethrowException(this);
-}
-
void ExecutionContext::throwReferenceError(const ValueRef value)
{
Scope scope(this);
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 2535161713..e5b0c431ca 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -97,6 +97,7 @@ struct Q_QML_EXPORT ExecutionContext
EvalCode *currentEvalCode;
const uchar **interpreterInstructionPointer;
+ char *jitInstructionPointer;
void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
{
@@ -110,6 +111,7 @@ struct Q_QML_EXPORT ExecutionContext
compilationUnit = 0;
currentEvalCode = 0;
interpreterInstructionPointer = 0;
+ jitInstructionPointer = 0;
}
CallContext *newCallContext(void *stackSpace, SafeValue *locals, FunctionObject *f, CallData *callData);
@@ -145,7 +147,6 @@ struct Q_QML_EXPORT ExecutionContext
// Can only be called from within catch(...), rethrows if no JS exception.
ReturnedValue catchException(StackTrace *trace = 0);
- void Q_NORETURN rethrowException();
void mark();
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 41eb6fe5ec..2c68c4f400 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -66,7 +66,6 @@
#include "qv4sequenceobject_p.h"
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
-#include "qv4stacktrace_p.h"
#ifdef V4_ENABLE_JIT
#include "qv4isel_masm_p.h"
@@ -464,10 +463,12 @@ Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QString &pattern,
if (flags & QQmlJS::V4IR::RegExp::RegExp_Multiline)
multiline = true;
- return newRegExpObject(RegExp::create(this, pattern, ignoreCase, multiline), global);
+ Scope scope(this);
+ Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline));
+ return newRegExpObject(re, global);
}
-Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExp* re, bool global)
+Returned<RegExpObject> *ExecutionEngine::newRegExpObject(Referenced<RegExp> re, bool global)
{
RegExpObject *object = new (memoryManager) RegExpObject(this, re, global);
return object->asReturned<RegExpObject>();
@@ -566,7 +567,6 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const
namespace {
struct LineNumberResolver {
const ExecutionEngine* engine;
- QScopedPointer<QV4::NativeStackTrace> nativeTrace;
LineNumberResolver(const ExecutionEngine *engine)
: engine(engine)
@@ -575,17 +575,12 @@ namespace {
void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
- if (context->interpreterInstructionPointer) {
- qptrdiff offset = *context->interpreterInstructionPointer - 1 - function->codeData;
- frame->line = function->lineNumberForProgramCounter(offset);
- } else {
- if (!nativeTrace)
- nativeTrace.reset(new QV4::NativeStackTrace(engine->current));
-
- NativeFrame nativeFrame = nativeTrace->nextFrame();
- if (nativeFrame.function == function)
- frame->line = nativeFrame.line;
- }
+ qptrdiff offset;
+ if (context->interpreterInstructionPointer)
+ offset = *context->interpreterInstructionPointer - 1 - function->codeData;
+ else
+ offset = context->jitInstructionPointer - (char*)function->codePtr;
+ frame->line = function->lineNumberForProgramCounter(offset);
}
};
}
@@ -673,12 +668,16 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
if (n <= argumentsAccessors.size())
return;
+ Scope scope(this);
+ ScopedFunctionObject get(scope);
+ ScopedFunctionObject set(scope);
+
uint oldSize = argumentsAccessors.size();
argumentsAccessors.resize(n);
for (int i = oldSize; i < n; ++i) {
- FunctionObject *get = new (memoryManager) ArgumentsGetterFunction(rootContext, i);
- FunctionObject *set = new (memoryManager) ArgumentsSetterFunction(rootContext, i);
- Property pd = Property::fromAccessor(get, set);
+ get = new (memoryManager) ArgumentsGetterFunction(rootContext, i);
+ set = new (memoryManager) ArgumentsSetterFunction(rootContext, i);
+ Property pd = Property::fromAccessor(get.getPointer(), set.getPointer());
argumentsAccessors[i] = pd;
}
}
@@ -827,19 +826,9 @@ void ExecutionEngine::throwException(const ValueRef value)
throwInternal();
}
-void ExecutionEngine::rethrowException(ExecutionContext *intermediateCatchingContext)
-{
- if (hasException) {
- while (current != intermediateCatchingContext)
- popContext();
- }
- rethrowInternal();
-}
-
ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace)
{
- if (!hasException)
- rethrowInternal();
+ Q_ASSERT(hasException);
while (current != catchingContext)
popContext();
if (trace)
@@ -851,6 +840,28 @@ ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext,
return res;
}
+QQmlError ExecutionEngine::convertJavaScriptException(ExecutionContext *context)
+{
+ QV4::StackTrace trace;
+ QV4::Scope scope(context);
+ QV4::ScopedValue exception(scope, context->catchException(&trace));
+ QQmlError error;
+ if (!trace.isEmpty()) {
+ QV4::StackFrame frame = trace.first();
+ error.setUrl(QUrl(frame.source));
+ error.setLine(frame.line);
+ error.setColumn(frame.column);
+ }
+ QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
+ if (!!errorObj && errorObj->asSyntaxError()) {
+ QV4::ScopedString m(scope, errorObj->engine()->newString("message"));
+ QV4::ScopedValue v(scope, errorObj->get(m));
+ error.setDescription(v->toQStringNoThrow());
+ } else
+ error.setDescription(exception->toQStringNoThrow());
+ return error;
+}
+
#if !defined(V4_CXX_ABI_EXCEPTION)
struct DummyException
{};
@@ -859,11 +870,6 @@ void ExecutionEngine::throwInternal()
{
throw DummyException();
}
-
-void ExecutionEngine::rethrowInternal()
-{
- throw;
-}
#endif
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine_cxxabi.cpp b/src/qml/jsruntime/qv4engine_cxxabi.cpp
index 6141753ccc..f29af5a284 100644
--- a/src/qml/jsruntime/qv4engine_cxxabi.cpp
+++ b/src/qml/jsruntime/qv4engine_cxxabi.cpp
@@ -118,21 +118,39 @@ void ExecutionEngine::throwInternal()
std::terminate();
}
-void ExecutionEngine::rethrowInternal()
-{
- cxa_eh_globals *globals = __cxa_get_globals();
- cxa_exception *exception = globals->caughtExceptions;
+QT_END_NAMESPACE
- // Make sure we only re-throw our foreign exceptions. For general re-throw
- // we'd need different code.
-#ifndef __ARM_EABI_UNWINDER__
- Q_ASSERT(exception->unwindHeader.exception_class == 0x514d4c4a53563400); // QMLJSV40
+/*
+ * We override these EABI defined symbols on Android, where we must statically link in the unwinder from libgcc.a
+ * and thus also ensure that compiler generated cleanup code / landing pads end up calling these stubs, that
+ * ultimately return control to our copy of the unwinder. The symbols are also exported from gnustl_shared, which
+ * comes later in the link line.
+ */
+#if defined(__ANDROID__) && defined(__ARM_EABI_UNWINDER__)
+#pragma GCC visibility push(default)
+#ifdef __thumb__
+asm (" .pushsection .text.__cxa_end_cleanup\n"
+" .global __cxa_end_cleanup\n"
+" .type __cxa_end_cleanup, \"function\"\n"
+" .thumb_func\n"
+"__cxa_end_cleanup:\n"
+" push\t{r1, r2, r3, r4}\n"
+" bl\t__gnu_end_cleanup\n"
+" pop\t{r1, r2, r3, r4}\n"
+" bl\t_Unwind_Resume @ Never returns\n"
+" .popsection\n");
+#else
+asm (" .pushsection .text.__cxa_end_cleanup\n"
+" .global __cxa_end_cleanup\n"
+" .type __cxa_end_cleanup, \"function\"\n"
+"__cxa_end_cleanup:\n"
+" stmfd\tsp!, {r1, r2, r3, r4}\n"
+" bl\t__gnu_end_cleanup\n"
+" ldmfd\tsp!, {r1, r2, r3, r4}\n"
+" bl\t_Unwind_Resume @ Never returns\n"
+" .popsection\n");
+#endif
+#pragma GCC visibility pop
#endif
-
- globals->caughtExceptions = 0;
- _Unwind_RaiseException(&exception->unwindHeader);
-}
-
-QT_END_NAMESPACE
#endif
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index e70ac7b24f..24fb4ad923 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -56,6 +56,7 @@ class PageAllocation;
QT_BEGIN_NAMESPACE
class QV8Engine;
+class QQmlError;
namespace QV4 {
namespace Debugging {
@@ -286,7 +287,7 @@ struct Q_QML_EXPORT ExecutionEngine
Returned<DateObject> *newDateObject(const QDateTime &dt);
Returned<RegExpObject> *newRegExpObject(const QString &pattern, int flags);
- Returned<RegExpObject> *newRegExpObject(RegExp* re, bool global);
+ Returned<RegExpObject> *newRegExpObject(Referenced<RegExp> re, bool global);
Returned<RegExpObject> *newRegExpObject(const QRegExp &re);
Returned<Object> *newErrorObject(const ValueRef value);
@@ -326,11 +327,12 @@ struct Q_QML_EXPORT ExecutionEngine
StackTrace exceptionStackTrace;
void Q_NORETURN throwException(const ValueRef value);
- void Q_NORETURN rethrowException(ExecutionContext *intermediateCatchingContext);
ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace);
+ // Use only inside catch(...) -- will re-throw if no JS exception
+ static QQmlError convertJavaScriptException(QV4::ExecutionContext *context);
+
void Q_NORETURN throwInternal();
- void Q_NORETURN rethrowInternal();
// ----
@@ -351,6 +353,23 @@ inline ExecutionContext *ExecutionEngine::popContext()
return current;
}
+struct ExecutionContextSaver
+{
+ ExecutionEngine *engine;
+ ExecutionContext *savedContext;
+
+ ExecutionContextSaver(ExecutionContext *context)
+ : engine(context->engine)
+ , savedContext(context)
+ {
+ }
+ ~ExecutionContextSaver()
+ {
+ while (engine->current != savedContext)
+ engine->popContext();
+ }
+};
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 65fec54be6..291d7cc033 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -65,14 +65,14 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
formals.fill(0);
const quint32 *formalsIndices = compiledFunction->formalsTable();
for (int i = 0; i < compiledFunction->nFormals; ++i)
- formals[i] = engine->newString(unit->data->stringAt(formalsIndices[i]))->getPointer();
+ formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
locals.resize(compiledFunction->nLocals);
locals.fill(0);
const quint32 *localsIndices = compiledFunction->localsTable();
for (int i = 0; i < compiledFunction->nLocals; ++i)
- locals[i] = engine->newString(unit->data->stringAt(localsIndices[i]))->getPointer();
+ locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString();
}
Function::~Function()
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 34ab5df73a..35c98897a0 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -86,13 +86,24 @@ struct Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) {
- SafeValue *stack = ctx->engine->jsStackTop;
- try {
- return codePtr(ctx, data);
- } catch (...) {
- ctx->engine->jsStackTop = stack;
- ctx->rethrowException();
- }
+
+ struct StackSaver {
+ ExecutionEngine *engine;
+ SafeValue *stack;
+
+ StackSaver(ExecutionEngine *engine)
+ : engine(engine)
+ , stack(engine->jsStackTop)
+ {}
+
+ ~StackSaver()
+ {
+ engine->jsStackTop = stack;
+ }
+ };
+
+ StackSaver(ctx->engine);
+ return codePtr(ctx, data);
}
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index e67b3ef771..55baef06db 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -115,7 +115,6 @@ FunctionObject::FunctionObject(InternalClass *ic)
type = Type_FunctionObject;
needsActivation = false;
- usesArgumentsObject = false;
strictMode = false;
}
@@ -135,7 +134,6 @@ void FunctionObject::init(const StringRef n, bool createProto)
type = Type_FunctionObject;
needsActivation = true;
- usesArgumentsObject = false;
strictMode = false;
#ifndef QT_NO_DEBUG
assert(scope->next != (ExecutionContext *)0x1);
@@ -414,7 +412,6 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
ExecutionEngine *v4 = scope->engine;
needsActivation = function->needsActivation();
- usesArgumentsObject = function->usesArgumentsObject();
strictMode = function->isStrict();
formalParameterCount = function->formals.size();
formalParameterList = function->formals.constData();
@@ -446,16 +443,8 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
- ScopedValue result(scope);
- SAVE_JS_STACK(f->scope);
- try {
- result = f->function->code(ctx, f->function->codeData);
- } catch (...) {
- context->rethrowException();
- }
- CHECK_JS_STACK(f->scope);
- ctx->engine->popContext();
-
+ ExecutionContextSaver ctxSaver(context);
+ ScopedValue result(scope, f->function->code(ctx, f->function->codeData));
if (result->isObject())
return result.asReturnedValue();
return obj.asReturnedValue();
@@ -477,16 +466,8 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
}
}
- ScopedValue result(scope);
- SAVE_JS_STACK(f->scope);
- try {
- result = f->function->code(ctx, f->function->codeData);
- } catch (...) {
- context->rethrowException();
- }
- CHECK_JS_STACK(f->scope);
- ctx->engine->popContext();
- return result.asReturnedValue();
+ ExecutionContextSaver ctxSaver(context);
+ return f->function->code(ctx, f->function->codeData);
}
DEFINE_MANAGED_VTABLE(SimpleScriptFunction);
@@ -511,7 +492,6 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
ExecutionEngine *v4 = scope->engine;
needsActivation = function->needsActivation();
- usesArgumentsObject = function->usesArgumentsObject();
strictMode = function->isStrict();
formalParameterCount = function->formals.size();
formalParameterList = function->formals.constData();
@@ -544,16 +524,12 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
callData->thisObject = obj;
ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData);
- try {
- Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData));
- ctx->engine->popContext();
+ ExecutionContextSaver ctxSaver(context);
+ Scoped<Object> result(scope, f->function->code(ctx, f->function->codeData));
- if (!result)
- return obj.asReturnedValue();
- return result.asReturnedValue();
- } catch (...) {
- context->rethrowException();
- }
+ if (!result)
+ return obj.asReturnedValue();
+ return result.asReturnedValue();
}
ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
@@ -574,16 +550,8 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
}
}
- ScopedValue result(scope);
- SAVE_JS_STACK(f->scope);
- try {
- result = f->function->code(ctx, f->function->codeData);
- } catch (...) {
- context->rethrowException();
- }
- CHECK_JS_STACK(f->scope);
- ctx->engine->popContext();
- return result.asReturnedValue();
+ ExecutionContextSaver ctxSaver(context);
+ return f->function->code(ctx, f->function->codeData);
}
@@ -596,7 +564,6 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
, code(code)
{
vtbl = &static_vtbl;
- isBuiltinFunction = true;
}
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
@@ -618,15 +585,8 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
ctx.callData = callData;
v4->pushContext(&ctx);
- ScopedValue result(scope);
- try {
- result = f->code(&ctx);
- } catch (...) {
- context->rethrowException();
- }
-
- context->engine->popContext();
- return result.asReturnedValue();
+ ExecutionContextSaver ctxSaver(context);
+ return f->code(&ctx);
}
ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
@@ -642,15 +602,8 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
ctx.callData = callData;
v4->pushContext(&ctx);
- ScopedValue result(scope);
- try {
- result = f->code(&ctx, f->index);
- } catch (...) {
- context->rethrowException();
- }
-
- context->engine->popContext();
- return result.asReturnedValue();
+ ExecutionContextSaver ctxSaver(context);
+ return f->code(&ctx, f->index);
}
DEFINE_MANAGED_VTABLE(IndexedBuiltinFunction);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 24231165df..eeb041ddc0 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -193,7 +193,6 @@ struct IndexedBuiltinFunction: FunctionObject
, index(index)
{
vtbl = &static_vtbl;
- isBuiltinFunction = true;
}
static ReturnedValue construct(Managed *m, CallData *)
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 3569247459..e0f51d22e5 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -55,7 +55,9 @@ namespace std {
inline bool isinf(double d) { return !_finite(d) && !_isnan(d); }
inline bool isnan(double d) { return !!_isnan(d); }
inline bool isfinite(double d) { return _finite(d); }
+#if _MSC_VER < 1800
inline bool signbit(double d) { return _copysign(1.0, d) < 0; }
+#endif
} // namespace std
@@ -64,6 +66,41 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#define qOffsetOf(s, m) ((size_t)((((char *)&(((s *)64)->m)) - 64)))
+// Decide whether to enable or disable the JIT
+
+// White list architectures
+
+#if defined(Q_PROCESSOR_X86)
+#define V4_ENABLE_JIT
+#elif defined(Q_PROCESSOR_X86_64)
+#define V4_ENABLE_JIT
+#elif defined(Q_PROCESSOR_ARM_32)
+
+#if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4)
+#define V4_ENABLE_JIT
+#endif
+
+#endif
+
+// Black list some platforms
+#if defined(V4_ENABLE_JIT)
+#if defined(Q_OS_WINCE) || defined(Q_OS_IOS) || defined(Q_OS_WIN64)
+ #undef V4_ENABLE_JIT
+#endif
+#endif
+
+// Do certain things depending on whether the JIT is enabled or disabled
+
+#ifdef V4_ENABLE_JIT
+#define ENABLE_YARR_JIT 1
+#define ENABLE_JIT 1
+#define ENABLE_ASSEMBLER 1
+#else
+#define ENABLE_YARR_JIT 0
+#define ENABLE_ASSEMBLER 0
+#define ENABLE_JIT 0
+#endif
+
#if defined(Q_OS_QNX)
#include <math.h>
#undef isnan
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index e1e986e85f..4dcdb08415 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -355,6 +355,27 @@ EvalFunction::EvalFunction(ExecutionContext *scope)
ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
{
+ struct ContextStateSaver {
+ ExecutionContext *savedContext;
+ bool strictMode;
+ ExecutionContext::EvalCode *evalCode;
+ CompiledData::CompilationUnit *compilationUnit;
+
+ ContextStateSaver(ExecutionContext *context)
+ : savedContext(context)
+ , strictMode(context->strictMode)
+ , evalCode(context->currentEvalCode)
+ , compilationUnit(context->compilationUnit)
+ {}
+
+ ~ContextStateSaver()
+ {
+ savedContext->strictMode = strictMode;
+ savedContext->currentEvalCode = evalCode;
+ savedContext->compilationUnit = compilationUnit;
+ }
+ };
+
if (callData->argc < 1)
return Encode::undefined();
@@ -386,46 +407,28 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
strictMode = function->isStrict() || (ctx->strictMode);
- usesArgumentsObject = function->usesArgumentsObject();
needsActivation = function->needsActivation();
if (strictMode) {
- FunctionObject *e = FunctionObject::creatScriptFunction(ctx, function);
+ ScopedFunctionObject e(scope, FunctionObject::creatScriptFunction(ctx, function));
ScopedCallData callData(scope, 0);
callData->thisObject = ctx->callData->thisObject;
return e->call(callData);
}
+ ExecutionContextSaver ctxSaver(parentContext);
+ ContextStateSaver stateSaver(ctx);
+
ExecutionContext::EvalCode evalCode;
evalCode.function = function;
evalCode.next = ctx->currentEvalCode;
ctx->currentEvalCode = &evalCode;
// set the correct strict mode flag on the context
- bool cstrict = ctx->strictMode;
ctx->strictMode = strictMode;
-
- CompiledData::CompilationUnit * const oldCompilationUnit = ctx->compilationUnit;
ctx->compilationUnit = function->compilationUnit;
- ScopedValue result(scope);
- try {
- result = function->code(ctx, function->codeData);
- } catch (...) {
- ctx->strictMode = cstrict;
- ctx->currentEvalCode = evalCode.next;
- ctx->compilationUnit = oldCompilationUnit;
- ctx->rethrowException();
- }
-
- ctx->strictMode = cstrict;
- ctx->currentEvalCode = evalCode.next;
- ctx->compilationUnit = oldCompilationUnit;
-
- while (engine->current != parentContext)
- engine->popContext();
-
- return result.asReturnedValue();
+ return function->code(ctx, function->codeData);
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 2295fb5aa8..331b528409 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -881,6 +881,9 @@ JsonObject::JsonObject(ExecutionEngine *engine)
{
type = Type_JSONObject;
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
defineDefaultProperty(QStringLiteral("parse"), method_parse, 2);
defineDefaultProperty(QStringLiteral("stringify"), method_stringify, 3);
}
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 03608d2556..31bb8f2b94 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -84,6 +84,7 @@ void Managed::operator delete(void *ptr)
Managed *m = static_cast<Managed *>(ptr);
m->vtbl = 0;
m->_data = 0;
+ m->markBit = 0;
m->~Managed();
}
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index d189c1961b..b4469c8048 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -159,7 +159,7 @@ private:
protected:
Managed(InternalClass *internal)
: _data(0), vtbl(&static_vtbl), internalClass(internal)
- { inUse = 1; extensible = 1; hasAccessorProperty = 0; }
+ { inUse = 1; extensible = 1; }
public:
void *operator new(size_t size, MemoryManager *mm);
@@ -282,22 +282,24 @@ public:
ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); }
+ enum {
+ SimpleArray = 1
+ };
+
union {
uint _data;
struct {
- uint markBit : 1;
- uint inUse : 1;
- uint extensible : 1; // used by Object
- uint isNonStrictArgumentsObject : 1;
- uint isBuiltinFunction : 1; // used by FunctionObject
- uint needsActivation : 1; // used by FunctionObject
- uint usesArgumentsObject : 1; // used by FunctionObject
- uint strictMode : 1; // used by FunctionObject
- uint type : 8;
- mutable uint subtype : 3;
- uint bindingKeyFlag : 1;
- uint hasAccessorProperty : 1;
- uint unused : 11;
+ uchar markBit : 1;
+ uchar inUse : 1;
+ uchar extensible : 1; // used by Object
+ uchar isNonStrictArgumentsObject : 1;
+ uchar needsActivation : 1; // used by FunctionObject
+ uchar strictMode : 1; // used by FunctionObject
+ uchar bindingKeyFlag : 1;
+ uchar hasAccessorProperty : 1;
+ uchar type;
+ mutable uchar subtype;
+ uchar flags;
};
};
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index fcff9e4aca..6280b7c392 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -55,6 +55,9 @@ MathObject::MathObject(ExecutionEngine *engine)
{
type = Type_MathObject;
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0)));
defineReadonlyProperty(QStringLiteral("LN2"), Primitive::fromDouble(::log(2.0)));
defineReadonlyProperty(QStringLiteral("LN10"), Primitive::fromDouble(::log(10.0)));
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 81b9e1a053..a03f2865f1 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -171,11 +171,7 @@ struct MemoryManager::Data
memset(allocCount, 0, sizeof(allocCount));
scribble = !qgetenv("QV4_MM_SCRIBBLE").isEmpty();
aggressiveGC = !qgetenv("QV4_MM_AGGRESSIVE_GC").isEmpty();
- exactGC = !qgetenv("QV4_MM_EXACT_GC").isEmpty();
- if (aggressiveGC)
- qDebug() << "Using aggressive garbage collection";
- if (exactGC)
- qDebug() << "Using exact garbage collection";
+ exactGC = qgetenv("QV4_MM_CONSERVATIVE_GC").isEmpty();
}
~Data()
@@ -290,7 +286,9 @@ Managed *MemoryManager::alloc(std::size_t size)
std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end());
char *chunk = (char *)allocation.memory.base();
char *end = chunk + allocation.memory.size() - size;
+#ifndef QT_NO_DEBUG
memset(chunk, 0, allocation.memory.size());
+#endif
Managed **last = &m_d->smallItems[pos];
while (chunk <= end) {
Managed *o = reinterpret_cast<Managed *>(chunk);
@@ -336,37 +334,38 @@ void MemoryManager::mark()
persistent = persistent->next;
}
- // push all caller saved registers to the stack, so we can find the objects living in these registers
+ collectFromJSStack();
+
+ if (!m_d->exactGC) {
+ // push all caller saved registers to the stack, so we can find the objects living in these registers
#if COMPILER(MSVC)
# if CPU(X86_64)
- HANDLE thread = GetCurrentThread();
- WOW64_CONTEXT ctxt;
- /*bool success =*/ Wow64GetThreadContext(thread, &ctxt);
+ HANDLE thread = GetCurrentThread();
+ WOW64_CONTEXT ctxt;
+ /*bool success =*/ Wow64GetThreadContext(thread, &ctxt);
# elif CPU(X86)
- HANDLE thread = GetCurrentThread();
- CONTEXT ctxt;
- /*bool success =*/ GetThreadContext(thread, &ctxt);
+ HANDLE thread = GetCurrentThread();
+ CONTEXT ctxt;
+ /*bool success =*/ GetThreadContext(thread, &ctxt);
# endif // CPU
#elif COMPILER(CLANG) || COMPILER(GCC)
# if CPU(X86_64)
- quintptr regs[5];
- asm(
- "mov %%rbp, %0\n"
- "mov %%r12, %1\n"
- "mov %%r13, %2\n"
- "mov %%r14, %3\n"
- "mov %%r15, %4\n"
- : "=m" (regs[0]), "=m" (regs[1]), "=m" (regs[2]), "=m" (regs[3]), "=m" (regs[4])
- :
- :
- );
+ quintptr regs[5];
+ asm(
+ "mov %%rbp, %0\n"
+ "mov %%r12, %1\n"
+ "mov %%r13, %2\n"
+ "mov %%r14, %3\n"
+ "mov %%r15, %4\n"
+ : "=m" (regs[0]), "=m" (regs[1]), "=m" (regs[2]), "=m" (regs[3]), "=m" (regs[4])
+ :
+ :
+ );
# endif // CPU
#endif // COMPILER
- collectFromJSStack();
-
- if (!m_d->exactGC)
collectFromStack();
+ }
// Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
// keeps all of its children alive in JavaScript.
@@ -399,7 +398,7 @@ void MemoryManager::mark()
}
}
-std::size_t MemoryManager::sweep(bool lastSweep)
+void MemoryManager::sweep(bool lastSweep)
{
PersistentValuePrivate *weak = m_weakValues;
while (weak) {
@@ -431,12 +430,11 @@ std::size_t MemoryManager::sweep(bool lastSweep)
}
}
- std::size_t freedCount = 0;
GCDeletable *deletable = 0;
GCDeletable **firstDeletable = &deletable;
for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
- freedCount += sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
+ sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
ExecutionContext *ctx = m_contextList;
ExecutionContext **n = &m_contextList;
@@ -459,15 +457,11 @@ std::size_t MemoryManager::sweep(bool lastSweep)
delete deletable;
deletable = next;
}
-
- return freedCount;
}
-std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable)
+void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable)
{
// qDebug("chunkStart @ %p, size=%x, pos=%x (%x)", chunkStart, size, size>>4, m_d->smallItems[size >> 4]);
- std::size_t freedCount = 0;
-
Managed **f = &m_d->smallItems[size >> 4];
#ifdef V4_USE_VALGRIND
@@ -499,15 +493,12 @@ std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t
#endif
*f = m;
SCRIBBLE(m, 0x99, size);
- ++freedCount;
}
}
}
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
-
- return freedCount;
}
bool MemoryManager::isGCBlocked() const
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index abbc0a7b4e..95f49545b8 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -132,8 +132,8 @@ private:
void collectFromStack() const;
void collectFromJSStack() const;
void mark();
- std::size_t sweep(bool lastSweep = false);
- std::size_t sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable);
+ void sweep(bool lastSweep = false);
+ void sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable);
protected:
QScopedPointer<Data> m_d;
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index a07e5dfe1d..b04c65196e 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -76,6 +76,7 @@ Object::Object(ExecutionEngine *engine)
{
vtbl = &static_vtbl;
type = Type_Object;
+ flags = SimpleArray;
memset(memberData, 0, sizeof(Property)*memberDataAlloc);
}
@@ -86,6 +87,7 @@ Object::Object(InternalClass *internalClass)
{
vtbl = &static_vtbl;
type = Type_Object;
+ flags = SimpleArray;
if (internalClass->size >= memberDataAlloc) {
memberDataAlloc = internalClass->size;
@@ -239,19 +241,39 @@ void Object::markObjects(Managed *that)
{
Object *o = static_cast<Object *>(that);
- for (int i = 0; i < o->internalClass->size; ++i) {
- const Property &pd = o->memberData[i];
- if (o->internalClass->propertyData[i].isData()) {
- if (Managed *m = pd.value.asManaged())
- m->mark();
- } else {
- if (pd.getter())
- pd.getter()->mark();
- if (pd.setter())
- pd.setter()->mark();
+ if (!o->hasAccessorProperty) {
+ for (int i = 0; i < o->internalClass->size; ++i)
+ o->memberData[i].value.mark();
+ } else {
+ for (int i = 0; i < o->internalClass->size; ++i) {
+ const Property &pd = o->memberData[i];
+ if (o->internalClass->propertyData[i].isAccessor()) {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
+ } else {
+ pd.value.mark();
+ }
+ }
+ }
+ if (o->flags & SimpleArray) {
+ for (uint i = 0; i < o->arrayDataLen; ++i)
+ o->arrayData[i].value.mark();
+ return;
+ } else {
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ const Property &pd = o->arrayData[i];
+ if (o->arrayAttributes && o->arrayAttributes[i].isAccessor()) {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
+ } else {
+ pd.value.mark();
+ }
}
}
- o->markArrayObjects();
}
void Object::ensureMemberIndex(uint idx)
@@ -304,14 +326,10 @@ Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
uint pidx = propertyIndexFromArrayIndex(index);
if (pidx < UINT_MAX) {
Property *p = arrayData + pidx;
- if (!arrayAttributes || arrayAttributes[pidx].isData()) {
+ if (!p->value.isEmpty() && !(arrayAttributes && arrayAttributes[pidx].isGeneric())) {
if (attrs)
*attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
return p;
- } else if (arrayAttributes[pidx].isAccessor()) {
- if (attrs)
- *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Accessor);
- return p;
}
}
if (isStringObject()) {
@@ -356,7 +374,7 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
uint pidx = o->propertyIndexFromArrayIndex(index);
if (pidx < UINT_MAX) {
Property *p = o->arrayData + pidx;
- if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ if (!p->value.isEmpty()) {
if (attrs)
*attrs = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
return p;
@@ -448,7 +466,8 @@ PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
if (pidx < UINT_MAX) {
if (o->arrayAttributes)
return o->arrayAttributes[pidx];
- return Attr_Data;
+ if (!o->arrayData[pidx].value.isEmpty())
+ return Attr_Data;
}
if (o->isStringObject()) {
Property *p = static_cast<const StringObject *>(o)->getIndex(index);
@@ -578,7 +597,7 @@ Property *Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name
Property *p = o->arrayData + pidx;
PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
++it->arrayIndex;
- if ((!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric())
+ if (!p->value.isEmpty()
&& (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
*index = it->arrayIndex - 1;
if (attrs)
@@ -639,7 +658,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
while (o) {
uint pidx = o->propertyIndexFromArrayIndex(index);
if (pidx < UINT_MAX) {
- if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ if (!o->arrayData[pidx].value.isEmpty()) {
pd = o->arrayData + pidx;
if (o->arrayAttributes)
attrs = o->arrayAttributes[pidx];
@@ -757,13 +776,9 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
PropertyAttributes attrs;
uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX) {
- if (arrayAttributes && arrayAttributes[pidx].isGeneric()) {
- pidx = UINT_MAX;
- } else {
- pd = arrayData + pidx;
- attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
- }
+ if (pidx < UINT_MAX && !arrayData[pidx].value.isEmpty()) {
+ pd = arrayData + pidx;
+ attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
}
if (!pd && isStringObject()) {
@@ -852,14 +867,13 @@ bool Object::internalDeleteIndexedProperty(uint index)
uint pidx = propertyIndexFromArrayIndex(index);
if (pidx == UINT_MAX)
return true;
- if (arrayAttributes && arrayAttributes[pidx].isGeneric())
+ if (arrayData[pidx].value.isEmpty())
return true;
if (!arrayAttributes || arrayAttributes[pidx].isConfigurable()) {
- arrayData[pidx].value = Primitive::undefinedValue();
- if (!arrayAttributes)
- ensureArrayAttributes();
- arrayAttributes[pidx].clear();
+ arrayData[pidx].value = Primitive::emptyValue();
+ if (arrayAttributes)
+ arrayAttributes[pidx].clear();
if (sparseArray) {
arrayData[pidx].value.int_32 = arrayFreeList;
arrayFreeList = pidx;
@@ -951,7 +965,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop
// Clause 1
{
uint pidx = propertyIndexFromArrayIndex(index);
- if (pidx < UINT_MAX && (!arrayAttributes || !arrayAttributes[pidx].isGeneric()))
+ if (pidx < UINT_MAX && !arrayData[pidx].value.isEmpty())
current = arrayData + pidx;
if (!current && isStringObject())
current = static_cast<StringObject *>(this)->getIndex(index);
@@ -1000,7 +1014,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, con
}
// clause 8
- if (attrs.isGeneric())
+ if (attrs.isGeneric() || current->value.isEmpty())
goto accept;
// clause 9
@@ -1086,6 +1100,7 @@ void Object::copyArrayData(Object *other)
arrayOffset = 0;
if (other->sparseArray) {
+ flags &= ~SimpleArray;
sparseArray = new SparseArray(*other->sparseArray);
arrayFreeList = other->arrayFreeList;
}
@@ -1120,7 +1135,7 @@ ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endInd
Property *end = pd + endIndex;
pd += fromIndex;
while (pd < end) {
- if (!arrayAttributes || !arrayAttributes[pd - arrayData].isGeneric()) {
+ if (!pd->value.isEmpty()) {
value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data);
if (__qmljs_strict_equal(value, v))
return Encode((uint)(pd - arrayData));
@@ -1156,8 +1171,8 @@ void Object::arrayConcat(const ArrayObject *other)
int oldSize = arrayLength();
arrayReserve(oldSize + other->arrayDataLen);
if (oldSize > arrayDataLen) {
- ensureArrayAttributes();
- std::fill(arrayAttributes + arrayDataLen, arrayAttributes + oldSize, PropertyAttributes());
+ for (int i = arrayDataLen; i < oldSize; ++i)
+ arrayData[i].value = Primitive::emptyValue();
}
if (other->arrayAttributes) {
for (int i = 0; i < other->arrayDataLen; ++i) {
@@ -1166,10 +1181,8 @@ void Object::arrayConcat(const ArrayObject *other)
arrayDataLen = oldSize + i + 1;
if (arrayAttributes)
arrayAttributes[oldSize + i] = Attr_Data;
- if (!exists) {
- ensureArrayAttributes();
- arrayAttributes[oldSize + i].clear();
- }
+ if (!exists)
+ arrayData[oldSize + i].value = Primitive::emptyValue();
}
} else {
arrayDataLen = oldSize + other->arrayDataLen;
@@ -1200,13 +1213,16 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
// into data properties and then sort. This is in line with the sentence above.
if (arrayAttributes) {
for (uint i = 0; i < len; i++) {
- if (arrayAttributes[i].isGeneric()) {
+ if ((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty()) {
while (--len > i)
- if (!arrayAttributes[len].isGeneric())
+ if (!((arrayAttributes && arrayAttributes[len].isGeneric())|| arrayData[len].value.isEmpty()))
break;
arrayData[i].value = getValue(arrayData + len, arrayAttributes[len]);
- arrayAttributes[i] = Attr_Data;
- arrayAttributes[len].clear();
+ arrayData[len].value = Primitive::emptyValue();
+ if (arrayAttributes) {
+ arrayAttributes[i] = Attr_Data;
+ arrayAttributes[len].clear();
+ }
} else if (arrayAttributes[i].isAccessor()) {
arrayData[i].value = getValue(arrayData + i, arrayAttributes[i]);
arrayAttributes[i] = Attr_Data;
@@ -1233,9 +1249,10 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
void Object::initSparse()
{
if (!sparseArray) {
+ flags &= ~SimpleArray;
sparseArray = new SparseArray;
for (int i = 0; i < arrayDataLen; ++i) {
- if (!arrayAttributes || !arrayAttributes[i].isGeneric()) {
+ if (!((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty())) {
SparseArrayNode *n = sparseArray->insert(i);
n->value = i + arrayOffset;
}
@@ -1309,6 +1326,7 @@ void Object::ensureArrayAttributes()
if (arrayAttributes)
return;
+ flags &= ~SimpleArray;
arrayAttributes = new PropertyAttributes[arrayAlloc];
for (uint i = 0; i < arrayDataLen; ++i)
arrayAttributes[i] = Attr_Data;
@@ -1376,22 +1394,6 @@ bool Object::setArrayLength(uint newLen) {
return ok;
}
-void Object::markArrayObjects() const
-{
- for (uint i = 0; i < arrayDataLen; ++i) {
- const Property &pd = arrayData[i];
- if (!arrayAttributes || arrayAttributes[i].isData()) {
- if (Managed *m = pd.value.asManaged())
- m->mark();
- } else if (arrayAttributes[i].isAccessor()) {
- if (pd.getter())
- pd.getter()->mark();
- if (pd.setter())
- pd.setter()->mark();
- }
- }
-}
-
DEFINE_MANAGED_VTABLE(ArrayObject);
ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 032aadd5a6..097d40db55 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -255,8 +255,6 @@ public:
return arrayData + index;
}
- void markArrayObjects() const;
-
void push_back(const ValueRef v);
SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
@@ -340,6 +338,7 @@ struct BooleanObject: Object {
protected:
BooleanObject(InternalClass *ic)
: Object(ic) {
+ vtbl = &static_vtbl;
type = Type_BooleanObject;
value = Encode(false);
}
@@ -357,6 +356,7 @@ struct NumberObject: Object {
protected:
NumberObject(InternalClass *ic)
: Object(ic) {
+ vtbl = &static_vtbl;
type = Type_NumberObject;
value = Encode((int)0);
}
@@ -420,9 +420,12 @@ inline Property *Object::arrayInsert(uint index, PropertyAttributes attributes)
if (index >= arrayAlloc)
arrayReserve(index + 1);
if (index >= arrayDataLen) {
- ensureArrayAttributes();
- for (uint i = arrayDataLen; i < index; ++i)
- arrayAttributes[i].clear();
+ // mark possible hole in the array
+ for (uint i = arrayDataLen; i < index; ++i) {
+ arrayData[i].value = Primitive::emptyValue();
+ if (arrayAttributes)
+ arrayAttributes[i].clear();
+ }
arrayDataLen = index + 1;
}
pd = arrayData + index;
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 21cbc8d7fd..7cfda589e5 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -259,7 +259,7 @@ ReturnedValue ObjectPrototype::method_seal(SimpleCallContext *ctx)
o->ensureArrayAttributes();
for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!o->arrayAttributes[i].isGeneric())
+ if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
o->arrayAttributes[i].setConfigurable(false);
}
@@ -279,7 +279,7 @@ ReturnedValue ObjectPrototype::method_freeze(SimpleCallContext *ctx)
o->ensureArrayAttributes();
for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!o->arrayAttributes[i].isGeneric())
+ if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
o->arrayAttributes[i].setConfigurable(false);
if (o->arrayAttributes[i].isData())
o->arrayAttributes[i].setWritable(false);
@@ -318,7 +318,7 @@ ReturnedValue ObjectPrototype::method_isSealed(SimpleCallContext *ctx)
return Encode(false);
for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!o->arrayAttributes[i].isGeneric())
+ if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
if (o->arrayAttributes[i].isConfigurable())
return Encode(false);
}
@@ -346,7 +346,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(SimpleCallContext *ctx)
return Encode(false);
for (uint i = 0; i < o->arrayDataLen; ++i) {
- if (!o->arrayAttributes[i].isGeneric())
+ if (!(o->arrayAttributes[i].isGeneric() || o->arrayData[i].value.isEmpty()))
if (o->arrayAttributes[i].isConfigurable() || o->arrayAttributes[i].isWritable())
return Encode(false);
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index d42d842ab7..1fd47c7c66 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -243,6 +243,9 @@ QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
{
vtbl = &static_vtbl;
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
m_destroy = engine->newIdentifier(QStringLiteral("destroy"));
}
@@ -260,7 +263,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
result = ddata->propertyCache->property(name, m_object, qmlContext);
- if (!result)
+ else
result = QQmlPropertyCache::property(engine->v8Engine->engine(), m_object, name, qmlContext, *local);
return result;
}
@@ -724,7 +727,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
try {
f->call(callData);
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
if (error.description().isEmpty())
error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
@@ -1433,14 +1436,15 @@ void *CallArgument::dataPtr()
{
if (type == -1)
return qvariantPtr->data();
- else
+ else if (type != 0)
return (void *)&allocData;
+ return 0;
}
void CallArgument::initAsType(int callType)
{
if (type != 0) { cleanup(); type = 0; }
- if (callType == QMetaType::UnknownType) return;
+ if (callType == QMetaType::UnknownType || callType == QMetaType::Void) return;
if (callType == qMetaTypeId<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue();
@@ -1475,9 +1479,6 @@ void CallArgument::initAsType(int callType)
} else if (callType == QMetaType::QJsonValue) {
type = callType;
jsonValuePtr = new (&allocData) QJsonValue();
- } else if (callType == QMetaType::Void) {
- type = -1;
- qvariantPtr = new (&allocData) QVariant();
} else {
type = -1;
qvariantPtr = new (&allocData) QVariant(callType, (void *)0);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 9c7fe94759..6eaa8c387d 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -79,7 +79,7 @@ RegExpObject::RegExpObject(InternalClass *ic)
init(ic->engine);
}
-RegExpObject::RegExpObject(ExecutionEngine *engine, RegExp* value, bool global)
+RegExpObject::RegExpObject(ExecutionEngine *engine, Referenced<RegExp> value, bool global)
: Object(engine->regExpClass)
, value(value)
, global(global)
@@ -132,6 +132,9 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
pattern = ecmaPattern;
}
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
init(engine);
@@ -248,7 +251,8 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
if (!f->isUndefined())
ctx->throwTypeError();
- return Encode(ctx->engine->newRegExpObject(re->value, re->global));
+ Scoped<RegExp> newRe(scope, re->value);
+ return Encode(ctx->engine->newRegExpObject(newRe, re->global));
}
QString pattern;
@@ -274,7 +278,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
}
}
- RegExp *regexp = RegExp::create(ctx->engine, pattern, ignoreCase, multiLine);
+ Scoped<RegExp> regexp(scope, RegExp::create(ctx->engine, pattern, ignoreCase, multiLine));
if (!regexp->isValid())
ctx->throwSyntaxError(0);
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 764470e776..0ef95a36e2 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -83,7 +83,7 @@ struct RegExpObject: Object {
Property *lastIndexProperty(ExecutionContext *ctx);
bool global;
- RegExpObject(ExecutionEngine *engine, RegExp* value, bool global);
+ RegExpObject(ExecutionEngine *engine, Referenced<RegExp> value, bool global);
RegExpObject(ExecutionEngine *engine, const QRegExp &re);
~RegExpObject() {}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6b3afcc300..6f914fa3c2 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -500,7 +500,8 @@ ReturnedValue __qmljs_get_element(ExecutionContext *ctx, const ValueRef object,
uint pidx = o->propertyIndexFromArrayIndex(idx);
if (pidx < UINT_MAX) {
if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
- return o->arrayData[pidx].value.asReturnedValue();
+ if (!o->arrayData[pidx].value.isEmpty())
+ return o->arrayData[pidx].value.asReturnedValue();
}
}
@@ -996,13 +997,7 @@ ReturnedValue __qmljs_builtin_define_array(ExecutionContext *ctx, Value *values,
a->arrayDataLen = length;
Property *pd = a->arrayData;
for (uint i = 0; i < length; ++i) {
- if (values[i].isEmpty()) {
- a->ensureArrayAttributes();
- pd->value = Primitive::undefinedValue();
- a->arrayAttributes[i].clear();
- } else {
- pd->value = values[i];
- }
+ pd->value = values[i];
++pd;
}
a->setArrayLengthUnchecked(length);
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 4081be54e8..d30132140b 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -66,7 +66,6 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
vtbl = &static_vtbl;
function = f;
function->compilationUnit->ref();
- usesArgumentsObject = function->usesArgumentsObject();
needsActivation = function->needsActivation();
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
@@ -80,7 +79,6 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
{
vtbl = &static_vtbl;
function = 0;
- usesArgumentsObject = false;
needsActivation = false;
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
@@ -229,6 +227,27 @@ void Script::parse()
ReturnedValue Script::run()
{
+ struct ContextStateSaver {
+ ExecutionContext *savedContext;
+ bool strictMode;
+ Lookup *lookups;
+ CompiledData::CompilationUnit *compilationUnit;
+
+ ContextStateSaver(ExecutionContext *context)
+ : savedContext(context)
+ , strictMode(context->strictMode)
+ , lookups(context->lookups)
+ , compilationUnit(context->compilationUnit)
+ {}
+
+ ~ContextStateSaver()
+ {
+ savedContext->strictMode = strictMode;
+ savedContext->lookups = lookups;
+ savedContext->compilationUnit = compilationUnit;
+ }
+ };
+
if (!parsed)
parse();
if (!vmFunction)
@@ -240,29 +259,13 @@ ReturnedValue Script::run()
if (qml.isUndefined()) {
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
- bool strict = scope->strictMode;
- Lookup *oldLookups = scope->lookups;
- CompiledData::CompilationUnit * const oldCompilationUnit = scope->compilationUnit;
-
+ ExecutionContextSaver ctxSaver(scope);
+ ContextStateSaver stateSaver(scope);
scope->strictMode = vmFunction->isStrict();
scope->lookups = vmFunction->compilationUnit->runtimeLookups;
scope->compilationUnit = vmFunction->compilationUnit;
- QV4::ScopedValue result(valueScope);
- try {
- result = vmFunction->code(scope, vmFunction->codeData);
- } catch (...) {
- scope->strictMode = strict;
- scope->lookups = oldLookups;
- scope->compilationUnit = oldCompilationUnit;
- scope->rethrowException();
- }
-
- scope->lookups = oldLookups;
- scope->compilationUnit = oldCompilationUnit;
-
- return result.asReturnedValue();
-
+ return vmFunction->code(scope, vmFunction->codeData);
} else {
ScopedObject qmlObj(valueScope, qml.value());
FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index c535dbea09..320646805b 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -175,6 +175,9 @@ public:
{
type = Type_QmlSequence;
vtbl = &static_vtbl;
+ flags &= ~SimpleArray;
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
init();
}
@@ -186,6 +189,9 @@ public:
{
type = Type_QmlSequence;
vtbl = &static_vtbl;
+ flags &= ~SimpleArray;
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
loadReference();
init();
}
diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp
index a9faf634c9..ec6b0f5ad1 100644
--- a/src/qml/jsruntime/qv4sparsearray.cpp
+++ b/src/qml/jsruntime/qv4sparsearray.cpp
@@ -73,7 +73,9 @@ bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) co
return result->toNumber() <= 0;
}
- return p1.value.toString(m_context)->toQString() < p2.value.toString(m_context)->toQString();
+ ScopedString p1s(scope, p1.value.toString(m_context));
+ ScopedString p2s(scope, p2.value.toString(m_context));
+ return p1s->toQString() < p2s->toQString();
}
diff --git a/src/qml/jsruntime/qv4stacktrace.cpp b/src/qml/jsruntime/qv4stacktrace.cpp
deleted file mode 100644
index 905111a23e..0000000000
--- a/src/qml/jsruntime/qv4stacktrace.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#if defined(_WIN32) && !(defined(WINCE) || defined(_WIN32_WCE))
-#include <windows.h>
-#include <DbgHelp.h>
-#endif
-
-#include "qv4stacktrace_p.h"
-#include "qv4function_p.h"
-#include "qv4engine_p.h"
-#include "qv4unwindhelper_p.h"
-
-#if defined(V4_CXX_ABI_EXCEPTION) || (defined(Q_OS_DARWIN) && !defined(Q_PROCESSOR_ARM_32))
-#define USE_UNWIND_BACKTRACE
-#endif
-
-#if defined(USE_UNWIND_BACKTRACE)
-#include <unwind.h>
-
-struct BacktraceHelper
-{
- void **array;
- int maximumSize;
- int frameCount;
-};
-
-static _Unwind_Reason_Code bt_helper(struct _Unwind_Context *ctx, void *data)
-{
- BacktraceHelper *helper = reinterpret_cast<BacktraceHelper*>(data);
-
- if (helper->frameCount != -1) {
- helper->array[helper->frameCount] = (void*)_Unwind_GetIP(ctx);
-
- if (helper->frameCount > 0 && helper->array[helper->frameCount] == helper->array[helper->frameCount - 1])
- return _URC_END_OF_STACK;
- }
- ++helper->frameCount;
- if (helper->frameCount == helper->maximumSize)
- return _URC_END_OF_STACK;
- return _URC_NO_REASON;
-}
-
-static int get_backtrace_from_libunwind(void **array, int size)
-{
- BacktraceHelper helper;
- helper.array = array;
- helper.maximumSize = size;
- helper.frameCount = -1; // To skip this function
- _Unwind_Backtrace(&bt_helper, &helper);
- return helper.frameCount;
-}
-#endif
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-NativeStackTrace::NativeStackTrace(ExecutionContext *context)
-{
- engine = context->engine;
- currentNativeFrame = 0;
-
-#if defined(USE_UNWIND_BACKTRACE)
- UnwindHelper::prepareForUnwind(context);
-
- nativeFrameCount = get_backtrace_from_libunwind(&trace[0], sizeof(trace) / sizeof(trace[0]));
-#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
-
- int machineType = 0;
-
- CONTEXT winContext;
- memset(&winContext, 0, sizeof(winContext));
- winContext.ContextFlags = CONTEXT_FULL;
- RtlCaptureContext(&winContext);
-
- STACKFRAME64 sf64;
- memset(&sf64, 0, sizeof(sf64));
-
-#if defined(Q_PROCESSOR_X86_32)
- machineType = IMAGE_FILE_MACHINE_I386;
-
- sf64.AddrFrame.Offset = winContext.Ebp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Eip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Esp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#elif defined(Q_PROCESSOR_X86_64)
- machineType = IMAGE_FILE_MACHINE_AMD64;
-
- sf64.AddrFrame.Offset = winContext.Rbp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Rip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Rsp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#else
-#error "Platform unsupported!"
-#endif
-
- nativeFrameCount = 0;
-
- while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
-
- if (sf64.AddrReturn.Offset == 0)
- break;
-
- trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
- nativeFrameCount++;
- if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
- break;
- }
-
-#else
- nativeFrameCount = 0;
-#endif
- }
-
-NativeFrame NativeStackTrace::nextFrame() {
- NativeFrame frame;
- frame.function = 0;
- frame.line = -1;
-
- for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
- quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
- // The pointers from the back trace point to the return address, but we are interested in
- // the caller site.
- pc = pc - 1;
-
- Function *f = engine->functionForProgramCounter(pc);
- if (!f)
- continue;
-
- frame.function = f;
- frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->codePtr));
- }
-
- return frame;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4stacktrace_p.h b/src/qml/jsruntime/qv4stacktrace_p.h
deleted file mode 100644
index 79cb4d1813..0000000000
--- a/src/qml/jsruntime/qv4stacktrace_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QV4STACKTRACE_P_H
-#define QV4STACKTRACE_P_H
-
-#include <qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-struct Function;
-struct ExecutionEngine;
-struct ExecutionContext;
-
-struct NativeFrame {
- Function *function;
- int line;
-};
-
-struct NativeStackTrace
-{
- void *trace[100];
- int nativeFrameCount;
- int currentNativeFrame;
- ExecutionEngine *engine;
-
- NativeStackTrace(ExecutionContext *context);
-
- NativeFrame nextFrame();
-};
-
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4STACKTRACE_P_H
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 7e503e4b1a..25e1ea55c2 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -82,6 +82,10 @@ StringObject::StringObject(InternalClass *ic)
{
vtbl = &static_vtbl;
type = Type_StringObject;
+
+ Scope scope(engine());
+ ScopedObject protectThis(scope, this);
+
value = ic->engine->newString("")->asReturnedValue();
tmpProperty.value = Primitive::undefinedValue();
@@ -94,6 +98,10 @@ StringObject::StringObject(ExecutionEngine *engine, const ValueRef val)
{
vtbl = &static_vtbl;
type = Type_StringObject;
+
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
value = *val;
tmpProperty.value = Primitive::undefinedValue();
diff --git a/src/qml/jsruntime/qv4value_def_p.h b/src/qml/jsruntime/qv4value_def_p.h
index c8d03cfeed..163aed9abc 100644
--- a/src/qml/jsruntime/qv4value_def_p.h
+++ b/src/qml/jsruntime/qv4value_def_p.h
@@ -194,8 +194,8 @@ struct Q_QML_EXPORT Value
inline bool isUndefined() const { return tag == Undefined_Type; }
inline bool isNull() const { return tag == _Null_Type; }
inline bool isBoolean() const { return tag == _Boolean_Type; }
- inline bool isInteger() const { return tag == _Integer_Type; }
#if QT_POINTER_SIZE == 8
+ inline bool isInteger() const { return (val >> IsNumber_Shift) == 1; }
inline bool isDouble() const { return (val >> IsDouble_Shift); }
inline bool isNumber() const { return (val >> IsNumber_Shift); }
inline bool isManaged() const { return !(val >> IsManaged_Shift); }
@@ -227,6 +227,7 @@ struct Q_QML_EXPORT Value
}
bool isNaN() const { return (tag & 0x7fff8000) == 0x00078000; }
#else
+ inline bool isInteger() const { return tag == _Integer_Type; }
inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
inline bool isManaged() const { return tag == Managed_Type; }
@@ -242,7 +243,7 @@ struct Q_QML_EXPORT Value
void setDouble(double d) { dbl = d; }
bool isNaN() const { return (tag & QV4::Value::NotDouble_Mask) == QV4::Value::NaN_Mask; }
#endif
- inline bool isString() const;
+ bool isString() const;
inline bool isObject() const;
inline bool isInt32() {
if (tag == _Integer_Type)
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 362f41affe..a2137ee849 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -200,10 +200,17 @@ inline bool Value::toBoolean() const
inline uint Value::asArrayIndex() const
{
+#if QT_POINTER_SIZE == 8
+ if (!isNumber())
+ return UINT_MAX;
+ if (isInteger())
+ return int_32 >= 0 ? (uint)int_32 : UINT_MAX;
+#else
if (isInteger() && int_32 >= 0)
return (uint)int_32;
if (!isDouble())
return UINT_MAX;
+#endif
double d = doubleValue();
uint idx = (uint)d;
if (idx != d)
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 2fe9c717bd..a37da31782 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -66,7 +66,7 @@ VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
{
vtbl = &static_vtbl;
if (isScarce())
- internalClass->engine->scarceResources.insert(this);
+ engine->scarceResources.insert(this);
}
QVariant VariantObject::toVariant(const QV4::ValueRef v)
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 8cc68e3643..de4fec4d56 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -2679,10 +2679,6 @@ case $rule_number: {
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
- if (lexer->qmlMode()) {
- const QString msg = qApp->translate("QQmlParser", "Deprecated JavaScript `with' statement detected in QML expression. Support for this will be removed in Qt 5.2!");
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, node->withToken, msg));
- }
} break;
./
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index 4f58e7f8ea..195b98bfd7 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -102,6 +102,7 @@ public:
~Engine();
void setCode(const QString &code);
+ const QString &code() const { return _code; }
void addComment(int pos, int len, int line, int col);
QList<AST::SourceLocation> comments() const;
diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp
index 75f0f743b8..b86b4a987f 100644
--- a/src/qml/parser/qqmljsparser.cpp
+++ b/src/qml/parser/qqmljsparser.cpp
@@ -1560,10 +1560,6 @@ case 317: {
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
- if (lexer->qmlMode()) {
- const QString msg = qApp->translate("QQmlParser", "Deprecated JavaScript `with' statement detected in QML expression. Support for this will be removed in Qt 5.2!");
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, node->withToken, msg));
- }
} break;
case 318: {
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index 1b25ed2e55..8b499d9b6d 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -65,6 +65,8 @@ struct QFiniteStack {
inline void deallocate();
inline void allocate(int size);
+ inline int capacity() const { return _alloc; }
+
inline bool isEmpty() const;
inline const T &top() const;
inline T &top();
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 35de0ac358..9fcef176ad 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -243,6 +243,9 @@ void QQmlCompiledData::initialize(QQmlEngine *engine)
{
Q_ASSERT(!hasEngine());
QQmlCleanup::addToEngine(engine);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ if (compilationUnit && !compilationUnit->engine)
+ compilationUnit->linkToEngine(v4);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index a17080f559..2cfb074aae 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -62,6 +62,7 @@
#include "qqmlglobal_p.h"
#include "qqmlbinding_p.h"
#include "qqmlabstracturlinterceptor.h"
+#include "qqmlcodegenerator_p.h"
#include <QDebug>
#include <QPointF>
@@ -809,6 +810,8 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
this->unit = unit;
this->unitRoot = root;
this->output = out;
+ this->jsModule.reset(new QQmlJS::V4IR::Module);
+ this->jsModule->isQmlModule = true;
// Compile types
const QList<QQmlTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes();
@@ -915,6 +918,16 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
if (!buildObject(tree, BindingContext()) || !completeComponentBuild())
return;
+ if (!jsModule->functions.isEmpty()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data());
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, jsModule.data(), &jsUnitGenerator));
+ isel->setUseFastLookups(false);
+ QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true);
+ output->compilationUnit = jsUnit;
+ output->compilationUnit->ref();
+ }
+
Instruction::Init init;
init.bindingsSize = compileState->totalBindingsCount;
init.parserStatusSize = compileState->parserStatusCount;
@@ -1323,11 +1336,12 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
} else if (v->type == Value::SignalExpression) {
Instruction::StoreSignal store;
+ store.runtimeFunctionIndex = compileState->runtimeFunctionIndices.at(v->signalData.functionIndex);
store.handlerName = output->indexForString(prop->name().toString());
store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
store.value = output->indexForString(v->value.asScript());
- store.context = v->signalExpressionContextStack;
+ store.context = v->signalData.signalExpressionContextStack;
store.line = v->location.start.line;
store.column = v->location.start.column;
output->addInstruction(store);
@@ -1621,6 +1635,42 @@ int QQmlCompiler::translationContextIndex()
return cachedTranslationContextIndex;
}
+static AST::FunctionDeclaration *convertSignalHandlerExpressionToFunctionDeclaration(QQmlJS::Engine *jsEngine,
+ AST::Node *node,
+ const QString &signalName,
+ const QList<QByteArray> &parameters)
+{
+ QQmlJS::MemoryPool *pool = jsEngine->pool();
+
+ AST::FormalParameterList *paramList = 0;
+ foreach (const QByteArray &param, parameters) {
+ QStringRef paramNameRef = jsEngine->newStringRef(QString::fromUtf8(param));
+
+ if (paramList)
+ paramList = new (pool) AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ AST::Statement *statement = node->statementCast();
+ if (!statement) {
+ AST::ExpressionNode *expr = node->expressionCast();
+ Q_ASSERT(expr);
+ statement = new (pool) AST::ExpressionStatement(expr);
+ }
+ AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement);
+ AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement);
+ elements = elements->finish();
+
+ AST::FunctionBody *body = new (pool) AST::FunctionBody(elements);
+
+ AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine->newStringRef(signalName), paramList, body);
+ return functionDeclaration;
+}
+
bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj,
const BindingContext &ctxt)
{
@@ -1687,7 +1737,13 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o
//all handlers should be on the original, rather than cloned signals in order
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
- prop->values.first()->signalExpressionContextStack = ctxt.stack;
+ prop->values.first()->signalData.signalExpressionContextStack = ctxt.stack;
+
+ QList<QByteArray> parameters = obj->metatype->signalParameterNames(prop->index);
+
+ AST::FunctionDeclaration *funcDecl = convertSignalHandlerExpressionToFunctionDeclaration(unit->parser().jsEngine(), prop->values.first()->value.asAST(), propName.toString(), parameters);
+ compileState->functionsToCompile.append(funcDecl);
+ prop->values.first()->signalData.functionIndex = compileState->functionsToCompile.count() - 1;
QString errorString;
obj->metatype->signalParameterStringForJS(prop->index, &errorString);
@@ -3185,24 +3241,8 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
// Dynamic slot data - comes after the property data
for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) {
- int paramCount = s->parameterNames.count();
-
- QString funcScript;
- int namesSize = 0;
- if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */);
- funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ +
- namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */);
- funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('(');
- for (int jj = 0; jj < paramCount; ++jj) {
- if (jj) funcScript.append(QLatin1Char(','));
- funcScript.append(QLatin1String(s->parameterNames.at(jj)));
- }
- funcScript += QLatin1Char(')') + s->body + QLatin1Char(')');
-
- QByteArray utf8 = funcScript.toUtf8();
- VMD::MethodData methodData = { s->parameterNames.count(),
- dynamicData.size(),
- utf8.length(),
+ VMD::MethodData methodData = { /*runtimeFunctionIndex*/ 0, // To be filled in later
+ s->parameterNames.count(),
s->location.start.line };
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
@@ -3210,7 +3250,12 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod
vmd->methodCount++;
md = methodData;
- dynamicData.append((const char *)utf8.constData(), utf8.length());
+ QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod cmm;
+ cmm.obj = obj;
+ cmm.methodIndex = vmd->methodCount - 1;
+ compileState->functionsToCompile.append(s->funcDecl);
+ cmm.compiledFunctionIndex = compileState->functionsToCompile.count() - 1;
+ compileState->compiledMetaMethods.append(cmm);
}
if (aliasCount)
@@ -3519,7 +3564,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
Instruction::StoreBinding store;
- store.value = output->indexForString(js.expression.asScript());
+ store.functionIndex = js.compiledIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.line = binding->location.start.line;
@@ -3579,15 +3624,52 @@ bool QQmlCompiler::completeComponentBuild()
aliasObject = compileState->aliasingObjects.next(aliasObject))
COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
+ const QQmlScript::Parser &parser = unit->parser();
+ QQmlJS::Engine *jsEngine = parser.jsEngine();
+ QQmlJS::MemoryPool *pool = jsEngine->pool();
+
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
JSBindingReference &binding = *b;
binding.dataType = BindingReference::QtScript;
+ QQmlJS::AST::Node *node = binding.expression.asAST();
+ // Always wrap this in an ExpressionStatement, to make sure that
+ // property var foo: function() { ... } results in a closure initialization.
+ if (!node->statementCast()) {
+ AST::ExpressionNode *expr = node->expressionCast();
+ node = new (pool) AST::ExpressionStatement(expr);
+ }
+
+ compileState->functionsToCompile.append(node);
+ binding.compiledIndex = compileState->functionsToCompile.count() - 1;
+
if (componentStats)
componentStats->componentStat.scriptBindings.append(b->value->location);
}
+ if (!compileState->functionsToCompile.isEmpty()) {
+ JSCodeGen jsCodeGen;
+
+ const QString &sourceCode = jsEngine->code();
+ AST::UiProgram *qmlRoot = parser.qmlRoot();
+
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, compileState->functionsToCompile);
+ compileState->runtimeFunctionIndices = runtimeFunctionIndices;
+
+ for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
+ JSBindingReference &binding = *b;
+ binding.compiledIndex = runtimeFunctionIndices[binding.compiledIndex];
+ }
+
+ foreach (const QQmlCompilerTypes::ComponentCompileState::CompiledMetaMethod &cmm, compileState->compiledMetaMethods) {
+ typedef QQmlVMEMetaData VMD;
+ VMD *vmd = (QQmlVMEMetaData *)cmm.obj->synthdata.data();
+ VMD::MethodData &md = *(vmd->methodData() + cmm.methodIndex);
+ md.runtimeFunctionIndex = runtimeFunctionIndices.at(cmm.compiledFunctionIndex);
+ }
+ }
+
// Check pop()'s matched push()'s
Q_ASSERT(compileState->objectDepth.depth() == 0);
Q_ASSERT(compileState->listDepth.depth() == 0);
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index b0fad4708b..142d8c68b1 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -63,6 +63,7 @@
#include "qqmltypenamecache_p.h"
#include "qqmltypeloader_p.h"
#include "private/qv4identifier_p.h"
+#include <private/qqmljsastfwd_p.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qset.h>
@@ -301,6 +302,16 @@ namespace QQmlCompilerTypes {
typedef QFieldList<O, &O::nextAliasingObject> AliasingObjectsList;
AliasingObjectsList aliasingObjects;
QQmlScript::Object *root;
+ QList<QQmlJS::AST::Node*> functionsToCompile;
+ QVector<int> runtimeFunctionIndices;
+
+ struct CompiledMetaMethod
+ {
+ QQmlScript::Object *obj;
+ int methodIndex;
+ int compiledFunctionIndex; // index in functionToCompile
+ };
+ QList<CompiledMetaMethod> compiledMetaMethods;
};
};
@@ -460,6 +471,8 @@ private:
int cachedComponentTypeRef;
int cachedTranslationContextIndex;
+ QScopedPointer<QQmlJS::V4IR::Module> jsModule;
+
// Compiler component statistics. Only collected if QML_COMPILER_STATS=1
struct ComponentStat
{
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index c4bc242bd9..ab08fb78e3 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1094,7 +1094,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
}
incubator.clear();
- QQmlIncubatorPrivate *p = incubator.d;
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(incubator.d);
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
@@ -1105,11 +1105,13 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
-class QmlIncubatorObject : public QV4::Object, public QQmlIncubator
+class QQmlComponentIncubator;
+
+class QmlIncubatorObject : public QV4::Object
{
Q_MANAGED
public:
- QmlIncubatorObject(QV8Engine *engine, IncubationMode = Asynchronous);
+ QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
static QV4::ReturnedValue method_get_statusChanged(QV4::SimpleCallContext *ctx);
static QV4::ReturnedValue method_set_statusChanged(QV4::SimpleCallContext *ctx);
@@ -1120,18 +1122,39 @@ public:
static void destroy(Managed *that);
static void markObjects(Managed *that);
+ QScopedPointer<QQmlComponentIncubator> incubator;
QV8Engine *v8;
QPointer<QObject> parent;
QV4::SafeValue valuemap;
QV4::SafeValue qmlGlobal;
QV4::SafeValue m_statusChanged;
-protected:
- virtual void statusChanged(Status);
- virtual void setInitialState(QObject *);
+
+ void statusChanged(QQmlIncubator::Status);
+ void setInitialState(QObject *);
};
DEFINE_MANAGED_VTABLE(QmlIncubatorObject);
+class QQmlComponentIncubator : public QQmlIncubator
+{
+public:
+ QQmlComponentIncubator(QmlIncubatorObject *inc, IncubationMode mode)
+ : QQmlIncubator(mode)
+ , incubatorObject(inc)
+ {}
+
+ virtual void statusChanged(Status s) {
+ incubatorObject->statusChanged(s);
+ }
+
+ virtual void setInitialState(QObject *o) {
+ incubatorObject->setInitialState(o);
+ }
+
+ QmlIncubatorObject *incubatorObject;
+};
+
+
static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
{
if (parent) {
@@ -1375,9 +1398,10 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
}
r->parent = parent;
- create(*r.getPointer(), creationContext());
+ QQmlIncubator *incubator = r.getPointer()->incubator.data();
+ create(*incubator, creationContext());
- if (r->status() == QQmlIncubator::Null) {
+ if (incubator->status() == QQmlIncubator::Null) {
args->setReturnValue(QV4::Encode::null());
} else {
args->setReturnValue(r.asReturnedValue());
@@ -1429,7 +1453,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::SimpleCallContext
if (!o)
ctx->throwTypeError();
- return QV4::QObjectWrapper::wrap(ctx->engine, o->object());
+ return QV4::QObjectWrapper::wrap(ctx->engine, o->incubator->object());
}
QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallContext *ctx)
@@ -1439,7 +1463,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallCon
if (!o)
ctx->throwTypeError();
- o->forceCompletion();
+ o->incubator->forceCompletion();
return QV4::Encode::undefined();
}
@@ -1451,7 +1475,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::SimpleCallContext
if (!o)
ctx->throwTypeError();
- return QV4::Encode(o->status());
+ return QV4::Encode(o->incubator->status());
}
QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::SimpleCallContext *ctx)
@@ -1471,6 +1495,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::SimpleCallC
if (!o || ctx->callData->argc < 1)
ctx->throwTypeError();
+
o->m_statusChanged = ctx->callData->args[0];
return QV4::Encode::undefined();
}
@@ -1479,9 +1504,10 @@ QQmlComponentExtension::~QQmlComponentExtension()
{
}
-QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, IncubationMode m)
- : Object(QV8Engine::getV4(engine)), QQmlIncubator(m)
+QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode m)
+ : Object(QV8Engine::getV4(engine))
{
+ incubator.reset(new QQmlComponentIncubator(this, m));
v8 = engine;
vtbl = &static_vtbl;
@@ -1512,28 +1538,32 @@ void QmlIncubatorObject::setInitialState(QObject *o)
void QmlIncubatorObject::destroy(Managed *that)
{
QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
- assert(o);
+ Q_ASSERT(o);
o->~QmlIncubatorObject();
}
void QmlIncubatorObject::markObjects(QV4::Managed *that)
{
QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
- assert(o);
+ Q_ASSERT(o);
o->valuemap.mark();
o->qmlGlobal.mark();
o->m_statusChanged.mark();
+ Object::markObjects(that);
}
-void QmlIncubatorObject::statusChanged(Status s)
+void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
- if (s == Ready) {
- Q_ASSERT(QQmlData::get(object()));
- QQmlData::get(object())->explicitIndestructibleSet = false;
- QQmlData::get(object())->indestructible = false;
+ QV4::Scope scope(QV8Engine::getV4(v8));
+ // hold the incubated object in a scoped value to prevent it's destruction before this method returns
+ QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, incubator->object()));
+
+ if (s == QQmlIncubator::Ready) {
+ Q_ASSERT(QQmlData::get(incubator->object()));
+ QQmlData::get(incubator->object())->explicitIndestructibleSet = false;
+ QQmlData::get(incubator->object())->indestructible = false;
}
- QV4::Scope scope(QV8Engine::getV4(v8));
QV4::ScopedFunctionObject f(scope, m_statusChanged);
if (f) {
QV4::ExecutionContext *ctx = scope.engine->current;
@@ -1543,7 +1573,7 @@ void QmlIncubatorObject::statusChanged(Status s)
callData->args[0] = QV4::Primitive::fromUInt32(s);
f->call(callData);
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error);
}
}
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index c67e45a833..5a2d6c4e00 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -196,9 +196,9 @@ public:
return uniqueId++;
}
- // Unfortunate workaround to avoid a circular dependency between
+ // Unfortunate workaround to avoid a circular dependency between
// qqmlengine_p.h and qqmlincubator_p.h
- struct Incubator {
+ struct Incubator : public QSharedData {
QIntrusiveListNode next;
// Unfortunate workaround for MSVC
QIntrusiveListNode nextWaitingFor;
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 3a4179717a..ad95ecdf06 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -138,28 +138,6 @@ QQmlError::~QQmlError()
delete d; d = 0;
}
-QQmlError QQmlError::catchJavaScriptException(QV4::ExecutionContext *context)
-{
- QV4::StackTrace trace;
- QV4::Scope scope(context);
- QV4::ScopedValue exception(scope, context->catchException(&trace));
- QQmlError error;
- if (!trace.isEmpty()) {
- QV4::StackFrame frame = trace.first();
- error.setUrl(QUrl(frame.source));
- error.setLine(frame.line);
- error.setColumn(frame.column);
- }
- QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
- if (!!errorObj && errorObj->asSyntaxError()) {
- QV4::ScopedString m(scope, errorObj->engine()->newString("message"));
- QV4::ScopedValue v(scope, errorObj->get(m));
- error.setDescription(v->toQStringNoThrow());
- } else
- error.setDescription(exception->toQStringNoThrow());
- return error;
-}
-
/*!
Returns true if this error is valid, otherwise false.
*/
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h
index 50491b911c..e69b3c15ba 100644
--- a/src/qml/qml/qqmlerror.h
+++ b/src/qml/qml/qqmlerror.h
@@ -49,10 +49,6 @@
QT_BEGIN_NAMESPACE
-namespace QV4 {
-struct ExecutionContext;
-}
-
class QDebug;
class QQmlErrorPrivate;
class Q_QML_EXPORT QQmlError
@@ -63,9 +59,6 @@ public:
QQmlError &operator=(const QQmlError &);
~QQmlError();
- // Use only inside catch(...) -- will re-throw if no JS exception
- static QQmlError catchJavaScriptException(QV4::ExecutionContext *context);
-
bool isValid() const;
QUrl url() const;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7d18c893a7..63151b18bf 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1833,44 +1833,47 @@ bool QQmlImportDatabase::importPlugin(QObject *instance, const QString &basePath
const char *moduleId = bytes.constData();
QStringList registrationFailures;
+ {
+ // Create a scope for QWriteLocker to keep it as narrow as possible, and
+ // to ensure that we release it before the call to initalizeEngine below
+ QWriteLocker lock(QQmlMetaType::typeRegistrationLock());
+
+ if (!typeNamespace.isEmpty()) {
+ // This is an 'identified' module
+ if (typeNamespace != uri) {
+ // The namespace for type registrations must match the URI for locating the module
+ QQmlError error;
+ error.setDescription(tr("Module namespace '%1' does not match import URI '%2'").arg(typeNamespace).arg(uri));
+ errors->prepend(error);
+ return false;
+ }
- QWriteLocker lock(QQmlMetaType::typeRegistrationLock());
-
- if (!typeNamespace.isEmpty()) {
- // This is an 'identified' module
- if (typeNamespace != uri) {
- // The namespace for type registrations must match the URI for locating the module
- QQmlError error;
- error.setDescription(tr("Module namespace '%1' does not match import URI '%2'").arg(typeNamespace).arg(uri));
- errors->prepend(error);
- return false;
- }
-
- if (QQmlMetaType::namespaceContainsRegistrations(typeNamespace)) {
- // Other modules have already installed to this namespace
- QQmlError error;
- error.setDescription(tr("Namespace '%1' has already been used for type registration").arg(typeNamespace));
- errors->prepend(error);
- return false;
+ if (QQmlMetaType::namespaceContainsRegistrations(typeNamespace)) {
+ // Other modules have already installed to this namespace
+ QQmlError error;
+ error.setDescription(tr("Namespace '%1' has already been used for type registration").arg(typeNamespace));
+ errors->prepend(error);
+ return false;
+ } else {
+ QQmlMetaType::protectNamespace(typeNamespace);
+ }
} else {
- QQmlMetaType::protectNamespace(typeNamespace);
+ // This is not an identified module - provide a warning
+ qWarning().nospace() << qPrintable(tr("Module '%1' does not contain a module identifier directive - it cannot be protected from external registrations.").arg(uri));
}
- } else {
- // This is not an identified module - provide a warning
- qWarning().nospace() << qPrintable(tr("Module '%1' does not contain a module identifier directive - it cannot be protected from external registrations.").arg(uri));
- }
- QQmlMetaType::setTypeRegistrationNamespace(typeNamespace);
+ QQmlMetaType::setTypeRegistrationNamespace(typeNamespace);
- if (QQmlExtensionPlugin *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
- // basepath should point to the directory of the module, not the plugin file itself:
- QQmlExtensionPluginPrivate::get(plugin)->baseUrl = QUrl::fromLocalFile(basePath);
- }
+ if (QQmlExtensionPlugin *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
+ // basepath should point to the directory of the module, not the plugin file itself:
+ QQmlExtensionPluginPrivate::get(plugin)->baseUrl = QUrl::fromLocalFile(basePath);
+ }
- iface->registerTypes(moduleId);
+ iface->registerTypes(moduleId);
- registrationFailures = QQmlMetaType::typeRegistrationFailures();
- QQmlMetaType::setTypeRegistrationNamespace(QString());
+ registrationFailures = QQmlMetaType::typeRegistrationFailures();
+ QQmlMetaType::setTypeRegistrationNamespace(QString());
+ } // QWriteLocker lock(QQmlMetaType::typeRegistrationLock())
if (!registrationFailures.isEmpty()) {
if (errors) {
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 39c7f29fb9..ade4634c2d 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -52,7 +52,7 @@
// async if nested cases
void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
{
- QQmlIncubatorPrivate *p = i.d;
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(i.d);
QQmlIncubator::IncubationMode mode = i.incubationMode();
@@ -63,7 +63,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
mode = QQmlIncubator::Synchronous;
// Need to find the first constructing context and see if it is asynchronous
- QQmlIncubatorPrivate *parentIncubator = 0;
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator;
QQmlContextData *cctxt = forContext;
while (cctxt) {
if (cctxt->activeVMEData) {
@@ -76,7 +76,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
if (parentIncubator && parentIncubator->isAsynchronous) {
mode = QQmlIncubator::Asynchronous;
p->waitingOnMe = parentIncubator;
- parentIncubator->waitingFor.insert(p);
+ parentIncubator->waitingFor.insert(p.data());
}
}
@@ -85,8 +85,7 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
inProgressCreations++;
if (mode == QQmlIncubator::Synchronous) {
- typedef QQmlIncubatorPrivate IP;
- QRecursionWatcher<IP, &IP::recursion> watcher(p);
+ QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(p.data());
p->changeStatus(QQmlIncubator::Loading);
@@ -95,14 +94,14 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
p->incubate(i);
}
} else {
- incubatorList.insert(p);
+ incubatorList.insert(p.data());
incubatorCount++;
p->vmeGuard.guard(&p->vme);
p->changeStatus(QQmlIncubator::Loading);
if (incubationController)
- incubationController->incubatingObjectCountChanged(incubatorCount);
+ incubationController->incubatingObjectCountChanged(incubatorCount);
}
}
@@ -132,15 +131,15 @@ QQmlIncubationController *QQmlEngine::incubationController() const
return d->incubationController;
}
-QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q,
- QQmlIncubator::IncubationMode m)
-: q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
- result(0), compiledData(0), vme(this), waitingOnMe(0)
+QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m)
+ : q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute),
+ result(0), compiledData(0), vme(this), waitingOnMe(0)
{
}
QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
{
+ clear();
}
void QQmlIncubatorPrivate::clear()
@@ -154,7 +153,7 @@ void QQmlIncubatorPrivate::clear()
enginePriv->incubatorCount--;
QQmlIncubationController *controller = enginePriv->incubationController;
if (controller)
- controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
+ controller->incubatingObjectCountChanged(enginePriv->incubatorCount);
} else if (compiledData) {
compiledData->release();
compiledData = 0;
@@ -240,10 +239,7 @@ Return the number of objects currently incubating.
*/
int QQmlIncubationController::incubatingObjectCount() const
{
- if (d)
- return d->incubatorCount;
- else
- return 0;
+ return d ? d->incubatorCount : 0;
}
/*!
@@ -257,14 +253,26 @@ void QQmlIncubationController::incubatingObjectCountChanged(int incubatingObject
Q_UNUSED(incubatingObjectCount);
}
+void QQmlIncubatorPrivate::forceCompletion(QQmlVME::Interrupt &i)
+{
+ while (QQmlIncubator::Loading == status) {
+ while (QQmlIncubator::Loading == status && !waitingFor.isEmpty())
+ static_cast<QQmlIncubatorPrivate *>(waitingFor.first())->forceCompletion(i);
+ if (QQmlIncubator::Loading == status)
+ incubate(i);
+ }
+}
+
void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
{
if (!compiledData)
return;
+
QML_MEMORY_SCOPE_URL(compiledData->url);
- typedef QQmlIncubatorPrivate IP;
- QRecursionWatcher<IP, &IP::recursion> watcher(this);
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
+
+ QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this);
QQmlEngine *engine = compiledData->engine;
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
@@ -301,7 +309,8 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
- q->setInitialState(result);
+ if (q)
+ q->setInitialState(result);
}
if (watcher.hasRecursed())
@@ -337,13 +346,11 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i)
finishIncubate:
if (progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty()) {
- typedef QQmlIncubatorPrivate IP;
-
- QQmlIncubatorPrivate *isWaiting = waitingOnMe;
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> isWaiting = waitingOnMe;
clear();
if (isWaiting) {
- QRecursionWatcher<IP, &IP::recursion> watcher(isWaiting);
+ QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(isWaiting.data());
changeStatus(calculateStatus());
if (!watcher.hasRecursed())
isWaiting->incubate(i);
@@ -369,14 +376,13 @@ Incubate objects for \a msecs, or until there are no more objects to incubate.
*/
void QQmlIncubationController::incubateFor(int msecs)
{
- if (!d || d->incubatorCount == 0)
+ if (!d || !d->incubatorCount)
return;
QQmlVME::Interrupt i(msecs * 1000000);
i.reset();
do {
- QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
- p->incubate(i);
+ static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
@@ -389,14 +395,13 @@ the bool pointed to by \a flag to false when it wants incubation to be interrupt
*/
void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
{
- if (!d || d->incubatorCount == 0)
+ if (!d || !d->incubatorCount)
return;
QQmlVME::Interrupt i(flag, msecs * 1000000);
i.reset();
do {
- QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate*)d->incubatorList.first();
- p->incubate(i);
+ static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
@@ -487,16 +492,20 @@ or stutters into the application, should use the AsynchronousIfNested incubation
Create a new incubator with the specified \a mode
*/
QQmlIncubator::QQmlIncubator(IncubationMode mode)
-: d(new QQmlIncubatorPrivate(this, mode))
+ : d(new QQmlIncubatorPrivate(this, mode))
{
+ d->ref.ref();
}
/*! \internal */
QQmlIncubator::~QQmlIncubator()
{
- clear();
+ d->q = 0;
- delete d; d = 0;
+ if (!d->ref.deref()) {
+ delete d;
+ }
+ d = 0;
}
/*!
@@ -531,8 +540,7 @@ Ready state, the created object is \b not deleted.
*/
void QQmlIncubator::clear()
{
- typedef QQmlIncubatorPrivate IP;
- QRecursionWatcher<IP, &IP::recursion> watcher(d);
+ QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(d);
Status s = status();
@@ -550,16 +558,18 @@ void QQmlIncubator::clear()
d->clear();
// if we're waiting on any incubators then they should be cleared too.
- while (d->waitingFor.first())
- static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q->clear();
+ while (d->waitingFor.first()) {
+ QQmlIncubator * i = static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q;
+ if (i)
+ i->clear();
+ }
d->vme.reset();
d->vmeGuard.clear();
Q_ASSERT(d->compiledData == 0);
- Q_ASSERT(d->waitingOnMe == 0);
+ Q_ASSERT(d->waitingOnMe.data() == 0);
Q_ASSERT(d->waitingFor.isEmpty());
- Q_ASSERT(!d->nextWaitingFor.isInList());
d->errors.clear();
d->progress = QQmlIncubatorPrivate::Execute;
@@ -587,12 +597,7 @@ returns, the incubator will not be in the Loading state.
void QQmlIncubator::forceCompletion()
{
QQmlVME::Interrupt i;
- while (Loading == status()) {
- while (Loading == status() && !d->waitingFor.isEmpty())
- static_cast<QQmlIncubatorPrivate *>(d->waitingFor.first())->incubate(i);
- if (Loading == status())
- d->incubate(i);
- }
+ d->forceCompletion(i);
}
/*!
@@ -656,8 +661,10 @@ Return the incubated object if the status is Ready, otherwise 0.
*/
QObject *QQmlIncubator::object() const
{
- if (status() != Ready) return 0;
- else return d->result;
+ if (status() != Ready)
+ return 0;
+ else
+ return d->result;
}
/*!
@@ -690,15 +697,15 @@ void QQmlIncubatorPrivate::changeStatus(QQmlIncubator::Status s)
return;
status = s;
- q->statusChanged(status);
+ if (q)
+ q->statusChanged(status);
}
QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const
{
if (!errors.isEmpty())
return QQmlIncubator::Error;
- else if (result && progress == QQmlIncubatorPrivate::Completed &&
- waitingFor.isEmpty())
+ else if (result && progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty())
return QQmlIncubator::Ready;
else if (compiledData)
return QQmlIncubator::Loading;
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 229919f37a..e7246ce3b2 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -91,7 +91,7 @@ public:
QQmlVME vme;
QQmlVMEGuard vmeGuard;
- QQmlIncubatorPrivate *waitingOnMe;
+ QExplicitlySharedDataPointer<QQmlIncubatorPrivate> waitingOnMe;
typedef QQmlEnginePrivate::Incubator QIPBase;
QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
@@ -99,6 +99,7 @@ public:
void clear();
+ void forceCompletion(QQmlVME::Interrupt &i);
void incubate(QQmlVME::Interrupt &i);
};
diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp
index 626140d99d..33ea3bb7d9 100644
--- a/src/qml/qml/qqmlinstruction.cpp
+++ b/src/qml/qml/qqmlinstruction.cpp
@@ -222,7 +222,7 @@ void QQmlCompiledData::dump(QQmlInstruction *instr, int idx)
qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
break;
case QQmlInstruction::StoreBinding:
- qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
+ qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.functionIndex << "\t" << instr->assignBinding.context;
break;
case QQmlInstruction::StoreValueSource:
qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property.coreIndex << "\t" << instr->assignValueSource.castValue;
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index be27f9069c..01b6fa41a4 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -237,7 +237,7 @@ union QQmlInstruction
struct instr_assignBinding {
QML_INSTR_HEADER
QQmlPropertyRawData property;
- int value;
+ int functionIndex; // index in CompiledData::runtimeFunctions
short context;
short owner;
bool isRoot:1;
@@ -392,6 +392,7 @@ union QQmlInstruction
};
struct instr_storeSignal {
QML_INSTR_HEADER
+ int runtimeFunctionIndex;
int handlerName;
int parameters;
int signalIndex;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 8751d9c500..37a9e398f8 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -86,7 +86,7 @@ void QQmlDelayedError::setErrorObject(QObject *object)
void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionContext *context)
{
- m_error = QQmlError::catchJavaScriptException(context);
+ m_error = QV4::ExecutionEngine::convertJavaScriptException(context);
}
@@ -306,7 +306,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
script.parse();
result = script.run();
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
if (error.description().isEmpty())
error.setDescription(QLatin1String("Exception occurred during function evaluation"));
if (error.line() == -1)
@@ -340,7 +340,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q
script.parse();
result = script.qmlBinding();
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
if (error.description().isEmpty())
error.setDescription(QLatin1String("Exception occurred during function evaluation"));
if (error.line() == -1)
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index c1ec5dc1c1..0364659ecc 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -57,6 +57,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine)
v8(engine)
{
vtbl = &static_vtbl;
+ flags &= ~SimpleArray;
}
QmlListWrapper::~QmlListWrapper()
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index e41248b4ca..56776dcb82 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -445,9 +445,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml
for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) {
const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex);
- VMD::MethodData methodData = { int(s->nFormals),
- /* body offset*/0,
- /* body length*/0,
+ VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
+ int(s->nFormals),
/* s->location.start.line */0 }; // ###
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
@@ -488,10 +487,8 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD
, _vmeMetaObject(0)
, _qmlContext(0)
{
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- if (compiledData->compilationUnit && !compiledData->compilationUnit->engine)
- compiledData->compilationUnit->linkToEngine(v4);
-
+ if (!compiledData->isInitialized())
+ compiledData->initialize(engine);
}
QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
@@ -1242,6 +1239,11 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
}
} else {
Q_ASSERT(typeRef.component);
+ if (typeRef.component->qmlUnit->isSingleton())
+ {
+ recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
+ return 0;
+ }
QmlObjectCreator subCreator(context, typeRef.component);
instance = subCreator.create();
if (!instance) {
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index 278287e697..5745f35498 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -357,9 +357,18 @@ void QQmlOpenMetaObject::setCached(bool c)
int QQmlOpenMetaObject::createProperty(const char *name, const char *)
{
- if (d->autoCreate)
- return d->type->createProperty(name);
- else
+ if (d->autoCreate) {
+ int result = d->type->createProperty(name);
+
+ if (QQmlData *ddata = QQmlData::get(d->object, /*create*/false)) {
+ if (ddata->propertyCache) {
+ ddata->propertyCache->release();
+ ddata->propertyCache = 0;
+ }
+ }
+
+ return result;
+ } else
return -1;
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index e498ca5dee..2cb944d824 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1419,8 +1419,7 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, T name,
if (cache) {
rv = cache->property(name, obj, context);
- }
- if (!rv) {
+ } else {
local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
if (local.isValid())
rv = &local;
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index 7996f9f48c..9fd06aa934 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -202,7 +202,7 @@ QQmlScript::Object::DynamicSignal::DynamicSignal()
}
QQmlScript::Object::DynamicSlot::DynamicSlot()
-: nextSlot(0), nameIndex(-1)
+: funcDecl(0), nextSlot(0), nameIndex(-1)
{
}
@@ -895,7 +895,7 @@ bool ProcessAST::visit(AST::UiPragma *node)
// For now the only valid pragma is Singleton, so lets validate the input
if (!node->pragmaType->name.isNull())
{
- if (QLatin1String("Singleton") == node->pragmaType->name.toString())
+ if (QLatin1String("Singleton") == node->pragmaType->name)
{
pragma.type = QQmlScript::Pragma::Singleton;
} else {
@@ -991,7 +991,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
const TypeNameToType *t = propTypeNameToTypes + typeIndex;
if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) {
type = t;
break;
}
@@ -1033,7 +1033,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
Object::DynamicProperty::Type type;
if ((unsigned)memberType.length() == strlen("alias") &&
- QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
+ QHashedString::compare(memberType.constData(), "alias", int(strlen("alias")))) {
type = Object::DynamicProperty::Alias;
typeFound = true;
}
@@ -1041,7 +1041,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
+ QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) {
type = t->type;
typeFound = true;
}
@@ -1053,7 +1053,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
if (typeModifier.isEmpty()) {
type = Object::DynamicProperty::Custom;
} else if((unsigned)typeModifier.length() == strlen("list") &&
- QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
+ QHashedString::compare(typeModifier.constData(), "list", int(strlen("list")))) {
type = Object::DynamicProperty::CustomList;
} else {
QQmlError error;
@@ -1284,9 +1284,8 @@ bool ProcessAST::visit(AST::UiSourceElement *node)
AST::SourceLocation loc = funDecl->rparenToken;
loc.offset = loc.end();
loc.startColumn += 1;
- QString body = textAt(loc, funDecl->rbraceToken);
slot->name = funDecl->name;
- slot->body = body;
+ slot->funcDecl = funDecl;
obj->dynamicSlots.append(slot);
} else {
@@ -1303,7 +1302,7 @@ bool ProcessAST::visit(AST::UiSourceElement *node)
QQmlScript::Parser::Parser()
-: root(0), data(0)
+: root(0), _qmlRoot(0), data(0)
{
}
@@ -1380,6 +1379,8 @@ bool QQmlScript::Parser::parse(const QString &qmlcode, const QByteArray & /* pre
_errors[ii].setUrl(url);
}
+ _qmlRoot = parser.ast();
+
return _errors.isEmpty();
}
@@ -1759,6 +1760,7 @@ void QQmlScript::Parser::clear()
}
_pool.clear();
+ _qmlRoot = 0;
}
int QQmlScript::Parser::findOrCreateTypeId(const QString &name, Object *object)
@@ -1782,4 +1784,9 @@ void QQmlScript::Parser::setTree(QQmlScript::Object *tree)
root = tree;
}
+Engine *QQmlScript::Parser::jsEngine() const
+{
+ return data ? &data->engine : 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h
index 790f1b2b81..86bbc1fb3a 100644
--- a/src/qml/qml/qqmlscript_p.h
+++ b/src/qml/qml/qqmlscript_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
class QByteArray;
class QQmlPropertyCache;
-namespace QQmlJS { namespace AST { class Node; class StringLiteral; } }
+namespace QQmlJS { class Engine; namespace AST { class Node; class StringLiteral; class UiProgram; class FunctionDeclaration; } }
namespace QQmlCompilerTypes { struct BindingReference; struct ComponentCompileState; }
namespace QQmlScript {
@@ -227,9 +227,13 @@ public:
LocationSpan location;
// Used by compiler
+ struct SignalData {
+ int signalExpressionContextStack;
+ int functionIndex; // before gen() index in functionsToCompile, then index in runtime functions
+ };
union {
QQmlCompilerTypes::BindingReference *bindingReference;
- int signalExpressionContextStack;
+ SignalData signalData;
};
// Used in Property::ValueList lists
@@ -433,8 +437,8 @@ public:
{
DynamicSlot();
+ QQmlJS::AST::FunctionDeclaration *funcDecl;
QHashedStringRef name;
- QString body;
QList<QByteArray> parameterNames;
LocationSpan location;
@@ -511,6 +515,9 @@ public:
void setScriptFile(const QString &filename) {_scriptFile = filename; }
QString scriptFile() const { return _scriptFile; }
+ QQmlJS::AST::UiProgram *qmlRoot() const { return _qmlRoot; }
+ QQmlJS::Engine *jsEngine() const;
+
// ### private:
QList<QQmlError> _errors;
@@ -520,6 +527,7 @@ public:
QList<Pragma> _pragmas;
QList<TypeReference*> _refTypes;
QString _scriptFile;
+ QQmlJS::AST::UiProgram *_qmlRoot;
ParserJsASTData *data;
};
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 76cb0ce38f..601c1b8bdc 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2218,7 +2218,24 @@ void QQmlTypeData::dataReceived(const Data &data)
}
}
- foreach (const QQmlScript::Pragma &pragma, scriptParser.pragmas()) {
+ // ### convert to use new data structure once old compiler is gone.
+ if (m_useNewCompiler && m_newPragmas.isEmpty()) {
+ m_newPragmas.reserve(parsedQML->pragmas.size());
+ foreach (QtQml::Pragma *p, parsedQML->pragmas) {
+ QQmlScript::Pragma pragma;
+ pragma.location.start.line = p->location.line;
+ pragma.location.start.column = p->location.column;
+
+ switch (p->type) {
+ case QtQml::Pragma::PragmaSingleton: pragma.type = QQmlScript::Pragma::Singleton; break;
+ default: break;
+ }
+
+ m_newPragmas << pragma;
+ }
+ }
+
+ foreach (const QQmlScript::Pragma &pragma, m_useNewCompiler ? m_newPragmas : scriptParser.pragmas()) {
if (!addPragma(pragma, &errors)) {
Q_ASSERT(errors.size());
setError(errors);
@@ -2280,6 +2297,12 @@ void QQmlTypeData::compile()
foreach (const QString &ns, m_namespaces)
m_compiledData->importCache->add(ns);
+ // Add any Composite Singletons that were used to the import cache
+ for (int i = 0; i < compositeSingletons().count(); ++i) {
+ m_compiledData->importCache->add(compositeSingletons().at(i).type->qmlTypeName(),
+ compositeSingletons().at(i).type->sourceUrl(), compositeSingletons().at(i).prefix);
+ }
+
m_imports.populateCache(m_compiledData->importCache);
m_compiledData->importCache->addref();
@@ -2335,7 +2358,7 @@ void QQmlTypeData::compile()
// Compile JS binding expressions and signal handlers
JSCodeGen jsCodeGen;
- jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), parsedQML.data());
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(finalUrlString(), parsedQML.data());
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
@@ -2346,7 +2369,7 @@ void QQmlTypeData::compile()
// Generate QML compiled type data structures
QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML.data());
+ QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*parsedQML.data(), runtimeFunctionIndices);
if (jsUnit) {
Q_ASSERT(!jsUnit->data);
@@ -2767,7 +2790,7 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
m_program->qml = qmlglobal;
m_program->run();
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
if (error.isValid())
ep->warning(error);
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index b9bf056cb3..b93cf2942d 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -460,6 +460,7 @@ private:
// --- new compiler
QScopedPointer<QtQml::ParsedQML> parsedQML;
QList<QQmlScript::Import> m_newImports;
+ QList<QQmlScript::Pragma> m_newPragmas;
// ---
QList<ScriptReference> m_scripts;
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 9583fa1d68..c1c05fac11 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -226,6 +226,18 @@ static QVariant variantFromString(const QString &string)
return QQmlStringConverters::variantFromString(string);
}
+static QV4::ExecutionContext *qmlBindingContext(QQmlEngine *engine, QV4::ExecutionEngine *v4, QV4::SafeValue *qmlBindingWrappers, QQmlContextData *context, QObject *scope, int objIdx)
+{
+ QV4::Scope valueScope(v4);
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, qmlBindingWrappers[objIdx]);
+ if (!wrapper) {
+ QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, scope));
+ wrapper = new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject);
+ qmlBindingWrappers[objIdx] = wrapper;
+ }
+ return wrapper->context();
+}
+
// XXX we probably need some form of "work count" here to prevent us checking this
// for every instruction.
#define QML_BEGIN_INSTR_COMMON(I) { \
@@ -343,6 +355,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QV4::ExecutionEngine *v4 = ep->v4engine();
QV4::Scope valueScope(v4);
QV4::ScopedValue tmpValue(valueScope);
+ QV4::SafeValue *qmlBindingWrappers = valueScope.alloc(objects.capacity());
+ std::fill(qmlBindingWrappers, qmlBindingWrappers + objects.capacity(), QV4::Primitive::undefinedValue());
int status = -1; // needed for dbus
QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
@@ -546,6 +560,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->outerContext = CTXT;
ddata->lineNumber = instr.line;
ddata->columnNumber = instr.column;
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CompleteQMLObject)
QML_BEGIN_INSTR(CreateCppObject)
@@ -618,6 +633,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->parentFrozen = true;
}
objects.push(o);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CreateCppObject)
QML_BEGIN_INSTR(CreateSimpleObject)
@@ -647,6 +663,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
ddata->parentFrozen = true;
objects.push(o);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(CreateSimpleObject)
QML_BEGIN_INSTR(SetId)
@@ -685,6 +702,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QQmlComponentPrivate::get(qcomp)->creationContext = CTXT;
objects.push(qcomp);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
INSTRUCTIONSTREAM += instr.count;
QML_END_INSTR(CreateComponent)
@@ -696,7 +714,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
const QQmlVMEMetaData *data =
(const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData();
- (void)new QQmlVMEMetaObject(target, propertyCache, data);
+ QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, target, objects.count() - 1);
+ (void)new QQmlVMEMetaObject(target, propertyCache, data, qmlContext, COMP);
QQmlData *ddata = QQmlData::get(target, true);
if (ddata->propertyCache) ddata->propertyCache->release();
@@ -758,13 +777,16 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QObject *target = objects.top();
QObject *context = objects.at(objects.count() - 1 - instr.context);
+ QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context);
+
+ QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.runtimeFunctionIndex];
+
+ tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+
QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine);
QQmlBoundSignalExpression *expr =
new QQmlBoundSignalExpression(target, instr.signalIndex,
- CTXT, context, PRIMITIVES.at(instr.value),
- COMP->name, instr.line, instr.column,
- PRIMITIVES.at(instr.handlerName),
- PRIMITIVES.at(instr.parameters));
+ CTXT, context, tmpValue);
bs->takeExpression(expr);
QML_END_INSTR(StoreSignal)
@@ -810,9 +832,13 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
QML_NEXT_INSTR(StoreBinding);
- QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value),
- context, CTXT, COMP->name, instr.line,
- instr.column);
+ QV4::ExecutionContext *qmlContext = qmlBindingContext(engine, QV8Engine::getV4(engine), qmlBindingWrappers, CTXT, context, objects.count() - 1 - instr.context);
+
+ QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.functionIndex];
+
+ tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+
+ QQmlBinding *bind = new QQmlBinding(tmpValue, context, CTXT, COMP->name, instr.line, instr.column);
bindValues.push(bind);
bind->m_mePtr = &bindValues.top();
bind->setTarget(target, instr.property, CTXT);
@@ -919,6 +945,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
VME_EXCEPTION(tr("Unable to create attached object"), instr.line);
objects.push(qmlObject);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchAttached)
QML_BEGIN_INSTR(FetchQList)
@@ -947,6 +974,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
VME_EXCEPTION(tr("Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.property).name())), instr.line);
objects.push(obj);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchObject)
QML_BEGIN_INSTR(PopQList)
@@ -1003,6 +1031,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
Q_ASSERT(valueHandler);
valueHandler->read(target, instr.property);
objects.push(valueHandler);
+ qmlBindingWrappers[objects.count() - 1] = QV4::Primitive::undefinedValue();
QML_END_INSTR(FetchValueType)
QML_BEGIN_INSTR(PopValueType)
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 5e76143cca..e76b485a5c 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -75,7 +75,6 @@ class QObject;
class QJSValue;
class QQmlScriptData;
class QQmlCompiledData;
-class QQmlCompiledData;
class QQmlContextData;
namespace QQmlVMETypes {
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 7c033acf47..5752033744 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -559,7 +559,7 @@ QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o)
QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
QQmlPropertyCache *cache,
- const QQmlVMEMetaData *meta)
+ const QQmlVMEMetaData *meta, QV4::ExecutionContext *qmlBindingContext, QQmlCompiledData *compiledData)
: object(obj),
ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta),
hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1),
@@ -603,6 +603,21 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (needsJSWrapper)
ensureQObjectWrapper();
+
+ if (qmlBindingContext && metaData->methodCount) {
+ v8methods = new QV4::PersistentValue[metaData->methodCount];
+
+ QV4::CompiledData::CompilationUnit *compilationUnit = compiledData->compilationUnit;
+ QV4::Scope scope(QQmlEnginePrivate::get(ctxt->engine)->v4engine());
+ QV4::ScopedObject o(scope);
+ for (int index = 0; index < metaData->methodCount; ++index) {
+ QQmlVMEMetaData::MethodData *data = metaData->methodData() + index;
+
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex];
+ o = QV4::FunctionObject::creatScriptFunction(qmlBindingContext, runtimeFunction);
+ v8methods[index] = o;
+ }
+ }
}
QQmlVMEMetaObject::~QQmlVMEMetaObject()
@@ -945,7 +960,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
result = function->call(callData);
if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
if (error.isValid())
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
@@ -974,19 +989,6 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index)
if (!v8methods)
v8methods = new QV4::PersistentValue[metaData->methodCount];
- if (v8methods[index].isUndefined()) {
- QQmlVMEMetaData::MethodData *data = metaData->methodData() + index;
-
- const char *body = ((const char*)metaData) + data->bodyOffset;
- int bodyLength = data->bodyLength;
-
- // XXX We should evaluate all methods in a single big script block to
- // improve the call time between dynamic methods defined on the same
- // object
- v8methods[index] = QQmlExpressionPrivate::evalFunction(ctxt, object, QString::fromUtf8(body, bodyLength),
- ctxt->urlString, data->lineNumber);
- }
-
return v8methods[index].value();
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 056139114c..25a577d2e6 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -119,9 +119,8 @@ struct QQmlVMEMetaData
};
struct MethodData {
+ int runtimeFunctionIndex;
int parameterCount;
- int bodyOffset;
- int bodyLength;
quint16 lineNumber;
};
@@ -159,7 +158,8 @@ class QQmlVMEMetaObjectEndpoint;
class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject
{
public:
- QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data);
+ QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data,
+ QV4::ExecutionContext *qmlBindingContext = 0, QQmlCompiledData *compiledData = 0);
~QQmlVMEMetaObject();
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 6aeabf9221..aff0cf2b59 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -259,6 +259,10 @@ public:
: Object(engine)
{
vtbl = &static_vtbl;
+
+ Scope scope(engine);
+ ScopedObject protectThis(scope, this);
+
defineAccessorProperty(QStringLiteral("nodeName"), method_get_nodeName, 0);
defineAccessorProperty(QStringLiteral("nodeValue"), method_get_nodeValue, 0);
defineAccessorProperty(QStringLiteral("nodeType"), method_get_nodeType, 0);
@@ -1568,7 +1572,7 @@ void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me)
// the source is changed). We do nothing in this case, as the evaluation
// cannot succeed.
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->v8Engine->engine()), error);
}
}
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 8136b495e9..10f957ab40 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -72,7 +72,6 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
, flag(flag)
{
vtbl = &static_vtbl;
- isBuiltinFunction = true;
}
static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *)
@@ -1525,8 +1524,7 @@ void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelInd
void QQmlDelegateModel::_q_layoutChanged()
{
- Q_D(QQmlDelegateModel);
- _q_itemsChanged(0, d->m_count, QVector<int>());
+ _q_modelReset();
}
QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj)
@@ -3188,6 +3186,7 @@ public:
: Object(engine)
{
vtbl = &static_vtbl;
+ flags &= ~SimpleArray;
}
virtual ~QQmlDelegateModelGroupChangeArray() {}
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 9b8616d5e7..322b4b8df0 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -367,7 +367,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
callData->args[1] = value;
f->call(callData);
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
reportScriptException(script, error);
}
}
@@ -404,7 +404,7 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
program.parse();
program.run();
} catch (...) {
- QQmlError error = QQmlError::catchJavaScriptException(ctx);
+ QQmlError error = QV4::ExecutionEngine::convertJavaScriptException(ctx);
reportScriptException(script, error);
}
} else {
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index e3b2f4640d..fce7c05e00 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -36,7 +36,7 @@ interfaces and applications with QML. This page lists every QML type provided
by this module, organized according to category and purpose.
-\section1 Importing \c QtQuick
+\section1 Importing Qt Quick
The types provided by the \l {Qt Quick} module are only available in a QML document
if that document imports the \c QtQuick namespace.
@@ -1058,3 +1058,17 @@ console.log(c + " " + d); // false true
\sa {QML Basic Types}
*/
+
+/*!
+\qmlmodule QtTest 1.0
+\title Qt Quick Test
+\brief This module provides QML types to unit test your QML application
+
+You can import this module using the following statement:
+\code
+import QtTest 1.0
+\endcode
+
+For more information about how to use these types, see
+\l{Qt Quick Test Reference Documentation}.
+*/
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index deb6aa164c..088e62d81a 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -47,7 +47,7 @@ create user interfaces. Please see \l{Qt Quick Controls}
for more information.
For those new to QML and Qt Quick, please see
-\l{QML Application Developer Resources}
+\l{QML Applications}
for an introduction to writing QML applications.
\section1 Important Concepts in Qt Quick
@@ -74,7 +74,7 @@ When using the \c QtQuick module, you will need to know how to write QML
applications using the QML language. In particular, you should have a grasp
of the \l{qtquick-quickstart-basics.html}{QML Basics} and
\l{qtquick-quickstart-essentials.html}{QML Essentials} from the
-\l{qtquick-applicationdevelopers.html}{QML Application Developer Resources}.
+\l{QML Applications}.
To find out more about using the QML language, see the \l{Qt QML} module documentation.
@@ -135,7 +135,7 @@ module
Further information for writing QML applications:
\list
-\li \l{QML Application Developer Resources}
+\li \l{QML Applications}
- essential information for application development with QML and Qt Quick
\li \l{Qt QML} - documentation for the
Qt QML module, which provides the QML engine and language infrastructure
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 6f7cd77486..2fb6cb9f63 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -545,6 +545,9 @@ public:
QQuickJSContext2DPrototype(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
+
defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
defineDefaultProperty(QStringLiteral("moveTo"), method_moveTo, 0);
@@ -868,6 +871,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
: QV4::Object(engine)
{
vtbl = &static_vtbl;
+ flags &= ~SimpleArray;
}
static void destroy(QV4::Managed *that) {
@@ -890,6 +894,10 @@ struct QQuickJSContext2DImageData : public QV4::Object
: QV4::Object(engine)
{
vtbl = &static_vtbl;
+ pixelData = QV4::Primitive::undefinedValue();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedObject protectThis(scope, this);
defineAccessorProperty(QStringLiteral("width"), method_get_width, 0);
defineAccessorProperty(QStringLiteral("height"), method_get_height, 0);
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 3a32169447..846de15581 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -80,14 +80,14 @@ static const char vertexShaderCode[] =
"}\n";
static const char fragmentShaderCode[] =
- "uniform sampler2D texture;\n"
+ "uniform sampler2D _qt_texture;\n"
"uniform lowp float qt_Opacity;\n"
"\n"
"varying highp vec4 fTexS;\n"
"varying lowp float progress;\n"
"\n"
"void main() {\n"
- " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), progress) * qt_Opacity;\n"
+ " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), progress) * qt_Opacity;\n"
"}\n";
class QQuickAnimatedSpriteMaterial : public QSGMaterial
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 3cbcf1937f..9fc9752707 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -560,10 +560,14 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
- if (!node)
+ bool updatePixmap = d->pixmapChanged;
+ if (!node) {
node = d->sceneGraphContext()->createImageNode();
+ updatePixmap = true;
+ }
- node->setTexture(texture);
+ if (updatePixmap)
+ node->setTexture(texture);
// Don't implicitly create the scalegrid in the rendering thread...
QRectF innerSourceRect(0, 0, 1, 1);
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index b94d8dd4b0..f0a68b184a 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -948,16 +948,15 @@ void QQuickFlickable::setPixelAligned(bool align)
qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event)
{
- if (0 != event->timestamp() && QQuickItemPrivate::consistentTime == -1)
+ if (0 != event->timestamp())
return event->timestamp();
-
- return QQuickItemPrivate::elapsed(timer);
+ return timer.elapsed();
}
void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
{
Q_Q(QQuickFlickable);
- QQuickItemPrivate::start(timer);
+ timer.start();
if (interactive && timeline.isActive()
&& ((qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity && !hData.fixingUp && !hData.inOvershoot)
|| (qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity && !vData.fixingUp && !vData.inOvershoot))) {
@@ -1016,8 +1015,8 @@ void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
if (wasFlicking)
emit q->flickingChanged();
lastPosTime = lastPressTime = computeCurrentTime(event);
- QQuickItemPrivate::start(vData.velocityTime);
- QQuickItemPrivate::start(hData.velocityTime);
+ vData.velocityTime.start();
+ hData.velocityTime.start();
}
void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
@@ -1466,7 +1465,7 @@ void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent,
QQuickTimeLineCallback::Callback fixupCallback)
{
if (pressed || calcVelocity) {
- int elapsed = QQuickItemPrivate::restart(data.velocityTime);
+ int elapsed = data.velocityTime.restart();
if (elapsed > 0) {
qreal velocity = (data.lastPos - data.move.value()) * 1000 / elapsed;
if (qAbs(velocity) > 0) {
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 3a8fd99a66..d6be13f3c0 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -666,7 +666,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
if (d->pixmapChanged) {
// force update the texture in the node to trigger reconstruction of
// geometry and the likes when a atlas segment has changed.
- node->setTexture(0);
if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat))
node->setTexture(texture->removedFromAtlas());
else
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 73bca67a1e..c3b221b2c8 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -7030,58 +7030,6 @@ QDebug operator<<(QDebug debug, QQuickItem *item)
}
#endif
-qint64 QQuickItemPrivate::consistentTime = -1;
-void QQuickItemPrivate::setConsistentTime(qint64 t)
-{
- consistentTime = t;
-}
-
-class QElapsedTimerConsistentTimeHack
-{
-public:
- void start() {
- t1 = QQuickItemPrivate::consistentTime;
- t2 = 0;
- }
- qint64 elapsed() {
- return QQuickItemPrivate::consistentTime - t1;
- }
- qint64 restart() {
- qint64 val = QQuickItemPrivate::consistentTime - t1;
- t1 = QQuickItemPrivate::consistentTime;
- t2 = 0;
- return val;
- }
-
-private:
- qint64 t1;
- qint64 t2;
-};
-
-void QQuickItemPrivate::start(QElapsedTimer &t)
-{
- if (QQuickItemPrivate::consistentTime == -1)
- t.start();
- else
- ((QElapsedTimerConsistentTimeHack*)&t)->start();
-}
-
-qint64 QQuickItemPrivate::elapsed(QElapsedTimer &t)
-{
- if (QQuickItemPrivate::consistentTime == -1)
- return t.elapsed();
- else
- return ((QElapsedTimerConsistentTimeHack*)&t)->elapsed();
-}
-
-qint64 QQuickItemPrivate::restart(QElapsedTimer &t)
-{
- if (QQuickItemPrivate::consistentTime == -1)
- return t.restart();
- else
- return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
-}
-
/*!
\fn bool QQuickItem::isTextureProvider() const
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index b1e63e6535..f731acabbb 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -587,12 +587,6 @@ public:
virtual void mirrorChange() {}
- static qint64 consistentTime;
- static void setConsistentTime(qint64 t);
- static void start(QElapsedTimer &);
- static qint64 elapsed(QElapsedTimer &);
- static qint64 restart(QElapsedTimer &);
-
void incrementCursorCount(int delta);
};
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index ff31d9de4e..d8132bdd12 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1568,11 +1568,9 @@ qreal QQuickPathViewPrivate::calcVelocity() const
qint64 QQuickPathViewPrivate::computeCurrentTime(QInputEvent *event)
{
- if (0 != event->timestamp() && QQuickItemPrivate::consistentTime == -1) {
+ if (0 != event->timestamp())
return event->timestamp();
- }
-
- return QQuickItemPrivate::elapsed(timer);
+ return timer.elapsed();
}
void QQuickPathView::mousePressEvent(QMouseEvent *event)
@@ -1613,7 +1611,7 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
else
stealMouse = false;
- QQuickItemPrivate::start(timer);
+ timer.start();
lastPosTime = computeCurrentTime(event);
tl.clear();
}
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index fc2b9772d7..c72c2276e0 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -1288,7 +1288,7 @@ Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
}
/*!
- \qmlproperty enumeration QtQuick::Grid::horizontalItmeAlignment
+ \qmlproperty enumeration QtQuick::Grid::horizontalItemAlignment
\qmlproperty enumeration QtQuick::Grid::verticalItemAlignment
\qmlproperty enumeration QtQuick::Grid::effectiveHorizontalItemAlignment
diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp
index 3b2b3269e2..3c1492e0b3 100644
--- a/src/quick/items/qquickspritesequence.cpp
+++ b/src/quick/items/qquickspritesequence.cpp
@@ -79,14 +79,14 @@ static const char vertexShaderCode[] =
"}\n";
static const char fragmentShaderCode[] =
- "uniform sampler2D texture;\n"
+ "uniform sampler2D _qt_texture;\n"
"uniform lowp float qt_Opacity;\n"
"\n"
"varying highp vec4 fTexS;\n"
"varying lowp float progress;\n"
"\n"
"void main() {\n"
- " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), progress) * qt_Opacity;\n"
+ " gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), texture2D(_qt_texture, fTexS.zw), progress) * qt_Opacity;\n"
"}\n";
class QQuickSpriteSequenceMaterial : public QSGMaterial
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index e178a3ea45..5216fca355 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -172,6 +172,8 @@ void QQmlQtQuick2DebugStatesDelegate::resetBindingForInvalidProperty(QObject *ob
void QQmlQtQuick2Module::defineModule()
{
+ QQuick_initializeProviders();
+
QQuickUtilModule::defineModule();
QQmlEnginePrivate::defineQtQuick2Module();
QQuickItemsModule::defineModule();
diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h
index 8cbd0b9782..f67a08c218 100644
--- a/src/quick/qtquickglobal_p.h
+++ b/src/quick/qtquickglobal_p.h
@@ -57,4 +57,10 @@
#define Q_QUICK_PRIVATE_EXPORT Q_QUICK_EXPORT
+QT_BEGIN_NAMESPACE
+
+void QQuick_initializeProviders();
+
+QT_END_NAMESPACE
+
#endif // QTQUICKGLOBAL_P_H
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index caa0d032a4..bb8e3c4b36 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -408,7 +408,11 @@ QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &
QSGGlyphNode *QSGContext::createNativeGlyphNode()
{
#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
- return createGlyphNode();
+ Q_D(QSGContext);
+ if (d->distanceFieldDisabled)
+ return new QSGDefaultGlyphNode;
+ else
+ return createGlyphNode();
#else
return new QSGDefaultGlyphNode;
#endif
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 50009d7709..39d9832f58 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -101,10 +101,10 @@ const char *QSGTextMaskShader::vertexShader() const {
const char *QSGTextMaskShader::fragmentShader() const {
return
"varying highp vec2 sampleCoord; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"void main() { \n"
- " lowp vec4 glyph = texture2D(texture, sampleCoord); \n"
+ " lowp vec4 glyph = texture2D(_qt_texture, sampleCoord); \n"
" gl_FragColor = vec4(glyph.rgb * color.a, glyph.a); \n"
"}";
}
@@ -389,14 +389,14 @@ const char *QSGStyledTextShader::fragmentShader() const
return
"varying highp vec2 sampleCoord; \n"
"varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- " lowp float glyph = texture2D(texture, sampleCoord).a; \n"
- " lowp float style = clamp(texture2D(texture, shiftedSampleCoord).a - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = style * styleColor + glyph * color; \n"
+ "void main() { \n"
+ " lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
+ " lowp float style = clamp(texture2D(_qt_texture, shiftedSampleCoord).a - glyph, \n"
+ " 0.0, 1.0); \n"
+ " gl_FragColor = style * styleColor + glyph * color; \n"
"}";
}
@@ -444,18 +444,18 @@ const char *QSGOutlinedTextShader::fragmentShader() const
"varying highp vec2 sCoordDown; \n"
"varying highp vec2 sCoordLeft; \n"
"varying highp vec2 sCoordRight; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- "lowp float glyph = texture2D(texture, sampleCoord).a; \n"
- " lowp float outline = clamp(clamp(texture2D(texture, sCoordUp).a + \n"
- " texture2D(texture, sCoordDown).a + \n"
- " texture2D(texture, sCoordLeft).a + \n"
- " texture2D(texture, sCoordRight).a, \n"
- " 0.0, 1.0) - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = outline * styleColor + glyph * color; \n"
+ "void main() { \n"
+ "lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
+ " lowp float outline = clamp(clamp(texture2D(_qt_texture, sCoordUp).a + \n"
+ " texture2D(_qt_texture, sCoordDown).a + \n"
+ " texture2D(_qt_texture, sCoordLeft).a + \n"
+ " texture2D(_qt_texture, sCoordRight).a, \n"
+ " 0.0, 1.0) - glyph, \n"
+ " 0.0, 1.0); \n"
+ " gl_FragColor = outline * styleColor + glyph * color; \n"
"}";
}
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index 349a92ac7f..11d0e5dbeb 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -298,15 +298,13 @@ void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
void QSGDefaultImageNode::setTexture(QSGTexture *texture)
{
- if (texture == m_material.texture())
- return;
+ Q_ASSERT(texture);
m_material.setTexture(texture);
m_materialO.setTexture(texture);
m_smoothMaterial.setTexture(texture);
- // Texture cleanup
- if (texture)
- m_material.setFlag(QSGMaterial::Blending, texture->hasAlphaChannel());
+ m_material.setFlag(QSGMaterial::Blending, texture->hasAlphaChannel());
+
markDirty(DirtyMaterial);
// Because the texture can be a different part of the atlas, we need to update it...
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 0cf7abed2e..125243847a 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -96,15 +96,15 @@ const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
return
- "varying highp vec2 sampleCoord; \n"
- "uniform mediump sampler2D texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " gl_FragColor = color * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(texture, sampleCoord).a); \n"
+ "varying highp vec2 sampleCoord; \n"
+ "uniform mediump sampler2D _qt_texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform mediump float alphaMin; \n"
+ "uniform mediump float alphaMax; \n"
+ "void main() { \n"
+ " gl_FragColor = color * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(_qt_texture, sampleCoord).a); \n"
"}";
}
@@ -366,7 +366,7 @@ protected:
const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
return
"varying highp vec2 sampleCoord; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"uniform lowp vec4 styleColor; \n"
"uniform mediump float alphaMin; \n"
@@ -374,7 +374,7 @@ const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
"uniform mediump float outlineAlphaMax0; \n"
"uniform mediump float outlineAlphaMax1; \n"
"void main() { \n"
- " mediump float d = texture2D(texture, sampleCoord).a; \n"
+ " mediump float d = texture2D(_qt_texture, sampleCoord).a; \n"
" gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
" * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
"}";
@@ -514,19 +514,19 @@ const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp float a = smoothstep(alphaMin, alphaMax, texture2D(texture, sampleCoord).a);\n"
- " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(texture, shiftedSampleCoord).a); \n"
- " gl_FragColor = mix(shifted, color, a); \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "uniform sampler2D _qt_texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform mediump float alphaMin; \n"
+ "uniform mediump float alphaMax; \n"
+ "void main() { \n"
+ " highp float a = smoothstep(alphaMin, alphaMax, texture2D(_qt_texture, sampleCoord).a); \n"
+ " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(_qt_texture, shiftedSampleCoord).a); \n"
+ " gl_FragColor = mix(shifted, color, a); \n"
"}";
}
@@ -607,17 +607,17 @@ const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() cons
"varying highp vec3 sampleNearLeft; \n"
"varying highp vec3 sampleNearRight; \n"
"varying highp vec3 sampleFarRight; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"uniform mediump float alphaMin; \n"
"uniform mediump float alphaMax; \n"
"void main() { \n"
" highp vec4 n; \n"
- " n.x = texture2DProj(texture, sampleFarLeft).a; \n"
- " n.y = texture2DProj(texture, sampleNearLeft).a; \n"
- " highp float c = texture2D(texture, sampleCoord).a; \n"
- " n.z = texture2DProj(texture, sampleNearRight).a; \n"
- " n.w = texture2DProj(texture, sampleFarRight).a; \n"
+ " n.x = texture2DProj(_qt_texture, sampleFarLeft).a; \n"
+ " n.y = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
+ " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
+ " n.z = texture2DProj(_qt_texture, sampleNearRight).a; \n"
+ " n.w = texture2DProj(_qt_texture, sampleFarRight).a; \n"
#if 0
// Blurrier, faster.
" n = smoothstep(alphaMin, alphaMax, n); \n"
@@ -638,18 +638,18 @@ const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() cons
// return
// "#extension GL_OES_standard_derivatives: enable \n"
// "varying highp vec2 sampleCoord; \n"
-// "uniform sampler2D texture; \n"
+// "uniform sampler2D _qt_texture; \n"
// "uniform lowp vec4 color; \n"
// "uniform highp float alphaMin; \n"
// "uniform highp float alphaMax; \n"
// "void main() { \n"
// " highp vec2 delta = dFdx(sampleCoord); \n"
// " highp vec4 n; \n"
-// " n.x = texture2D(texture, sampleCoord - 0.667 * delta).a; \n"
-// " n.y = texture2D(texture, sampleCoord - 0.333 * delta).a; \n"
-// " highp float c = texture2D(texture, sampleCoord).a; \n"
-// " n.z = texture2D(texture, sampleCoord + 0.333 * delta).a; \n"
-// " n.w = texture2D(texture, sampleCoord + 0.667 * delta).a; \n"
+// " n.x = texture2D(_qt_texture, sampleCoord - 0.667 * delta).a; \n"
+// " n.y = texture2D(_qt_texture, sampleCoord - 0.333 * delta).a; \n"
+// " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
+// " n.z = texture2D(_qt_texture, sampleCoord + 0.333 * delta).a; \n"
+// " n.w = texture2D(_qt_texture, sampleCoord + 0.667 * delta).a; \n"
// " n = smoothstep(alphaMin, alphaMax, n); \n"
// " c = smoothstep(alphaMin, alphaMax, c); \n"
// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
@@ -746,14 +746,14 @@ const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::fragmentShader() cons
return
"varying highp vec3 sampleNearLeft; \n"
"varying highp vec3 sampleNearRight; \n"
- "uniform sampler2D texture; \n"
+ "uniform sampler2D _qt_texture; \n"
"uniform lowp vec4 color; \n"
"uniform mediump float alphaMin; \n"
"uniform mediump float alphaMax; \n"
"void main() { \n"
" highp vec2 n; \n"
- " n.x = texture2DProj(texture, sampleNearLeft).a; \n"
- " n.y = texture2DProj(texture, sampleNearRight).a; \n"
+ " n.x = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
+ " n.y = texture2DProj(_qt_texture, sampleNearRight).a; \n"
" n = smoothstep(alphaMin, alphaMax, n); \n"
" highp float c = 0.5 * (n.x + n.y); \n"
" gl_FragColor = vec4(n.x, c, n.y, c) * color.w; \n"
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
index fb9eebf403..34a884348d 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
@@ -531,7 +531,7 @@ void QSGSharedDistanceFieldGlyphCache::saveTexture(GLuint textureId, int width,
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
- int textureUniformLocation = glGetUniformLocation(shaderProgram, "texture");
+ int textureUniformLocation = glGetUniformLocation(shaderProgram, "_qt_texture");
glUniform1i(textureUniformLocation, 0);
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index d19c047e5a..7421db1db1 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -406,22 +406,26 @@ bool QSGRenderThread::event(QEvent *e)
pendingUpdate |= SyncRequest;
return true;
- case WM_TryRelease:
+ case WM_TryRelease: {
RLDEBUG1(" Render: WM_TryRelease");
mutex.lock();
+ WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (m_windows.size() == 0) {
- WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
RLDEBUG1(" Render: - setting exit flag and invalidating GL");
invalidateOpenGL(wme->window, wme->inDestructor);
shouldExit = !gl;
if (sleeping)
stopEventProcessing = true;
+ } else if (wme->window == gl->surface()) {
+ RLDEBUG1(" Render: - destroying the current window. Calling doneCurrent()...");
+ gl->doneCurrent();
} else {
RLDEBUG1(" Render: - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
mutex.unlock();
return true;
+ }
case WM_Grab: {
RLDEBUG1(" Render: WM_Grab");
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 5d9946a37b..fc1d6cecbc 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -173,8 +173,7 @@ QRectF QSGSimpleTextureNode::rect() const
*/
void QSGSimpleTextureNode::setTexture(QSGTexture *texture)
{
- if (m_material.texture() == texture)
- return;
+ Q_ASSERT(texture);
m_material.setTexture(texture);
m_opaque_material.setTexture(texture);
Q_D(QSGSimpleTextureNode);
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 7d226ed0f7..152d1f34c9 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -1025,14 +1025,11 @@ static QQuickGuiProvider *getGuiProvider()
return &guiProvider;
}
-static bool initializeProviders()
+void QQuick_initializeProviders()
{
QQml_addValueTypeProvider(getValueTypeProvider());
QQml_setColorProvider(getColorProvider());
QQml_setGuiProvider(getGuiProvider());
- return true;
}
-Q_CONSTRUCTOR_FUNCTION(initializeProviders)
-
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index b8f3ecf7d6..f2b2d2af06 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -548,6 +548,8 @@ void QQuickStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textI
textOut += QChar(60);
else if (entity == QLatin1String("amp"))
textOut += QChar(38);
+ else if (entity == QLatin1String("quot"))
+ textOut += QChar(34);
return;
}
++entityLength;