aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-04-03 13:35:26 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-04-03 13:35:30 +0200
commit0eeb7ada04cc81d0ab1b61747bdf92fd7c33e1ec (patch)
treebe4d0201b81b098a2976e857b5c6642f9c96e6ac /src
parent349d3400c11c0ad1c9aaec01c44b174dbb6ebf9a (diff)
parente4894fe13d178b6aa8b5580b402df2d1b4f2615c (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/MacroAssembler.h11
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM64.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h4
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerMIPS.h1
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86.h1
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86_64.h52
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h44
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp71
-rw-r--r--src/imports/builtins/builtins.qmltypes32
-rw-r--r--src/imports/imports.pro4
-rw-r--r--src/imports/localstorage/plugin.cpp2
-rw-r--r--src/imports/particles/plugins.qmltypes6
-rw-r--r--src/imports/qtquick2/plugins.qmltypes114
-rw-r--r--src/imports/testlib/plugins.qmltypes42
-rw-r--r--src/imports/window/plugins.qmltypes56
-rw-r--r--src/particles/particles.pri10
-rw-r--r--src/particles/qquickparticlesmodule.cpp6
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp105
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h30
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp7
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp17
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h21
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp45
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp17
-rw-r--r--src/plugins/scenegraph/openvg/openvg.pro7
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp5
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h2
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp25
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h3
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvglayer.h1
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp4
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h2
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgspritenode.h2
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp26
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h4
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h4
-rw-r--r--src/qml/compiler/qv4codegen.cpp16
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp9
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_p.h4
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp5
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp4
-rw-r--r--src/qml/compiler/qv4compileddata.cpp66
-rw-r--r--src/qml/compiler/qv4compileddata_p.h32
-rw-r--r--src/qml/compiler/qv4compiler.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp75
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h2
-rw-r--r--src/qml/compiler/qv4jsir.cpp6
-rw-r--r--src/qml/compiler/qv4jsir_p.h40
-rw-r--r--src/qml/compiler/qv4ssa.cpp195
-rw-r--r--src/qml/compiler/qv4ssa_p.h13
-rw-r--r--src/qml/configure.json13
-rw-r--r--src/qml/debugger/qqmldebug.cpp10
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h18
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc13
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc14
-rw-r--r--src/qml/jit/qv4assembler.cpp73
-rw-r--r--src/qml/jit/qv4assembler_p.h413
-rw-r--r--src/qml/jit/qv4binop.cpp12
-rw-r--r--src/qml/jit/qv4binop_p.h4
-rw-r--r--src/qml/jit/qv4isel_masm.cpp116
-rw-r--r--src/qml/jit/qv4isel_masm_p.h18
-rw-r--r--src/qml/jit/qv4regalloc.cpp8
-rw-r--r--src/qml/jit/qv4targetplatform_p.h34
-rw-r--r--src/qml/jit/qv4unop.cpp2
-rw-r--r--src/qml/jsapi/qjsengine.cpp4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h26
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp195
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h161
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp230
-rw-r--r--src/qml/jsruntime/qv4context_p.h157
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp9
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h13
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h3
-rw-r--r--src/qml/jsruntime/qv4engine.cpp51
-rw-r--r--src/qml/jsruntime/qv4engine_p.h30
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp44
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h14
-rw-r--r--src/qml/jsruntime/qv4function.cpp7
-rw-r--r--src/qml/jsruntime/qv4function_p.h6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp59
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h30
-rw-r--r--src/qml/jsruntime/qv4global_p.h6
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp1
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp26
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp60
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h23
-rw-r--r--src/qml/jsruntime/qv4managed.cpp1
-rw-r--r--src/qml/jsruntime/qv4managed_p.h6
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp15
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h35
-rw-r--r--src/qml/jsruntime/qv4object.cpp168
-rw-r--r--src/qml/jsruntime/qv4object_p.h46
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp8
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp11
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h2
-rw-r--r--src/qml/jsruntime/qv4property_p.h15
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp4
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h9
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp11
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h20
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp6
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp67
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h39
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp22
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h388
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4script_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp17
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h9
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp22
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h19
-rw-r--r--src/qml/jsruntime/qv4value_p.h3
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp212
-rw-r--r--src/qml/memory/memory.pri3
-rw-r--r--src/qml/memory/qv4heap_p.h31
-rw-r--r--src/qml/memory/qv4mm.cpp331
-rw-r--r--src/qml/memory/qv4mm_p.h40
-rw-r--r--src/qml/memory/qv4mmdefs_p.h118
-rw-r--r--src/qml/memory/qv4writebarrier_p.h239
-rw-r--r--src/qml/qml/qqmlcomponent.cpp40
-rw-r--r--src/qml/qml/qqmlengine.cpp4
-rw-r--r--src/qml/qml/qqmlexpression.cpp1
-rw-r--r--src/qml/qml/qqmlimport.cpp39
-rw-r--r--src/qml/qml/qqmllist.cpp10
-rw-r--r--src/qml/qml/qqmlmetatype.cpp12
-rw-r--r--src/qml/qml/qqmlnotifier.cpp4
-rw-r--r--src/qml/qml/qqmlproperty.cpp16
-rw-r--r--src/qml/qml/qqmltypeloader.cpp172
-rw-r--r--src/qml/qml/qqmltypeloader_p.h34
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp55
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp54
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp17
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp7
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp4
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp8
-rw-r--r--src/quick/accessible/qaccessiblequickview_p.h1
-rw-r--r--src/quick/configure.json9
-rw-r--r--src/quick/doc/snippets/qml/localstorage/hello.qml76
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc22
-rw-r--r--src/quick/doc/src/concepts/positioning/topic.qdoc2
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc14
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp24
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp7
-rw-r--r--src/quick/items/qquickevents.cpp8
-rw-r--r--src/quick/items/qquickflickable.cpp18
-rw-r--r--src/quick/items/qquickitem.cpp33
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickmousearea.cpp28
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp10
-rw-r--r--src/quick/items/qquickpainteditem_p.h2
-rw-r--r--src/quick/items/qquickpositioners_p.h2
-rw-r--r--src/quick/items/qquickshadereffect.cpp7
-rw-r--r--src/quick/items/qquickshadereffect_p.h4
-rw-r--r--src/quick/items/qquickstateoperations.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp66
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp9
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp20
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h2
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp6
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h7
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp1
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext.cpp1
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp5
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h2
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode.cpp128
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.h23
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp7
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp14
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp16
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp42
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h2
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgdistancefieldutil.cpp95
-rw-r--r--src/quick/scenegraph/util/qsgdistancefieldutil_p.h91
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.cpp12
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.h1
-rw-r--r--src/quick/util/qquickanimatorjob.cpp7
-rw-r--r--src/quick/util/qquickimageprovider.cpp18
-rw-r--r--src/quickwidgets/qquickwidget.cpp9
-rw-r--r--src/quickwidgets/qquickwidget_p.h2
-rw-r--r--src/src.pro4
200 files changed, 3940 insertions, 2589 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h
index 7d9f156c8c..f37861eb66 100644
--- a/src/3rdparty/masm/assembler/MacroAssembler.h
+++ b/src/3rdparty/masm/assembler/MacroAssembler.h
@@ -94,6 +94,7 @@ public:
using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact;
using Jump = typename MacroAssemblerBase::Jump;
using PatchableJump = typename MacroAssemblerBase::PatchableJump;
+ using MacroAssemblerBase::PointerSize;
using MacroAssemblerBase::pop;
using MacroAssemblerBase::jump;
@@ -200,19 +201,19 @@ public:
// described in terms of other macro assembly methods.
void pop()
{
- addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister);
+ addPtr(TrustedImm32(PointerSize), MacroAssemblerBase::stackPointerRegister);
}
void peek(RegisterID dest, int index = 0)
{
- loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
+ loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)), dest);
}
Address addressForPoke(int index)
{
- return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*)));
+ return Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize));
}
-
+
void poke(RegisterID src, int index = 0)
{
storePtr(src, addressForPoke(index));
@@ -223,10 +224,12 @@ public:
store32(value, addressForPoke(index));
}
+#if !defined(V4_BOOTSTRAP)
void poke(TrustedImmPtr imm, int index = 0)
{
storePtr(imm, addressForPoke(index));
}
+#endif
#if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP)
void peek64(RegisterID dest, int index = 0)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
index a11637f7ca..11f1672e15 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
@@ -127,6 +127,8 @@ private:
static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
public:
+ static const int PointerSize = 8;
+
MacroAssemblerARM64()
: m_dataMemoryTempRegister(this, dataTempRegister)
, m_cachedMemoryTempRegister(this, memoryTempRegister)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 806f2e13b6..fe8170d098 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -46,6 +46,8 @@ protected: // the YarrJIT needs know about addressTempRegister in order to push
inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
public:
+ static const int PointerSize = 4;
+
MacroAssemblerARMv7()
: m_makeJumpPatchable(false)
{
@@ -1242,7 +1244,7 @@ public:
void pop(RegisterID dest)
{
// store postindexed with writeback
- m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
+ m_assembler.ldr(dest, ARMRegisters::sp, 4 /*sizeof(void*)*/, false, true);
}
void push(RegisterID src)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
index 68584527fc..f2ad6a4470 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
@@ -37,6 +37,7 @@ namespace JSC {
class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
public:
typedef MIPSRegisters::FPRegisterID FPRegisterID;
+ static const int PointerSize = 4;
MacroAssemblerMIPS()
: m_fixedWidth(false)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
index 742a4b48f7..280cf427fc 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
@@ -35,6 +35,7 @@ namespace JSC {
class MacroAssemblerX86 : public MacroAssemblerX86Common {
public:
static const Scale ScalePtr = TimesFour;
+ static const int PointerSize = 4;
using MacroAssemblerX86Common::add32;
using MacroAssemblerX86Common::and32;
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
index 3566702413..c7c6aae637 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
@@ -37,6 +37,7 @@ namespace JSC {
class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
public:
static const Scale ScalePtr = TimesEight;
+ static const int PointerSize = 8;
using MacroAssemblerX86Common::add32;
using MacroAssemblerX86Common::and32;
@@ -327,14 +328,61 @@ public:
m_assembler.xorq_ir(imm.m_value, srcDest);
}
+ void lshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.shlq_i8r(imm.m_value, dest);
+ }
+
+ void lshift64(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.shlq_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only shift by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.shlq_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
+ void rshift64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.sarq_i8r(imm.m_value, dest);
+ }
+
+ void rshift64(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.sarq_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only shift by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.sarq_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
void urshift64(TrustedImm32 imm, RegisterID dest)
{
m_assembler.shrq_i8r(imm.m_value, dest);
}
- void lshift64(TrustedImm32 imm, RegisterID dest)
+ void urshift64(RegisterID src, RegisterID dest)
{
- m_assembler.shlq_i8r(imm.m_value, dest);
+ if (src == X86Registers::ecx)
+ m_assembler.shrq_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only shift by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.shrq_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
}
void load64(ImplicitAddress address, RegisterID dest)
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index 24462ef38f..b71cf290f8 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -253,6 +253,7 @@ public:
{
}
+#if defined(V4_BOOTSTRAP)
template <typename LabelType>
class Jump {
template<class TemplateAssemblerType>
@@ -291,6 +292,7 @@ public:
private:
AssemblerLabel m_label;
};
+#endif
// Stack operations:
@@ -723,6 +725,21 @@ public:
}
}
+ void sarq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+ }
+
+ void sarq_i8r(int imm, RegisterID dst)
+ {
+ if (imm == 1)
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
+ else {
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
+ m_formatter.immediate8(imm);
+ }
+ }
+
void shrq_i8r(int imm, RegisterID dst)
{
// ### doesn't work when removing the "0 &&"
@@ -734,6 +751,11 @@ public:
}
}
+ void shrq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst);
+ }
+
void shlq_i8r(int imm, RegisterID dst)
{
// ### doesn't work when removing the "0 &&"
@@ -745,7 +767,10 @@ public:
}
}
-
+ void shlq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
+ }
#endif
void sarl_i8r(int imm, RegisterID dst)
@@ -793,23 +818,6 @@ public:
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
}
-#if CPU(X86_64)
- void sarq_CLr(RegisterID dst)
- {
- m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
- }
-
- void sarq_i8r(int imm, RegisterID dst)
- {
- if (imm == 1)
- m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
- else {
- m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
- m_formatter.immediate8(imm);
- }
- }
-#endif
-
void imull_rr(RegisterID src, RegisterID dst)
{
m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src);
diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
index 0a6eda8b98..4cebc35cce 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp
@@ -55,71 +55,48 @@ static inline DWORD protection(bool writable, bool executable)
void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable)
{
- void *result;
- if (qt_winrt_use_jit) {
- result = VirtualAllocFromApp(0, bytes, MEM_RESERVE, protection(writable, executable));
- if (!result) {
- qt_winrt_use_jit = false;
- return reserveUncommitted(bytes, UnknownUsage, writable, executable);
- }
- } else {
- static const size_t pageSize = getPageSize();
- result = _aligned_malloc(bytes, pageSize);
- if (!result)
- CRASH();
- memset(result, 0, bytes);
- }
+ void *result = VirtualAllocFromApp(0, bytes, MEM_RESERVE, protection(writable, executable));
return result;
}
-void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable, bool includesGuardPages)
{
void *result;
- if (qt_winrt_use_jit) {
- result = VirtualAllocFromApp(0, bytes, MEM_RESERVE | MEM_COMMIT,
- protection(writable, executable));
- if (!result) {
- qt_winrt_use_jit = false;
- return reserveAndCommit(bytes, usage, writable, executable, includesGuardPages);
- }
+ result = VirtualAllocFromApp(0, bytes, MEM_RESERVE | MEM_COMMIT,
+ protection(writable, executable));
- if (includesGuardPages) {
- size_t guardSize = pageSize();
- DWORD oldProtect;
- if (!VirtualProtectFromApp(result, guardSize, protection(false, false), &oldProtect) ||
- !VirtualProtectFromApp(static_cast<char*>(result) + bytes - guardSize, guardSize,
- protection(false, false), &oldProtect)) {
- CRASH();
- }
+ if (includesGuardPages && qt_winrt_use_jit) {
+ size_t guardSize = pageSize();
+ DWORD oldProtect;
+ if (!VirtualProtectFromApp(result, guardSize, protection(false, false), &oldProtect) ||
+ !VirtualProtectFromApp(static_cast<char*>(result) + bytes - guardSize, guardSize,
+ protection(false, false), &oldProtect)) {
+ CRASH();
}
- } else {
- result = reserveUncommitted(bytes, usage, writable, executable);
}
return result;
}
-void OSAllocator::commit(void*, size_t, bool, bool)
+void OSAllocator::commit(void *bytes, size_t size, bool writable, bool executable)
{
- CRASH(); // Unimplemented
+ void *result = VirtualAllocFromApp(bytes, size, MEM_COMMIT,
+ protection(writable, executable));
+ if (!result)
+ CRASH();
}
-void OSAllocator::decommit(void* address, size_t)
+void OSAllocator::decommit(void* address, size_t bytes)
{
- if (qt_winrt_use_jit)
- Q_UNREACHABLE();
- else
- _aligned_free(address);
+ bool result = VirtualFree(address, bytes, MEM_DECOMMIT);
+ if (!result)
+ CRASH();
}
-void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+void OSAllocator::releaseDecommitted(void* address, size_t)
{
- if (qt_winrt_use_jit) {
- bool result = VirtualFree(address, 0, MEM_RELEASE);
- if (!result)
- CRASH();
- } else {
- decommit(address, bytes);
- }
+ bool result = VirtualFree(address, 0, MEM_RELEASE);
+ if (!result)
+ CRASH();
}
bool OSAllocator::canAllocateExecutableMemory()
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index 88e3ac6634..ac95a8837b 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -150,6 +150,25 @@ Module {
}
}
Enum {
+ name: "TextFlag"
+ values: {
+ "TextSingleLine": 256,
+ "TextDontClip": 512,
+ "TextExpandTabs": 1024,
+ "TextShowMnemonic": 2048,
+ "TextWordWrap": 4096,
+ "TextWrapAnywhere": 8192,
+ "TextDontPrint": 16384,
+ "TextIncludeTrailingSpaces": 134217728,
+ "TextHideMnemonic": 32768,
+ "TextJustificationForced": 65536,
+ "TextForceLeftToRight": 131072,
+ "TextForceRightToLeft": 262144,
+ "TextLongestVariant": 524288,
+ "TextBypassShaping": 1048576
+ }
+ }
+ Enum {
name: "TextElideMode"
values: {
"ElideLeft": 0,
@@ -440,7 +459,8 @@ Module {
"AA_SynthesizeMouseForUnhandledTabletEvents": 24,
"AA_CompressHighFrequencyEvents": 25,
"AA_DontCheckOpenGLContextThreadAffinity": 26,
- "AA_AttributeCount": 27
+ "AA_DisableShaderDiskCache": 27,
+ "AA_AttributeCount": 28
}
}
Enum {
@@ -1096,7 +1116,8 @@ Module {
"SystemLocaleLongDate": 5,
"DefaultLocaleShortDate": 6,
"DefaultLocaleLongDate": 7,
- "RFC2822Date": 8
+ "RFC2822Date": 8,
+ "ISODateWithMs": 9
}
}
Enum {
@@ -1607,6 +1628,13 @@ Module {
"MouseEventFlagMask": 255
}
}
+ Enum {
+ name: "ChecksumType"
+ values: {
+ "ChecksumIso3309": 0,
+ "ChecksumItuV41": 1
+ }
+ }
}
Component { name: "QEasingCurve"; prototype: "QQmlEasingValueType" }
}
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 20ade45fc8..d16ac05669 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,5 +1,7 @@
TEMPLATE = subdirs
+QT_FOR_CONFIG += quick-private
+
SUBDIRS += \
builtins \
qtqml \
@@ -18,7 +20,7 @@ qtHaveModule(quick) {
sharedimage \
testlib
- qtConfig(opengl(es1|es2)?): \
+ qtConfig(quick-particles): \
SUBDIRS += particles
}
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 60b8dad5fb..8679750842 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -564,7 +564,7 @@ Database connections are automatically closed during Javascript garbage collecti
The API can be used from JavaScript functions in your QML:
-\snippet localstorage/localstorage/hello.qml 0
+\snippet qml/localstorage/hello.qml 0
The API conforms to the Synchronous API of the HTML5 Web Database API,
\link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink.
diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes
index 5c4bd01980..6c7c98cc71 100644
--- a/src/imports/particles/plugins.qmltypes
+++ b/src/imports/particles/plugins.qmltypes
@@ -275,11 +275,11 @@ Module {
Parameter { name: "arg"; type: "double" }
}
Method {
- name: "setAcceleration"
+ name: "setMagnitude"
Parameter { name: "arg"; type: "double" }
}
Method {
- name: "setMagnitude"
+ name: "setAcceleration"
Parameter { name: "arg"; type: "double" }
}
Method {
@@ -552,7 +552,7 @@ Module {
Parameter { name: "arg"; type: "bool" }
}
Method {
- name: "setmirrored"
+ name: "setMirrored"
Parameter { name: "arg"; type: "bool" }
}
}
diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes
index 441cd743aa..a9534b5ccc 100644
--- a/src/imports/qtquick2/plugins.qmltypes
+++ b/src/imports/qtquick2/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.8'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.9'
Module {
dependencies: []
@@ -440,6 +440,13 @@ Module {
}
}
Component {
+ name: "QPointingDeviceUniqueId"
+ exports: ["QtQuick/PointingDeviceUniqueId 2.9"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "numericId"; type: "qlonglong"; isReadonly: true }
+ }
+ Component {
name: "QQmlApplication"
prototype: "QObject"
Property { name: "arguments"; type: "QStringList"; isReadonly: true }
@@ -1159,6 +1166,8 @@ Module {
Property { name: "supportsMultipleWindows"; type: "bool"; isReadonly: true }
Property { name: "state"; type: "Qt::ApplicationState"; isReadonly: true }
Property { name: "font"; type: "QFont"; isReadonly: true }
+ Property { name: "displayName"; type: "string" }
+ Property { name: "screens"; type: "QQuickScreenInfo"; isList: true; isReadonly: true }
Signal {
name: "stateChanged"
Parameter { name: "state"; type: "Qt::ApplicationState" }
@@ -1168,9 +1177,13 @@ Module {
name: "QQuickBasePositioner"
defaultProperty: "data"
prototype: "QQuickImplicitSizeItem"
- exports: ["QtQuick/Positioner 2.0", "QtQuick/Positioner 2.6"]
+ exports: [
+ "QtQuick/Positioner 2.0",
+ "QtQuick/Positioner 2.6",
+ "QtQuick/Positioner 2.9"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0, 6]
+ exportMetaObjectRevisions: [0, 6, 9]
attachedType: "QQuickPositionerAttached"
Property { name: "spacing"; type: "double" }
Property { name: "populate"; type: "QQuickTransition"; isPointer: true }
@@ -1186,6 +1199,8 @@ Module {
Signal { name: "leftPaddingChanged"; revision: 6 }
Signal { name: "rightPaddingChanged"; revision: 6 }
Signal { name: "bottomPaddingChanged"; revision: 6 }
+ Signal { name: "positioningComplete"; revision: 9 }
+ Method { name: "forceLayout"; revision: 9 }
}
Component {
name: "QQuickBehavior"
@@ -1502,8 +1517,8 @@ Module {
name: "QQuickFlickable"
defaultProperty: "flickableData"
prototype: "QQuickItem"
- exports: ["QtQuick/Flickable 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/Flickable 2.0", "QtQuick/Flickable 2.9"]
+ exportMetaObjectRevisions: [0, 9]
Enum {
name: "BoundsBehavior"
values: {
@@ -1563,6 +1578,8 @@ Module {
isPointer: true
}
Property { name: "pixelAligned"; type: "bool" }
+ Property { name: "horizontalOvershoot"; revision: 9; type: "double"; isReadonly: true }
+ Property { name: "verticalOvershoot"; revision: 9; type: "double"; isReadonly: true }
Property { name: "flickableData"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "flickableChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
Signal { name: "isAtBoundaryChanged" }
@@ -1572,6 +1589,8 @@ Module {
Signal { name: "flickEnded" }
Signal { name: "dragStarted" }
Signal { name: "dragEnded" }
+ Signal { name: "horizontalOvershootChanged"; revision: 9 }
+ Signal { name: "verticalOvershootChanged"; revision: 9 }
Method {
name: "resizeContent"
Parameter { name: "w"; type: "double" }
@@ -2084,8 +2103,13 @@ Module {
name: "QQuickItem"
defaultProperty: "data"
prototype: "QObject"
- exports: ["QtQuick/Item 2.0", "QtQuick/Item 2.1", "QtQuick/Item 2.4"]
- exportMetaObjectRevisions: [0, 1, 2]
+ exports: [
+ "QtQuick/Item 2.0",
+ "QtQuick/Item 2.1",
+ "QtQuick/Item 2.4",
+ "QtQuick/Item 2.7"
+ ]
+ exportMetaObjectRevisions: [0, 1, 2, 7]
Enum {
name: "TransformOrigin"
values: {
@@ -2210,23 +2234,21 @@ Module {
Parameter { name: "point"; type: "QPointF" }
}
Method {
- name: "mapToGlobal"
- revision: 7
- type: "QPointF"
- Parameter { name: "point"; type: "QPointF" }
+ name: "mapFromItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
- name: "mapFromGlobal"
- revision: 7
- type: "QPointF"
- Parameter { name: "point"; type: "QPointF" }
+ name: "mapToItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
- name: "mapFromItem"
+ name: "mapFromGlobal"
+ revision: 7
Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method {
- name: "mapToItem"
+ name: "mapToGlobal"
+ revision: 7
Parameter { type: "QQmlV4Function"; isPointer: true }
}
Method { name: "forceActiveFocus" }
@@ -2259,6 +2281,11 @@ Module {
type: "bool"
Parameter { name: "fileName"; type: "string" }
}
+ Method {
+ name: "saveToFile"
+ type: "bool"
+ Parameter { name: "fileName"; type: "string" }
+ }
}
Component {
name: "QQuickItemLayer"
@@ -2318,9 +2345,13 @@ Module {
name: "QQuickItemView"
defaultProperty: "flickableData"
prototype: "QQuickFlickable"
- exports: ["QtQuick/ItemView 2.1", "QtQuick/ItemView 2.3"]
+ exports: [
+ "QtQuick/ItemView 2.1",
+ "QtQuick/ItemView 2.3",
+ "QtQuick/ItemView 2.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [1, 2]
+ exportMetaObjectRevisions: [1, 2, 7]
Enum {
name: "LayoutDirection"
values: {
@@ -2495,6 +2526,10 @@ Module {
Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true }
}
Signal {
+ name: "shortcutOverride"
+ Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true }
+ }
+ Signal {
name: "digit0Pressed"
Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true }
}
@@ -2757,9 +2792,10 @@ Module {
exports: [
"QtQuick/MouseArea 2.0",
"QtQuick/MouseArea 2.4",
- "QtQuick/MouseArea 2.5"
+ "QtQuick/MouseArea 2.5",
+ "QtQuick/MouseArea 2.9"
]
- exportMetaObjectRevisions: [0, 1, 2]
+ exportMetaObjectRevisions: [0, 1, 2, 9]
Property { name: "mouseX"; type: "double"; isReadonly: true }
Property { name: "mouseY"; type: "double"; isReadonly: true }
Property { name: "containsMouse"; type: "bool"; isReadonly: true }
@@ -2774,6 +2810,7 @@ Module {
Property { name: "propagateComposedEvents"; type: "bool" }
Property { name: "cursorShape"; type: "Qt::CursorShape" }
Property { name: "containsPress"; revision: 1; type: "bool"; isReadonly: true }
+ Property { name: "pressAndHoldInterval"; revision: 9; type: "int" }
Signal { name: "hoveredChanged" }
Signal { name: "scrollGestureEnabledChanged"; revision: 2 }
Signal {
@@ -2816,6 +2853,7 @@ Module {
Signal { name: "exited" }
Signal { name: "canceled" }
Signal { name: "containsPressChanged"; revision: 1 }
+ Signal { name: "pressAndHoldIntervalChanged"; revision: 9 }
}
Component {
name: "QQuickMultiPointTouchArea"
@@ -3600,14 +3638,20 @@ Module {
Component {
name: "QQuickShortcut"
prototype: "QObject"
- exports: ["QtQuick/Shortcut 2.5", "QtQuick/Shortcut 2.6"]
- exportMetaObjectRevisions: [0, 1]
+ exports: [
+ "QtQuick/Shortcut 2.5",
+ "QtQuick/Shortcut 2.6",
+ "QtQuick/Shortcut 2.9"
+ ]
+ exportMetaObjectRevisions: [0, 1, 9]
Property { name: "sequence"; type: "QVariant" }
+ Property { name: "sequences"; revision: 9; type: "QVariantList" }
Property { name: "nativeText"; revision: 1; type: "string"; isReadonly: true }
Property { name: "portableText"; revision: 1; type: "string"; isReadonly: true }
Property { name: "enabled"; type: "bool" }
Property { name: "autoRepeat"; type: "bool" }
Property { name: "context"; type: "Qt::ShortcutContext" }
+ Signal { name: "sequencesChanged"; revision: 9 }
Signal { name: "activated" }
Signal { name: "activatedAmbiguously" }
}
@@ -3926,9 +3970,10 @@ Module {
"QtQuick/Text 2.0",
"QtQuick/Text 2.2",
"QtQuick/Text 2.3",
- "QtQuick/Text 2.6"
+ "QtQuick/Text 2.6",
+ "QtQuick/Text 2.9"
]
- exportMetaObjectRevisions: [0, 2, 3, 6]
+ exportMetaObjectRevisions: [0, 2, 3, 6, 9]
Enum {
name: "HAlignment"
values: {
@@ -4038,6 +4083,7 @@ Module {
Property { name: "leftPadding"; revision: 6; type: "double" }
Property { name: "rightPadding"; revision: 6; type: "double" }
Property { name: "bottomPadding"; revision: 6; type: "double" }
+ Property { name: "fontInfo"; revision: 9; type: "QJSValue"; isReadonly: true }
Signal {
name: "textChanged"
Parameter { name: "text"; type: "string" }
@@ -4093,7 +4139,9 @@ Module {
Signal { name: "leftPaddingChanged"; revision: 6 }
Signal { name: "rightPaddingChanged"; revision: 6 }
Signal { name: "bottomPaddingChanged"; revision: 6 }
+ Signal { name: "fontInfoChanged"; revision: 9 }
Method { name: "doLayout" }
+ Method { name: "forceLayout"; revision: 9 }
Method {
name: "linkAt"
revision: 3
@@ -4390,9 +4438,10 @@ Module {
"QtQuick/TextInput 2.2",
"QtQuick/TextInput 2.4",
"QtQuick/TextInput 2.6",
- "QtQuick/TextInput 2.7"
+ "QtQuick/TextInput 2.7",
+ "QtQuick/TextInput 2.9"
]
- exportMetaObjectRevisions: [0, 2, 3, 6, 7]
+ exportMetaObjectRevisions: [0, 2, 3, 6, 7, 9]
Enum {
name: "EchoMode"
values: {
@@ -4497,6 +4546,7 @@ Module {
Property { name: "bottomPadding"; revision: 6; type: "double" }
Signal { name: "accepted" }
Signal { name: "editingFinished"; revision: 2 }
+ Signal { name: "textEdited"; revision: 9 }
Signal {
name: "fontChanged"
Parameter { name: "font"; type: "QFont" }
@@ -4657,13 +4707,16 @@ Module {
Component {
name: "QQuickTouchPoint"
prototype: "QObject"
- exports: ["QtQuick/TouchPoint 2.0"]
- exportMetaObjectRevisions: [0]
+ exports: ["QtQuick/TouchPoint 2.0", "QtQuick/TouchPoint 2.9"]
+ exportMetaObjectRevisions: [0, 0]
Property { name: "pointId"; type: "int"; isReadonly: true }
+ Property { name: "uniqueId"; revision: 9; type: "QPointingDeviceUniqueId"; isReadonly: true }
Property { name: "pressed"; type: "bool"; isReadonly: true }
Property { name: "x"; type: "double"; isReadonly: true }
Property { name: "y"; type: "double"; isReadonly: true }
+ Property { name: "ellipseDiameters"; revision: 9; type: "QSizeF"; isReadonly: true }
Property { name: "pressure"; type: "double"; isReadonly: true }
+ Property { name: "rotation"; revision: 9; type: "double"; isReadonly: true }
Property { name: "velocity"; type: "QVector2D"; isReadonly: true }
Property { name: "area"; type: "QRectF"; isReadonly: true }
Property { name: "startX"; type: "double"; isReadonly: true }
@@ -4672,6 +4725,9 @@ Module {
Property { name: "previousY"; type: "double"; isReadonly: true }
Property { name: "sceneX"; type: "double"; isReadonly: true }
Property { name: "sceneY"; type: "double"; isReadonly: true }
+ Signal { name: "uniqueIdChanged"; revision: 9 }
+ Signal { name: "ellipseDiametersChanged"; revision: 9 }
+ Signal { name: "rotationChanged"; revision: 9 }
}
Component { name: "QQuickTransform"; prototype: "QObject" }
Component {
diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes
index 563778e55e..5d7ca51adc 100644
--- a/src/imports/testlib/plugins.qmltypes
+++ b/src/imports/testlib/plugins.qmltypes
@@ -4,11 +4,45 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick QtTest 1.1'
+// 'qmlplugindump -nonrelocatable -noforceqtquick QtTest 1.2'
Module {
dependencies: ["QtQuick 2.0"]
Component {
+ name: "QQuickTouchEventSequence"
+ prototype: "QObject"
+ Method {
+ name: "press"
+ type: "QObject*"
+ Parameter { name: "touchId"; type: "int" }
+ Parameter { name: "item"; type: "QObject"; isPointer: true }
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ Method {
+ name: "move"
+ type: "QObject*"
+ Parameter { name: "touchId"; type: "int" }
+ Parameter { name: "item"; type: "QObject"; isPointer: true }
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ Method {
+ name: "release"
+ type: "QObject*"
+ Parameter { name: "touchId"; type: "int" }
+ Parameter { name: "item"; type: "QObject"; isPointer: true }
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ Method {
+ name: "stationary"
+ type: "QObject*"
+ Parameter { name: "touchId"; type: "int" }
+ }
+ Method { name: "commit"; type: "QObject*" }
+ }
+ Component {
name: "QuickTestEvent"
prototype: "QObject"
exports: ["QtTest/TestEvent 1.0"]
@@ -127,6 +161,12 @@ Module {
Parameter { name: "yDelta"; type: "int" }
Parameter { name: "delay"; type: "int" }
}
+ Method {
+ name: "touchEvent"
+ type: "QQuickTouchEventSequence*"
+ Parameter { name: "item"; type: "QObject"; isPointer: true }
+ }
+ Method { name: "touchEvent"; type: "QQuickTouchEventSequence*" }
}
Component {
name: "QuickTestResult"
diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes
index a79bd8c332..cea2a910a7 100644
--- a/src/imports/window/plugins.qmltypes
+++ b/src/imports/window/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtQuick.Window 2.2'
+// 'qmlplugindump -nonrelocatable QtQuick.Window 2.3'
Module {
dependencies: ["QtQuick 2.8"]
@@ -24,14 +24,28 @@ Module {
Component {
name: "QQuickScreen"
prototype: "QObject"
- exports: ["QtQuick.Window/Screen 2.0"]
+ exports: ["QtQuick.Window/Screen 2.0", "QtQuick.Window/Screen 2.3"]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1]
attachedType: "QQuickScreenAttached"
}
Component {
name: "QQuickScreenAttached"
+ prototype: "QQuickScreenInfo"
+ Property { name: "orientationUpdateMask"; type: "Qt::ScreenOrientations" }
+ Method {
+ name: "angleBetween"
+ type: "int"
+ Parameter { name: "a"; type: "int" }
+ Parameter { name: "b"; type: "int" }
+ }
+ }
+ Component {
+ name: "QQuickScreenInfo"
prototype: "QObject"
+ exports: ["QtQuick.Window/ScreenInfo 2.3"]
+ isCreatable: false
+ exportMetaObjectRevisions: [2]
Property { name: "name"; type: "string"; isReadonly: true }
Property { name: "width"; type: "int"; isReadonly: true }
Property { name: "height"; type: "int"; isReadonly: true }
@@ -42,25 +56,18 @@ Module {
Property { name: "devicePixelRatio"; type: "double"; isReadonly: true }
Property { name: "primaryOrientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
Property { name: "orientation"; type: "Qt::ScreenOrientation"; isReadonly: true }
- Property { name: "orientationUpdateMask"; type: "Qt::ScreenOrientations" }
+ Property { name: "virtualX"; revision: 1; type: "int"; isReadonly: true }
+ Property { name: "virtualY"; revision: 1; type: "int"; isReadonly: true }
Signal { name: "desktopGeometryChanged" }
- Method {
- name: "angleBetween"
- type: "int"
- Parameter { name: "a"; type: "int" }
- Parameter { name: "b"; type: "int" }
- }
+ Signal { name: "virtualXChanged"; revision: 1 }
+ Signal { name: "virtualYChanged"; revision: 1 }
}
Component {
name: "QQuickWindow"
defaultProperty: "data"
prototype: "QWindow"
- exports: [
- "QtQuick.Window/Window 2.0",
- "QtQuick.Window/Window 2.1",
- "QtQuick.Window/Window 2.2"
- ]
- exportMetaObjectRevisions: [0, 1, 2]
+ exports: ["QtQuick.Window/Window 2.0"]
+ exportMetaObjectRevisions: [0]
Enum {
name: "SceneGraphError"
values: {
@@ -125,11 +132,16 @@ Module {
name: "QQuickWindowQmlImpl"
defaultProperty: "data"
prototype: "QQuickWindow"
- exports: ["QtQuick.Window/Window 2.1", "QtQuick.Window/Window 2.2"]
- exportMetaObjectRevisions: [0, 1]
+ exports: [
+ "QtQuick.Window/Window 2.1",
+ "QtQuick.Window/Window 2.2",
+ "QtQuick.Window/Window 2.3"
+ ]
+ exportMetaObjectRevisions: [0, 1, 2]
attachedType: "QQuickWindowAttached"
Property { name: "visible"; type: "bool" }
Property { name: "visibility"; type: "Visibility" }
+ Property { name: "screen"; revision: 2; type: "QObject"; isPointer: true }
Signal {
name: "visibleChanged"
Parameter { name: "arg"; type: "bool" }
@@ -138,6 +150,7 @@ Module {
name: "visibilityChanged"
Parameter { name: "visibility"; type: "QWindow::Visibility" }
}
+ Signal { name: "screenChanged"; revision: 2 }
}
Component {
name: "QWindow"
@@ -153,6 +166,13 @@ Module {
"FullScreen": 5
}
}
+ Enum {
+ name: "AncestorMode"
+ values: {
+ "ExcludeTransients": 0,
+ "IncludeTransients": 1
+ }
+ }
Property { name: "title"; type: "string" }
Property { name: "modality"; type: "Qt::WindowModality" }
Property { name: "flags"; type: "Qt::WindowFlags" }
diff --git a/src/particles/particles.pri b/src/particles/particles.pri
index af71634ec6..576d826903 100644
--- a/src/particles/particles.pri
+++ b/src/particles/particles.pri
@@ -1,6 +1,5 @@
HEADERS += \
$$PWD/qquickangledirection_p.h \
- $$PWD/qquickcustomparticle_p.h \
$$PWD/qquickcustomaffector_p.h \
$$PWD/qquickellipseextruder_p.h \
$$PWD/qquicktrailemitter_p.h \
@@ -33,7 +32,6 @@ HEADERS += \
SOURCES += \
$$PWD/qquickangledirection.cpp \
- $$PWD/qquickcustomparticle.cpp \
$$PWD/qquickcustomaffector.cpp \
$$PWD/qquickellipseextruder.cpp \
$$PWD/qquicktrailemitter.cpp \
@@ -63,6 +61,14 @@ SOURCES += \
$$PWD/qquickparticlegroup.cpp \
$$PWD/qquickgroupgoal.cpp
+qtConfig(quick-shadereffect) {
+HEADERS += \
+ $$PWD/qquickcustomparticle_p.h
+
+SOURCES += \
+ $$PWD/qquickcustomparticle.cpp
+}
+
OTHER_FILES += \
$$PWD/shaders/customparticletemplate.vert \
$$PWD/shaders/customparticle.vert \
diff --git a/src/particles/qquickparticlesmodule.cpp b/src/particles/qquickparticlesmodule.cpp
index accdb668de..03f47a3961 100644
--- a/src/particles/qquickparticlesmodule.cpp
+++ b/src/particles/qquickparticlesmodule.cpp
@@ -37,8 +37,12 @@
**
****************************************************************************/
+#include <private/qtquickglobal_p.h>
+
#include "qquickangledirection_p.h"
+#if QT_CONFIG(quick_shadereffect)
#include "qquickcustomparticle_p.h"
+#endif
#include "qquickellipseextruder_p.h"
#include "qquicktrailemitter_p.h"
#include "qquickfriction_p.h"
@@ -84,7 +88,9 @@ void QQuickParticlesModule::defineModule()
qmlRegisterType<QQuickParticleGroup>(uri, 2, 0, "ParticleGroup");
qmlRegisterType<QQuickImageParticle>(uri, 2, 0, "ImageParticle");
+#if QT_CONFIG(quick_shadereffect)
qmlRegisterType<QQuickCustomParticle>(uri, 2, 0, "CustomParticle");
+#endif
qmlRegisterType<QQuickItemParticle>(uri, 2, 0, "ItemParticle");
qmlRegisterType<QQuickParticleEmitter>(uri, 2, 0, "Emitter");
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index a4bad5618b..430ba4f255 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -55,11 +55,11 @@
QT_BEGIN_NAMESPACE
-QV4::CallContext *QV4DataCollector::findContext(int frame)
+QV4::SimpleCallContext *QV4DataCollector::findContext(int frame)
{
QV4::ExecutionContext *ctx = engine()->currentContext;
while (ctx) {
- QV4::CallContext *cCtxt = ctx->asCallContext();
+ QV4::SimpleCallContext *cCtxt = ctx->asSimpleCallContext();
if (cCtxt && cCtxt->d()->v4Function) {
if (frame < 1)
return cCtxt;
@@ -71,7 +71,7 @@ QV4::CallContext *QV4DataCollector::findContext(int frame)
return 0;
}
-QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope)
+QV4::Heap::SimpleCallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope)
{
if (!ctxt)
return 0;
@@ -81,7 +81,7 @@ QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt,
for (; scope > 0 && ctx; --scope)
ctx = ctx->d()->outer;
- return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0;
+ return (ctx && ctx->d()) ? ctx->asSimpleCallContext()->d() : 0;
}
QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes(int frame)
@@ -89,13 +89,13 @@ QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeType
QVector<QV4::Heap::ExecutionContext::ContextType> types;
QV4::Scope scope(engine());
- QV4::CallContext *sctxt = findContext(frame);
+ QV4::SimpleCallContext *sctxt = findContext(frame);
if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext)
return types;
QV4::ScopedContext it(scope, sctxt);
for (; it; it = it->d()->outer)
- types.append(it->d()->type);
+ types.append(QV4::Heap::ExecutionContext::ContextType(it->d()->type));
return types;
}
@@ -118,15 +118,18 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s
}
}
-QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine)
+QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine)
+ : m_engine(engine), m_namesAsObjects(true), m_redundantRefs(true)
{
m_values.set(engine, engine->newArrayObject());
}
+// TODO: Directly call addRef() once we don't need to support redundantRefs anymore
QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value)
{
Ref ref = addRef(value);
- m_collectedRefs.append(ref);
+ if (m_redundantRefs)
+ m_collectedRefs.append(ref);
return ref;
}
@@ -184,30 +187,48 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution
case QV4::Value::Integer_Type:
dict.insert(valueKey, value->integerValue());
return 0;
- default: // double
- dict.insert(valueKey, value->doubleValue());
+ default: {// double
+ const double val = value->doubleValue();
+ if (qIsFinite(val))
+ dict.insert(valueKey, val);
+ else if (qIsNaN(val))
+ dict.insert(valueKey, QStringLiteral("NaN"));
+ else if (val < 0)
+ dict.insert(valueKey, QStringLiteral("-Infinity"));
+ else
+ dict.insert(valueKey, QStringLiteral("Infinity"));
return 0;
}
+ }
}
-QJsonObject QV4DataCollector::lookupRef(Ref ref)
+QJsonObject QV4DataCollector::lookupRef(Ref ref, bool deep)
{
QJsonObject dict;
- if (lookupSpecialRef(ref, &dict))
- return dict;
+
+ if (m_namesAsObjects) {
+ if (lookupSpecialRef(ref, &dict))
+ return dict;
+ }
+
+ if (m_redundantRefs)
+ deep = true;
dict.insert(QStringLiteral("handle"), qint64(ref));
QV4::Scope scope(engine());
QV4::ScopedValue value(scope, getValue(ref));
- if (const QV4::Object *o = collectProperty(value, engine(), dict))
- dict.insert(QStringLiteral("properties"), collectProperties(o));
+ const QV4::Object *object = collectProperty(value, engine(), dict);
+ if (deep && object)
+ dict.insert(QStringLiteral("properties"), collectProperties(object));
return dict;
}
+// TODO: Drop this method once we don't need to support namesAsObjects anymore
QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName)
{
+ Q_ASSERT(m_namesAsObjects);
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
QJsonObject dict;
@@ -220,8 +241,10 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa
return ref;
}
+// TODO: Drop this method once we don't need to support namesAsObjects anymore
QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
{
+ Q_ASSERT(m_namesAsObjects);
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
QJsonObject dict;
@@ -250,6 +273,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
if (!ctxt)
return false;
+ Refs collectedRefs;
QV4::ScopedValue v(scope);
int nFormals = ctxt->formalCount();
for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
@@ -258,7 +282,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
qName = name->string;
names.append(qName);
v = ctxt->argument(i);
- collect(v);
+ collectedRefs.append(collect(v));
}
for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
@@ -267,21 +291,26 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
qName = name->string;
names.append(qName);
v = ctxt->d()->locals[i];
- collect(v);
+ collectedRefs.append(collect(v));
}
QV4::ScopedObject scopeObject(scope, engine()->newObject());
- Q_ASSERT(names.size() == m_collectedRefs.size());
+ Q_ASSERT(names.size() == collectedRefs.size());
QV4::ScopedString propName(scope);
- for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
+ for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
propName = engine()->newString(names.at(i));
- scopeObject->put(propName, QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i))));
+ scopeObject->put(propName, QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i))));
}
Ref scopeObjectRef = addRef(scopeObject);
- dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
- m_collectedRefs.append(scopeObjectRef);
+ if (m_redundantRefs) {
+ dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
+ m_collectedRefs.append(scopeObjectRef);
+ } else {
+ *dict = lookupRef(scopeObjectRef, true);
+ }
+
return true;
}
@@ -293,15 +322,16 @@ QJsonObject toRef(QV4DataCollector::Ref ref) {
QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
{
- QV4DataCollector::Ref ref;
-
QJsonObject frame;
frame[QLatin1String("index")] = frameNr;
frame[QLatin1String("debuggerFrame")] = false;
- ref = addFunctionRef(stackFrame.function);
- frame[QLatin1String("func")] = toRef(ref);
- ref = addScriptRef(stackFrame.source);
- frame[QLatin1String("script")] = toRef(ref);
+ if (m_namesAsObjects) {
+ frame[QLatin1String("func")] = toRef(addFunctionRef(stackFrame.function));
+ frame[QLatin1String("script")] = toRef(addScriptRef(stackFrame.source));
+ } else {
+ frame[QLatin1String("func")] = stackFrame.function;
+ frame[QLatin1String("script")] = stackFrame.source;
+ }
frame[QLatin1String("line")] = stackFrame.line - 1;
if (stackFrame.column >= 0)
frame[QLatin1String("column")] = stackFrame.column;
@@ -310,7 +340,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int
QV4::Scope scope(engine());
QV4::ScopedContext ctxt(scope, findContext(frameNr));
while (ctxt) {
- if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
+ if (QV4::SimpleCallContext *cCtxt = ctxt->asSimpleCallContext()) {
if (cCtxt->d()->activation)
break;
}
@@ -318,7 +348,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int
}
if (ctxt) {
- QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation);
+ QV4::ScopedValue o(scope, ctxt->asSimpleCallContext()->d()->activation);
frame[QLatin1String("receiver")] = toRef(collect(o));
}
@@ -340,15 +370,17 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int
return frame;
}
+// TODO: Drop this method once we don't need to support redundantRefs anymore
QJsonArray QV4DataCollector::flushCollectedRefs()
{
+ Q_ASSERT(m_redundantRefs);
QJsonArray refs;
std::sort(m_collectedRefs.begin(), m_collectedRefs.end());
for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
QV4DataCollector::Ref ref = m_collectedRefs.at(i);
if (i > 0 && ref == m_collectedRefs.at(i - 1))
continue;
- refs.append(lookupRef(ref));
+ refs.append(lookupRef(ref, true));
}
m_collectedRefs.clear();
@@ -360,14 +392,16 @@ void QV4DataCollector::clear()
m_values.set(engine(), engine()->newArrayObject());
m_collectedRefs.clear();
m_specialRefs.clear();
+ m_namesAsObjects = true;
+ m_redundantRefs = true;
}
QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
{
class ExceptionStateSaver
{
- quint32 *hasExceptionLoc;
- quint32 hadException;
+ quint8 *hasExceptionLoc;
+ quint8 hadException;
public:
ExceptionStateSaver(QV4::ExecutionEngine *engine)
@@ -403,8 +437,10 @@ QV4::ReturnedValue QV4DataCollector::getValue(Ref ref)
return array->getIndexed(ref, Q_NULLPTR);
}
+// TODO: Drop this method once we don't need to support namesAsObjects anymore
bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict)
{
+ Q_ASSERT(m_namesAsObjects);
SpecialRefs::const_iterator it = m_specialRefs.constFind(ref);
if (it == m_specialRefs.cend())
return false;
@@ -442,7 +478,8 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop
if (value->isManaged() && !value->isString()) {
Ref ref = addRef(value);
dict.insert(QStringLiteral("ref"), qint64(ref));
- m_collectedRefs.append(ref);
+ if (m_redundantRefs)
+ m_collectedRefs.append(ref);
}
collectProperty(value, engine(), dict);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index fd6356f22e..de12e8d527 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -58,42 +58,50 @@ public:
typedef uint Ref;
typedef QVector<uint> Refs;
- static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope);
+ static QV4::Heap::SimpleCallContext *findScope(QV4::ExecutionContext *ctxt, int scope);
static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType);
QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame);
- QV4::CallContext *findContext(int frame);
+ QV4::SimpleCallContext *findContext(int frame);
QV4DataCollector(QV4::ExecutionEngine *engine);
- Ref collect(const QV4::ScopedValue &value);
- Ref addFunctionRef(const QString &functionName);
- Ref addScriptRef(const QString &scriptName);
+ Ref collect(const QV4::ScopedValue &value); // only for redundantRefs
+ Ref addFunctionRef(const QString &functionName); // only for namesAsObjects
+ Ref addScriptRef(const QString &scriptName); // only for namesAsObjects
+
+ void setNamesAsObjects(bool namesAsObjects) { m_namesAsObjects = namesAsObjects; }
+ bool namesAsObjects() const { return m_namesAsObjects; }
+
+ void setRedundantRefs(bool redundantRefs) { m_redundantRefs = redundantRefs; }
+ bool redundantRefs() const { return m_redundantRefs; }
bool isValidRef(Ref ref) const;
- QJsonObject lookupRef(Ref ref);
+ QJsonObject lookupRef(Ref ref, bool deep);
bool collectScope(QJsonObject *dict, int frameNr, int scopeNr);
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr);
QV4::ExecutionEngine *engine() const { return m_engine; }
- QJsonArray flushCollectedRefs();
+ QJsonArray flushCollectedRefs(); // only for redundantRefs
void clear();
private:
Ref addRef(QV4::Value value, bool deduplicate = true);
QV4::ReturnedValue getValue(Ref ref);
- bool lookupSpecialRef(Ref ref, QJsonObject *dict);
+ bool lookupSpecialRef(Ref ref, QJsonObject *dict); // only for namesAsObjects
QJsonArray collectProperties(const QV4::Object *object);
QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value);
void collectArgumentsInContext();
QV4::ExecutionEngine *m_engine;
- Refs m_collectedRefs;
+ Refs m_collectedRefs; // only for redundantRefs
QV4::PersistentValue m_values;
- typedef QHash<Ref, QJsonObject> SpecialRefs;
- SpecialRefs m_specialRefs;
+ typedef QHash<Ref, QJsonObject> SpecialRefs; // only for namesAsObjects
+ SpecialRefs m_specialRefs; // only for namesAsObjects
+ bool m_namesAsObjects;
+ bool m_redundantRefs;
};
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
index 5cc2043cb1..75cbc9eba1 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
@@ -230,7 +230,12 @@ void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal)
QMutexLocker locker(&m_lock);
if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) {
- m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext));
+ if (QV4::ExecutionContext *parentContext
+ = m_engine->parentContext(m_engine->currentContext)) {
+ m_currentContext.set(m_engine, *parentContext);
+ } else {
+ m_currentContext.clear();
+ }
m_stepping = StepOver;
m_returnedValue.set(m_engine, retVal);
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index d5fadad50a..107ec60943 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -151,7 +151,7 @@ void BacktraceJob::run()
result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
result.insert(QStringLiteral("frames"), frameArray);
}
- collectedRefs = collector->flushCollectedRefs();
+ flushRedundantRefs();
}
FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) :
@@ -166,7 +166,7 @@ void FrameJob::run()
success = false;
} else {
result = collector->buildFrame(frames[frameNr], frameNr);
- collectedRefs = collector->flushCollectedRefs();
+ flushRedundantRefs();
success = true;
}
}
@@ -196,7 +196,7 @@ void ScopeJob::run()
result[QLatin1String("index")] = scopeNr;
result[QLatin1String("frameIndex")] = frameNr;
result[QLatin1String("object")] = object;
- collectedRefs = collector->flushCollectedRefs();
+ flushRedundantRefs();
}
bool ScopeJob::wasSuccessful() const
@@ -226,9 +226,9 @@ void ValueLookupJob::run()
exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
break;
}
- result[QString::number(ref)] = collector->lookupRef(ref);
+ result[QString::number(ref)] = collector->lookupRef(ref, true);
}
- collectedRefs = collector->flushCollectedRefs();
+ flushRedundantRefs();
if (scopeObject)
engine->popContext();
}
@@ -249,8 +249,9 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &value)
{
if (hasExeption())
exception = value->toQStringNoThrow();
- result = collector->lookupRef(collector->collect(value));
- collectedRefs = collector->flushCollectedRefs();
+ result = collector->lookupRef(collector->collect(value), true);
+ if (collector->redundantRefs())
+ collectedRefs = collector->flushCollectedRefs();
}
const QString &ExpressionEvalJob::exceptionMessage() const
@@ -263,8 +264,10 @@ const QJsonObject &ExpressionEvalJob::returnValue() const
return result;
}
+// TODO: Drop this method once we don't need to support redundantRefs anymore
const QJsonArray &ExpressionEvalJob::refs() const
{
+ Q_ASSERT(collector->redundantRefs());
return collectedRefs;
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
index 00d3e6206a..eca8710e15 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
@@ -78,11 +78,24 @@ class CollectJob : public QV4DebugJob
protected:
QV4DataCollector *collector;
QJsonObject result;
- QJsonArray collectedRefs;
+ QJsonArray collectedRefs; // only for redundantRefs
+
+ void flushRedundantRefs()
+ {
+ if (collector->redundantRefs())
+ collectedRefs = collector->flushCollectedRefs();
+ }
+
public:
CollectJob(QV4DataCollector *collector) : collector(collector) {}
const QJsonObject &returnValue() const { return result; }
- const QJsonArray &refs() const { return collectedRefs; }
+
+ // TODO: Drop this method once we don't need to support redundantRefs anymore
+ const QJsonArray &refs() const
+ {
+ Q_ASSERT(collector->redundantRefs());
+ return collectedRefs;
+ }
};
class BacktraceJob: public CollectJob
@@ -133,7 +146,7 @@ class ExpressionEvalJob: public JavaScriptJob
QV4DataCollector *collector;
QString exception;
QJsonObject result;
- QJsonArray collectedRefs;
+ QJsonArray collectedRefs; // only for redundantRefs
public:
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context,
@@ -141,7 +154,7 @@ public:
void handleResult(QV4::ScopedValue &value) override;
const QString &exceptionMessage() const;
const QJsonObject &returnValue() const;
- const QJsonArray &refs() const;
+ const QJsonArray &refs() const; // only for redundantRefs
};
class GatherSourcesJob: public QV4DebugJob
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 1d2cc092dc..68cdb57a44 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -121,8 +121,18 @@ protected:
response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning());
}
+ QV4DataCollector *saneCollector(QV4Debugger *debugger)
+ {
+ QV4DataCollector *collector = debugger->collector();
+ collector->setNamesAsObjects(debugService->clientRequiresNamesAsObjects());
+ collector->setRedundantRefs(debugService->clientRequiresRedundantRefs());
+ return collector;
+ }
+
+ // TODO: drop this method once we don't need to support redundantRefs anymore.
void addRefs(const QJsonArray &refs)
{
+ Q_ASSERT(debugService->clientRequiresRedundantRefs());
response.insert(QStringLiteral("refs"), refs);
}
@@ -286,7 +296,7 @@ public:
return;
}
- BacktraceJob job(debugger->collector(), fromFrame, toFrame);
+ BacktraceJob job(saneCollector(debugger), fromFrame, toFrame);
debugger->runInEngine(&job);
// response:
@@ -295,7 +305,8 @@ public:
addSuccess(true);
addRunning();
addBody(job.returnValue());
- addRefs(job.refs());
+ if (debugService->clientRequiresRedundantRefs())
+ addRefs(job.refs());
}
};
@@ -322,7 +333,7 @@ public:
return;
}
- FrameJob job(debugger->collector(), frameNr);
+ FrameJob job(saneCollector(debugger), frameNr);
debugger->runInEngine(&job);
if (!job.wasSuccessful()) {
createErrorResponse(QStringLiteral("frame retrieval failed"));
@@ -337,7 +348,8 @@ public:
addSuccess(true);
addRunning();
addBody(job.returnValue());
- addRefs(job.refs());
+ if (debugService->clientRequiresRedundantRefs())
+ addRefs(job.refs());
}
};
@@ -369,7 +381,7 @@ public:
return;
}
- ScopeJob job(debugger->collector(), frameNr, scopeNr);
+ ScopeJob job(saneCollector(debugger), frameNr, scopeNr);
debugger->runInEngine(&job);
if (!job.wasSuccessful()) {
createErrorResponse(QStringLiteral("scope retrieval failed"));
@@ -382,7 +394,8 @@ public:
addSuccess(true);
addRunning();
addBody(job.returnValue());
- addRefs(job.refs());
+ if (debugService->clientRequiresRedundantRefs())
+ addRefs(job.refs());
}
};
@@ -410,7 +423,7 @@ public:
debugger = debuggers.first();
}
- ValueLookupJob job(handles, debugger->collector());
+ ValueLookupJob job(handles, saneCollector(debugger));
debugger->runInEngine(&job);
if (!job.exceptionMessage().isEmpty()) {
createErrorResponse(job.exceptionMessage());
@@ -421,7 +434,8 @@ public:
addSuccess(true);
addRunning();
addBody(job.returnValue());
- addRefs(job.refs());
+ if (debugService->clientRequiresRedundantRefs())
+ addRefs(job.refs());
}
}
};
@@ -630,7 +644,7 @@ public:
}
ExpressionEvalJob job(debugger->engine(), frame, context, expression,
- debugger->collector());
+ saneCollector(debugger));
debugger->runInEngine(&job);
if (job.hasExeption()) {
createErrorResponse(job.exceptionMessage());
@@ -640,7 +654,8 @@ public:
addSuccess(true);
addRunning();
addBody(job.returnValue());
- addRefs(job.refs());
+ if (debugService->clientRequiresRedundantRefs())
+ addRefs(job.refs());
}
}
};
@@ -662,7 +677,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command)
QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QV4DebugService>(1, parent),
- debuggerAgent(this), theSelectedFrame(0),
+ debuggerAgent(this), theSelectedFrame(0), redundantRefs(true), namesAsObjects(true),
unknownV8CommandHandler(new UnknownV8CommandHandler)
{
addHandler(new V8VersionRequest);
@@ -766,6 +781,14 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message)
TRACE_PROTOCOL(qDebug() << "... type:" << type);
if (type == V4_CONNECT) {
+ QJsonObject parameters = QJsonDocument::fromJson(payload).object();
+ namesAsObjects = true;
+ redundantRefs = true;
+ if (parameters.contains("namesAsObjects"))
+ namesAsObjects = parameters.value("namesAsObjects").toBool();
+ if (parameters.contains("redundantRefs"))
+ redundantRefs = parameters.value("redundantRefs").toBool();
+
emit messageToClient(name(), packMessage(type));
stopWaiting();
} else if (type == V4_PAUSE) {
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
index 69e32189b8..bb13890ae4 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -86,6 +86,9 @@ public:
int selectedFrame() const;
void selectFrame(int frameNr);
+ bool clientRequiresRedundantRefs() const { return redundantRefs; }
+ bool clientRequiresNamesAsObjects() const { return namesAsObjects; }
+
QV4DebuggerAgent debuggerAgent;
protected:
@@ -105,6 +108,9 @@ private:
static int sequence;
int theSelectedFrame;
+ bool redundantRefs;
+ bool namesAsObjects;
+
void addHandler(V8CommandHandler* handler);
QHash<QString, V8CommandHandler*> handlers;
QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler;
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
index 7f842419e7..6cb1ab4051 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
@@ -481,17 +481,20 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
QJsonArray output;
QV4::Scope scope(engine);
- if (QV4::CallContext *callContext = executionContext->asCallContext()) {
+ if (QV4::SimpleCallContext *callContext = executionContext->asSimpleCallContext()) {
QV4::Value thisObject = callContext->thisObject();
collector.collect(&output, QString(), QStringLiteral("this"), thisObject);
QV4::Identifier *const *variables = callContext->variables();
QV4::Identifier *const *formals = callContext->formals();
- for (unsigned i = 0, ei = callContext->variableCount(); i != ei; ++i) {
- QString qName;
- if (QV4::Identifier *name = variables[i])
- qName = name->string;
- QV4::Value val = callContext->d()->locals[i];
- collector.collect(&output, QString(), qName, val);
+ if (callContext->d()->type == QV4::Heap::ExecutionContext::Type_CallContext) {
+ QV4::CallContext *ctx = static_cast<QV4::CallContext *>(callContext);
+ for (unsigned i = 0, ei = ctx->variableCount(); i != ei; ++i) {
+ QString qName;
+ if (QV4::Identifier *name = variables[i])
+ qName = name->string;
+ QV4::Value val = ctx->d()->locals[i];
+ collector.collect(&output, QString(), qName, val);
+ }
}
for (unsigned i = 0, ei = callContext->formalCount(); i != ei; ++i) {
QString qName;
diff --git a/src/plugins/scenegraph/openvg/openvg.pro b/src/plugins/scenegraph/openvg/openvg.pro
index 6d5b190b37..43c2636343 100644
--- a/src/plugins/scenegraph/openvg/openvg.pro
+++ b/src/plugins/scenegraph/openvg/openvg.pro
@@ -31,7 +31,6 @@ HEADERS += \
qsgopenvghelpers.h \
qsgopenvgfontglyphcache.h \
qsgopenvgpainternode.h \
- qsgopenvgspritenode.h \
qsgopenvgrenderable.h \
qopenvgoffscreensurface.h
@@ -52,6 +51,10 @@ SOURCES += \
qsgopenvghelpers.cpp \
qsgopenvgfontglyphcache.cpp \
qsgopenvgpainternode.cpp \
- qsgopenvgspritenode.cpp \
qsgopenvgrenderable.cpp \
qopenvgoffscreensurface.cpp
+
+qtConfig(quick-sprite) {
+ HEADERS += qsgopenvgspritenode.h
+ SOURCES += qsgopenvgspritenode.cpp
+}
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp
index 41fce7c7fc..76ebb7c4ee 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp
@@ -45,7 +45,9 @@
#include "qsgopenvgglyphnode_p.h"
#include "qsgopenvgfontglyphcache.h"
#include "qsgopenvgpainternode.h"
+#if QT_CONFIG(quick_sprite)
#include "qsgopenvgspritenode.h"
+#endif
#include "qopenvgcontext_p.h"
@@ -171,11 +173,12 @@ int QSGOpenVGRenderContext::maxTextureSize() const
return qMin(width, height);
}
-
+#if QT_CONFIG(quick_sprite)
QSGSpriteNode *QSGOpenVGContext::createSpriteNode()
{
return new QSGOpenVGSpriteNode();
}
+#endif
QSGRendererInterface *QSGOpenVGContext::rendererInterface(QSGRenderContext *renderContext)
{
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h
index fa9939a253..31a1e8643f 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h
@@ -95,7 +95,9 @@ public:
QSurfaceFormat defaultSurfaceFormat() const override;
QSGInternalRectangleNode *createInternalRectangleNode() override;
QSGInternalImageNode *createInternalImageNode() override;
+#if QT_CONFIG(quick_sprite)
QSGSpriteNode *createSpriteNode() override;
+#endif
QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
};
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp
index dd630c776f..df47e920af 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp
@@ -94,7 +94,7 @@ void QSGOpenVGFontGlyphCache::populate(const QVector<quint32> &glyphs)
referencedGlyphs.insert(glyphIndex);
- if (!m_cachedGlyphs.contains(glyphIndex)) {
+ if (!m_glyphReferences.contains(glyphIndex)) {
newGlyphs.insert(glyphIndex);
}
}
@@ -119,17 +119,9 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet<quint32> &glyphs)
{
VGfloat origin[2];
VGfloat escapement[2];
- QRectF metrics;
QRawFont rawFont = m_referenceFont;
- // Before adding any new glyphs, remove any unused glyphs
- for (auto glyph : qAsConst(m_unusedGlyphs)) {
- vgClearGlyph(m_font, glyph);
- }
-
for (auto glyph : glyphs) {
- m_cachedGlyphs.insert(glyph);
-
// Calculate the path for the glyph and cache it.
QPainterPath path = rawFont.pathForGlyph(glyph);
VGPath vgPath;
@@ -151,12 +143,23 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet<quint32> &glyphs)
void QSGOpenVGFontGlyphCache::referenceGlyphs(const QSet<quint32> &glyphs)
{
- m_unusedGlyphs -= glyphs;
+ for (auto glyph : glyphs) {
+ if (m_glyphReferences.contains(glyph))
+ m_glyphReferences[glyph] += 1;
+ else
+ m_glyphReferences.insert(glyph, 1);
+ }
}
void QSGOpenVGFontGlyphCache::releaseGlyphs(const QSet<quint32> &glyphs)
{
- m_unusedGlyphs += glyphs;
+ for (auto glyph : glyphs) {
+ int references = m_glyphReferences[glyph] -= 1;
+ if (references == 0) {
+ vgClearGlyph(m_font, glyph);
+ m_glyphReferences.remove(glyph);
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h
index a88d28b0fe..107ec0c892 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h
@@ -87,8 +87,7 @@ private:
int m_glyphCount;
VGFont m_font;
- QSet<quint32> m_cachedGlyphs;
- QSet<quint32> m_unusedGlyphs;
+ QHash<quint32, int> m_glyphReferences;
};
diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.h b/src/plugins/scenegraph/openvg/qsgopenvglayer.h
index 2af0bfb40f..8deedc3347 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvglayer.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.h
@@ -83,6 +83,7 @@ public:
void setDevicePixelRatio(qreal ratio) override;
void setMirrorHorizontal(bool mirror) override;
void setMirrorVertical(bool mirror) override;
+ void setSamples(int) override { }
public slots:
void markDirtyTexture() override;
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
index 8aa179f705..41606c653a 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
@@ -43,7 +43,9 @@
#include "qsgopenvgpublicnodes.h"
#include "qsgopenvgglyphnode_p.h"
#include "qsgopenvgpainternode.h"
+#if QT_CONFIG(quick_sprite)
#include "qsgopenvgspritenode.h"
+#endif
#include "qsgopenvgrenderable.h"
#include "qopenvgcontext_p.h"
@@ -209,6 +211,7 @@ void QSGOpenVGNodeVisitor::endVisit(QSGRootNode *)
{
}
+#if QT_CONFIG(quick_sprite)
bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node)
{
renderRenderableNode(static_cast<QSGOpenVGSpriteNode*>(node));
@@ -218,6 +221,7 @@ bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node)
void QSGOpenVGNodeVisitor::endVisit(QSGSpriteNode *)
{
}
+#endif
bool QSGOpenVGNodeVisitor::visit(QSGRenderNode *)
{
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
index 4805d63024..c6461ca67d 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
@@ -73,8 +73,10 @@ public:
void endVisit(QSGGlyphNode *) override;
bool visit(QSGRootNode *) override;
void endVisit(QSGRootNode *) override;
+#if QT_CONFIG(quick_sprite)
bool visit(QSGSpriteNode *) override;
void endVisit(QSGSpriteNode *) override;
+#endif
bool visit(QSGRenderNode *) override;
void endVisit(QSGRenderNode *) override;
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h
index 3ade2ef8ad..d47b389a0b 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h
@@ -43,6 +43,8 @@
#include <private/qsgadaptationlayer_p.h>
#include "qsgopenvgrenderable.h"
+QT_REQUIRE_CONFIG(quick_sprite);
+
QT_BEGIN_NAMESPACE
class QSGOpenVGTexture;
class QSGOpenVGSpriteNode : public QSGSpriteNode, public QSGOpenVGRenderable
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 030f485504..218f5675dc 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1361,7 +1361,7 @@ bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *prope
return QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr);
}
-QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes)
+QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit;
QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output);
@@ -1404,17 +1404,16 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine
qmlUnit->stringTableSize = output.jsGenerator.stringTable.stringCount();
#ifndef V4_BOOTSTRAP
- if (!dependentTypes.isEmpty()) {
+ if (dependencyHasher) {
QCryptographicHash hash(QCryptographicHash::Md5);
- if (dependentTypes.addToHash(&hash, engine)) {
+ if (dependencyHasher(&hash)) {
QByteArray checksum = hash.result();
Q_ASSERT(checksum.size() == sizeof(qmlUnit->dependencyMD5Checksum));
memcpy(qmlUnit->dependencyMD5Checksum, checksum.constData(), sizeof(qmlUnit->dependencyMD5Checksum));
}
}
#else
- Q_UNUSED(dependentTypes);
- Q_UNUSED(engine);
+ Q_UNUSED(dependencyHasher);
#endif
// write imports
@@ -2116,7 +2115,8 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
-
+ object->flags = serializedObject->flags;
+ object->id = serializedObject->id;
object->location = serializedObject->location;
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
@@ -2175,6 +2175,15 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
object->properties->append(p);
}
+ {
+ const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
+ for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
+ QmlIR::Alias *a = pool->New<QmlIR::Alias>();
+ *static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
+ object->aliases->append(a);
+ }
+ }
+
QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
@@ -2205,6 +2214,11 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
const QString name = unit->stringAt(compiledFunction->nameIndex);
f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0);
+ f->formals.allocate(pool, int(compiledFunction->nFormals));
+ formalNameIdx = compiledFunction->formalsTable();
+ for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
+ f->formals[i] = *formalNameIdx;
+
object->functions->append(f);
}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 2022112e07..64bf111d9a 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -548,7 +548,7 @@ public:
struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
{
- QV4::CompiledData::Unit *generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes);
+ QV4::CompiledData::Unit *generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher());
private:
typedef bool (Binding::*BindingFilter)() const;
@@ -622,7 +622,7 @@ private:
int _importedScriptsTemp;
};
-struct IRLoader {
+struct Q_QML_PRIVATE_EXPORT IRLoader {
IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
void load();
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 85267225be..a3b8784fc8 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -58,10 +58,11 @@ QT_BEGIN_NAMESPACE
QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, typeData(typeData)
+ , dependencyHasher(dependencyHasher)
, typeNameCache(typeNameCache)
, document(parsedQML)
{
@@ -156,7 +157,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
// Generate QML compiled type data structures
QmlIR::QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, QQmlEnginePrivate::get(engine), resolvedTypes);
+ QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, dependencyHasher);
Q_ASSERT(document->javaScriptCompilationUnit);
// The js unit owns the data and will free the qml unit.
@@ -1108,10 +1109,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
continue;
}
- // Try again later and resolve the target alias first.
- _objectsWithAliases.append(objectIndex);
// restore
alias->idIndex = idIndex;
+ // Try again later and resolve the target alias first.
break;
}
}
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 2b59e7e42f..11261e3099 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -89,7 +89,8 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
@@ -139,6 +140,7 @@ private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
QQmlTypeData *typeData;
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 0afc97e4bf..3234e7ee63 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1497,7 +1497,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
IR::Function *f = _function;
while (f && e->parent) {
- if (f->insideWithOrCatch || (f->isNamedExpression && f->name == name))
+ if (f->insideWithOrCatch || (f->isNamedExpression && QStringRef(f->name) == name))
return _block->NAME(name, line, col);
int index = e->findMember(name);
@@ -1508,7 +1508,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
al->isArgumentsOrEval = true;
return al;
}
- const int argIdx = f->indexOfArgument(&name);
+ const int argIdx = f->indexOfArgument(QStringRef(&name));
if (argIdx != -1)
return _block->ARG(argIdx, scope);
@@ -2269,7 +2269,7 @@ bool Codegen::visit(DoWhileStatement *ast)
_block = loopbody;
statement(ast->statement);
- _block->JUMP(loopcond);
+ setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation());
_block = loopcond;
condition(ast->expression, loopbody, loopend);
@@ -2334,7 +2334,7 @@ bool Codegen::visit(ForEachStatement *ast)
return false;
move(*init, _block->TEMP(temp));
statement(ast->statement);
- _block->JUMP(foreachin);
+ setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
_block = foreachin;
@@ -2373,7 +2373,7 @@ bool Codegen::visit(ForStatement *ast)
_block = forbody;
statement(ast->statement);
- _block->JUMP(forstep);
+ setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
_block = forstep;
statement(ast->expression);
@@ -2473,7 +2473,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
int temp = _block->newTemp();
move(identifier(ast->declaration->name.toString()), _block->TEMP(temp));
statement(ast->statement);
- _block->JUMP(foreachin);
+ setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
_block = foreachin;
@@ -2512,7 +2512,7 @@ bool Codegen::visit(LocalForStatement *ast)
_block = forbody;
statement(ast->statement);
- _block->JUMP(forstep);
+ setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
_block = forstep;
statement(ast->expression);
@@ -2813,7 +2813,7 @@ bool Codegen::visit(WhileStatement *ast)
_block = whilebody;
statement(ast->statement);
- _block->JUMP(whilecond);
+ setLocation(_block->JUMP(whilecond), ast->lastSourceLocation());
_block = whileend;
leaveLoop();
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
index 2e1213464c..d94f7ac238 100644
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper.cpp
@@ -59,7 +59,7 @@ CompilationUnitMapper::~CompilationUnitMapper()
close();
}
-bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const QString &sourcePath, QString *errorString)
+bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString)
{
if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) {
*errorString = QStringLiteral("Magic bytes in the header do not match");
@@ -76,12 +76,7 @@ bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const
return false;
}
- {
- QFileInfo sourceCode(sourcePath);
- QDateTime sourceTimeStamp;
- if (sourceCode.exists())
- sourceTimeStamp = sourceCode.lastModified();
-
+ if (header->sourceTimeStamp) {
// Files from the resource system do not have any time stamps, so fall back to the application
// executable.
if (!sourceTimeStamp.isValid())
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h
index 5b6939f1cf..b24f98df7c 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/compiler/qv4compilationunitmapper_p.h
@@ -68,11 +68,11 @@ public:
CompilationUnitMapper();
~CompilationUnitMapper();
- CompiledData::Unit *open(const QString &cacheFilePath, const QString &sourcePath, QString *errorString);
+ CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
void close();
private:
- static bool verifyHeader(const QV4::CompiledData::Unit *header, const QString &sourcePath, QString *errorString);
+ static bool verifyHeader(const QV4::CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString);
#if defined(Q_OS_UNIX)
size_t length;
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
index 1aa3e05f5f..38dabc41cf 100644
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
@@ -43,6 +43,7 @@
#include <functional>
#include <private/qcore_unix_p.h>
#include <private/qdeferredcleanup_p.h>
+#include <QDateTime>
#include "qv4compileddata_p.h"
@@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
+CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
{
close();
@@ -72,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourcePath, errorString))
+ if (!verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
index 37cac846a0..d7a93ae233 100644
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
+CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString)
{
close();
@@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourcePath, errorString))
+ if (!verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr;
const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 8f8d374e24..c56f08c2f0 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -77,13 +77,7 @@ namespace QV4 {
namespace CompiledData {
-#ifdef V4_BOOTSTRAP
-static QString cacheFilePath(const QString &localSourcePath)
-{
- const QString localCachePath = localSourcePath + QLatin1Char('c');
- return localCachePath;
-}
-#else
+#if !defined(V4_BOOTSTRAP)
static QString cacheFilePath(const QUrl &url)
{
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
@@ -102,7 +96,6 @@ static QString cacheFilePath(const QUrl &url)
CompilationUnit::CompilationUnit()
: data(0)
, engine(0)
- , runtimeStrings(0)
, runtimeLookups(0)
, runtimeRegularExpressions(0)
, runtimeClasses(0)
@@ -132,8 +125,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*));
// memset the strings to 0 in case a GC run happens while we're within the loop below
memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*));
- for (uint i = 0; i < data->stringTableSize; ++i)
+ for (uint i = 0; i < data->stringTableSize; ++i) {
runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
+ runtimeStrings[i]->setMarkBit();
+ }
runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
// memset the regexps to 0 in case a GC run happens while we're within the loop below
@@ -147,7 +142,14 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
flags |= IR::RegExp::RegExp_IgnoreCase;
if (re->flags & CompiledData::RegExp::RegExp_Multiline)
flags |= IR::RegExp::RegExp_Multiline;
- runtimeRegularExpressions[i] = engine->newRegExpObject(data->stringAt(re->stringIndex), flags);
+ QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags);
+ runtimeRegularExpressions[i] = ro;
+#if WRITEBARRIER(steele)
+ if (engine->memoryManager->nextGCIsIncremental) {
+ ro->setMarkBit();
+ ro->setGrayBit();
+ }
+#endif
}
if (data->lookupTableSize) {
@@ -174,8 +176,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
l->level = -1;
l->index = UINT_MAX;
l->nameIndex = compiledLookups[i].nameIndex;
- if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter)
- l->engine = engine;
}
}
@@ -331,10 +331,9 @@ void CompilationUnit::finalize(QQmlEnginePrivate *engine)
totalObjectCount = objectCount;
}
-bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
- const ResolvedTypeReferenceMap &dependentTypes) const
+bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const
{
- if (dependentTypes.isEmpty()) {
+ if (!dependencyHasher) {
for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
if (data->dependencyMD5Checksum[i] != 0)
return false;
@@ -342,7 +341,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
return true;
}
QCryptographicHash hash(QCryptographicHash::Md5);
- if (!dependentTypes.addToHash(&hash, engine))
+ if (!dependencyHasher(&hash))
return false;
QByteArray checksum = hash.result();
Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum));
@@ -350,7 +349,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString)
{
if (!QQmlFile::isLocalFile(url)) {
*errorString = QStringLiteral("File has to be a local file.");
@@ -360,14 +359,14 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory
const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourceTimeStamp, errorString);
if (!mappedUnit)
return false;
const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
- if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
*errorString = QStringLiteral("QML source file has moved to a different location.");
return false;
}
@@ -408,27 +407,29 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
#endif // V4_BOOTSTRAP
#if defined(V4_BOOTSTRAP)
-bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
+bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString)
#else
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
#endif
{
errorString->clear();
+#if !defined(V4_BOOTSTRAP)
if (data->sourceTimeStamp == 0) {
*errorString = QStringLiteral("Missing time stamp for source file");
return false;
}
-#if !defined(V4_BOOTSTRAP)
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
+ const QString outputFileName = cacheFilePath(unitUrl);
#endif
+#if QT_CONFIG(temporaryfile)
// Foo.qml -> Foo.qmlc
- QSaveFile cacheFile(cacheFilePath(unitUrl));
+ QSaveFile cacheFile(outputFileName);
if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
*errorString = cacheFile.errorString();
return false;
@@ -459,6 +460,10 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
}
return true;
+#else
+ *errorString = QStringLiteral("features.temporaryfile is disabled.");
+ return false;
+#endif // QT_CONFIG(temporaryfile)
}
void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
@@ -480,10 +485,22 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
- QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
+ QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(compilationUnit->data);
+ auto ensureWritableUnit = [&jsUnit, &compilationUnit]() {
+ if (jsUnit == compilationUnit->data) {
+ char *unitCopy = (char*)malloc(jsUnit->unitSize);
+ memcpy(unitCopy, jsUnit, jsUnit->unitSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
+ }
+ };
QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
+ if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) {
+ ensureWritableUnit();
+ jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName);
+ }
+
// Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
// and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
// the string table.
@@ -546,6 +563,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
}
if (!signalParameterNameTable.isEmpty()) {
+ ensureWritableUnit();
Q_ASSERT(jsUnit != compilationUnit->data);
const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
uint newSize = jsUnit->unitSize + signalParameterTableSize;
@@ -764,7 +782,7 @@ void Unit::generateChecksum()
#ifndef V4_BOOTSTRAP
QCryptographicHash hash(QCryptographicHash::Md5);
- const int checksummableDataOffset = qOffsetOf(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum);
+ const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum);
const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset;
hash.addData(dataPtr, unitSize - checksummableDataOffset);
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 13a0c4b075..6e9121b5e3 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x09
+#define QV4_DATA_STRUCTURE_VERSION 0x11
class QIODevice;
class QQmlPropertyCache;
@@ -211,7 +211,8 @@ struct Function
HasDirectEval = 0x2,
UsesArgumentsObject = 0x4,
IsNamedExpression = 0x8,
- HasCatchOrWith = 0x10
+ HasCatchOrWith = 0x10,
+ CanUseSimpleCall = 0x20
};
// Absolute offset into file where the code for this function is located. Only used when the function
@@ -786,8 +787,10 @@ struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
{
bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
};
+
+using DependentTypesHasher = std::function<bool(QCryptographicHash *)>;
#else
-struct ResolvedTypeReferenceMap {};
+struct DependentTypesHasher {};
#endif
// index is per-object binding index
@@ -795,11 +798,15 @@ typedef QVector<QQmlPropertyData*> BindingPropertyData;
// This is how this hooks into the existing structures:
-//VM::Function
-// CompilationUnit * (for functions that need to clean up)
-// CompiledData::Function *compiledFunction
+struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
+{
+ QV4::Heap::String **runtimeStrings = 0; // Array
+};
+
+Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
-struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
+struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public QQmlRefCount
{
#ifdef V4_BOOTSTRAP
CompilationUnit()
@@ -818,11 +825,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
#ifndef V4_BOOTSTRAP
ExecutionEngine *engine;
-#endif
-
- QV4::Heap::String **runtimeStrings; // Array
-#ifndef V4_BOOTSTRAP
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
@@ -860,8 +863,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QVector<QQmlScriptData *> dependentScripts;
ResolvedTypeReferenceMap resolvedTypes;
- bool verifyChecksum(QQmlEngine *engine,
- const ResolvedTypeReferenceMap &dependentTypes) const;
+ bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const;
int metaTypeId;
int listMetaTypeId;
@@ -899,7 +901,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
void destroy() Q_DECL_OVERRIDE;
- bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
+ bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
@@ -908,7 +910,7 @@ protected:
public:
#if defined(V4_BOOTSTRAP)
- bool saveToDisk(const QString &unitUrl, QString *errorString);
+ bool saveToDisk(const QString &outputFileName, QString *errorString);
#else
bool saveToDisk(const QUrl &unitUrl, QString *errorString);
#endif
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 9cfac4a676..b81d724fe7 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -296,6 +296,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
function->flags |= CompiledData::Function::IsNamedExpression;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
+ if (irFunction->canUseSimpleCall())
+ function->flags |= CompiledData::Function::CanUseSimpleCall;
function->nFormals = irFunction->formals.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -425,7 +427,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
}
unit.indexOfRootFunction = -1;
unit.sourceFileIndex = getStringId(irModule->fileName);
- unit.sourceTimeStamp = irModule->sourceTimeStamp;
+ unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0;
unit.nImports = 0;
unit.offsetToImports = 0;
unit.nObjects = 0;
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 53d9956315..fbd6ac8f99 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -690,7 +690,7 @@ union Instr
};
struct instr_binop {
MOTH_INSTR_HEADER
- uint alu; // offset inside the runtime methods
+ int alu; // QV4::Runtime::RuntimeMethods enum value
Param lhs;
Param rhs;
Param result;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 04844302d9..aefb084971 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -55,70 +55,70 @@ using namespace QV4::Moth;
namespace {
-inline uint aluOpFunction(IR::AluOp op)
+inline QV4::Runtime::RuntimeMethods aluOpFunction(IR::AluOp op)
{
switch (op) {
case IR::OpInvalid:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpIfTrue:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpNot:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpUMinus:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpUPlus:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpCompl:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpBitAnd:
- return offsetof(QV4::Runtime, bitAnd);
+ return QV4::Runtime::bitAnd;
case IR::OpBitOr:
- return offsetof(QV4::Runtime, bitOr);
+ return QV4::Runtime::bitOr;
case IR::OpBitXor:
- return offsetof(QV4::Runtime, bitXor);
+ return QV4::Runtime::bitXor;
case IR::OpAdd:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpSub:
- return offsetof(QV4::Runtime, sub);
+ return QV4::Runtime::sub;
case IR::OpMul:
- return offsetof(QV4::Runtime, mul);
+ return QV4::Runtime::mul;
case IR::OpDiv:
- return offsetof(QV4::Runtime, div);
+ return QV4::Runtime::div;
case IR::OpMod:
- return offsetof(QV4::Runtime, mod);
+ return QV4::Runtime::mod;
case IR::OpLShift:
- return offsetof(QV4::Runtime, shl);
+ return QV4::Runtime::shl;
case IR::OpRShift:
- return offsetof(QV4::Runtime, shr);
+ return QV4::Runtime::shr;
case IR::OpURShift:
- return offsetof(QV4::Runtime, ushr);
+ return QV4::Runtime::ushr;
case IR::OpGt:
- return offsetof(QV4::Runtime, greaterThan);
+ return QV4::Runtime::greaterThan;
case IR::OpLt:
- return offsetof(QV4::Runtime, lessThan);
+ return QV4::Runtime::lessThan;
case IR::OpGe:
- return offsetof(QV4::Runtime, greaterEqual);
+ return QV4::Runtime::greaterEqual;
case IR::OpLe:
- return offsetof(QV4::Runtime, lessEqual);
+ return QV4::Runtime::lessEqual;
case IR::OpEqual:
- return offsetof(QV4::Runtime, equal);
+ return QV4::Runtime::equal;
case IR::OpNotEqual:
- return offsetof(QV4::Runtime, notEqual);
+ return QV4::Runtime::notEqual;
case IR::OpStrictEqual:
- return offsetof(QV4::Runtime, strictEqual);
+ return QV4::Runtime::strictEqual;
case IR::OpStrictNotEqual:
- return offsetof(QV4::Runtime, strictNotEqual);
+ return QV4::Runtime::strictNotEqual;
case IR::OpInstanceof:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpIn:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpAnd:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
case IR::OpOr:
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
default:
Q_ASSERT(!"Unknown AluOp");
- return 0;
+ return QV4::Runtime::InvalidRuntimeMethod;
}
};
@@ -889,24 +889,25 @@ Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR
if (oper == IR::OpInstanceof || oper == IR::OpIn || oper == IR::OpAdd) {
Instruction::BinopContext binop;
if (oper == IR::OpInstanceof)
- binop.alu = offsetof(QV4::Runtime, instanceof);
+ binop.alu = QV4::Runtime::instanceof;
else if (oper == IR::OpIn)
- binop.alu = offsetof(QV4::Runtime, in);
+ binop.alu = QV4::Runtime::in;
else
- binop.alu = offsetof(QV4::Runtime, add);
+ binop.alu = QV4::Runtime::add;
binop.lhs = getParam(leftSource);
binop.rhs = getParam(rightSource);
binop.result = getResultParam(target);
- Q_ASSERT(binop.alu);
+ Q_ASSERT(binop.alu != QV4::Runtime::InvalidRuntimeMethod);
addInstruction(binop);
return binop.result;
} else {
+ auto binopFunc = aluOpFunction(oper);
+ Q_ASSERT(binopFunc != QV4::Runtime::InvalidRuntimeMethod);
Instruction::Binop binop;
- binop.alu = aluOpFunction(oper);
+ binop.alu = binopFunc;
binop.lhs = getParam(leftSource);
binop.rhs = getParam(rightSource);
binop.result = getResultParam(target);
- Q_ASSERT(binop.alu);
addInstruction(binop);
return binop.result;
}
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 41469f1985..4b84bd2831 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -179,7 +179,7 @@ private:
int scratchTempIndex() const { return _function->tempCount; }
int callDataStart() const { return scratchTempIndex() + 1; }
- int outgoingArgumentTempStart() const { return callDataStart() + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); }
+ int outgoingArgumentTempStart() const { return callDataStart() + offsetof(QV4::CallData, args)/sizeof(QV4::Value); }
int frameSize() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
template <int Instr>
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 5687834b00..cc2f9b7cf2 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -348,11 +348,7 @@ Module::~Module()
void Module::setFileName(const QString &name)
{
- if (fileName.isEmpty())
- fileName = name;
- else {
- Q_ASSERT(fileName == name);
- }
+ fileName = name;
}
Function::Function(Module *module, Function *outer, const QString &name)
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 04bc3d86e5..f7c7b76ea8 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -61,6 +61,7 @@
#include <QtCore/QBitArray>
#include <QtCore/qurl.h>
#include <QtCore/QVarLengthArray>
+#include <QtCore/QDateTime>
#include <qglobal.h>
#if defined(CONST) && defined(Q_OS_WIN)
@@ -507,6 +508,16 @@ struct Q_AUTOTEST_EXPORT Temp: Expr {
, memberResolver(0)
{}
+ Temp(Type type, Kind kind, unsigned index)
+ : Expr(TempExpr)
+ , index(index)
+ , isReadOnly(0)
+ , kind(kind)
+ , memberResolver(0)
+ {
+ this->type = type;
+ }
+
void init(unsigned kind, unsigned index)
{
this->index = index;
@@ -932,7 +943,7 @@ struct Q_QML_PRIVATE_EXPORT Module {
QVector<Function *> functions;
Function *rootFunction;
QString fileName;
- qint64 sourceTimeStamp;
+ QDateTime sourceTimeStamp;
bool isQmlModule; // implies rootFunction is always 0
uint unitFlags; // flags merged into CompiledData::Unit::flags
#ifdef QT_NO_QML_DEBUGGER
@@ -945,7 +956,6 @@ struct Q_QML_PRIVATE_EXPORT Module {
Module(bool debugMode)
: rootFunction(0)
- , sourceTimeStamp(0)
, isQmlModule(false)
, unitFlags(0)
#ifndef QT_NO_QML_DEBUGGER
@@ -1342,6 +1352,31 @@ struct Function {
int getNewStatementId() { return _statementCount++; }
int statementCount() const { return _statementCount; }
+ bool canUseSimpleCall() const {
+ return nestedFunctions.isEmpty() &&
+ locals.isEmpty() && formals.size() <= QV4::Global::ReservedArgumentCount &&
+ !hasTry && !hasWith && !isNamedExpression && !usesArgumentsObject && !hasDirectEval;
+ }
+
+ bool argLocalRequiresWriteBarrier(ArgLocal *al) const {
+ uint scope = al->scope;
+ const IR::Function *f = this;
+ while (scope) {
+ f = f->outer;
+ --scope;
+ }
+ return !f->canUseSimpleCall();
+ }
+ int localsCountForScope(ArgLocal *al) const {
+ uint scope = al->scope;
+ const IR::Function *f = this;
+ while (scope) {
+ f = f->outer;
+ --scope;
+ }
+ return f->locals.size();
+ }
+
private:
BasicBlock *getOrCreateBasicBlock(int index);
void setStatementCount(int cnt);
@@ -1410,6 +1445,7 @@ public:
ArgLocal *newArgLocal = f->New<ArgLocal>();
newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope);
newArgLocal->type = argLocal->type;
+ newArgLocal->isArgumentsOrEval = argLocal->isArgumentsOrEval;
return newArgLocal;
}
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 10f0bbcf8f..cc542e94e7 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -3581,16 +3581,43 @@ public:
, _replacement(0)
{}
- void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0)
+ bool operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0)
{
Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
-// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout<<endl;
-
qSwap(_toReplace, toReplace);
qSwap(_replacement, replacement);
const QVector<Stmt *> &uses = _defUses.uses(*_toReplace);
+
+ // Prevent the following:
+ // L3:
+ // %1 = phi L1: %2, L2: %3
+ // %4 = phi L1: %5, L2: %6
+ // %6 = %1
+ // From turning into:
+ // L3:
+ // %1 = phi L1: %2, L2: %3
+ // %4 = phi L1: %5, L2: %1
+ //
+ // Because both phi nodes are "executed in parallel", we cannot replace %6 by %1 in the
+ // second phi node. So, if the defining statement for a temp is a phi node, and one of the
+ // uses of the to-be-replaced statement is a phi node in the same block as the defining
+ // statement, bail out.
+ if (Temp *r = _replacement->asTemp()) {
+ if (_defUses.defStmt(*r)->asPhi()) {
+ BasicBlock *replacementDefBlock = _defUses.defStmtBlock(*r);
+ for (Stmt *use : uses) {
+ if (Phi *usePhi = use->asPhi()) {
+ if (_defUses.defStmtBlock(*usePhi->targetTemp) == replacementDefBlock)
+ return false;
+ }
+ }
+ }
+ }
+
+// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout<<endl;
+
if (newUses)
newUses->reserve(uses.size());
@@ -3606,6 +3633,7 @@ public:
qSwap(_replacement, replacement);
qSwap(_toReplace, toReplace);
+ return true;
}
private:
@@ -4082,11 +4110,12 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
// copy propagation:
if (Temp *sourceTemp = m->source->asTemp()) {
QVector<Stmt *> newT2Uses;
- replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
- defUses.removeUse(s, *sourceTemp);
- defUses.addUses(*sourceTemp, newT2Uses);
- defUses.removeDef(*targetTemp);
- W.remove(s);
+ if (replaceUses(targetTemp, sourceTemp, W, &newT2Uses)) {
+ defUses.removeUse(s, *sourceTemp);
+ defUses.addUses(*sourceTemp, newT2Uses);
+ defUses.removeDef(*targetTemp);
+ W.remove(s);
+ }
continue;
}
@@ -5635,25 +5664,97 @@ void MoveMapping::add(Expr *from, Temp *to) {
_moves.append(m);
}
+// Order the moves that are generated when resolving edges during register allocation (see [Wimmer1]
+// section 6 for details). Now these moves form one or more graphs, so we have to output them in
+// such an order that values don't get overwritten:
+// r1 <- r0
+// r2 <- r1
+// That input has to be ordered as follows in order to prevent the value in r1 from being lost:
+// r2 <- r1
+// r1 <- r0
+//
+// So, the algorithm is to output the leaves first, and take them out of the input. This will result
+// in some moves to become leaves (in the above example: when leaf r2 <- r1 is generated and taken
+// away, the r1 <- r0 is now a leaf), so we can output those and take those out, and repeat until
+// there are no more leafs.
+//
+// The tricky part is that there might be cycles:
+// r4 <- r5
+// r5 <- r4
+// These have to be turned into a "register swap":
+// r4 <=> r5
+//
+// So after running the above algorithm where we progressively remove the leaves, we are left with
+// zero or more cycles. To resolve those, we break one of the edges of the cycle, and for all other
+// edges we generate swaps. Note that the swaps will always occur as the last couple of moves,
+// because otherwise they might clobber sources for moves:
+// r4 <=> r5
+// r6 <- r5
+// Here, the value of r5 is already overwritten with the one in r4, so the correct order is:
+// r6 <- r5
+// r4 <=> r5
void MoveMapping::order()
{
- QList<Move> todo = _moves;
- QList<Move> output, swaps;
+ QList<Move> output;
output.reserve(_moves.size());
- QList<Move> delayed;
- delayed.reserve(_moves.size());
- while (!todo.isEmpty()) {
- const Move m = todo.first();
- todo.removeFirst();
- schedule(m, todo, delayed, output, swaps);
- }
+ while (!_moves.isEmpty()) {
+ // Take out all leaf edges, because we can output them without any problems.
+ int nextLeaf = findLeaf();
+ if (nextLeaf == -1)
+ break; // No more leafs left, we're done here.
+ output.append(_moves.takeAt(nextLeaf));
+ // Now there might be new leaf edges: any move that had the input of the previously found
+ // leaf as an output, so loop around.
+ }
+
+ while (!_moves.isEmpty()) {
+ // We're now left with one or more cycles.
+ // Step one: break the/a cycle.
+ _moves.removeFirst();
+ // Step two: find the other edges of the cycle, starting with the one of that is now a leaf.
+ while (!_moves.isEmpty()) {
+ int nextLeaf = findLeaf();
+ if (nextLeaf == -1)
+ break; // We're done with this cycle.
+ Move m = _moves.takeAt(nextLeaf);
+ // Step three: get the edges from the cycle and turn it into a swap
+ m.needsSwap = true;
+ output.append(m);
+ // Because we took out a leaf, find the next one.
+ }
+ // We're done with the cycle, let's see if there are more.
+ }
+
+ _moves = output;
+}
+
+int MoveMapping::findLeaf() const
+{
+ for (int i = 0, e = _moves.size(); i != e; ++i) {
+ // Take an edge from the list...
+ const Temp *target = _moves.at(i).to;
+ // ... and see if its target is used as a source...
+ bool targetUsedAsSource = false;
+ for (int j = 0; j != e; ++j) {
+ if (i == j)
+ continue;
- output += swaps;
+ Expr *source = _moves.at(j).from;
+ if (const Temp *sourceTemp = source->asTemp()) {
+ if (overlappingStorage(*target, *sourceTemp)) {
+ targetUsedAsSource = true;
+ break;
+ }
+ }
+ }
+ // ... if not, we have a leaf edge ...
+ if (!targetUsedAsSource)
+ return i;
+ // .. otherwise we try the next one.
+ }
- Q_ASSERT(todo.isEmpty());
- Q_ASSERT(delayed.isEmpty());
- qSwap(_moves, output);
+ return -1; // No leaf found
}
QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *function, bool atEnd) const
@@ -5695,60 +5796,12 @@ void MoveMapping::dump() const
}
}
-MoveMapping::Action MoveMapping::schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed,
- QList<Move> &output, QList<Move> &swaps) const
-{
- const Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed);
- for (const Move &dependency : usages) {
- if (!output.contains(dependency)) {
- if (delayed.contains(dependency)) {
- // We have a cycle! Break it by swapping instead of assigning.
- if (DebugMoveMapping) {
- delayed += m;
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream out(&buf);
- IRPrinter printer(&out);
- out<<"we have a cycle! temps:" << endl;
- for (const Move &m : qAsConst(delayed)) {
- out<<"\t";
- printer.print(m.to);
- out<<" <- ";
- printer.print(m.from);
- out<<endl;
- }
- qDebug("%s", buf.data().constData());
- delayed.removeOne(m);
- }
-
- return NeedsSwap;
- } else {
- delayed.append(m);
- todo.removeOne(dependency);
- Action action = schedule(dependency, todo, delayed, output, swaps);
- delayed.removeOne(m);
- Move mm(m);
- if (action == NeedsSwap) {
- mm.needsSwap = true;
- swaps.append(mm);
- } else {
- output.append(mm);
- }
- return action;
- }
- }
- }
-
- output.append(m);
- return NormalMove;
-}
-
// References:
// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
-// CGO’10, ACM Press, 2010
+// CGO'10, ACM Press, 2010
// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
-// Execution Environments, pages 132–141. ACM Press, 2005.
+// Execution Environments, pages 132-141. ACM Press, 2005.
// [Briggs] P. Briggs, K.D. Cooper, T.J. Harvey, and L.T. Simpson. Practical Improvements to the
// Construction and Destruction of Static Single Assignment Form.
// [Appel] A.W. Appel. Modern Compiler Implementation in Java. Second edition, Cambridge
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index c07abd04c4..24257e99e9 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -265,15 +265,18 @@ private:
QHash<BasicBlock *, BasicBlock *> startEndLoops;
};
-class MoveMapping
+class Q_AUTOTEST_EXPORT MoveMapping
{
+#ifdef V4_AUTOTEST
+public:
+#endif
struct Move {
Expr *from;
Temp *to;
bool needsSwap;
- Move(Expr *from, Temp *to)
- : from(from), to(to), needsSwap(false)
+ Move(Expr *from, Temp *to, bool needsSwap = false)
+ : from(from), to(to), needsSwap(needsSwap)
{}
bool operator==(const Move &other) const
@@ -293,9 +296,7 @@ public:
void dump() const;
private:
- enum Action { NormalMove, NeedsSwap };
- Action schedule(const Move &m, QList<Move> &todo, QList<Move> &delayed, QList<Move> &output,
- QList<Move> &swaps) const;
+ int findLeaf() const;
};
/*
diff --git a/src/qml/configure.json b/src/qml/configure.json
index d22ba3b8f0..2c4887365f 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -22,6 +22,19 @@
"label": "QML network support",
"purpose": "Provides network transparency for QML",
"output": [ "publicFeature" ]
+ },
+ "qml-profiler": {
+ "label": "Command line QML Profiler",
+ "purpose": "The QML Profiler retrieves QML tracing data from an application.",
+ "condition": [
+ "features.commandlineparser",
+ "features.localserver",
+ "features.process",
+ "features.qml-debug",
+ "features.qml-network",
+ "features.xmlstreamwriter"
+ ],
+ "output": [ "privateFeature" ]
}
},
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 15230d75a5..681dc06215 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -42,6 +42,7 @@
#include "qqmldebugserviceinterfaces_p.h"
#include <private/qqmlengine_p.h>
+#include <private/qv4compileddata_p.h>
QT_BEGIN_NAMESPACE
@@ -181,12 +182,12 @@ bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName,
return connector ? connector->open(configuration) : false;
}
-enum { HookCount = 3 };
+enum { HookCount = 4 };
// Only add to the end, and bump version if you do.
quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
// Version of this Array. Bump if you add to end.
- 1,
+ 2,
// Number of entries in this array.
HookCount,
@@ -194,7 +195,10 @@ quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
// TypeInformationVersion, an integral value, bumped whenever private
// object sizes or member offsets that are used in Qt Creator's
// data structure "pretty printing" change.
- 2
+ 3,
+
+ // Version of the cache data.
+ QV4_DATA_STRUCTURE_VERSION
};
Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0]));
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 2fe3a588c3..707ef1a937 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -67,13 +67,15 @@ class QQuickWindow;
#ifdef QT_NO_QML_DEBUGGER
-struct QV4DebugService
+class QV4DebugService
{
+public:
void signalEmitted(const QString &) {}
};
-struct QQmlProfilerService
+class QQmlProfilerService
{
+public:
void startProfiling(QJSEngine *engine, quint64 features = std::numeric_limits<quint64>::max())
{
Q_UNUSED(engine);
@@ -83,21 +85,23 @@ struct QQmlProfilerService
void stopProfiling(QJSEngine *) {}
};
-struct QQmlEngineDebugService
+class QQmlEngineDebugService
{
+public:
void objectCreated(QJSEngine *, QObject *) {}
virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {}
};
-struct QQmlInspectorService {
+class QQmlInspectorService {
+public:
void addWindow(QQuickWindow *) {}
void setParentWindow(QQuickWindow *, QWindow *) {}
void removeWindow(QQuickWindow *) {}
};
-struct QDebugMessageService {};
-struct QQmlEngineControlService {};
-struct QQmlNativeDebugService {};
+class QDebugMessageService {};
+class QQmlEngineControlService {};
+class QQmlNativeDebugService {};
#else
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 41fb2c5b7b..88f8e94f25 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE
#define Q_QML_PROFILE(feature, profiler, Method)
#define Q_QML_OC_PROFILE(member, Code)
-struct QQmlProfiler {};
+class QQmlProfiler {};
struct QQmlBindingProfiler
{
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index 1e33f2f641..7e9a22f5d3 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -74,6 +74,19 @@ Note that QML makes the following modifications to native objects:
\li Locale-aware conversion functions are added to the \l Date and \l Number prototypes.
\endlist
+In addition, QML also extends the behavior of the instanceof function to
+allow for type checking against QML types. This means that you may use it to
+verify that a variable is indeed the type you expect, for example:
+
+\qml
+ var v = something();
+ if (!v instanceof Item) {
+ throw new TypeError("I need an Item type!");
+ }
+
+ ...
+\endqml
+
\section1 JavaScript Environment Restrictions
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index a03c382ed5..834684fe6d 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -168,8 +168,9 @@
from \a uri having version number composed from \a versionMajor and
\a versionMinor.
- While the type has a name and a type, it cannot be created, and the
- given error \a reason will result if creation is attempted.
+ While the type has a name and a type, it cannot be created. An error
+ message with the given \a reason is printed if the user attempts to
+ create an instance of this type.
This is useful where the type is only intended for providing attached
properties, enum values or an abstract base class with its extension.
@@ -189,11 +190,14 @@
from \a uri having version number composed from \a versionMajor and
\a versionMinor.
- This function is useful to register Q_NAMESPACE namespaces.
+ An instance of the meta object cannot be created. An error message with
+ the given \a reason is printed if the user attempts to create it.
+
+ This function is useful for registering Q_NAMESPACE namespaces.
Returns the QML type id.
- Example:
+ For example:
\code
namespace MyNamespace {
@@ -209,7 +213,7 @@
qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "io.qt", 1, 0, "MyNamespace", "Access to enums & flags only");
\endcode
- Now on QML side you can use the registered enums:
+ On the QML side, you can now use the registered enums:
\code
Component.onCompleted: console.log(MyNamespace.Key2)
\endcode
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index ca270a0648..583719a3c7 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -95,6 +95,12 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
codeRefs[i] = codeRef;
+
+ static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
+ if (showCode) {
+ WTF::dataLogF("Mapped JIT code for %s\n", qPrintable(stringAt(compiledFunction->nameIndex)));
+ disassemble(codeRef.code(), compiledFunction->codeSize, " ", WTF::dataFile());
+ }
}
return true;
@@ -246,13 +252,16 @@ void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e)
+typename Assembler<TargetConfiguration>::Pointer
+Assembler<TargetConfiguration>::loadAddressForWriting(RegisterID tmp, IR::Expr *e, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = WriteBarrier::NoBarrier;
IR::Temp *t = e->asTemp();
if (t)
return loadTempAddress(t);
else
- return loadArgLocalAddress(tmp, e->asArgLocal());
+ return loadArgLocalAddressForWriting(tmp, e->asArgLocal(), barrier);
}
template <typename TargetConfiguration>
@@ -265,29 +274,42 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>:
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
+typename Assembler<TargetConfiguration>::Pointer
+Assembler<TargetConfiguration>::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier;
+
int32_t offset = 0;
int scope = al->scope;
- loadPtr(Address(EngineRegister, qOffsetOf(ExecutionEngine, current)), baseReg);
- if (scope) {
- loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg);
+ loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg);
+
+ const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, outer));
+ const qint32 localsOffset = targetStructureOffset(Heap::CallContextData::baseOffset + offsetof(Heap::CallContextData, function))
+ + 8 // locals is always 8 bytes away from function, regardless of pointer size.
+ + offsetof(ValueArray<0>, values);
+
+ while (scope) {
+ loadPtr(Address(baseReg, outerOffset), baseReg);
--scope;
- while (scope) {
- loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg);
- --scope;
- }
}
switch (al->kind) {
case IR::ArgLocal::Formal:
case IR::ArgLocal::ScopedFormal: {
- loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, callData)), baseReg);
- offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ if (barrier && *barrier == WriteBarrier::Barrier) {
+ // if we need a barrier, the baseReg has to point to the ExecutionContext
+ // callData comes directly after locals, calculate the offset using that
+ offset = localsOffset + _function->localsCountForScope(al) * sizeof(Value);
+ offset += sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ } else {
+ const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData));
+ loadPtr(Address(baseReg, callDataOffset), baseReg);
+ offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ }
} break;
case IR::ArgLocal::Local:
case IR::ArgLocal::ScopedLocal: {
- loadPtr(Address(baseReg, qOffsetOf(CallContext::Data, locals)), baseReg);
- offset = al->index * sizeof(Value);
+ offset = localsOffset + al->index * sizeof(Value);
} break;
default:
Q_UNREACHABLE();
@@ -298,9 +320,9 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>:
template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
{
- loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
- loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
+ loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister);
+ loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister);
+ loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg);
const int id = _jsGenerator->registerString(string);
return Pointer(reg, id * sizeof(QV4::String*));
}
@@ -314,8 +336,8 @@ typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>:
template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
{
- loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
- loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
+ loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg);
+ loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg);
const int index = _jsGenerator->registerConstant(v.asReturnedValue());
return Address(baseReg, index * sizeof(QV4::Value));
}
@@ -330,8 +352,9 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString
template <typename TargetConfiguration>
void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
{
- Address addr = loadAddress(ScratchRegister, destination);
- storeValue(value, addr);
+ WriteBarrier::Type barrier;
+ Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier);
+ storeValue(value, addr, barrier);
}
template <typename TargetConfiguration>
@@ -356,6 +379,8 @@ void Assembler<TargetConfiguration>::enterStandardStackFrame(const RegisterInfor
slotAddr.offset -= RegisterSize;
storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr);
}
+
+ platformFinishEnteringStandardStackFrame(this);
}
template <typename TargetConfiguration>
@@ -418,7 +443,7 @@ typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::ge
// It's not a number type, so it cannot be in a register.
Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType);
- Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src);
+ Assembler::Pointer tagAddr = loadAddressForReading(Assembler::ScratchRegister, src);
tagAddr.offset += 4;
load32(tagAddr, Assembler::ScratchRegister);
@@ -516,9 +541,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo
const int locals = stackLayout().calculateJSStackFrameSize();
subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
- loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
- loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister);
- storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+ storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
ret();
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index fd65c9b3d2..d4a18ae886 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -57,6 +57,7 @@
#include "private/qv4value_p.h"
#include "private/qv4context_p.h"
#include "private/qv4engine_p.h"
+#include "private/qv4writebarrier_p.h"
#include "qv4targetplatform_p.h"
#include <config.h>
@@ -131,7 +132,7 @@ typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingS
#define isel_stringIfy(s) isel_stringIfyx(s)
#define generateRuntimeCall(as, t, function, ...) \
- as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
+ as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(QV4::Runtime::function), __VA_ARGS__)
template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform, int RegisterSize>
@@ -153,34 +154,94 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ static void emitSetGrayBit(JITAssembler *as, RegisterID base)
+ {
+ bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
+
+ as->push(TargetPlatform::EngineRegister); // free up one register for work
+
+ RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ as->move(base, grayBitmap);
+ Q_ASSERT(base != grayBitmap);
+ as->urshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ as->lshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
+
+ RegisterID index = base;
+ as->move(base, index);
+ as->sub32(grayBitmap, index);
+ as->urshift32(TrustedImm32(Chunk::SlotSizeShift), index);
+ RegisterID grayIndex = TargetPlatform::EngineRegister;
+ as->move(index, grayIndex);
+ as->urshift32(TrustedImm32(Chunk::BitShift), grayIndex);
+ as->lshift32(TrustedImm32(2), grayIndex); // 4 bytes per quintptr
+ as->add32(grayIndex, grayBitmap);
+ as->and32(TrustedImm32(Chunk::Bits - 1), index);
+
+ RegisterID bit = TargetPlatform::EngineRegister;
+ as->move(TrustedImm32(1), bit);
+ as->lshift32(index, bit);
+
+ as->load32(Pointer(grayBitmap, 0), index);
+ as->or32(bit, index);
+ as->store32(index, Pointer(grayBitmap, 0));
+
+ as->pop(TargetPlatform::EngineRegister);
+ }
+
+#if WRITEBARRIER(steele)
+ static void emitWriteBarrier(JITAssembler *as, Address addr)
+ {
+// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ // if (engine->writeBarrier)
+// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test);
+// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0));
+ // ### emit fence
+ emitSetGrayBit(as, addr.base);
+// jump.link(as);
+ }
+#elif WRITEBARRIER(none)
+ static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
+#endif
+
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
{
as->MacroAssembler::loadDouble(addr, dest);
}
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
as->MacroAssembler::storeDouble(source, addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, addr);
}
static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
{
- Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
- as->storeDouble(source, ptr);
+ WriteBarrier::Type barrier;
+ Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
+ as->storeDouble(source, ptr, barrier);
}
- static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
{
as->store32(TrustedImm32(value.int_32()), destination);
destination.offset += 4;
as->store32(TrustedImm32(value.tag()), destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
{
as->loadDouble(source, TargetPlatform::FPGpr0);
- as->storeDouble(TargetPlatform::FPGpr0, destination);
+ // We need to pass NoBarrier to storeDouble and call emitWriteBarrier ourselves, as the
+ // code in storeDouble assumes the type we're storing is actually a double, something
+ // that isn't always the case here.
+ as->storeDouble(TargetPlatform::FPGpr0, destination, WriteBarrier::NoBarrier);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
@@ -193,12 +254,14 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
}
- static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
{
Address destination = dest;
as->store32(TargetPlatform::LowReturnValueRegister, destination);
destination.offset += 4;
as->store32(TargetPlatform::HighReturnValueRegister, destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, dest);
}
static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
@@ -234,7 +297,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNREACHABLE();
}
} else {
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, t);
as->load32(addr, lowReg);
addr.offset += 4;
as->load32(addr, highReg);
@@ -295,7 +358,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- Pointer tagAddr = as->loadAddress(scratchRegister, right);
+ Pointer tagAddr = as->loadAddressForReading(scratchRegister, right);
as->load32(tagAddr, tagRegister);
Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
as->addPatch(falseBlock, j);
@@ -312,7 +375,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
{
Q_ASSERT(source->type == IR::VarType);
// load the tag:
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
Pointer tagAddr = addr;
tagAddr.offset += 4;
as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
@@ -323,10 +386,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
as->load32(addr, TargetPlatform::ReturnValueRegister);
- Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ WriteBarrier::Type barrier;
+ Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, targetAddr);
} else {
as->load32(addr, (RegisterID) targetTemp->index);
}
@@ -335,17 +401,19 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
// not an int:
fallback.link(as);
generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
as->storeInt32(TargetPlatform::ReturnValueRegister, target);
intDone.link(as);
}
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
{
as->store32(registerWithPtr, destAddr);
destAddr.offset += 4;
as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destAddr);
}
static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
@@ -384,41 +452,94 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ static void emitSetGrayBit(JITAssembler *as, RegisterID base)
+ {
+ bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
+
+ as->push(TargetPlatform::EngineRegister); // free up one register for work
+
+ RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ as->move(base, grayBitmap);
+ Q_ASSERT(base != grayBitmap);
+ as->urshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ as->lshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
+
+ RegisterID index = base;
+ as->move(base, index);
+ as->sub64(grayBitmap, index);
+ as->urshift64(TrustedImm32(Chunk::SlotSizeShift), index);
+ RegisterID grayIndex = TargetPlatform::EngineRegister;
+ as->move(index, grayIndex);
+ as->urshift64(TrustedImm32(Chunk::BitShift), grayIndex);
+ as->lshift64(TrustedImm32(3), grayIndex); // 8 bytes per quintptr
+ as->add64(grayIndex, grayBitmap);
+ as->and64(TrustedImm32(Chunk::Bits - 1), index);
+
+ RegisterID bit = TargetPlatform::EngineRegister;
+ as->move(TrustedImm32(1), bit);
+ as->lshift64(index, bit);
+
+ as->load64(Pointer(grayBitmap, 0), index);
+ as->or64(bit, index);
+ as->store64(index, Pointer(grayBitmap, 0));
+
+ as->pop(TargetPlatform::EngineRegister);
+ }
+
+#if WRITEBARRIER(steele)
+ static void emitWriteBarrier(JITAssembler *as, Address addr)
+ {
+// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ // if (engine->writeBarrier)
+// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test);
+// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0));
+ // ### emit fence
+ emitSetGrayBit(as, addr.base);
+// jump.link(as);
+ }
+#elif WRITEBARRIER(none)
+ static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
+#endif
+
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
{
as->load64(addr, TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
}
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
as->store64(TargetPlatform::ReturnValueRegister, addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, addr);
}
static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
{
as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
- Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
+ WriteBarrier::Type barrier;
+ Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store64(TargetPlatform::ReturnValueRegister, ptr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, ptr);
}
static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
{
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
}
- static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
{
as->store64(TargetPlatform::ReturnValueRegister, dest);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, dest);
}
static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
@@ -427,16 +548,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
if (t->type == IR::DoubleType) {
as->moveDoubleTo64((FPRegisterID) t->index,
TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask),
- TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
} else if (t->type == IR::UInt32Type) {
RegisterID srcReg = (RegisterID) t->index;
Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0));
as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
Jump done = as->jump();
intRange.link(as);
as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
@@ -462,7 +580,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
TargetPlatform::ReturnValueRegister);
}
} else {
- as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier);
}
}
@@ -471,18 +589,20 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
}
- static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
{
as->store64(TrustedImm64(value.rawValue()), destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
{
// Use ReturnValueRegister as "scratch" register because loadArgument
// and storeArgument are functions that may need a scratch register themselves.
loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0);
- as->storeReturnValue(destination);
+ as->storeReturnValue(destination, barrier);
}
static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
@@ -518,7 +638,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNUSED(argumentNumber);
if (al) {
- Pointer addr = as->loadArgLocalAddress(dest, al);
+ Pointer addr = as->loadArgLocalAddressForReading(dest, al);
as->load64(addr, dest);
} else {
QV4::Value undefined = QV4::Primitive::undefinedValue();
@@ -587,7 +707,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- Pointer addr = as->loadAddress(scratchRegister, right);
+ Pointer addr = as->loadAddressForReading(scratchRegister, right);
as->load64(addr, tagRegister);
const TrustedImm64 tag(0);
generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
@@ -596,7 +716,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(source->type == IR::VarType);
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
as->load64(addr, TargetPlatform::ScratchRegister);
as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
@@ -611,8 +731,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump fallback = as->branch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0));
// it's a double
- as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
- as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0);
Jump success =
as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister,
@@ -621,25 +740,30 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
// not an int:
fallback.link(as);
generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
isIntConvertible.link(as);
success.link(as);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ WriteBarrier::Type barrier;
+ Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, targetAddr);
} else {
as->storeInt32(TargetPlatform::ReturnValueRegister, target);
}
}
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
{
as->store64(registerWithPtr, destAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destAddr);
}
static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
@@ -718,8 +842,15 @@ public:
using JITTargetPlatform::registerForArgument;
using JITTargetPlatform::FPGpr0;
using JITTargetPlatform::platformEnterStandardStackFrame;
+ using JITTargetPlatform::platformFinishEnteringStandardStackFrame;
using JITTargetPlatform::platformLeaveStandardStackFrame;
+ static qint32 targetStructureOffset(qint32 hostOffset)
+ {
+ Q_ASSERT(hostOffset % QT_POINTER_SIZE == 0);
+ return (hostOffset * RegisterSize) / QT_POINTER_SIZE;
+ }
+
using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
struct LookupCall {
@@ -735,7 +866,7 @@ public:
struct RuntimeCall {
Address addr;
- inline RuntimeCall(uint offset = uint(INT_MIN));
+ inline RuntimeCall(Runtime::RuntimeMethods method = Runtime::InvalidRuntimeMethod);
bool isValid() const { return addr.offset >= 0; }
};
@@ -969,9 +1100,16 @@ public:
Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Pointer loadAddress(RegisterID tmp, IR::Expr *t);
+ Pointer loadAddressForWriting(RegisterID tmp, IR::Expr *t, WriteBarrier::Type *barrier);
+ Pointer loadAddressForReading(RegisterID tmp, IR::Expr *t) {
+ return loadAddressForWriting(tmp, t, 0);
+ }
+
Pointer loadTempAddress(IR::Temp *t);
- Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al);
+ Pointer loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier);
+ Pointer loadArgLocalAddressForReading(RegisterID baseReg, IR::ArgLocal *al) {
+ return loadArgLocalAddressForWriting(baseReg, al, 0);
+ }
Pointer loadStringAddress(RegisterID reg, const QString &string);
Address loadConstant(IR::Const *c, RegisterID baseReg);
Address loadConstant(const Primitive &v, RegisterID baseReg);
@@ -993,16 +1131,16 @@ public:
Pointer addr(_stackLayout->savedRegPointer(argumentNumber));
switch (t->type) {
case IR::BoolType:
- storeBool((RegisterID) t->index, addr);
+ storeBool((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::SInt32Type:
- storeInt32((RegisterID) t->index, addr);
+ storeInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::UInt32Type:
- storeUInt32((RegisterID) t->index, addr);
+ storeUInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::DoubleType:
- storeDouble((FPRegisterID) t->index, addr);
+ storeDouble((FPRegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
default:
Q_UNIMPLEMENTED();
@@ -1033,7 +1171,7 @@ public:
if (!temp.value) {
RegisterSizeDependentOps::zeroRegister(this, dest);
} else {
- Pointer addr = toAddress(dest, temp.value, argumentNumber);
+ Pointer addr = toAddress(dest, temp.value, argumentNumber, 0);
loadArgumentInRegister(addr, dest, argumentNumber);
}
}
@@ -1046,7 +1184,7 @@ public:
void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
{
Q_ASSERT(temp.value);
- Pointer addr = loadAddress(dest, temp.value);
+ Pointer addr = loadAddressForReading(dest, temp.value);
loadArgumentInRegister(addr, dest, argumentNumber);
}
@@ -1079,8 +1217,10 @@ public:
move(imm32, dest);
}
- void storeReturnValue(RegisterID dest)
+ void storeReturnValue(RegisterID dest, WriteBarrier::Type barrier = WriteBarrier::NoBarrier)
{
+ Q_UNUSED(barrier);
+ Q_ASSERT(barrier == WriteBarrier::NoBarrier);
move(ReturnValueRegister, dest);
}
@@ -1088,7 +1228,7 @@ public:
{
subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp);
+ storeReturnValue(tmp, WriteBarrier::NoBarrier);
toUInt32Register(tmp, dest);
addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
}
@@ -1098,9 +1238,9 @@ public:
RegisterSizeDependentOps::storeReturnValue(this, dest);
}
- void storeReturnValue(const Pointer &dest)
+ void storeReturnValue(const Pointer &dest, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeReturnValue(this, dest);
+ RegisterSizeDependentOps::storeReturnValue(this, dest, barrier);
}
void storeReturnValue(IR::Expr *target)
@@ -1108,22 +1248,19 @@ public:
if (!target)
return;
- if (IR::Temp *temp = target->asTemp()) {
- if (temp->kind == IR::Temp::PhysicalRegister) {
- if (temp->type == IR::DoubleType)
- storeReturnValue((FPRegisterID) temp->index);
- else if (temp->type == IR::UInt32Type)
- storeUInt32ReturnValue((RegisterID) temp->index);
- else
- storeReturnValue((RegisterID) temp->index);
- return;
- } else {
- Pointer addr = loadTempAddress(temp);
- storeReturnValue(addr);
- }
- } else if (IR::ArgLocal *al = target->asArgLocal()) {
- Pointer addr = loadArgLocalAddress(ScratchRegister, al);
- storeReturnValue(addr);
+ IR::Temp *temp = target->asTemp();
+ if (temp && temp->kind == IR::Temp::PhysicalRegister) {
+ if (temp->type == IR::DoubleType)
+ storeReturnValue((FPRegisterID) temp->index);
+ else if (temp->type == IR::UInt32Type)
+ storeUInt32ReturnValue((RegisterID) temp->index);
+ else
+ storeReturnValue((RegisterID) temp->index);
+ return;
+ } else {
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeReturnValue(addr, barrier);
}
}
@@ -1160,7 +1297,7 @@ public:
void loadArgumentOnStack(PointerToValue temp, int argumentNumber)
{
if (temp.value) {
- Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
+ Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber, 0);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
@@ -1180,7 +1317,7 @@ public:
{
Q_ASSERT (temp.value);
- Pointer ptr = loadAddress(ScratchRegister, temp.value);
+ Pointer ptr = loadAddressForReading(ScratchRegister, temp.value);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
@@ -1191,7 +1328,7 @@ public:
moveDouble((FPRegisterID) sourceTemp->index, dest);
return;
}
- Pointer ptr = loadAddress(ScratchRegister, source);
+ Pointer ptr = loadAddressForReading(ScratchRegister, source);
loadDouble(ptr, dest);
}
@@ -1210,53 +1347,65 @@ public:
RegisterSizeDependentOps::loadDouble(this, addr, dest);
}
- void storeDouble(FPRegisterID source, Address addr)
+ void storeDouble(FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeDouble(this, source, addr);
+ RegisterSizeDependentOps::storeDouble(this, source, addr, barrier);
}
template <typename Result, typename Source>
- void copyValue(Result result, Source source);
+ void copyValue(Result result, Source source, WriteBarrier::Type barrier);
template <typename Result>
- void copyValue(Result result, IR::Expr* source);
+ void copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier);
// The scratch register is used to calculate the temp address for the source.
- void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister)
+ void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister, WriteBarrier::Type barrier)
{
Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
- TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target);
+ loadRawValue(loadAddressForReading(scratchRegister, source), FPGpr0);
+ storeRawValue(FPGpr0, target, barrier);
}
// The scratch register is used to calculate the temp address for the source.
void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
{
- TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister);
- TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target));
+ loadRawValue(source, fpScratchRegister);
+ WriteBarrier::Type barrier;
+ Pointer dest = loadAddressForWriting(scratchRegister, target, &barrier);
+ storeRawValue(fpScratchRegister, dest, barrier);
}
- void storeValue(QV4::Primitive value, RegisterID destination)
+ void loadRawValue(Pointer source, FPRegisterID dest)
{
- Q_UNUSED(value);
- Q_UNUSED(destination);
- Q_UNREACHABLE();
+ TargetConfiguration::MacroAssembler::loadDouble(source, dest);
}
- void storeValue(QV4::Primitive value, Address destination)
+ void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeValue(this, value, destination);
+ TargetConfiguration::MacroAssembler::storeDouble(source, dest);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, dest);
+ }
+
+ void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
+ {
+ RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
}
void storeValue(QV4::Primitive value, IR::Expr* temp);
+ void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) {
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
+ }
+
void enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave);
void leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave);
void checkException() {
- load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
+ this->load8(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister);
Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
addPatch(catchBlock, exceptionThrown);
@@ -1307,7 +1456,7 @@ public:
template <int ArgumentIndex, typename Parameter>
struct SizeOnStack
{
- enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, sizeof(void*), 0>::Chosen };
+ enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, RegisterSize, 0>::Chosen };
};
template <int ArgumentIndex>
@@ -1324,8 +1473,8 @@ public:
// IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
// load the table from the context
- loadPtr(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), ScratchRegister);
- loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
+ loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister);
+ loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lookups))),
lookupCall.addr.base);
// pre-calculate the indirect address for the lookupCall table:
if (lookupCall.addr.offset)
@@ -1418,8 +1567,10 @@ public:
generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType());
}
- Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset)
+ Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = WriteBarrier::NoBarrier;
if (IR::Const *c = e->asConst()) {
Address addr = _stackLayout->savedRegPointer(offset);
Address tagAddr = addr;
@@ -1435,14 +1586,16 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return Pointer(_stackLayout->savedRegPointer(offset));
- return loadAddress(tmpReg, e);
+ return loadAddressForWriting(tmpReg, e, barrier);
}
- void storeBool(RegisterID reg, Pointer addr)
+ void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
store32(reg, addr);
addr.offset += 4;
store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
void storeBool(RegisterID src, RegisterID dest)
@@ -1459,8 +1612,9 @@ public:
}
}
- Pointer addr = loadAddress(ScratchRegister, target);
- storeBool(reg, addr);
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeBool(reg, addr, barrier);
}
void storeBool(bool value, IR::Expr *target) {
@@ -1482,25 +1636,24 @@ public:
move(src, dest);
}
- void storeInt32(RegisterID reg, Pointer addr)
+ void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
store32(reg, addr);
addr.offset += 4;
store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
void storeInt32(RegisterID reg, IR::Expr *target)
{
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) targetTemp->index);
- } else {
- Pointer addr = loadTempAddress(targetTemp);
- storeInt32(reg, addr);
- }
- } else if (IR::ArgLocal *al = target->asArgLocal()) {
- Pointer addr = loadArgLocalAddress(ScratchRegister, al);
- storeInt32(reg, addr);
+ IR::Temp *targetTemp = target->asTemp();
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) targetTemp->index);
+ } else {
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeInt32(reg, addr, barrier);
}
}
@@ -1509,15 +1662,15 @@ public:
move(src, dest);
}
- void storeUInt32(RegisterID reg, Pointer addr)
+ void storeUInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
// The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
- storeDouble(FPGpr0, addr);
+ storeDouble(FPGpr0, addr, barrier);
Jump done = jump();
intRange.link(this);
- storeInt32(reg, addr);
+ storeInt32(reg, addr, barrier);
done.link(this);
}
@@ -1527,8 +1680,9 @@ public:
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
move(reg, (RegisterID) targetTemp->index);
} else {
- Pointer addr = loadAddress(ScratchRegister, target);
- storeUInt32(reg, addr);
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeUInt32(reg, addr, barrier);
}
}
@@ -1563,7 +1717,7 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return (RegisterID) t->index;
- return toInt32Register(loadAddress(scratchReg, e), scratchReg);
+ return toInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
}
RegisterID toInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1583,7 +1737,7 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return (RegisterID) t->index;
- return toUInt32Register(loadAddress(scratchReg, e), scratchReg);
+ return toUInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
}
RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1623,9 +1777,9 @@ public:
const int locals = _stackLayout->calculateJSStackFrameSize();
if (locals <= 0)
return;
- loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister);
+ loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))), JITTargetPlatform::LocalsRegister);
RegisterSizeDependentOps::initializeLocalVariables(this, locals);
- storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+ storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
}
Label exceptionReturnLabel;
@@ -1655,39 +1809,40 @@ private:
template <typename TargetConfiguration>
template <typename Result, typename Source>
-void Assembler<TargetConfiguration>::copyValue(Result result, Source source)
+void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
}
template <typename TargetConfiguration>
template <typename Result>
-void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source)
+void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier)
{
if (source->type == IR::BoolType) {
RegisterID reg = toInt32Register(source, ScratchRegister);
- storeBool(reg, result);
+ storeBool(reg, result, barrier);
} else if (source->type == IR::SInt32Type) {
RegisterID reg = toInt32Register(source, ScratchRegister);
- storeInt32(reg, result);
+ storeInt32(reg, result, barrier);
} else if (source->type == IR::UInt32Type) {
RegisterID reg = toUInt32Register(source, ScratchRegister);
- storeUInt32(reg, result);
+ storeUInt32(reg, result, barrier);
} else if (source->type == IR::DoubleType) {
- storeDouble(toDoubleRegister(source), result);
+ storeDouble(toDoubleRegister(source), result, barrier);
} else if (source->asTemp() || source->asArgLocal()) {
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
} else if (IR::Const *c = source->asConst()) {
QV4::Primitive v = convertToValue(c);
- storeValue(v, result);
+ storeValue(v, result, barrier);
} else {
Q_UNREACHABLE();
}
}
template <typename TargetConfiguration>
-inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(uint offset)
- : addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime))
+inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(Runtime::RuntimeMethods method)
+ : addr(Assembler::EngineRegister,
+ method == Runtime::InvalidRuntimeMethod ? -1 : (Assembler<TargetConfiguration>::targetStructureOffset(offsetof(EngineBase, runtime) + Runtime::runtimeMethodOffset(method))))
{
}
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index 22067bbb13..a1c65f644c 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -165,17 +165,17 @@ struct ArchitectureSpecificBinaryOperation<Assembler<AssemblerTargetConfiguratio
#endif
#define OP(op) \
- { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
+ { "Runtime::" isel_stringIfy(op), QV4::Runtime::op, QV4::Runtime::InvalidRuntimeMethod, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define OPCONTEXT(op) \
- { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
+ { "Runtime::" isel_stringIfy(op), QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::op, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define INLINE_OP(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), offsetof(QV4::Runtime, op), INT_MIN, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
+ { "Runtime::" isel_stringIfy(op), QV4::Runtime::op, QV4::Runtime::InvalidRuntimeMethod, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define INLINE_OPCONTEXT(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), INT_MIN, offsetof(QV4::Runtime, op), memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
+ { "Runtime::" isel_stringIfy(op), QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::op, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
#define NULL_OP \
- { 0, 0, 0, 0, 0, false }
+ { 0, QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::InvalidRuntimeMethod, 0, 0, false }
template <typename JITAssembler>
const typename Binop<JITAssembler>::OpInfo Binop<JITAssembler>::operations[IR::LastAluOp + 1] = {
@@ -492,7 +492,7 @@ bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource
return false;
}
} else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource);
+ Pointer rhsAddr = as->loadAddressForReading(JITAssembler::ScratchRegister, rightSource);
switch (op) {
case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index d2d9ba7753..1b1ab7f24d 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -88,8 +88,8 @@ struct Binop {
struct OpInfo {
const char *name;
- int fallbackImplementation; // offsetOf(Runtime,...)
- int contextImplementation; // offsetOf(Runtime,...)
+ Runtime::RuntimeMethods fallbackImplementation;
+ Runtime::RuntimeMethods contextImplementation;
MemRegOp inlineMemRegOp;
ImmRegOp inlineImmRegOp;
bool needsExceptionCheck;
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 69d6951bb9..9841620481 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -132,8 +132,8 @@ void InstructionSelection<JITAssembler>::run(int functionIndex)
for (IR::Stmt *s : _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
- _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
- Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister);
+ Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber)));
_as->store32(TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
@@ -350,11 +350,11 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
bool isData = it->expr->asConst()->value;
it = it->next;
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
if (!isData) {
it = it->next;
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
}
}
@@ -376,10 +376,10 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayValueCount;
// Index
- _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
+ _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Value
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
}
@@ -400,14 +400,14 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayGetterSetterCount;
// Index
- _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
+ _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Getter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
// Setter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
}
@@ -447,9 +447,11 @@ void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
- _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
- _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, temp, &barrier);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ReturnValueRegister);
+ _as->loadPtr(Address(JITTargetPlatform::ReturnValueRegister,JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ReturnValueRegister);
+ _as->copyValue(addr, Address(JITTargetPlatform::ReturnValueRegister, offsetof(CallData, thisObject)), barrier);
}
template <typename JITAssembler>
@@ -503,8 +505,9 @@ void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr
{
Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
_as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
- Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target);
- JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr);
+ WriteBarrier::Type barrier;
+ Pointer destAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, target, &barrier);
+ JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr, barrier);
}
template <typename JITAssembler>
@@ -519,7 +522,7 @@ void InstructionSelection<JITAssembler>::getActivationProperty(const IR::Name *n
{
if (useFastLookups && name->global) {
uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
+ generateLookupCall(target, index, offsetof(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
return;
}
generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id));
@@ -545,7 +548,7 @@ void InstructionSelection<JITAssembler>::getProperty(IR::Expr *base, const QStri
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
+ generateLookupCall(target, index, offsetof(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
} else {
generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister,
PointerToValue(base), StringToIndex(name));
@@ -584,7 +587,7 @@ void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr
{
if (useFastLookups) {
uint index = registerSetterLookup(targetName);
- generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter),
+ generateLookupCall(JITAssembler::Void, index, offsetof(QV4::Lookup, setter),
JITTargetPlatform::EngineRegister,
PointerToValue(targetBase),
PointerToValue(source));
@@ -620,7 +623,8 @@ void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *in
{
if (useFastLookups) {
uint lookup = registerIndexedGetterLookup();
- generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter),
+ generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter),
+ JITTargetPlatform::EngineRegister,
PointerToValue(base),
PointerToValue(index));
return;
@@ -635,7 +639,8 @@ void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *
{
if (useFastLookups) {
uint lookup = registerIndexedSetterLookup();
- generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
+ generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter),
+ JITTargetPlatform::EngineRegister,
PointerToValue(targetBase), PointerToValue(targetIndex),
PointerToValue(source));
return;
@@ -711,8 +716,10 @@ void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *t
}
}
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrier);
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(addr, source, JITTargetPlatform::ScratchRegister, barrier);
}
template <typename JITAssembler>
@@ -739,14 +746,13 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
} else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
- Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target);
- // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
- auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as);
- platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0);
- platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1);
- platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr);
- platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr);
+ WriteBarrier::Type barrierForSource, barrierForTarget;
+ Pointer sAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, source, &barrierForSource);
+ Pointer tAddr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrierForTarget);
+ _as->loadRawValue(sAddr, JITTargetPlatform::FPGpr0);
+ _as->loadRawValue(tAddr, JITTargetPlatform::FPGpr1);
+ _as->storeRawValue(JITTargetPlatform::FPGpr1, sAddr, barrierForSource);
+ _as->storeRawValue(JITTargetPlatform::FPGpr0, tAddr, barrierForTarget);
return;
}
}
@@ -757,14 +763,15 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
Q_ASSERT(memExpr);
Q_ASSERT(regTemp);
- Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr);
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, memExpr, &barrier);
if (regTemp->type == IR::DoubleType) {
_as->loadDouble(addr, JITTargetPlatform::FPGpr0);
- _as->storeDouble((FPRegisterID) regTemp->index, addr);
+ _as->storeDouble((FPRegisterID) regTemp->index, addr, barrier);
_as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
} else if (regTemp->type == IR::UInt32Type) {
_as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
- _as->storeUInt32((RegisterID) regTemp->index, addr);
+ _as->storeUInt32((RegisterID) regTemp->index, addr, barrier);
_as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
} else {
_as->load32(addr, JITTargetPlatform::ScratchRegister);
@@ -784,6 +791,7 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
Q_UNREACHABLE();
}
_as->store32(TrustedImm32(tag), addr);
+ _as->emitWriteBarrier(addr, barrier);
}
_as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
}
@@ -791,12 +799,12 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
#define setOp(op, opName, operation) \
do { \
- op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ op = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
#define setOpContext(op, opName, operation) \
do { \
- opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ opContext = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
@@ -913,13 +921,13 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
+ _as->loadDouble(_as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
_as->storeDouble(JITTargetPlatform::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
@@ -938,7 +946,7 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I
// it is a double:
isDbl.link(_as);
- Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr2 = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
_as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
@@ -996,7 +1004,7 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR:
_as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
case IR::VarType:
default:
- Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
Pointer tagAddr = addr;
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
@@ -1061,7 +1069,7 @@ void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, I
case IR::StringType:
default:
generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
- _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
_as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
} // switch (source->type)
@@ -1073,21 +1081,21 @@ void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, I
switch (source->type) {
case IR::VarType: {
// load the tag:
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
TrustedImm32(Value::Integer_Type_Internal));
- Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
_as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
- _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
_as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
intDone.link(_as);
@@ -1192,7 +1200,7 @@ void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
reg = JITTargetPlatform::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond);
+ Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal));
@@ -1297,9 +1305,9 @@ int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* a
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
else
- _as->copyValue(dst, arg);
+ _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
}
return argc;
@@ -1313,15 +1321,15 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
++argc;
}
- Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag));
+ Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag));
_as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
- p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc));
+ p = _as->stackLayout().callDataAddress(offsetof(CallData, argc));
_as->store32(TrustedImm32(argc), p);
- p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject));
+ p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject));
if (!thisObject)
- _as->storeValue(QV4::Primitive::undefinedValue(), p);
+ _as->storeValue(QV4::Primitive::undefinedValue(), p, WriteBarrier::NoBarrier);
else
- _as->copyValue(p, thisObject);
+ _as->copyValue(p, thisObject, WriteBarrier::NoBarrier);
int i = 0;
for (IR::ExprList *it = args; it; it = it->next, ++i) {
@@ -1329,9 +1337,9 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
else
- _as->copyValue(dst, arg);
+ _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
}
return argc;
}
@@ -1449,7 +1457,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
return true;
}
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
_as->load32(tagAddr, tagReg);
@@ -1532,7 +1540,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop,
return true;
}
- Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc);
+ Pointer otherAddr = _as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
@@ -1581,7 +1589,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOr
return true;
}
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
_as->load32(tagAddr, tagReg);
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 5c046cb397..0d02284539 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -209,7 +209,7 @@ private:
_as->convertInt32ToDouble((RegisterID) sourceTemp->index,
(FPRegisterID) targetTemp->index);
} else {
- _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp),
+ _as->convertInt32ToDouble(_as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, sourceTemp),
(FPRegisterID) targetTemp->index);
}
} else {
@@ -223,7 +223,7 @@ private:
_as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
JITTargetPlatform::FPGpr0);
- _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target));
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
@@ -240,7 +240,7 @@ private:
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
JITTargetPlatform::FPGpr0, tmpReg);
- _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target));
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
@@ -260,8 +260,8 @@ private:
void calculateRegistersToSave(const RegisterInformation &used);
- template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ template <typename Retval, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
// Note: using the return value register is intentional: for ABIs where the first parameter
// goes into the same register as the return value (currently only ARM), the prepareCall
@@ -271,7 +271,7 @@ private:
_as->generateFunctionCallImp(true, retval, "lookup getter/setter",
typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
- arg1, arg2, arg3);
+ arg1, arg2, arg3, arg4);
}
template <typename Retval, typename Arg1, typename Arg2>
@@ -280,6 +280,12 @@ private:
generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
}
+ template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, arg3, typename JITAssembler::VoidType());
+ }
+
IR::BasicBlock *_block;
BitVector _removableJumps;
JITAssembler* _as;
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index e5abaa7458..8eafaaaa8a 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -1138,6 +1138,8 @@ private:
mapping.add(moveFrom, moveTo);
}
+ if (DebugRegAlloc)
+ mapping.dump();
mapping.order();
if (DebugRegAlloc)
mapping.dump();
@@ -1958,10 +1960,10 @@ void RegisterAllocator::dump(IR::Function *function) const
// References:
// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
-// CGO’10, ACM Press, 2010
+// CGO'10, ACM Press, 2010
// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
-// Execution Environments, pages 132–141. ACM Press, 2005.
+// Execution Environments, pages 132-141. ACM Press, 2005.
// [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan
// Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming
-// Language Design and Implementation, pages 142–151, June 1998.
+// Language Design and Implementation, pages 142-151, June 1998.
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index fcc600eb2e..ce6156802d 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -55,6 +55,7 @@
#if ENABLE(ASSEMBLER)
+#include <private/qv4value_p.h>
#include "qv4registerinfo_p.h"
#include <assembler/MacroAssembler.h>
@@ -140,6 +141,7 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0)
@@ -194,6 +196,7 @@ public:
static const RegisterID EngineRegister = JSC::X86Registers::r14;
static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13;
static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
@@ -209,7 +212,7 @@ public:
<< RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
// r11 is used as scratch register by the macro assembler
<< RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
@@ -244,6 +247,10 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
+ {
+ as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
+ }
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0)
@@ -274,6 +281,7 @@ public:
static const RegisterID EngineRegister = JSC::X86Registers::r14;
static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13;
static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
@@ -289,7 +297,7 @@ public:
<< RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
// r11 is used as scratch register by the macro assembler
<< RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
@@ -322,6 +330,10 @@ public:
static const int StackShadowSpace = 32;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
+ {
+ as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
+ }
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0)
@@ -358,7 +370,7 @@ public:
// There are two designated frame-pointer registers on ARM, depending on which instruction set
// is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
// accordingly, and assign the locals-register to the "other" register.
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
@@ -385,7 +397,7 @@ public:
<< RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#if !CPU(ARM_THUMB2)
+#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
<< RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#endif
<< RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
@@ -393,7 +405,7 @@ public:
<< RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
#endif
<< RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
<< RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#endif
<< RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
@@ -440,6 +452,8 @@ public:
as->push(FramePointerRegister);
}
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
+
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0) {
@@ -475,6 +489,7 @@ public:
static const RegisterID ScratchRegister = JSC::ARM64Registers::x9;
static const RegisterID EngineRegister = JSC::ARM64Registers::x27;
static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
+ static const RegisterID DoubleMaskRegister = JSC::ARM64Registers::x26;
static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
@@ -505,7 +520,7 @@ public:
<< RI(JSC::ARM64Registers::x23, QStringLiteral("x23"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::x24, QStringLiteral("x24"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::x25, QStringLiteral("x25"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x26, QStringLiteral("x26"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::ARM64Registers::x26, QStringLiteral("x26"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::ARM64Registers::x27, QStringLiteral("x27"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::ARM64Registers::x28, QStringLiteral("x28"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -572,6 +587,11 @@ public:
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
+ {
+ as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
+ }
+
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0)
@@ -661,6 +681,8 @@ public:
as->push(FramePointerRegister);
}
+ static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
+
static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
{
if (frameSize > 0)
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 76c6457d67..896be07ed5 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -48,7 +48,7 @@ using namespace JIT;
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
do { \
- call = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
+ call = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); name = "Runtime::" stringIfy(operation); \
needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 4404a5d79f..b52c859ecb 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -333,7 +333,7 @@ QJSEngine::~QJSEngine()
*/
void QJSEngine::collectGarbage()
{
- d->m_v4Engine->memoryManager->runGC();
+ d->m_v4Engine->memoryManager->runGC(/* forceFullCollection = */ true);
}
#if QT_DEPRECATED_SINCE(5, 6)
@@ -525,7 +525,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
\since 5.8
Creates a JavaScript object that wraps the given QMetaObject
- The metaObject must outlive the script engine. It is recommended to only
+ The \a metaObject must outlive the script engine. It is recommended to only
use this method with static metaobjects.
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 7c1cc92a13..318db4f904 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -48,32 +48,33 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject);
void Heap::ArgumentsObject::init(QV4::CallContext *context)
{
+ ExecutionEngine *v4 = context->d()->engine;
+
Object::init();
fullyCreated = false;
- this->context = context->d();
+ this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
- ExecutionEngine *v4 = context->d()->engine;
Scope scope(v4);
Scoped<QV4::ArgumentsObject> args(scope, this);
if (context->d()->strictMode) {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller()));
- *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
+ args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
args->arrayReserve(context->argc());
args->arrayPut(0, context->args(), context->argc());
args->d()->fullyCreated = true;
} else {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
- *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue();
+ args->setProperty(CalleePropertyIndex, context->d()->function);
}
Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length()));
- *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc);
+ args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc));
}
void ArgumentsObject::fullyCreate()
@@ -89,9 +90,9 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
if (numAccessors) {
- d()->mappedArguments = md->allocate(engine(), numAccessors);
+ d()->mappedArguments.set(scope.engine, md->allocate(engine(), numAccessors));
for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
+ d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]);
arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
}
}
@@ -107,22 +108,22 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
fullyCreate();
Scope scope(engine);
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
ScopedProperty map(scope);
PropertyAttributes mapAttrs;
+ uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc));
bool isMapped = false;
- uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc);
- if (pd && index < (uint)numAccessors)
- isMapped = arrayData()->attributes(index).isAccessor() &&
- pd->getter() == context()->engine->argumentsAccessors[index].getter();
+ if (arrayData() && index < numAccessors &&
+ arrayData()->attributes(index).isAccessor() &&
+ arrayData()->get(index) == context()->engine->argumentsAccessors[index].getter()->asReturnedValue())
+ isMapped = true;
if (isMapped) {
Q_ASSERT(arrayData());
mapAttrs = arrayData()->attributes(index);
- map->copy(pd, mapAttrs);
+ arrayData()->getProperty(index, map, &mapAttrs);
setArrayAttributes(index, Attr_Data);
- pd = arrayData()->getProperty(index);
- pd->value = d()->mappedArguments->data[index];
+ ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) };
+ arrayIndex.set(scope.engine, d()->mappedArguments->values[index]);
}
bool strict = engine->current->strictMode;
@@ -140,8 +141,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
- pd = arrayData()->getProperty(index);
- pd->copy(map, mapAttrs);
+ arrayData()->setProperty(engine, index, map);
}
}
@@ -235,17 +235,6 @@ void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData
scope.result = Encode::undefined();
}
-void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that);
- if (o->context)
- o->context->mark(e);
- if (o->mappedArguments)
- o->mappedArguments->mark(e);
-
- Object::markObjects(that, e);
-}
-
uint ArgumentsObject::getLength(const Managed *m)
{
const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index f80ade9611..46e1f884e8 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -59,26 +59,35 @@ namespace QV4 {
namespace Heap {
-struct ArgumentsGetterFunction : FunctionObject {
+#define ArgumentsGetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsGetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsSetterFunction : FunctionObject {
+#define ArgumentsSetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsSetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsObject : Object {
+#define ArgumentsObjectMembers(class, Member) \
+ Member(class, Pointer, CallContext *, context) \
+ Member(class, Pointer, MemberData *, mappedArguments) \
+ Member(class, NoMark, bool, fullyCreated)
+
+DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
+ DECLARE_MARK_TABLE(ArgumentsObject);
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 3
};
void init(QV4::CallContext *context);
- Pointer<CallContext> context;
- bool fullyCreated;
- Pointer<MemberData> mappedArguments;
};
}
@@ -131,7 +140,6 @@ struct ArgumentsObject: Object {
static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static uint getLength(const Managed *m);
void fullyCreate();
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index d8a7de5466..4a619858b4 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -50,6 +50,7 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON
const QV4::VTable QV4::ArrayData::static_vtbl = {
0,
+ 0,
QV4::ArrayData::IsExecutionContext,
QV4::ArrayData::IsString,
QV4::ArrayData::IsObject,
@@ -128,7 +129,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
if (d->type() < Heap::ArrayData::Sparse) {
offset = d->d()->offset;
- toCopy = d->d()->len;
+ toCopy = d->d()->values.size;
} else {
toCopy = d->alloc();
}
@@ -149,7 +150,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
n->init();
n->offset = 0;
- n->len = d ? d->d()->len : 0;
+ n->values.size = d ? d->d()->values.size : 0;
newData = n;
} else {
Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size);
@@ -158,7 +159,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
}
newData->setAlloc(alloc);
newData->setType(newType);
- newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0);
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : 0);
o->setArrayData(newData);
if (d) {
@@ -170,12 +171,14 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
newData->attrs()[i] = Attr_Data;
}
- if (toCopy > d->d()->alloc - offset) {
- uint copyFromStart = toCopy - (d->d()->alloc - offset);
- memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart);
+ if (toCopy > d->d()->values.alloc - offset) {
+ uint copyFromStart = toCopy - (d->d()->values.alloc - offset);
+ // no write barrier required here
+ memcpy(newData->d()->values.values + toCopy - copyFromStart, d->d()->values.values, sizeof(Value)*copyFromStart);
toCopy -= copyFromStart;
}
- memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy);
+ // no write barrier required here
+ memcpy(newData->d()->values.values, d->d()->values.values + offset, sizeof(Value)*toCopy);
}
if (newType != Heap::ArrayData::Sparse)
@@ -195,22 +198,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
lastFree = &sparse->freeList;
storeValue(lastFree, 0);
for (uint i = 0; i < toCopy; ++i) {
- if (!sparse->arrayData[i].isEmpty()) {
+ if (!sparse->values[i].isEmpty()) {
SparseArrayNode *n = sparse->sparse->insert(i);
n->value = i;
} else {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
}
}
- if (toCopy < sparse->alloc) {
- for (uint i = toCopy; i < sparse->alloc; ++i) {
+ if (toCopy < sparse->values.alloc) {
+ for (uint i = toCopy; i < sparse->values.alloc; ++i) {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
storeValue(lastFree, UINT_MAX);
}
@@ -233,24 +236,10 @@ void ArrayData::ensureAttributes(Object *o)
ArrayData::realloc(o, Heap::ArrayData::Simple, 0, true);
}
-
-void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d);
- uint end = dd->offset + dd->len;
- if (end > dd->alloc) {
- for (uint i = 0; i < end - dd->alloc; ++i)
- dd->arrayData[i].mark(e);
- end = dd->alloc;
- }
- for (uint i = dd->offset; i < end; ++i)
- dd->arrayData[i].mark(e);
-}
-
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
{
const Heap::SimpleArrayData *dd = static_cast<const Heap::SimpleArrayData *>(d);
- if (index >= dd->len)
+ if (index >= dd->values.size)
return Primitive::emptyValue().asReturnedValue();
return dd->data(index).asReturnedValue();
}
@@ -258,13 +247,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
bool SimpleArrayData::put(Object *o, uint index, const Value &value)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
+ Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor());
// ### honour attributes
- dd->data(index) = value;
- if (index >= dd->len) {
+ dd->setData(o->engine(), index, value);
+ if (index >= dd->values.size) {
if (dd->attrs)
dd->attrs[index] = Attr_Data;
- dd->len = index + 1;
+ dd->values.size = index + 1;
}
return true;
}
@@ -272,11 +261,11 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value)
bool SimpleArrayData::del(Object *o, uint index)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index >= dd->len)
+ if (index >= dd->values.size)
return true;
if (!dd->attrs || dd->attrs[index].isConfigurable()) {
- dd->data(index) = Primitive::emptyValue();
+ dd->setData(o->engine(), index, Primitive::emptyValue());
if (dd->attrs)
dd->attrs[index] = Attr_Data;
return true;
@@ -295,8 +284,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (dd->len + n > dd->alloc) {
- realloc(o, Heap::ArrayData::Simple, dd->len + n, false);
+ if (dd->values.size + n > dd->values.alloc) {
+ realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false);
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
@@ -304,70 +293,71 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
dd->offset -= n; // there is enough space left in front
} else {
// we need to wrap around, so:
- dd->offset = dd->alloc - // start at the back, but subtract:
+ dd->offset = dd->values.alloc - // start at the back, but subtract:
(n - dd->offset); // the number of items we can put in the free space at the start of the allocated array
}
- dd->len += n;
+ dd->values.size += n;
for (uint i = 0; i < n; ++i)
- dd->data(i) = values[i].asReturnedValue();
+ dd->setData(o->engine(), i, values[i]);
}
ReturnedValue SimpleArrayData::pop_front(Object *o)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (!dd->len)
+ if (!dd->values.size)
return Encode::undefined();
ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue();
- dd->offset = (dd->offset + 1) % dd->alloc;
- --dd->len;
+ dd->offset = (dd->offset + 1) % dd->values.alloc;
+ --dd->values.size;
return v;
}
uint SimpleArrayData::truncate(Object *o, uint newLen)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (dd->len < newLen)
+ if (dd->values.size < newLen)
return newLen;
if (!dd->attrs) {
- dd->len = newLen;
+ dd->values.size = newLen;
return newLen;
}
- while (dd->len > newLen) {
- if (!dd->data(dd->len - 1).isEmpty() && !dd->attrs[dd->len - 1].isConfigurable())
- return dd->len;
- --dd->len;
+ while (dd->values.size > newLen) {
+ if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable())
+ return dd->values.size;
+ --dd->values.size;
}
- return dd->len;
+ return dd->values.size;
}
uint SimpleArrayData::length(const Heap::ArrayData *d)
{
- return d->len;
+ return d->values.size;
}
bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index + n > dd->alloc) {
+ if (index + n > dd->values.alloc) {
reallocate(o, index + n + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- for (uint i = dd->len; i < index; ++i)
- dd->data(i) = Primitive::emptyValue();
+ QV4::ExecutionEngine *e = o->engine();
+ for (uint i = dd->values.size; i < index; ++i)
+ dd->setData(e, i, Primitive::emptyValue());
for (uint i = 0; i < n; ++i)
- dd->data(index + i) = values[i];
- dd->len = qMax(dd->len, index + n);
+ dd->setData(e, index + i, values[i]);
+ dd->values.size = qMax(dd->values.size, index + n);
return true;
}
void SparseArrayData::free(Heap::ArrayData *d, uint idx)
{
Q_ASSERT(d && d->type == Heap::ArrayData::Sparse);
- Value *v = d->arrayData + idx;
+ Value *v = d->values.values + idx;
if (d->attrs && d->attrs[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue());
@@ -380,15 +370,6 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx)
d->attrs[idx].clear();
}
-
-void SparseArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(d);
- uint l = dd->alloc;
- for (uint i = 0; i < l; ++i)
- dd->arrayData[i].mark(e);
-}
-
Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
realloc(o, Heap::ArrayData::Sparse, n, enforceAttributes);
@@ -404,32 +385,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
ReturnedValue *last = &dd->freeList;
while (1) {
if (Value::fromReturnedValue(*last).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 2, true);
+ reallocate(o, dd->values.alloc + 2, true);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
last = &dd->freeList;
Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX);
}
- Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
- if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
+ Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
+ if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
// found two slots in a row
uint idx = Value::fromReturnedValue(*last).emptyValue();
Value lastV = Value::fromReturnedValue(*last);
- lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value());
+ lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value());
*last = lastV.rawValue();
dd->attrs[idx] = Attr_Accessor;
return idx;
}
- last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef();
+ last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef();
}
} else {
if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 1, false);
+ reallocate(o, dd->values.alloc + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
uint idx = Value::fromReturnedValue(dd->freeList).value();
Q_ASSERT(idx != UINT_MAX);
- dd->freeList = dd->arrayData[idx].asReturnedValue();
+ dd->freeList = dd->values[idx].asReturnedValue();
Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty());
if (dd->attrs)
dd->attrs[idx] = Attr_Data;
@@ -443,7 +424,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index)
index = s->mappedIndex(index);
if (index == UINT_MAX)
return Primitive::emptyValue().asReturnedValue();
- return s->arrayData[index].asReturnedValue();
+ return s->values[index].asReturnedValue();
}
bool SparseArrayData::put(Object *o, uint index, const Value &value)
@@ -457,7 +438,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value)
if (n->value == UINT_MAX)
n->value = allocate(o);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = value;
+ s->setArrayData(o->engine(), n->value, value);
if (s->attrs)
s->attrs[n->value] = Attr_Data;
return true;
@@ -472,7 +453,7 @@ bool SparseArrayData::del(Object *o, uint index)
return true;
uint pidx = n->value;
- Q_ASSERT(!dd->arrayData[pidx].isEmpty());
+ Q_ASSERT(!dd->values[pidx].isEmpty());
bool isAccessor = false;
if (dd->attrs) {
@@ -485,11 +466,11 @@ bool SparseArrayData::del(Object *o, uint index)
if (isAccessor) {
// free up both indices
- dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
- dd->arrayData[pidx].setEmpty(pidx + 1);
+ dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(pidx + 1);
} else {
Q_ASSERT(dd->type == Heap::ArrayData::Sparse);
- dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
}
dd->freeList = Primitive::emptyValue(pidx).asReturnedValue();
@@ -518,10 +499,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>();
Q_ASSERT(!d->attrs);
- for (int i = n - 1; i >= 0; --i) {
+ for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
uint idx = allocate(o);
d = o->d()->arrayData.cast<Heap::SparseArrayData>();
- d->arrayData[idx] = values[i];
+ d->setArrayData(o->engine(), idx, values[i]);
d->sparse->push_front(idx);
}
}
@@ -533,7 +514,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o)
uint idx = d->sparse->pop_front();
ReturnedValue v;
if (idx != UINT_MAX) {
- v = d->arrayData[idx].asReturnedValue();
+ v = d->values[idx].asReturnedValue();
free(o->arrayData(), idx);
} else {
v = Encode::undefined();
@@ -611,24 +592,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
ScopedValue v(scope);
for (const SparseArrayNode *it = os->sparse->begin();
it != os->sparse->end(); it = it->nextNode()) {
- v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]);
+ v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]);
obj->arraySet(oldSize + it->key(), v);
}
} else {
for (const SparseArrayNode *it = other->d()->sparse->begin();
it != os->sparse->end(); it = it->nextNode())
- obj->arraySet(oldSize + it->key(), os->arrayData[it->value]);
+ obj->arraySet(oldSize + it->key(), os->values[it->value]);
}
} else {
Heap::SimpleArrayData *os = static_cast<Heap::SimpleArrayData *>(other->d());
uint toCopy = n;
uint chunk = toCopy;
- if (chunk > os->alloc - os->offset)
- chunk -= os->alloc - os->offset;
- obj->arrayPut(oldSize, os->arrayData + os->offset, chunk);
+ if (chunk > os->values.alloc - os->offset)
+ chunk -= os->values.alloc - os->offset;
+ obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
- obj->arrayPut(oldSize + chunk, os->arrayData, toCopy);
+ obj->arrayPut(oldSize + chunk, os->values.data(), toCopy);
}
return oldSize + n;
@@ -638,18 +619,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
{
if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) {
Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index < 0x1000 || index < d->len + (d->len >> 2)) {
- if (index >= d->alloc) {
+ if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) {
+ if (index >= d->values.alloc) {
o->arrayReserve(index + 1);
d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- if (index >= d->len) {
+ if (index >= d->values.size) {
// mark possible hole in the array
- for (uint i = d->len; i < index; ++i)
- d->data(i) = Primitive::emptyValue();
- d->len = index + 1;
+ for (uint i = d->values.size; i < index; ++i)
+ d->setData(o->engine(), i, Primitive::emptyValue());
+ d->values.size = index + 1;
}
- d->arrayData[d->mappedIndex(index)] = *v;
+ d->setData(o->engine(), index, *v);
return;
}
}
@@ -660,9 +641,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
if (n->value == UINT_MAX)
n->value = SparseArrayData::allocate(o, isAccessor);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = *v;
+ s->setArrayData(o->engine(), n->value, *v);
if (isAccessor)
- s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset];
+ s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]);
}
@@ -697,7 +678,7 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
callData->thisObject = Primitive::undefinedValue();
callData->args[0] = v1;
callData->args[1] = v2;
- result = scope.engine->runtime.callValue(scope.engine, m_comparefn, callData);
+ result = QV4::Runtime::method_callValue(scope.engine, m_comparefn, callData);
return result->toNumber() < 0;
}
@@ -799,7 +780,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
break;
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a);
+ d->setData(engine, i, Value::fromReturnedValue(thisObject->getValue(sparse->arrayData()[n->value], a)));
d->attrs[i] = a.isAccessor() ? Attr_Data : a;
n = n->nextNode();
@@ -809,12 +790,12 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- d->data(i) = sparse->arrayData()[n->value];
+ d->setData(engine, i, sparse->arrayData()[n->value]);
n = n->nextNode();
++i;
}
}
- d->len = i;
+ d->values.size = i;
if (len > i)
len = i;
if (n != sparse->sparse()->end()) {
@@ -822,7 +803,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
thisObject->initSparseArray();
while (n != sparse->sparse()->end()) {
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- thisObject->arraySet(n->value, reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
+ thisObject->arraySet(n->value, reinterpret_cast<const Property *>(sparse->arrayData() + n->value), a);
n = n->nextNode();
}
@@ -830,8 +811,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
} else {
Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > d->len)
- len = d->len;
+ if (len > d->values.size)
+ len = d->values.size;
// sort empty values to the end
for (uint i = 0; i < len; i++) {
@@ -840,8 +821,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!d->data(len).isEmpty())
break;
Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor());
- d->data(i) = d->data(len);
- d->data(len) = Primitive::emptyValue();
+ d->setData(engine, i, d->data(len));
+ d->setData(engine, len, Primitive::emptyValue());
}
}
@@ -852,7 +833,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
ArrayElementLessThan lessThan(engine, thisObject, comparefn);
- Value *begin = thisObject->arrayData()->arrayData;
+ Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 24b948f01e..c2c81e886b 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -90,27 +90,31 @@ struct ArrayVTable
namespace Heap {
-struct ArrayData : public Base {
- enum Type {
- Simple = 0,
- Complex = 1,
- Sparse = 2,
- Custom = 3
+#define ArrayDataMembers(class, Member) \
+ Member(class, NoMark, uint, type) \
+ Member(class, NoMark, uint, offset) \
+ Member(class, NoMark, PropertyAttributes *, attrs) \
+ Member(class, NoMark, ReturnedValue, freeList) \
+ Member(class, NoMark, SparseArray *, sparse) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(ArrayData, Base) {
+ DECLARE_MARK_TABLE(ArrayData);
+
+ enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 };
+
+ struct Index {
+ Heap::ArrayData *arrayData;
+ uint index;
+
+ void set(ExecutionEngine *e, Value newVal) {
+ arrayData->values.set(e, index, newVal);
+ }
+ const Value *operator->() const { return &arrayData->values[index]; }
+ const Value &operator*() const { return arrayData->values[index]; }
+ bool isNull() const { return !arrayData; }
};
- uint alloc;
- Type type;
- PropertyAttributes *attrs;
- union {
- uint len;
- ReturnedValue freeList;
- };
- union {
- uint offset;
- SparseArray *sparse;
- };
- Value arrayData[1];
-
bool isSparse() const { return type == Sparse; }
const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); }
@@ -118,35 +122,32 @@ struct ArrayData : public Base {
inline ReturnedValue get(uint i) const {
return vtable()->get(this, i);
}
- inline void getProperty(uint index, Property *p, PropertyAttributes *attrs);
- inline void setProperty(uint index, const Property *p);
- inline Property *getProperty(uint index);
- inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
+ inline void setProperty(ExecutionEngine *e, uint index, const Property *p);
+ inline Index getValueOrSetter(uint index, PropertyAttributes *attrs);
inline PropertyAttributes attributes(uint i) const;
bool isEmpty(uint i) const {
return get(i) == Primitive::emptyValue().asReturnedValue();
}
- inline ReturnedValue length() const {
+ inline uint length() const {
return vtable()->length(this);
}
+ void setArrayData(ExecutionEngine *e, uint index, Value newVal) {
+ values.set(e, index, newVal);
+ }
+
+ uint mappedIndex(uint index) const;
};
V4_ASSERT_IS_TRIVIAL(ArrayData)
struct SimpleArrayData : public ArrayData {
- uint mappedIndex(uint index) const { return (index + offset) % alloc; }
- Value data(uint index) const { return arrayData[mappedIndex(index)]; }
- Value &data(uint index) { return arrayData[mappedIndex(index)]; }
-
- Property *getProperty(uint index) {
- if (index >= len)
- return 0;
- index = mappedIndex(index);
- if (arrayData[index].isEmpty())
- return 0;
- return reinterpret_cast<Property *>(arrayData + index);
+ uint mappedIndex(uint index) const { return (index + offset) % values.alloc; }
+ const Value &data(uint index) const { return values[mappedIndex(index)]; }
+ void setData(ExecutionEngine *e, uint index, Value newVal) {
+ values.set(e, mappedIndex(index), newVal);
}
PropertyAttributes attributes(uint i) const {
@@ -168,13 +169,6 @@ struct SparseArrayData : public ArrayData {
return n->value;
}
- Property *getProperty(uint index) {
- SparseArrayNode *n = sparse->findNode(index);
- if (!n)
- return 0;
- return reinterpret_cast<Property *>(arrayData + n->value);
- }
-
PropertyAttributes attributes(uint i) const {
if (!attrs)
return Attr_Data;
@@ -189,16 +183,23 @@ struct Q_QML_EXPORT ArrayData : public Managed
{
typedef Heap::ArrayData::Type Type;
V4_MANAGED(ArrayData, Managed)
+ enum {
+ IsArrayData = true
+ };
- uint alloc() const { return d()->alloc; }
- uint &alloc() { return d()->alloc; }
- void setAlloc(uint a) { d()->alloc = a; }
- Type type() const { return d()->type; }
+ typedef Heap::ArrayData::Index Index;
+
+ uint alloc() const { return d()->values.alloc; }
+ uint &alloc() { return d()->values.alloc; }
+ void setAlloc(uint a) { d()->values.alloc = a; }
+ Type type() const { return static_cast<Type>(d()->type); }
void setType(Type t) { d()->type = t; }
PropertyAttributes *attrs() const { return d()->attrs; }
void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
- const Value *arrayData() const { return &d()->arrayData[0]; }
- Value *arrayData() { return &d()->arrayData[0]; }
+ const Value *arrayData() const { return d()->values.data(); }
+ void setArrayData(ExecutionEngine *e, uint index, Value newVal) {
+ d()->setArrayData(e, index, newVal);
+ }
const ArrayVTable *vtable() const { return d()->vtable(); }
bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
@@ -221,9 +222,6 @@ struct Q_QML_EXPORT ArrayData : public Managed
ReturnedValue get(uint i) const {
return d()->get(i);
}
- inline Property *getProperty(uint index) {
- return d()->getProperty(index);
- }
static void ensureAttributes(Object *o);
static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
@@ -239,15 +237,12 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
Value data(uint index) const { return d()->data(index); }
- Value &data(uint index) { return d()->data(index); }
- uint &len() { return d()->len; }
- uint len() const { return d()->len; }
+ uint &len() { return d()->values.size; }
+ uint len() const { return d()->values.size; }
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
static bool putArray(Object *o, uint index, const Value *values, uint n);
@@ -274,8 +269,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
@@ -290,30 +283,38 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
namespace Heap {
-void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
+inline uint ArrayData::mappedIndex(uint index) const
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- *attrs = attributes(index);
- p->value = pd->value;
- if (attrs->isAccessor())
- p->set = pd->set;
+ if (isSparse())
+ return static_cast<const SparseArrayData *>(this)->mappedIndex(index);
+ if (index >= values.size)
+ return UINT_MAX;
+ uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index);
+ return values[idx].isEmpty() ? UINT_MAX : idx;
}
-void ArrayData::setProperty(uint index, const Property *p)
+bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- pd->value = p->value;
- if (attributes(index).isAccessor())
- pd->set = p->set;
+ uint mapped = mappedIndex(index);
+ if (mapped == UINT_MAX) {
+ *attrs = Attr_Invalid;
+ return false;
+ }
+
+ *attrs = attributes(index);
+ p->value = *(Index{ this, mapped });
+ if (attrs->isAccessor())
+ p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ return true;
}
-inline Property *ArrayData::getProperty(uint index)
+void ArrayData::setProperty(QV4::ExecutionEngine *e, uint index, const Property *p)
{
- if (isSparse())
- return static_cast<SparseArrayData *>(this)->getProperty(index);
- return static_cast<SimpleArrayData *>(this)->getProperty(index);
+ uint mapped = mappedIndex(index);
+ Q_ASSERT(mapped != UINT_MAX);
+ values.set(e, mapped, p->value);
+ if (attributes(index).isAccessor())
+ values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set);
}
inline PropertyAttributes ArrayData::attributes(uint i) const
@@ -323,16 +324,16 @@ inline PropertyAttributes ArrayData::attributes(uint i) const
return static_cast<const SimpleArrayData *>(this)->attributes(i);
}
-Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
- Property *p = getProperty(index);
- if (!p) {
+ uint idx = mappedIndex(index);
+ if (idx == UINT_MAX) {
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
*attrs = attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx };
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 759354f4e2..a2c19e1f2d 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > sa->len)
- len = sa->len;
+ if (len > sa->values.size)
+ len = sa->values.size;
uint idx = fromIndex;
while (idx < len) {
value = sa->data(idx);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 740ebbe359..b71e71b92f 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -54,58 +54,50 @@
using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
+DEFINE_MANAGED_VTABLE(SimpleCallContext);
DEFINE_MANAGED_VTABLE(CallContext);
DEFINE_MANAGED_VTABLE(WithContext);
DEFINE_MANAGED_VTABLE(CatchContext);
DEFINE_MANAGED_VTABLE(GlobalContext);
-/* Function *f, int argc */
-#define requiredMemoryForExecutionContect(f, argc) \
- ((sizeof(CallContext::Data) + 7) & ~7) + \
- sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData)
-
Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
{
- Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(
- requiredMemoryForExecutionContect(function, callData->argc));
+ uint localsAndFormals = function->compiledFunction->nLocals + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + \
+ sizeof(Value) * (localsAndFormals) + sizeof(CallData) - sizeof(Value);
+
+ Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(requiredMemory);
c->init(d()->engine, Heap::ExecutionContext::Type_CallContext);
c->v4Function = function;
c->strictMode = function->isStrict();
- c->outer = this->d();
-
- c->activation = 0;
+ c->outer.set(d()->engine, this->d());
c->compilationUnit = function->compilationUnit;
- c->lookups = c->compilationUnit->runtimeLookups;
- c->constantTable = c->compilationUnit->constants;
- c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
+ c->lookups = function->compilationUnit->runtimeLookups;
+ c->constantTable = function->compilationUnit->constants;
const CompiledData::Function *compiledFunction = function->compiledFunction;
- int nLocals = compiledFunction->nLocals;
+ uint nLocals = compiledFunction->nLocals;
+ c->locals.size = nLocals;
+ c->locals.alloc = localsAndFormals;
+#if QT_POINTER_SIZE == 8
+ // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below
+ Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
+#else
if (nLocals)
- std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue());
+ std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue());
+#endif
- c->callData = reinterpret_cast<CallData *>(c->locals + nLocals);
- ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value));
+ c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals);
+ ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value));
if (callData->argc < static_cast<int>(compiledFunction->nFormals))
std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue());
return c;
}
-Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4)
-{
- Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4);
- return ctxt;
-}
-
-void Heap::CallContext::freeSimpleCallContext()
-{
- engine->memoryManager->freeSimpleCallContext();
-}
-
Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with)
{
return d()->engine->memoryManager->alloc<WithContext>(d(), with);
@@ -129,10 +121,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (!activation) {
if (!c->activation)
- c->activation = scope.engine->newObject();
+ c->activation.set(scope.engine, scope.engine->newObject());
activation = c->activation;
}
break;
@@ -166,41 +158,52 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
void Heap::GlobalContext::init(ExecutionEngine *eng)
{
Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext);
- global = eng->globalObject->d();
+ global.set(eng, eng->globalObject->d());
}
void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
const Value &exceptionValue)
{
Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext);
- outer = outerContext;
+ outer.set(engine, outerContext);
strictMode = outer->strictMode;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->exceptionVarName = exceptionVarName;
- this->exceptionValue = exceptionValue;
+ this->exceptionVarName.set(engine, exceptionVarName);
+ this->exceptionValue.set(engine, exceptionValue);
}
+void Heap::WithContext::init(ExecutionContext *outerContext, Object *with)
+{
+ Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext);
+ outer.set(engine, outerContext);
+ callData = outer->callData;
+ lookups = outer->lookups;
+ constantTable = outer->constantTable;
+ compilationUnit = outer->compilationUnit;
+
+ withObject.set(engine, with);
+}
-Identifier * const *CallContext::formals() const
+Identifier * const *SimpleCallContext::formals() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0;
}
-unsigned int CallContext::formalCount() const
+unsigned int SimpleCallContext::formalCount() const
{
return d()->v4Function ? d()->v4Function->nFormals : 0;
}
-Identifier * const *CallContext::variables() const
+Identifier * const *SimpleCallContext::variables() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0;
}
-unsigned int CallContext::variableCount() const
+unsigned int SimpleCallContext::variableCount() const
{
return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0;
}
@@ -210,7 +213,6 @@ unsigned int CallContext::variableCount() const
bool ExecutionContext::deleteProperty(String *name)
{
Scope scope(this);
- bool hasWith = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
@@ -221,7 +223,6 @@ bool ExecutionContext::deleteProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_WithContext: {
- hasWith = true;
ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
if (withObject->hasProperty(name))
return withObject->deleteProperty(name);
@@ -233,15 +234,16 @@ bool ExecutionContext::deleteProperty(String *name)
return global->deleteProperty(name);
break;
}
- case Heap::ExecutionContext::Type_CallContext:
- case Heap::ExecutionContext::Type_SimpleCallContext: {
+ case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) {
- uint index = c->v4Function->internalClass->find(name);
- if (index < UINT_MAX)
- // ### throw in strict mode?
- return false;
- }
+ uint index = c->v4Function->internalClass->find(name);
+ if (index < UINT_MAX)
+ // ### throw in strict mode?
+ return false;
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
ScopedObject qml(scope, c->activation);
if (qml && qml->hasProperty(name))
return qml->deleteProperty(name);
@@ -258,61 +260,6 @@ bool ExecutionContext::deleteProperty(String *name)
return true;
}
-bool CallContext::needsOwnArguments() const
-{
- QV4::Function *f = d()->v4Function;
- return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0));
-}
-
-void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
-{
- ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m);
-
- if (ctx->outer)
- ctx->outer->mark(engine);
-
- switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx);
- c->exceptionVarName->mark(engine);
- c->exceptionValue.mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_WithContext: {
- WithContext::Data *w = static_cast<WithContext::Data *>(ctx);
- if (w->withObject)
- w->withObject->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx);
- g->global->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_SimpleCallContext:
- break;
- case Heap::ExecutionContext::Type_CallContext: {
- QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- Q_ASSERT(c->v4Function);
- ctx->callData->thisObject.mark(engine);
- for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg)
- ctx->callData->args[arg].mark(engine);
- for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local)
- c->locals[local].mark(engine);
- if (c->activation)
- c->activation->mark(engine);
- if (c->function)
- c->function->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_QmlContext: {
- QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx);
- g->qml->mark(engine);
- break;
- }
- }
-}
-
// Do a standard call with this execution context as the outer scope
void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f)
{
@@ -320,7 +267,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function
Scoped<CallContext> ctx(scope, newCallContext(function, callData));
if (f)
- ctx->d()->function = f->d();
+ ctx->d()->function.set(scope.engine, f->d());
scope.engine->pushContext(ctx);
scope.result = Q_V4_PROFILE(scope.engine, function);
@@ -336,7 +283,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine);
+ SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine);
ctx->strictMode = function->isStrict();
ctx->callData = callData;
@@ -344,8 +291,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ctx->compilationUnit = function->compilationUnit;
ctx->lookups = function->compilationUnit->runtimeLookups;
ctx->constantTable = function->compilationUnit->constants;
- ctx->outer = this->d();
- ctx->locals = scope.alloc(function->compiledFunction->nLocals);
+ ctx->outer.set(scope.engine, this->d());
for (int i = callData->argc; i < (int)function->nFormals; ++i)
callData->args[i] = Encode::undefined();
@@ -371,7 +317,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
case Heap::ExecutionContext::Type_CatchContext: {
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d())) {
- c->exceptionValue = value;
+ c->exceptionValue.set(scope.engine, value);
return;
}
break;
@@ -390,15 +336,16 @@ void ExecutionContext::setProperty(String *name, const Value &value)
}
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (c->v4Function) {
uint index = c->v4Function->internalClass->find(name);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals) {
c->callData->args[c->v4Function->nFormals - index - 1] = value;
} else {
+ Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext);
index -= c->v4Function->nFormals;
- c->locals[index] = value;
+ static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value);
}
return;
}
@@ -439,13 +386,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (name->equals(d()->engine->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -453,7 +397,6 @@ ReturnedValue ExecutionContext::getProperty(String *name)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -469,17 +412,23 @@ ReturnedValue ExecutionContext::getProperty(String *name)
return v->asReturnedValue();
break;
}
- case Heap::ExecutionContext::Type_CallContext:
- case Heap::ExecutionContext::Type_SimpleCallContext: {
+ case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- uint index = c->v4Function->internalClass->find(name);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ uint index = c->v4Function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext);
+ return c->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+ if (c->v4Function->isNamedExpression()) {
+ if (c->function && name->equals(ScopedString(scope, c->v4Function->name())))
+ return c->function->asReturnedValue();
+ }
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -487,9 +436,6 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -516,13 +462,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (name->equals(d()->engine->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -530,7 +473,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -547,17 +489,22 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
return v->asReturnedValue();
break;
}
- case Heap::ExecutionContext::Type_CallContext:
- case Heap::ExecutionContext::Type_SimpleCallContext: {
+ case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- uint index = c->v4Function->internalClass->find(name);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ uint index = c->v4Function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ return c->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+ if (c->v4Function->isNamedExpression()) {
+ if (c->function && name->equals(ScopedString(scope, c->v4Function->name())))
+ return c->function->asReturnedValue();
+ }
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_SimpleCallContext: {
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -565,9 +512,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -591,7 +535,7 @@ Function *ExecutionContext::getFunction() const
Scope scope(d()->engine);
ScopedContext it(scope, this->d());
for (; it; it = it->d()->outer) {
- if (const CallContext *callCtx = it->asCallContext())
+ if (const SimpleCallContext *callCtx = it->asSimpleCallContext())
return callCtx->d()->v4Function;
else if (it->asCatchContext() || it->asWithContext())
continue; // look in the parent context for a FunctionObject
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index bcfee2e1f8..3b37ea69dc 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -61,18 +61,21 @@ class QQmlContextData;
namespace QV4 {
namespace CompiledData {
-struct CompilationUnit;
+struct CompilationUnitBase;
struct Function;
}
struct Function;
struct Identifier;
struct CallContext;
+struct SimpleCallContext;
struct CatchContext;
struct WithContext;
struct QmlContext;
struct QmlContextWrapper;
+// Attention: Make sure that this structure is the same size on 32-bit and 64-bit
+// architecture or you'll have to change the JIT code.
struct CallData
{
// below is to be compatible with Value. Initialize tag to 0
@@ -91,11 +94,27 @@ struct CallData
Value args[1];
};
+Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
+Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 8);
+Q_STATIC_ASSERT(offsetof(CallData, args) == 16);
+
namespace Heap {
struct QmlContext;
-struct ExecutionContext : Base {
+#define ExecutionContextMembers(class, Member) \
+ Member(class, NoMark, CallData *, callData) \
+ Member(class, NoMark, ExecutionEngine *, engine) \
+ Member(class, Pointer, ExecutionContext *, outer) \
+ Member(class, NoMark, Lookup *, lookups) \
+ Member(class, NoMark, const QV4::Value *, constantTable) \
+ Member(class, NoMark, CompiledData::CompilationUnitBase *, compilationUnit) \
+ Member(class, NoMark, int, lineNumber) // as member of non-pointer size this has to come last to preserve the ability to
+ // translate offsetof of it between 64-bit and 32-bit.
+
+DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
+ DECLARE_MARK_TABLE(ExecutionContext);
+
enum ContextType {
Type_GlobalContext = 0x1,
Type_CatchContext = 0x2,
@@ -114,23 +133,32 @@ struct ExecutionContext : Base {
lineNumber = -1;
}
- CallData *callData;
-
- ExecutionEngine *engine;
- Pointer<ExecutionContext> outer;
- Lookup *lookups;
- const QV4::Value *constantTable;
- CompiledData::CompilationUnit *compilationUnit;
-
- ContextType type : 8;
+ quint8 type;
bool strictMode : 8;
- int lineNumber;
+#if QT_POINTER_SIZE == 8
+ quint8 padding_[6];
+#else
+ quint8 padding_[2];
+#endif
};
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
+Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE);
+
+Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, engine) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, engine) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
-struct CallContext : ExecutionContext {
- static CallContext *createSimpleContext(ExecutionEngine *v4);
- void freeSimpleCallContext();
+#define SimpleCallContextMembers(class, Member) \
+ Member(class, Pointer, Object *, activation) \
+ Member(class, NoMark, QV4::Function *, v4Function)
+
+DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(SimpleCallContext);
void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
{
@@ -139,40 +167,66 @@ struct CallContext : ExecutionContext {
inline unsigned int formalParameterCount() const;
- Pointer<FunctionObject> function;
- QV4::Function *v4Function;
- Value *locals;
- Pointer<Object> activation;
};
-V4_ASSERT_IS_TRIVIAL(CallContext)
+V4_ASSERT_IS_TRIVIAL(SimpleCallContext)
+Q_STATIC_ASSERT(std::is_standard_layout<SimpleCallContextData>::value);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, activation) == 0);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, v4Function) == offsetof(SimpleCallContextData, activation) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContextData) == 2 * QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContext) == sizeof(ExecutionContext) + sizeof(SimpleCallContextData));
+
+#if QT_POINTER_SIZE == 8
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, ValueArray, ValueArray, locals)
+#else
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, NoMark, void *, padding) \
+ Member(class, ValueArray, ValueArray, locals)
+#endif
+
+DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) {
+ DECLARE_MARK_TABLE(CallContext);
+
+ using SimpleCallContext::formalParameterCount;
+};
+
+Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
+Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
+// IMPORTANT: we cannot do offsetof(CallContextData, locals) in the JIT as the offset does not scale with
+// the pointer size. On 32-bit ARM the offset of the ValueArray is aligned to 8 bytes, on 32-bit x86 for
+// example it is not. Therefore we have a padding in place and always have a distance of 8 bytes.
+Q_STATIC_ASSERT(offsetof(CallContextData, locals) == offsetof(CallContextData, function) + 8);
+
+#define GlobalContextMembers(class, Member) \
+ Member(class, Pointer, Object *, global)
+
+DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(GlobalContext);
-struct GlobalContext : ExecutionContext {
void init(ExecutionEngine *engine);
- Pointer<Object> global;
};
V4_ASSERT_IS_TRIVIAL(GlobalContext)
-struct CatchContext : ExecutionContext {
+#define CatchContextMembers(class, Member) \
+ Member(class, Pointer, String *, exceptionVarName) \
+ Member(class, HeapValue, HeapValue, exceptionValue)
+
+DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(CatchContext);
+
void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
- Pointer<String> exceptionVarName;
- Value exceptionValue;
};
V4_ASSERT_IS_TRIVIAL(CatchContext)
-struct WithContext : ExecutionContext {
- void init(ExecutionContext *outerContext, Object *with)
- {
- Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext);
- outer = outerContext;
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
-
- withObject = with;
- }
+#define WithContextMembers(class, Member) \
+ Member(class, Pointer, Object *, withObject)
- Pointer<Object> withObject;
+DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(WithContext);
+
+ void init(ExecutionContext *outerContext, Object *with);
};
V4_ASSERT_IS_TRIVIAL(WithContext)
@@ -200,15 +254,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ReturnedValue getPropertyAndBase(String *name, Value *base);
bool deleteProperty(String *name);
- inline CallContext *asCallContext();
- inline const CallContext *asCallContext() const;
+ inline SimpleCallContext *asSimpleCallContext();
+ inline const SimpleCallContext *asSimpleCallContext() const;
inline const CatchContext *asCatchContext() const;
inline const WithContext *asWithContext() const;
Function *getFunction() const;
- static void markObjects(Heap::Base *m, ExecutionEngine *e);
-
Value &thisObject() const {
return d()->callData->thisObject;
}
@@ -226,9 +278,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
void simpleCall(Scope &scope, CallData *callData, QV4::Function *function);
};
-struct Q_QML_EXPORT CallContext : public ExecutionContext
+struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext
{
- V4_MANAGED(CallContext, ExecutionContext)
+ V4_MANAGED(SimpleCallContext, ExecutionContext)
// formals are in reverse order
Identifier * const *formals() const;
@@ -237,14 +289,17 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
unsigned int variableCount() const;
inline ReturnedValue argument(int i) const;
- bool needsOwnArguments() const;
-
};
-inline ReturnedValue CallContext::argument(int i) const {
+inline ReturnedValue SimpleCallContext::argument(int i) const {
return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
+struct Q_QML_EXPORT CallContext : public SimpleCallContext
+{
+ V4_MANAGED(CallContext, SimpleCallContext)
+};
+
struct GlobalContext : public ExecutionContext
{
V4_MANAGED(GlobalContext, ExecutionContext)
@@ -261,14 +316,14 @@ struct WithContext : public ExecutionContext
V4_MANAGED(WithContext, ExecutionContext)
};
-inline CallContext *ExecutionContext::asCallContext()
+inline SimpleCallContext *ExecutionContext::asSimpleCallContext()
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<SimpleCallContext *>(this) : 0;
}
-inline const CallContext *ExecutionContext::asCallContext() const
+inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const SimpleCallContext *>(this) : 0;
}
inline const CatchContext *ExecutionContext::asCatchContext() const
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index a810b38f24..f1405e08ee 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -73,7 +73,7 @@ void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
- a->d()->buffer = buffer->d();
+ a->d()->buffer.set(scope.engine, buffer->d());
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
scope.result = a.asReturnedValue();
@@ -84,13 +84,6 @@ void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-
-void DataView::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- DataView::Data *v = static_cast<DataView::Data *>(that);
- v->buffer->mark(e);
-}
-
void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 11cc0a6bd9..5c50df4655 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -63,11 +63,14 @@ struct DataViewCtor : FunctionObject {
void init(QV4::ExecutionContext *scope);
};
-struct DataView : Object {
+#define DataViewMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset)
+
+DECLARE_HEAP_OBJECT(DataView, Object) {
+ DECLARE_MARK_TABLE(DataView);
void init() { Object::init(); }
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
};
}
@@ -84,8 +87,6 @@ struct DataView : Object
{
V4_OBJECT2(DataView, Object)
V4_PROTOTYPE(dataViewPrototype)
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct DataViewPrototype: Object
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 3b589a41f1..8e2eec03d2 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -61,8 +61,9 @@ namespace Debugging {
#ifdef QT_NO_QML_DEBUGGER
-struct Debugger
+class Debugger
{
+public:
bool pauseAtNextOpportunity() const { return false; }
void maybeBreakAtInstruction() {}
void enteringFunction() {}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 39b433e5f9..679cd41ce0 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -130,10 +130,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
- : current(0)
- , hasException(false)
- , callDepth(0)
- , memoryManager(new QV4::MemoryManager(this))
+ : callDepth(0)
, executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
, currentContext(0)
@@ -151,6 +148,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_profiler(0)
#endif
{
+ writeBarrierActive = true;
+
+ memoryManager = new QV4::MemoryManager(this);
+
if (maxCallDepth == -1) {
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
@@ -398,7 +399,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
//
// set up the global object
//
- rootContext()->d()->global = globalObject->d();
+ rootContext()->d()->global.set(scope.engine, globalObject->d());
rootContext()->d()->callData->thisObject = globalObject;
Q_ASSERT(globalObject->d()->vtable());
@@ -600,12 +601,14 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
d->init();
- d->alloc = length;
d->type = Heap::ArrayData::Simple;
d->offset = 0;
- d->len = length;
- memcpy(&d->arrayData, values, length*sizeof(Value));
- a->d()->arrayData = d;
+ d->values.alloc = length;
+ d->values.size = length;
+ // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
+ // the parent object
+ memcpy(&d->values.values, values, length*sizeof(Value));
+ a->d()->arrayData.set(this, d);
a->setArrayLengthUnchecked(length);
}
return a->d();
@@ -886,7 +889,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
QUrl base;
ExecutionContext *c = currentContext;
while (c) {
- CallContext *callCtx = c->asCallContext();
+ SimpleCallContext *callCtx = c->asSimpleCallContext();
if (callCtx && callCtx->d()->v4Function) {
base.setUrl(callCtx->d()->v4Function->sourceFile());
break;
@@ -929,23 +932,25 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
}
-void ExecutionEngine::markObjects()
+void ExecutionEngine::markObjects(bool incremental)
{
- identifierTable->mark(this);
+ if (!incremental) {
+ identifierTable->mark(this);
- for (int i = 0; i < nArgumentsAccessors; ++i) {
- const Property &pd = argumentsAccessors[i];
- if (Heap::FunctionObject *getter = pd.getter())
- getter->mark(this);
- if (Heap::FunctionObject *setter = pd.setter())
- setter->mark(this);
- }
+ for (int i = 0; i < nArgumentsAccessors; ++i) {
+ const Property &pd = argumentsAccessors[i];
+ if (Heap::FunctionObject *getter = pd.getter())
+ getter->mark(this);
+ if (Heap::FunctionObject *setter = pd.setter())
+ setter->mark(this);
+ }
- classPool->markObjects(this);
+ classPool->markObjects(this);
- for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
- it != end; ++it)
- (*it)->markObjects(this);
+ for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
+ it != end; ++it)
+ (*it)->markObjects(this);
+ }
}
ReturnedValue ExecutionEngine::throwError(const Value &value)
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 69aa389c44..1160d69c6c 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -54,7 +54,6 @@
#include "private/qv4isel_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
-#include "qv4runtimeapi_p.h"
#include <private/qintrusivelist_p.h>
#ifndef V4_BOOTSTRAP
@@ -88,7 +87,7 @@ struct CompilationUnit;
struct InternalClass;
struct InternalClassPool;
-struct Q_QML_EXPORT ExecutionEngine
+struct Q_QML_EXPORT ExecutionEngine : public EngineBase
{
private:
static qint32 maxCallDepth;
@@ -97,13 +96,8 @@ private:
friend struct ExecutionContext;
friend struct Heap::ExecutionContext;
public:
- Heap::ExecutionContext *current;
-
- Value *jsStackTop;
- quint32 hasException;
qint32 callDepth;
- MemoryManager *memoryManager;
ExecutableAllocator *executableAllocator;
ExecutableAllocator *regExpAllocator;
QScopedPointer<EvalISelFactory> iselFactory;
@@ -112,8 +106,6 @@ public:
Value *jsStackLimit;
- Runtime runtime;
-
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
enum { JSStackLimit = 4*1024*1024 };
@@ -126,7 +118,7 @@ public:
}
Heap::Base *popForGC() {
--jsStackTop;
- return jsStackTop->heapObject();
+ return jsStackTop->m();
}
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
@@ -454,7 +446,7 @@ public:
void requireArgumentsAccessors(int n);
- void markObjects();
+ void markObjects(bool incremental);
void initRootContext();
@@ -554,13 +546,19 @@ inline
void Heap::Base::mark(QV4::ExecutionEngine *engine)
{
Q_ASSERT(inUse());
- if (isMarked())
- return;
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ size_t index = h - c->realBase();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
+ quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
+ quintptr bit = Chunk::bitForIndex(index);
+ if (!(*bitmap & bit)) {
#ifndef QT_NO_DEBUG
- engine->assertObjectBelongsToEngine(*this);
+ engine->assertObjectBelongsToEngine(*this);
#endif
- setMarkBit();
- engine->pushForGC(this);
+ *bitmap |= bit;
+ engine->pushForGC(this);
+ }
}
inline void Value::mark(ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index f290bc5136..58742a0b84 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -78,10 +78,10 @@ void Heap::ErrorObject::init()
if (internalClass == scope.engine->errorProtoClass)
return;
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::undefinedValue());
}
void Heap::ErrorObject::init(const Value &message, ErrorType t)
@@ -92,17 +92,17 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t)
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
@@ -113,8 +113,8 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
StackFrame frame;
@@ -124,12 +124,12 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
e->d()->stackTrace->prepend(frame);
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
@@ -168,19 +168,11 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack = scope.engine->newString(trace);
+ This->d()->stack.set(scope.engine, scope.engine->newString(trace));
}
scope.result = This->d()->stack;
}
-void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that);
- if (This->stack)
- This->stack->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(ErrorObject);
DEFINE_OBJECT_VTABLE(SyntaxErrorObject);
@@ -327,9 +319,9 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj));
ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
- *obj->propertyData(Index_Constructor) = ctor;
- *obj->propertyData(Index_Message) = engine->id_empty();
- *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t)));
+ obj->setProperty(Index_Constructor, ctor->d());
+ obj->setProperty(Index_Message, engine->id_empty()->d());
+ obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t))));
if (t == Heap::ErrorObject::Error)
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 9ba9f05234..5afd9efcba 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -62,7 +62,12 @@ struct SyntaxErrorObject;
namespace Heap {
-struct ErrorObject : Object {
+
+#define ErrorObjectMembers(class, Member) \
+ Member(class, Pointer, String *, stack)
+
+DECLARE_HEAP_OBJECT(ErrorObject, Object) {
+ DECLARE_MARK_TABLE(ErrorObject);
enum ErrorType {
Error,
EvalError,
@@ -72,6 +77,8 @@ struct ErrorObject : Object {
TypeError,
URIError
};
+ StackTrace *stackTrace;
+ ErrorType errorType;
void init();
void init(const Value &message, ErrorType t = Error);
@@ -80,10 +87,6 @@ struct ErrorObject : Object {
delete stackTrace;
Object::destroy();
}
-
- ErrorType errorType;
- StackTrace *stackTrace;
- Pointer<String> stack;
};
struct EvalErrorObject : ErrorObject {
@@ -173,7 +176,6 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 358c2d079c..ed9e3699f2 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -83,10 +83,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
- activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject));
-
- canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) &&
- !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression();
+ canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall;
}
Function::~Function()
@@ -118,7 +115,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable);
- activationRequired = true;
+ canUseSimpleCall = false;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 54d0528c42..b11c8af94a 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -69,7 +69,6 @@ struct Q_QML_EXPORT Function {
// first nArguments names in internalClass are the actual arguments
InternalClass *internalClass;
uint nFormals;
- bool activationRequired;
bool hasQmlDependencies;
bool canUseSimpleCall;
@@ -89,9 +88,6 @@ struct Q_QML_EXPORT Function {
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
- inline bool needsActivation() const
- { return activationRequired; }
-
inline bool canUseSimpleFunction() const { return canUseSimpleCall; }
QQmlSourceLocation sourceLocation() const
@@ -102,7 +98,7 @@ struct Q_QML_EXPORT Function {
};
-inline unsigned int Heap::CallContext::formalParameterCount() const
+inline unsigned int Heap::SimpleCallContext::formalParameterCount() const
{
return v4Function ? v4Function->nFormals : 0;
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index e9431ed25e..5c8f03dc72 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -69,11 +69,13 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
+Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable);
+
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
{
Object::init();
function = nullptr;
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
f->init(name, createProto);
@@ -84,7 +86,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function
Object::init();
this->function = function;
function->compilationUnit->addref();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedString name(s, function->name());
ScopedFunctionObject f(s, this);
@@ -102,9 +104,9 @@ void Heap::FunctionObject::init()
{
Object::init();
function = nullptr;
- this->scope = internalClass->engine->rootContext()->d();
+ this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
- *propertyData(Index_Prototype) = Encode::undefined();
+ setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
@@ -124,10 +126,10 @@ void FunctionObject::init(String *n, bool createProto)
if (createProto) {
ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype()));
Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
- *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue();
- *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue();
+ proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d());
+ setProperty(Heap::FunctionObject::Index_Prototype, proto);
} else {
- *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined();
+ setProperty(Heap::FunctionObject::Index_Prototype, Primitive::undefinedValue());
}
if (n)
@@ -149,15 +151,6 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *)
scope.result = Encode::undefined();
}
-void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::FunctionObject *o = static_cast<Heap::FunctionObject *>(that);
- if (o->scope)
- o->scope->mark(e);
-
- Object::markObjects(that, e);
-}
-
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function);
@@ -309,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call
cData->args[i] = Primitive::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->len : 0;
+ uint alen = sad ? sad->values.size : 0;
if (alen > len)
alen = len;
for (uint i = 0; i < alen; ++i)
@@ -352,8 +345,9 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
if (callData->argc > 1) {
boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
- boundArgs->d()->size = callData->argc - 1;
- memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
+ boundArgs->d()->values.size = callData->argc - 1;
+ for (uint i = 0; i < static_cast<uint>(callData->argc - 1); ++i)
+ boundArgs->set(scope.engine, i, callData->args[i + 1]);
}
ExecutionContext *global = scope.engine->rootContext();
@@ -420,7 +414,7 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
{
FunctionObject::init();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
this->function = function;
function->compilationUnit->addref();
@@ -433,7 +427,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
ScopedString name(s, function->name());
f->init(name, true);
Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length);
- *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount());
+ setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount()));
if (scope->d()->strictMode) {
ScopedProperty pd(s);
@@ -479,7 +473,7 @@ void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callD
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
+ SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx->callData = callData;
v4->pushContext(ctx);
@@ -526,7 +520,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
+ SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx->callData = callData;
v4->pushContext(ctx);
@@ -543,12 +537,12 @@ DEFINE_OBJECT_VTABLE(BoundFunction);
void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
const Value &boundThis, QV4::MemberData *boundArgs)
{
+ Scope s(scope);
Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
- this->target = target->d();
- this->boundArgs = boundArgs ? boundArgs->d() : 0;
- this->boundThis = boundThis;
+ this->target.set(s.engine, target->d());
+ this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0);
+ this->boundThis.set(scope->engine(), boundThis);
- Scope s(scope);
ScopedObject f(s, this);
ScopedValue l(s, target->get(s.engine->id_length()));
@@ -606,14 +600,3 @@ void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
ScopedFunctionObject t(scope, f->target());
t->construct(scope, callData);
}
-
-void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that);
- if (o->target)
- o->target->mark(e);
- o->boundThis.mark(e);
- if (o->boundArgs)
- o->boundArgs->mark(e);
- FunctionObject::markObjects(that, e);
-}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 45d7485f1b..d8929026ca 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -65,7 +65,12 @@ struct BuiltinFunction;
namespace Heap {
-struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
+#define FunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(FunctionObject, Object) {
+ DECLARE_MARK_TABLE(FunctionObject);
enum {
Index_Prototype = 0,
Index_ProtoConstructor = 0
@@ -79,12 +84,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
- bool needsActivation() const { return function ? function->needsActivation() : false; }
-
- const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast<QV4::Object>(); }
- Pointer<ExecutionContext> scope;
- Function *function;
+ const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->as<QV4::Object>(); }
};
struct FunctionCtor : FunctionObject {
@@ -119,11 +120,15 @@ struct ScriptFunction : FunctionObject {
void init(QV4::ExecutionContext *scope, Function *function);
};
-struct BoundFunction : FunctionObject {
+#define BoundFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, target) \
+ Member(class, HeapValue, HeapValue, boundThis) \
+ Member(class, Pointer, MemberData *, boundArgs)
+
+DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(BoundFunction);
+
void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
- Pointer<FunctionObject> target;
- Value boundThis;
- Pointer<MemberData> boundArgs;
};
}
@@ -154,14 +159,11 @@ struct Q_QML_EXPORT FunctionObject: Object {
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
- bool needsActivation() const { return d()->needsActivation(); }
bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
QQmlSourceLocation sourceLocation() const;
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
@@ -259,8 +261,6 @@ struct BoundFunction: FunctionObject {
static void construct(const Managed *, Scope &scope, CallData *d);
static void call(const Managed *that, Scope &scope, CallData *dd);
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index b0d14fc2b4..0665295287 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -89,8 +89,6 @@ inline bool signbit(double d) { return _copysign(1.0, d) < 0; }
inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#endif
-#define qOffsetOf(s, m) ((size_t)((((char *)&(((s *)64)->m)) - 64)))
-
// Decide whether to enable or disable the JIT
// White list architectures
@@ -184,6 +182,7 @@ namespace Heap {
struct DataView;
struct TypedArray;
+ template <typename T, size_t> struct Pointer;
}
class MemoryManager;
@@ -198,9 +197,12 @@ struct ScriptFunction;
struct InternalClass;
struct Property;
struct Value;
+template<size_t> struct HeapValue;
+template<size_t> struct ValueArray;
struct Lookup;
struct ArrayData;
struct VTable;
+struct Function;
struct BooleanObject;
struct NumberObject;
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 3def6defbf..d3ef238716 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -81,6 +81,7 @@ void IdentifierTable::addEntry(Heap::String *str)
str->identifier = new Identifier;
str->identifier->string = str->toQString();
str->identifier->hashValue = hash;
+ str->setMarkBit();
bool grow = (alloc <= size*2);
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index bac71b4537..9b18a5566e 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -126,26 +126,6 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
Q_ASSERT(extensible);
}
-static void insertHoleIntoPropertyData(Object *object, int idx)
-{
- int icSize = object->internalClass()->size;
- int from = idx;
- int to = from + 1;
- if (from < icSize)
- memmove(object->propertyData(to), object->propertyData(from),
- (icSize - from - 1) * sizeof(Value));
-}
-
-static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
-{
- int delta = (accessor ? 2 : 1);
- int oldSize = object->internalClass()->size + delta;
- int to = idx;
- int from = to + delta;
- if (from < oldSize)
- memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
-}
-
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
{
uint idx;
@@ -157,10 +137,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu
object->setInternalClass(newClass);
if (newClass->size > oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size + 1);
- insertHoleIntoPropertyData(object, idx + 1);
+ object->d()->memberData->values.insertData(newClass->engine, idx + 1, Primitive::emptyValue());
} else if (newClass->size < oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size - 1);
- removeFromPropertyData(object, idx + 1);
+ object->d()->memberData->values.removeData(newClass->engine, idx + 1);
}
}
@@ -318,7 +298,7 @@ void InternalClass::removeMember(Object *object, Identifier *id)
Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1));
// remove the entry in the property data
- removeFromPropertyData(object, propIdx, accessor);
+ object->d()->memberData->values.removeData(oldClass->engine, propIdx, accessor ? 2 : 1);
t.lookup = object->internalClass();
Q_ASSERT(t.lookup);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 52ed449664..11d7767e05 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -59,7 +59,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -72,7 +72,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -94,7 +94,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -107,7 +107,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -116,20 +116,20 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return Primitive::emptyValue().asReturnedValue();
}
-ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (object.isObject() && index.asArrayIndex(idx)) {
l->indexedGetter = indexedGetterObjectInt;
- return indexedGetterObjectInt(l, object, index);
+ return indexedGetterObjectInt(l, engine, object, index);
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
Q_UNUSED(l);
- Scope scope(l->engine);
+ Scope scope(engine);
uint idx = 0;
bool isInt = index.asArrayIndex(idx);
@@ -147,7 +147,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
if (object.isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
- return l->engine->throwTypeError(message);
+ return engine->throwTypeError(message);
}
o = RuntimeHelpers::convertToObject(scope.engine, object);
@@ -173,7 +173,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
}
-ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -182,7 +182,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len)
+ if (idx < s->values.size)
if (!s->data(idx).isEmpty())
return s->data(idx).asReturnedValue();
}
@@ -190,25 +190,25 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
}
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
if (Object *o = object.objectValue()) {
uint idx;
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) {
l->indexedSetter = indexedSetterObjectInt;
- indexedSetterObjectInt(l, object, index, v);
+ indexedSetterObjectInt(l, engine, object, index, v);
return;
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
-void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value)
+void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
- Scope scope(l->engine);
+ Scope scope(engine);
ScopedObject o(scope, object.toObject(scope.engine));
if (scope.engine->hasException)
return;
@@ -217,8 +217,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
if (index.asArrayIndex(idx)) {
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -230,7 +230,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
o->put(name, value);
}
-void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -239,15 +239,15 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = v;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, v);
return;
}
}
}
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object)
@@ -772,7 +772,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
{
Object *o = object.as<Object>();
if (o && o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(engine, l->index, value);
return;
}
@@ -785,7 +785,7 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co
if (o && o->internalClass() == l->classList[0]) {
if (!o->prototype()) {
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -801,7 +801,7 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co
Heap::Object *p = o->prototype();
if (p && p->internalClass == l->classList[1]) {
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -819,7 +819,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
p = p->prototype;
if (p && p->internalClass == l->classList[2]) {
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -834,11 +834,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c
Object *o = object.as<Object>();
if (o) {
if (o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
if (o->internalClass() == l->classList[1]) {
- *o->propertyData(l->index2) = value;
+ o->setProperty(l->index2, value);
return;
}
}
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index c5ee92fedd..daf3c71e27 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -67,14 +67,13 @@ namespace QV4 {
struct Lookup {
enum { Size = 4 };
union {
- ReturnedValue (*indexedGetter)(Lookup *l, const Value &object, const Value &index);
- void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v);
+ ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
union {
- ExecutionEngine *engine;
InternalClass *classList[Size];
struct {
void *dummy0;
@@ -90,13 +89,13 @@ struct Lookup {
uint index;
uint nameIndex;
- static ReturnedValue indexedGetterGeneric(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterFallback(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- static void indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v);
- static void indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value);
- static void indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value);
+ static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -141,6 +140,12 @@ struct Lookup {
};
+Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
+// Ensure that these offsets are always at this point to keep generated code compatible
+// across 32-bit and 64-bit (matters when cross-compiling).
+Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0);
+Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 3a84a83b9c..1b43fd86e8 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -47,6 +47,7 @@ using namespace QV4;
const VTable Managed::static_vtbl =
{
0,
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 5c764e7ff0..3dc54b13da 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -53,6 +53,7 @@
#include "qv4global_p.h"
#include "qv4value_p.h"
#include <private/qv4heap_p.h>
+#include <private/qv4writebarrier_p.h>
QT_BEGIN_NAMESPACE
@@ -91,6 +92,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
dptr->_checkIsInitialized(); \
return dptr; \
} \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; \
V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass)
#define V4_MANAGED(DataClass, superClass) \
@@ -129,6 +131,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
{ \
parentVTable, \
+ markTable, \
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
@@ -139,7 +142,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
classname::MyType, \
#classname, \
Q_VTABLE_FUNCTION(classname, destroy), \
- markObjects, \
+ Q_VTABLE_FUNCTION(classname, markObjects), \
isEqualTo \
}
@@ -206,6 +209,7 @@ public:
bool markBit() const { return d()->isMarked(); }
static void destroy(Heap::Base *) {}
+ static void markObjects(Heap::Base *, ExecutionEngine *) {}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
return m();
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index db45c77472..8f862d63e9 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -45,24 +45,19 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(MemberData);
-void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::MemberData *m = static_cast<Heap::MemberData *>(that);
- for (uint i = 0; i < m->size; ++i)
- m->data[i].mark(e);
-}
-
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
- Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(!old || old->values.size < n);
Q_ASSERT(n);
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
if (old)
- memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
+ // no write barrier required here
+ memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value));
else
m->init();
- m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.size = m->values.alloc;
return m;
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index 5c89dfe8ec..fbe66757e0 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -59,12 +59,11 @@ namespace QV4 {
namespace Heap {
-struct MemberData : Base {
- union {
- uint size;
- double _dummy;
- };
- Value data[1];
+#define MemberDataMembers(class, Member) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(MemberData, Base) {
+ DECLARE_MARK_TABLE(MemberData);
};
V4_ASSERT_IS_TRIVIAL(MemberData)
@@ -74,14 +73,26 @@ struct MemberData : Managed
{
V4_MANAGED(MemberData, Managed)
- Value &operator[] (uint idx) { return d()->data[idx]; }
- const Value *data() const { return d()->data; }
- Value *data() { return d()->data; }
- inline uint size() const { return d()->size; }
+ struct Index {
+ Heap::MemberData *memberData;
+ uint index;
- static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
+ void set(ExecutionEngine *e, Value newVal) {
+ memberData->values.set(e, index, newVal);
+ }
+ const Value *operator->() const { return &memberData->values[index]; }
+ const Value &operator*() const { return memberData->values[index]; }
+ bool isNull() const { return !memberData; }
+ };
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ const Value &operator[] (uint idx) const { return d()->values[idx]; }
+ const Value *data() const { return d()->values.data(); }
+ void set(ExecutionEngine *e, uint index, Value v) { d()->values.set(e, index, v); }
+ void set(ExecutionEngine *e, uint index, Heap::Base *b) { d()->values.set(e, index, b); }
+
+ inline uint size() const { return d()->values.size; }
+
+ static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
};
}
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index dd3bbccde3..d400c2ae64 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -62,8 +62,8 @@ void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
bool hasMD = d()->memberData != nullptr;
- if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size))
- d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
+ if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size))
+ d()->memberData.set(engine(), MemberData::allocate(ic->engine, ic->size, d()->memberData));
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -76,9 +76,9 @@ void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) con
void Object::setProperty(uint index, const Property *p)
{
- *propertyData(index) = p->value;
+ setProperty(index, p->value);
if (internalClass()->propertyData.at(index).isAccessor())
- *propertyData(index + SetterOffset) = p->set;
+ setProperty(index + SetterOffset, p->set);
}
bool Object::setPrototype(Object *proto)
@@ -89,7 +89,7 @@ bool Object::setPrototype(Object *proto)
return false;
pp = pp->prototype;
}
- d()->prototype = proto ? proto->d() : 0;
+ d()->prototype.set(engine(), proto ? proto->d() : 0);
return true;
}
@@ -117,7 +117,7 @@ bool Object::putValue(uint memberIndex, const Value &value)
PropertyAttributes attrs = ic->propertyData[memberIndex];
if (attrs.isAccessor()) {
- FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
+ const FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
if (set) {
Scope scope(ic->engine);
ScopedFunctionObject setter(scope, set);
@@ -133,7 +133,7 @@ bool Object::putValue(uint memberIndex, const Value &value)
if (!attrs.isWritable())
goto reject;
- *propertyData(memberIndex) = value;
+ setProperty(memberIndex, value);
return true;
reject:
@@ -258,28 +258,16 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value
insertMember(name, value, Attr_ReadOnly_ButConfigurable);
}
-void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::Object *o = static_cast<Heap::Object *>(that);
-
- if (o->memberData)
- o->memberData->mark(e);
- if (o->arrayData)
- o->arrayData->mark(e);
- if (o->prototype)
- o->prototype->mark(e);
-}
-
void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
{
uint idx;
InternalClass::addMember(this, s, attributes, &idx);
if (attributes.isAccessor()) {
- *propertyData(idx + GetterOffset) = p->value;
- *propertyData(idx + SetterOffset) = p->set;
+ setProperty(idx + GetterOffset, p->value);
+ setProperty(idx + SetterOffset, p->set);
} else {
- *propertyData(idx) = p->value;
+ setProperty(idx, p->value);
}
}
@@ -308,12 +296,9 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p
void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
{
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
- if (pd) {
- *attrs = arrayData()->attributes(index);
- if (p)
- p->copy(pd, *attrs);
- return;
+ if (arrayData()) {
+ if (arrayData()->getProperty(index, p, attrs))
+ return;
}
if (isStringObject()) {
*attrs = Attr_NotConfigurable|Attr_NotWritable;
@@ -328,7 +313,7 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
}
// Section 8.12.2
-Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
+MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
@@ -337,36 +322,38 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
uint idx = o->internalClass->find(name);
if (idx < UINT_MAX) {
*attrs = o->internalClass->propertyData[idx];
- return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx);
+ return MemberData::Index{ o->memberData, attrs->isAccessor() ? idx + SetterOffset : idx };
}
o = o->prototype;
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
-Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
Heap::Object *o = d();
while (o) {
- Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0;
- if (p) {
- *attrs = o->arrayData->attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ if (o->arrayData) {
+ uint idx = o->arrayData->mappedIndex(index);
+ if (idx != UINT_MAX) {
+ *attrs = o->arrayData->attributes(index);
+ return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx };
+ }
}
if (o->vtable()->type == Type_StringObject) {
if (index < static_cast<const Heap::StringObject *>(o)->length()) {
// this is an evil hack, but it works, as the method is only ever called from putIndexed,
// where we don't use the returned pointer there for non writable attributes
*attrs = (Attr_NotWritable|Attr_NotConfigurable);
- return reinterpret_cast<Value *>(0x1);
+ return { reinterpret_cast<Heap::ArrayData *>(0x1), 0 };
}
}
o = o->prototype;
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
bool Object::hasProperty(String *name) const
@@ -539,7 +526,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
l->classList[0] = o->internalClass();
l->index = idx;
l->setter = Lookup::setter0;
- *o->propertyData(idx) = value;
+ o->setProperty(idx, value);
return;
}
@@ -594,7 +581,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
int k = it->arrayNode->key();
uint pidx = it->arrayNode->value;
Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
- Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx);
+ const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx);
it->arrayNode = it->arrayNode->nextNode();
PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
@@ -609,9 +596,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
it->arrayIndex = UINT_MAX;
}
// dense arrays
- while (it->arrayIndex < o->d()->arrayData->len) {
+ while (it->arrayIndex < o->d()->arrayData->values.size) {
Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Value &val = sa->data(it->arrayIndex);
+ const Value &val = sa->data(it->arrayIndex);
PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
++it->arrayIndex;
if (!val.isEmpty()
@@ -677,15 +664,14 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
{
- Property *pd = 0;
PropertyAttributes attrs;
Scope scope(engine());
ScopedObject o(scope, this);
+ ScopedProperty pd(scope);
+ bool exists = false;
while (o) {
- Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
- if (p) {
- pd = p;
- attrs = o->arrayData()->attributes(index);
+ if (o->arrayData() && o->arrayData()->getProperty(index, pd, &attrs)) {
+ exists = true;
break;
}
if (o->isStringObject()) {
@@ -700,7 +686,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
o = o->prototype();
}
- if (pd) {
+ if (exists) {
if (hasProperty)
*hasProperty = true;
return getValue(pd->value, attrs);
@@ -715,43 +701,44 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
bool Object::internalPut(String *name, const Value &value)
{
- if (internalClass()->engine->hasException)
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
return false;
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return putIndexed(idx, value);
- name->makeIdentifier(engine());
+ name->makeIdentifier(engine);
+ MemberData::Index memberIndex{0, 0};
uint member = internalClass()->find(name);
- Value *v = 0;
PropertyAttributes attrs;
if (member < UINT_MAX) {
attrs = internalClass()->propertyData[member];
- v = propertyData(attrs.isAccessor() ? member + SetterOffset : member);
+ memberIndex = { d()->memberData, (attrs.isAccessor() ? member + SetterOffset : member) };
}
// clause 1
- if (v) {
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (memberIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else if (isArrayObject() && name->equals(engine()->id_length())) {
+ else if (isArrayObject() && name->equals(engine->id_length())) {
bool ok;
uint l = value.asArrayLength(&ok);
if (!ok) {
- engine()->throwRangeError(value);
+ engine->throwRangeError(value);
return false;
}
ok = setArrayLength(l);
if (!ok)
goto reject;
} else {
- *v = value;
+ memberIndex.set(engine, value);
}
return true;
} else if (!prototype()) {
@@ -759,10 +746,11 @@ bool Object::internalPut(String *name, const Value &value)
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) {
+ Scope scope(engine);
+ memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs);
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!memberIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -775,11 +763,11 @@ bool Object::internalPut(String *name, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!memberIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(memberIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *memberIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
@@ -792,49 +780,51 @@ bool Object::internalPut(String *name, const Value &value)
reject:
// ### this should be removed once everything is ported to use Object::set()
- if (engine()->current->strictMode) {
+ if (engine->current->strictMode) {
QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
- engine()->throwTypeError(message);
+ engine->throwTypeError(message);
}
return false;
}
bool Object::internalPutIndexed(uint index, const Value &value)
{
- if (internalClass()->engine->hasException)
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
return false;
PropertyAttributes attrs;
- Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0;
+ ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 };
- if (!v && isStringObject()) {
+ if (arrayIndex.isNull() && isStringObject()) {
if (index < static_cast<StringObject *>(this)->length())
// not writable
goto reject;
}
// clause 1
- if (v) {
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (arrayIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else
- *v = value;
+
+ arrayIndex.set(engine, value);
return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) {
+ Scope scope(engine);
+ arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs);
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!arrayIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -847,11 +837,11 @@ bool Object::internalPutIndexed(uint index, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!arrayIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(arrayIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *arrayIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
@@ -864,8 +854,8 @@ bool Object::internalPutIndexed(uint index, const Value &value)
reject:
// ### this should be removed once everything is ported to use Object::setIndexed()
- if (engine()->current->strictMode)
- engine()->throwTypeError();
+ if (engine->current->strictMode)
+ engine->throwTypeError();
return false;
}
@@ -995,8 +985,8 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
// Clause 1
if (arrayData()) {
- hasProperty = arrayData()->getProperty(index);
- if (!hasProperty && isStringObject())
+ hasProperty = arrayData()->mappedIndex(index) != UINT_MAX;
+ if (!hasProperty && isStringObject())
hasProperty = (index < static_cast<StringObject *>(this)->length());
}
@@ -1108,7 +1098,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
setProperty(index, current);
} else {
setArrayAttributes(index, cattrs);
- arrayData()->setProperty(index, current);
+ arrayData()->setProperty(scope.engine, index, current);
}
return true;
reject:
@@ -1144,7 +1134,8 @@ void Object::copyArrayData(Object *other)
;
} else {
Q_ASSERT(!arrayData() && other->arrayData());
- ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false);
+ ArrayData::realloc(this, static_cast<ArrayData::Type>(other->d()->arrayData->type),
+ other->d()->arrayData->values.alloc, false);
if (other->arrayType() == Heap::ArrayData::Sparse) {
Heap::ArrayData *od = other->d()->arrayData;
Heap::ArrayData *dd = d()->arrayData;
@@ -1152,10 +1143,11 @@ void Object::copyArrayData(Object *other)
dd->freeList = od->freeList;
} else {
Heap::ArrayData *dd = d()->arrayData;
- dd->len = other->d()->arrayData->len;
+ dd->values.size = other->d()->arrayData->values.size;
dd->offset = other->d()->arrayData->offset;
}
- memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value));
+ // ### need a write barrier
+ memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 0d17afbf41..df9d68525d 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -67,19 +67,24 @@ struct BuiltinFunction;
namespace Heap {
-struct Object : Base {
+#define ObjectMembers(class, Member) \
+ Member(class, NoMark, InternalClass *, internalClass) \
+ Member(class, Pointer, Object *, prototype) \
+ Member(class, Pointer, MemberData *, memberData) \
+ Member(class, Pointer, ArrayData *, arrayData)
+
+DECLARE_HEAP_OBJECT(Object, Base) {
+ DECLARE_MARK_TABLE(Object);
void init() { Base::init(); }
void destroy() { Base::destroy(); }
- const Value *propertyData(uint index) const { return memberData->data + index; }
- Value *propertyData(uint index) { return memberData->data + index; }
-
- InternalClass *internalClass;
- Pointer<Object> prototype;
- Pointer<MemberData> memberData;
- Pointer<ArrayData> arrayData;
+ const Value *propertyData(uint index) const { return memberData->values.data() + index; }
+ void setProperty(ExecutionEngine *e, uint index, Value v) const { memberData->values.set(e, index, v); }
+ void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) const { memberData->values.set(e, index, b); }
};
+Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8)));
+
}
#define V4_OBJECT(superClass) \
@@ -114,7 +119,8 @@ struct Object : Base {
dptr->_checkIsInitialized(); \
return dptr; \
} \
- V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass);
+ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable;
#define V4_INTERNALCLASS(c) \
static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \
@@ -190,13 +196,16 @@ struct Q_QML_EXPORT Object: Managed {
void setInternalClass(InternalClass *ic);
const Value *propertyData(uint index) const { return d()->propertyData(index); }
- Value *propertyData(uint index) { return d()->propertyData(index); }
Heap::ArrayData *arrayData() const { return d()->arrayData; }
- void setArrayData(ArrayData *a) { d()->arrayData = a->d(); }
+ void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); }
void getProperty(uint index, Property *p, PropertyAttributes *attrs) const;
void setProperty(uint index, const Property *p);
+ void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); }
+ void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); }
+ void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(engine, index, v); }
+ void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); }
const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); }
Heap::Object *prototype() const { return d()->prototype; }
@@ -205,8 +214,8 @@ struct Q_QML_EXPORT Object: Managed {
void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0);
void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0);
- Value *getValueOrSetter(String *name, PropertyAttributes *attrs);
- Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs);
+ ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs);
bool hasProperty(String *name) const;
bool hasProperty(uint index) const;
@@ -296,7 +305,7 @@ public:
void push_back(const Value &v);
ArrayData::Type arrayType() const {
- return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple;
+ return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple;
}
// ### remove me
void setArrayType(ArrayData::Type t) {
@@ -400,7 +409,6 @@ public:
inline void call(Scope &scope, CallData *d) const
{ vtable()->call(this, scope, d); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static void construct(const Managed *m, Scope &scope, CallData *);
static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
@@ -465,7 +473,7 @@ struct ArrayObject : Object {
private:
void commonInit()
- { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); }
+ { setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); }
};
}
@@ -505,7 +513,7 @@ struct ArrayObject: Object {
inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject())
- *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l);
+ setProperty(Heap::ArrayObject::LengthPropertyIndex, Primitive::fromUInt32(l));
}
inline void Object::push_back(const Value &v)
@@ -522,7 +530,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
{
// ### Clean up
arrayCreate();
- if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
+ if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) {
initSparseArray();
} else {
arrayData()->vtable()->reallocate(this, index + 1, false);
@@ -537,7 +545,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
inline void Object::arraySet(uint index, const Value &value)
{
arrayCreate();
- if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
+ if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) {
initSparseArray();
}
ArrayData::insert(this, index, &value);
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index f650ffc7b1..2e72c0f13f 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -295,7 +295,7 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->d()->arrayData->alloc; ++i) {
+ for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->d()->arrayData->attrs[i].setConfigurable(false);
}
@@ -320,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->arrayData()->attrs[i].setConfigurable(false);
if (o->arrayData()->attrs[i].isData())
@@ -371,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable()) {
scope.result = Encode(false);
@@ -411,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
scope.result = Encode(false);
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 987c322e47..de82bf835f 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -215,15 +215,6 @@ void PersistentValueStorage::free(Value *v)
freePage(p);
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
-{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
- }
-}
-
void PersistentValueStorage::mark(ExecutionEngine *e)
{
Value *markBase = e->jsStackTop;
@@ -234,7 +225,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e)
if (Managed *m = p->values[i].as<Managed>())
m->mark(e);
}
- drainMarkStack(e, markBase);
+ e->memoryManager->drainMarkStack(markBase);
p = p->header.next;
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index f75ac4d33a..9de597ad0e 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Profiling {
-struct Profiler {};
+class Profiler {};
}
}
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 5069d7690b..2a5b6f7f74 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -78,12 +78,6 @@ struct Property {
attrs->resolve();
}
- static Property genericDescriptor() {
- Property pd;
- pd.value = Primitive::emptyValue();
- return pd;
- }
-
inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const;
inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs);
@@ -99,19 +93,12 @@ struct Property {
}
explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); }
- explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); }
- Property(FunctionObject *getter, FunctionObject *setter) {
- value = reinterpret_cast<Managed *>(getter);
- set = reinterpret_cast<Managed *>(setter);
- }
Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) {
value.setM(reinterpret_cast<Heap::Base *>(getter));
set.setM(reinterpret_cast<Heap::Base *>(setter));
}
- Property &operator=(Value v) { value = v; return *this; }
private:
- Property(const Property &);
- Property &operator=(const Property &);
+ Q_DISABLE_COPY(Property)
};
inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index cdc29c8b9c..56ecc9f682 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -298,14 +298,14 @@ bool QmlContextWrapper::put(Managed *m, String *name, const Value &value)
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
{
Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext);
- outer = outerContext->d();
+ outer.set(engine, outerContext->d());
strictMode = false;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->qml = qml->d();
+ this->qml.set(engine, qml->d());
}
Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction)
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 6e5e743609..835c9236fe 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -77,10 +77,13 @@ struct QmlContextWrapper : Object {
QQmlQPointer<QObject> scopeObject;
};
-struct QmlContext : ExecutionContext {
- void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+#define QmlContextMembers(class, Member) \
+ Member(class, Pointer, QmlContextWrapper *, qml)
+
+DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(QmlContext);
- Pointer<QmlContextWrapper> qml;
+ void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
};
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index c9b4b433bd..4f6c179026 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1704,7 +1704,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->setPropertyCache(valueType->d()->propertyCache());
method->d()->index = index;
- method->d()->valueTypeWrapper = valueType->d();
+ method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
return method.asReturnedValue();
}
@@ -1841,15 +1841,6 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
}
}
-void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that);
- if (This->valueTypeWrapper)
- This->valueTypeWrapper->mark(e);
-
- FunctionObject::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(QObjectMethod);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index d81ef2a680..c031a40211 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -95,7 +95,15 @@ private:
QQmlQPointer<QObject> qObj;
};
-struct QObjectMethod : FunctionObject {
+#define QObjectMethodMembers(class, Member) \
+ Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \
+ Member(class, NoMark, QQmlQPointer<QObject>, qObj) \
+ Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \
+ Member(class, NoMark, int, index)
+
+DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
+ DECLARE_MARK_TABLE(QObjectMethod);
+
void init(QV4::ExecutionContext *scope);
void destroy()
{
@@ -113,18 +121,10 @@ struct QObjectMethod : FunctionObject {
_propertyCache = c;
}
- Pointer<QQmlValueTypeWrapper> valueTypeWrapper;
-
const QMetaObject *metaObject();
QObject *object() const { return qObj.data(); }
void setObject(QObject *o) { qObj = o; }
-private:
- QQmlQPointer<QObject> qObj;
- QQmlPropertyCache *_propertyCache;
-
-public:
- int index;
};
struct QMetaObjectWrapper : FunctionObject {
@@ -243,8 +243,6 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
void callInternal(CallData *callData, Scope &scope) const;
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
};
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 9e94c58432..6778145ff1 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -126,9 +126,3 @@ void Heap::RegExp::destroy()
delete pattern;
Base::destroy();
}
-
-void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Q_UNUSED(that);
- Q_UNUSED(e);
-}
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index d3e63375a5..348af0fb14 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -119,8 +119,6 @@ struct RegExp : public Managed
int captureCount() const { return subPatternCount() + 1; }
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
friend class RegExpCache;
};
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 0894d0c25b..85e37ebe82 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -74,17 +74,17 @@ void Heap::RegExpObject::init()
Object::init();
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false);
- o->d()->global = false;
+ value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false));
+ global = false;
o->initProperties();
}
void Heap::RegExpObject::init(QV4::RegExp *value, bool global)
{
Object::init();
- this->global = global;
- this->value = value->d();
Scope scope(internalClass->engine);
+ this->global = global;
+ this->value.set(scope.engine, value->d());
Scoped<QV4::RegExpObject> o(scope, this);
o->initProperties();
}
@@ -137,14 +137,15 @@ void Heap::RegExpObject::init(const QRegExp &re)
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
+ o->d()->value.set(scope.engine,
+ QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false));
o->initProperties();
}
void RegExpObject::initProperties()
{
- *propertyData(Index_LastIndex) = Primitive::fromInt32(0);
+ setProperty(Index_LastIndex, Primitive::fromInt32(0));
Q_ASSERT(value());
@@ -156,25 +157,10 @@ void RegExpObject::initProperties()
p.replace('/', QLatin1String("\\/"));
}
- *propertyData(Index_Source) = engine()->newString(p);
- *propertyData(Index_Global) = Primitive::fromBoolean(global());
- *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase);
- *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine);
-}
-
-
-void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that);
- if (re->value)
- re->value->mark(e);
- Object::markObjects(that, e);
-}
-
-Value *RegExpObject::lastIndexProperty()
-{
- Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex()));
- return propertyData(0);
+ setProperty(Index_Source, engine()->newString(p));
+ setProperty(Index_Global, Primitive::fromBoolean(global()));
+ setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase));
+ setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine));
}
// Converts a JS RegExp to a QRegExp.
@@ -228,8 +214,8 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
void Heap::RegExpCtor::clearLastMatch()
{
- lastMatch = Primitive::nullValue();
- lastInput = internalClass->engine->id_empty()->d();
+ lastMatch.set(internalClass->engine, Primitive::nullValue());
+ lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d());
lastMatchStart = 0;
lastMatchEnd = 0;
}
@@ -303,15 +289,6 @@ void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that);
- This->lastMatch.mark(e);
- if (This->lastInput)
- This->lastInput->mark(e);
- FunctionObject::markObjects(that, e);
-}
-
void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
{
Scope scope(engine);
@@ -361,9 +338,9 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
RETURN_UNDEFINED();
QString s = str->toQString();
- int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0;
+ int offset = r->global() ? r->lastIndex() : 0;
if (offset < 0 || offset > s.length()) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -374,7 +351,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
regExpCtor->d()->clearLastMatch();
if (result == -1) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -390,17 +367,17 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
- *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result);
- *array->propertyData(Index_ArrayInput) = str;
+ array->setProperty(Index_ArrayIndex, Primitive::fromInt32(result));
+ array->setProperty(Index_ArrayInput, str);
RegExpCtor::Data *dd = regExpCtor->d();
- dd->lastMatch = array;
- dd->lastInput = str->d();
+ dd->lastMatch.set(scope.engine, array);
+ dd->lastInput.set(scope.engine, str->d());
dd->lastMatchStart = matchOffsets[0];
dd->lastMatchEnd = matchOffsets[1];
if (r->global())
- *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]);
+ r->setLastIndex(matchOffsets[1]);
scope.result = array;
}
@@ -432,7 +409,7 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call
scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
- r->d()->value = re->value();
+ r->d()->value.set(scope.engine, re->value());
r->d()->global = re->global();
RETURN_UNDEFINED();
}
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index c0c7dfa78a..0fcfe93135 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -73,21 +73,28 @@ namespace QV4 {
namespace Heap {
-struct RegExpObject : Object {
+#define RegExpObjectMembers(class, Member) \
+ Member(class, Pointer, RegExp *, value) \
+ Member(class, NoMark, bool, global)
+
+DECLARE_HEAP_OBJECT(RegExpObject, Object) {
+ DECLARE_MARK_TABLE(RegExpObject);
+
void init();
void init(QV4::RegExp *value, bool global);
void init(const QRegExp &re);
-
- Pointer<RegExp> value;
- bool global;
};
-struct RegExpCtor : FunctionObject {
+#define RegExpCtorMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, lastMatch) \
+ Member(class, Pointer, String *, lastInput) \
+ Member(class, NoMark, int, lastMatchStart) \
+ Member(class, NoMark, int, lastMatchEnd)
+
+DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
+ DECLARE_MARK_TABLE(RegExpCtor);
+
void init(QV4::ExecutionContext *scope);
- Value lastMatch;
- Pointer<String> lastInput;
- int lastMatchStart;
- int lastMatchEnd;
void clearLastMatch();
};
@@ -121,14 +128,19 @@ struct RegExpObject: Object {
void initProperties();
- Value *lastIndexProperty();
+ int lastIndex() const {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return propertyData(Index_LastIndex)->toInt32();
+ }
+ void setLastIndex(int index) {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return setProperty(Index_LastIndex, Primitive::fromInt32(index));
+ }
+
QRegExp toQRegExp() const;
QString toString() const;
QString source() const;
uint flags() const;
-
-protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpCtor: FunctionObject
@@ -142,7 +154,6 @@ struct RegExpCtor: FunctionObject
static void construct(const Managed *m, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpPrototype: RegExpObject
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6590054bf3..b28a5f9000 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -219,6 +219,14 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2)
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
#ifndef V4_BOOTSTRAP
+
+Runtime::Runtime()
+{
+#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast<void*>(&method_##name);
+FOR_EACH_RUNTIME_METHOD(INIT_METHOD)
+#undef INIT_METHOD
+}
+
void RuntimeHelpers::numberToString(QString *result, double num, int radix)
{
Q_ASSERT(result);
@@ -300,7 +308,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
{
- QV4::Function *clos = engine->current->compilationUnit->runtimeFunctions[functionId];
+ QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeFunctions[functionId];
Q_ASSERT(clos);
return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue();
}
@@ -643,8 +651,8 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
if (idx < UINT_MAX) {
if (o->arrayType() == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->arrayData());
- if (s && idx < s->len && !s->data(idx).isEmpty()) {
- s->data(idx) = value;
+ if (s && idx < s->values.size && !s->data(idx).isEmpty()) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -1301,7 +1309,7 @@ ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *value
ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
{
Scope scope(engine);
- QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId];
+ QV4::InternalClass *klass = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeClasses[classId];
ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype()));
{
@@ -1311,7 +1319,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
}
for (uint i = 0; i < klass->size; ++i)
- *o->propertyData(i) = *args++;
+ o->setProperty(i, *args++);
if (arrayValueCount > 0) {
ScopedValue entry(scope);
@@ -1413,7 +1421,7 @@ ReturnedValue Runtime::method_getQmlContext(NoThrowEngine *engine)
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
{
- return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
+ return static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeRegularExpressions[id].asReturnedValue();
}
ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
@@ -1743,6 +1751,8 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right)
return !left.isNaN();
if (left.type() == right.type()) {
+ if (left.isDouble() && left.doubleValue() == 0 && right.doubleValue() == 0)
+ return true; // this takes care of -0 == +0 (which obviously have different raw values)
if (!left.isManaged())
return false;
if (left.isString() == right.isString())
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 355b7890b6..302facba06 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+typedef uint Bool;
struct NoThrowEngine;
namespace {
@@ -90,256 +91,169 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
};
} // anonymous namespace
-#define RUNTIME_METHOD(returnvalue, name, args) \
- typedef returnvalue (*Method_##name)args; \
- enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \
- static returnvalue method_##name args; \
- const Method_##name name
-
-#define INIT_RUNTIME_METHOD(name) \
- name(method_##name)
+#define FOR_EACH_RUNTIME_METHOD(F) \
+ /* call */ \
+ F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
+ F(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
+ F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \
+ F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \
+ F(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
+ F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
+ F(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData)) \
+ F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \
+ \
+ /* construct */ \
+ F(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
+ F(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
+ F(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
+ F(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
+ F(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \
+ \
+ /* set & get */ \
+ F(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
+ F(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \
+ F(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \
+ F(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \
+ F(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex)) \
+ F(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \
+ \
+ /* typeof */ \
+ F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \
+ F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \
+ F(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \
+ F(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \
+ F(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
+ F(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
+ \
+ /* delete */ \
+ F(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
+ F(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
+ F(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \
+ F(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex)) \
+ \
+ /* exceptions & scopes */ \
+ F(void, throwException, (ExecutionEngine *engine, const Value &value)) \
+ F(ReturnedValue, unwindException, (ExecutionEngine *engine)) \
+ F(void, pushWithScope, (const Value &o, NoThrowEngine *engine)) \
+ F(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex)) \
+ F(void, popScope, (NoThrowEngine *engine)) \
+ \
+ /* closures */ \
+ F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \
+ \
+ /* function header */ \
+ F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \
+ F(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine)) \
+ F(void, convertThisToObject, (ExecutionEngine *engine)) \
+ \
+ /* literals */ \
+ F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \
+ F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)) \
+ F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \
+ \
+ /* foreach */ \
+ F(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in)) \
+ F(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator)) \
+ \
+ /* unary operators */ \
+ F(ReturnedValue, uPlus, (const Value &value)) \
+ F(ReturnedValue, uMinus, (const Value &value)) \
+ F(ReturnedValue, uNot, (const Value &value)) \
+ F(ReturnedValue, complement, (const Value &value)) \
+ F(ReturnedValue, increment, (const Value &value)) \
+ F(ReturnedValue, decrement, (const Value &value)) \
+ \
+ /* binary operators */ \
+ F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ F(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ F(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ F(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ F(ReturnedValue, bitOr, (const Value &left, const Value &right)) \
+ F(ReturnedValue, bitXor, (const Value &left, const Value &right)) \
+ F(ReturnedValue, bitAnd, (const Value &left, const Value &right)) \
+ F(ReturnedValue, sub, (const Value &left, const Value &right)) \
+ F(ReturnedValue, mul, (const Value &left, const Value &right)) \
+ F(ReturnedValue, div, (const Value &left, const Value &right)) \
+ F(ReturnedValue, mod, (const Value &left, const Value &right)) \
+ F(ReturnedValue, shl, (const Value &left, const Value &right)) \
+ F(ReturnedValue, shr, (const Value &left, const Value &right)) \
+ F(ReturnedValue, ushr, (const Value &left, const Value &right)) \
+ F(ReturnedValue, greaterThan, (const Value &left, const Value &right)) \
+ F(ReturnedValue, lessThan, (const Value &left, const Value &right)) \
+ F(ReturnedValue, greaterEqual, (const Value &left, const Value &right)) \
+ F(ReturnedValue, lessEqual, (const Value &left, const Value &right)) \
+ F(ReturnedValue, equal, (const Value &left, const Value &right)) \
+ F(ReturnedValue, notEqual, (const Value &left, const Value &right)) \
+ F(ReturnedValue, strictEqual, (const Value &left, const Value &right)) \
+ F(ReturnedValue, strictNotEqual, (const Value &left, const Value &right)) \
+ \
+ /* comparisons */ \
+ F(Bool, compareGreaterThan, (const Value &l, const Value &r)) \
+ F(Bool, compareLessThan, (const Value &l, const Value &r)) \
+ F(Bool, compareGreaterEqual, (const Value &l, const Value &r)) \
+ F(Bool, compareLessEqual, (const Value &l, const Value &r)) \
+ F(Bool, compareEqual, (const Value &left, const Value &right)) \
+ F(Bool, compareNotEqual, (const Value &left, const Value &right)) \
+ F(Bool, compareStrictEqual, (const Value &left, const Value &right)) \
+ F(Bool, compareStrictNotEqual, (const Value &left, const Value &right)) \
+ \
+ F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \
+ \
+ /* conversions */ \
+ F(Bool, toBoolean, (const Value &value)) \
+ F(ReturnedValue, toDouble, (const Value &value)) \
+ F(int, toInt, (const Value &value)) \
+ F(int, doubleToInt, (const double &d)) \
+ F(unsigned, toUInt, (const Value &value)) \
+ F(unsigned, doubleToUInt, (const double &d)) \
+ \
+ /* qml */ \
+ F(ReturnedValue, getQmlContext, (NoThrowEngine *engine)) \
+ F(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine)) \
+ F(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \
+ F(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)) \
+ F(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
+ \
+ F(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
+ F(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
+ F(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value))
struct Q_QML_PRIVATE_EXPORT Runtime {
- Runtime()
- : INIT_RUNTIME_METHOD(callGlobalLookup)
- , INIT_RUNTIME_METHOD(callActivationProperty)
- , INIT_RUNTIME_METHOD(callQmlScopeObjectProperty)
- , INIT_RUNTIME_METHOD(callQmlContextObjectProperty)
- , INIT_RUNTIME_METHOD(callProperty)
- , INIT_RUNTIME_METHOD(callPropertyLookup)
- , INIT_RUNTIME_METHOD(callElement)
- , INIT_RUNTIME_METHOD(callValue)
- , INIT_RUNTIME_METHOD(constructGlobalLookup)
- , INIT_RUNTIME_METHOD(constructActivationProperty)
- , INIT_RUNTIME_METHOD(constructProperty)
- , INIT_RUNTIME_METHOD(constructPropertyLookup)
- , INIT_RUNTIME_METHOD(constructValue)
- , INIT_RUNTIME_METHOD(setActivationProperty)
- , INIT_RUNTIME_METHOD(setProperty)
- , INIT_RUNTIME_METHOD(setElement)
- , INIT_RUNTIME_METHOD(getProperty)
- , INIT_RUNTIME_METHOD(getActivationProperty)
- , INIT_RUNTIME_METHOD(getElement)
- , INIT_RUNTIME_METHOD(typeofValue)
- , INIT_RUNTIME_METHOD(typeofName)
- , INIT_RUNTIME_METHOD(typeofScopeObjectProperty)
- , INIT_RUNTIME_METHOD(typeofContextObjectProperty)
- , INIT_RUNTIME_METHOD(typeofMember)
- , INIT_RUNTIME_METHOD(typeofElement)
- , INIT_RUNTIME_METHOD(deleteElement)
- , INIT_RUNTIME_METHOD(deleteMember)
- , INIT_RUNTIME_METHOD(deleteMemberString)
- , INIT_RUNTIME_METHOD(deleteName)
- , INIT_RUNTIME_METHOD(throwException)
- , INIT_RUNTIME_METHOD(unwindException)
- , INIT_RUNTIME_METHOD(pushWithScope)
- , INIT_RUNTIME_METHOD(pushCatchScope)
- , INIT_RUNTIME_METHOD(popScope)
- , INIT_RUNTIME_METHOD(closure)
- , INIT_RUNTIME_METHOD(declareVar)
- , INIT_RUNTIME_METHOD(setupArgumentsObject)
- , INIT_RUNTIME_METHOD(convertThisToObject)
- , INIT_RUNTIME_METHOD(arrayLiteral)
- , INIT_RUNTIME_METHOD(objectLiteral)
- , INIT_RUNTIME_METHOD(regexpLiteral)
- , INIT_RUNTIME_METHOD(foreachIterator)
- , INIT_RUNTIME_METHOD(foreachNextPropertyName)
- , INIT_RUNTIME_METHOD(uPlus)
- , INIT_RUNTIME_METHOD(uMinus)
- , INIT_RUNTIME_METHOD(uNot)
- , INIT_RUNTIME_METHOD(complement)
- , INIT_RUNTIME_METHOD(increment)
- , INIT_RUNTIME_METHOD(decrement)
- , INIT_RUNTIME_METHOD(instanceof)
- , INIT_RUNTIME_METHOD(in)
- , INIT_RUNTIME_METHOD(add)
- , INIT_RUNTIME_METHOD(addString)
- , INIT_RUNTIME_METHOD(bitOr)
- , INIT_RUNTIME_METHOD(bitXor)
- , INIT_RUNTIME_METHOD(bitAnd)
- , INIT_RUNTIME_METHOD(sub)
- , INIT_RUNTIME_METHOD(mul)
- , INIT_RUNTIME_METHOD(div)
- , INIT_RUNTIME_METHOD(mod)
- , INIT_RUNTIME_METHOD(shl)
- , INIT_RUNTIME_METHOD(shr)
- , INIT_RUNTIME_METHOD(ushr)
- , INIT_RUNTIME_METHOD(greaterThan)
- , INIT_RUNTIME_METHOD(lessThan)
- , INIT_RUNTIME_METHOD(greaterEqual)
- , INIT_RUNTIME_METHOD(lessEqual)
- , INIT_RUNTIME_METHOD(equal)
- , INIT_RUNTIME_METHOD(notEqual)
- , INIT_RUNTIME_METHOD(strictEqual)
- , INIT_RUNTIME_METHOD(strictNotEqual)
- , INIT_RUNTIME_METHOD(compareGreaterThan)
- , INIT_RUNTIME_METHOD(compareLessThan)
- , INIT_RUNTIME_METHOD(compareGreaterEqual)
- , INIT_RUNTIME_METHOD(compareLessEqual)
- , INIT_RUNTIME_METHOD(compareEqual)
- , INIT_RUNTIME_METHOD(compareNotEqual)
- , INIT_RUNTIME_METHOD(compareStrictEqual)
- , INIT_RUNTIME_METHOD(compareStrictNotEqual)
- , INIT_RUNTIME_METHOD(compareInstanceof)
- , INIT_RUNTIME_METHOD(compareIn)
- , INIT_RUNTIME_METHOD(toBoolean)
- , INIT_RUNTIME_METHOD(toDouble)
- , INIT_RUNTIME_METHOD(toInt)
- , INIT_RUNTIME_METHOD(doubleToInt)
- , INIT_RUNTIME_METHOD(toUInt)
- , INIT_RUNTIME_METHOD(doubleToUInt)
- , INIT_RUNTIME_METHOD(getQmlContext)
- , INIT_RUNTIME_METHOD(getQmlImportedScripts)
- , INIT_RUNTIME_METHOD(getQmlSingleton)
- , INIT_RUNTIME_METHOD(getQmlAttachedProperty)
- , INIT_RUNTIME_METHOD(getQmlScopeObjectProperty)
- , INIT_RUNTIME_METHOD(getQmlContextObjectProperty)
- , INIT_RUNTIME_METHOD(getQmlQObjectProperty)
- , INIT_RUNTIME_METHOD(getQmlSingletonQObjectProperty)
- , INIT_RUNTIME_METHOD(getQmlIdObject)
- , INIT_RUNTIME_METHOD(setQmlScopeObjectProperty)
- , INIT_RUNTIME_METHOD(setQmlContextObjectProperty)
- , INIT_RUNTIME_METHOD(setQmlQObjectProperty)
- { }
-
- // call
- RUNTIME_METHOD(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData));
-
- // construct
- RUNTIME_METHOD(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData));
- RUNTIME_METHOD(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData));
-
- // set & get
- RUNTIME_METHOD(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value));
- RUNTIME_METHOD(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value));
- RUNTIME_METHOD(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value));
- RUNTIME_METHOD(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index));
-
- // typeof
- RUNTIME_METHOD(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val));
- RUNTIME_METHOD(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
- RUNTIME_METHOD(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex));
- RUNTIME_METHOD(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index));
-
- // delete
- RUNTIME_METHOD(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index));
- RUNTIME_METHOD(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name));
- RUNTIME_METHOD(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex));
-
- // exceptions & scopes
- RUNTIME_METHOD(void, throwException, (ExecutionEngine *engine, const Value &value));
- RUNTIME_METHOD(ReturnedValue, unwindException, (ExecutionEngine *engine));
- RUNTIME_METHOD(void, pushWithScope, (const Value &o, NoThrowEngine *engine));
- RUNTIME_METHOD(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex));
- RUNTIME_METHOD(void, popScope, (NoThrowEngine *engine));
-
- // closures
- RUNTIME_METHOD(ReturnedValue, closure, (ExecutionEngine *engine, int functionId));
+ Runtime();
- // function header
- RUNTIME_METHOD(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine));
- RUNTIME_METHOD(void, convertThisToObject, (ExecutionEngine *engine));
-
- // literals
- RUNTIME_METHOD(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length));
- RUNTIME_METHOD(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags));
- RUNTIME_METHOD(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id));
-
- // foreach
- RUNTIME_METHOD(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in));
- RUNTIME_METHOD(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator));
-
- // unary operators
typedef ReturnedValue (*UnaryOperation)(const Value &value);
- RUNTIME_METHOD(ReturnedValue, uPlus, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, uMinus, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, uNot, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, complement, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, increment, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, decrement, (const Value &value));
-
- // binary operators
typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right);
- RUNTIME_METHOD(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, bitOr, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, bitXor, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, bitAnd, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, sub, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, mul, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, div, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, mod, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, shl, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, shr, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, ushr, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, greaterThan, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, lessThan, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, greaterEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, lessEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, equal, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, notEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, strictEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(ReturnedValue, strictNotEqual, (const Value &left, const Value &right));
-
- // comparisons
- RUNTIME_METHOD(Bool, compareGreaterThan, (const Value &l, const Value &r));
- RUNTIME_METHOD(Bool, compareLessThan, (const Value &l, const Value &r));
- RUNTIME_METHOD(Bool, compareGreaterEqual, (const Value &l, const Value &r));
- RUNTIME_METHOD(Bool, compareLessEqual, (const Value &l, const Value &r));
- RUNTIME_METHOD(Bool, compareEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(Bool, compareNotEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(Bool, compareStrictEqual, (const Value &left, const Value &right));
- RUNTIME_METHOD(Bool, compareStrictNotEqual, (const Value &left, const Value &right));
+#define DEFINE_RUNTIME_METHOD_ENUM(returnvalue, name, args) name,
+ enum RuntimeMethods {
+ FOR_EACH_RUNTIME_METHOD(DEFINE_RUNTIME_METHOD_ENUM)
+ RuntimeMethodCount,
+ InvalidRuntimeMethod = RuntimeMethodCount
+ };
+#undef DEFINE_RUNTIME_METHOD_ENUM
- RUNTIME_METHOD(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right));
- RUNTIME_METHOD(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right));
+ void *runtimeMethods[RuntimeMethodCount];
- // conversions
- RUNTIME_METHOD(Bool, toBoolean, (const Value &value));
- RUNTIME_METHOD(ReturnedValue, toDouble, (const Value &value));
- RUNTIME_METHOD(int, toInt, (const Value &value));
- RUNTIME_METHOD(int, doubleToInt, (const double &d));
- RUNTIME_METHOD(unsigned, toUInt, (const Value &value));
- RUNTIME_METHOD(unsigned, doubleToUInt, (const double &d));
+ static uint runtimeMethodOffset(RuntimeMethods method) { return method*QT_POINTER_SIZE; }
- // qml
- RUNTIME_METHOD(ReturnedValue, getQmlContext, (NoThrowEngine *engine));
- RUNTIME_METHOD(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine));
- RUNTIME_METHOD(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex));
- RUNTIME_METHOD(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex));
- RUNTIME_METHOD(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired));
- RUNTIME_METHOD(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired));
- RUNTIME_METHOD(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
- RUNTIME_METHOD(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired));
- RUNTIME_METHOD(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index));
+#define RUNTIME_METHOD(returnvalue, name, args) \
+ typedef returnvalue (*Method_##name)args; \
+ enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \
+ static returnvalue method_##name args;
+ FOR_EACH_RUNTIME_METHOD(RUNTIME_METHOD)
+#undef RUNTIME_METHOD
- RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
- RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value));
- RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value));
};
-#undef RUNTIME_METHOD
-#undef INIT_RUNTIME_METHOD
+static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");
+static_assert(offsetof(Runtime, runtimeMethods) == 0, "JIT expects this to be the first member");
+static_assert(sizeof(Runtime::BinaryOperation) == sizeof(void*), "JIT expects a function pointer to fit into a regular pointer, for cross-compilation offset translation");
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 6775028272..894434be16 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -366,7 +366,7 @@ struct Scoped
struct ScopedCallData {
ScopedCallData(const Scope &scope, int argc = 0)
{
- int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value);
+ int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)));
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
ptr->tag = QV4::Value::Integer_Type_Internal;
ptr->argc = argc;
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index f96f0254a5..4ebe2dd609 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -72,7 +72,7 @@ struct ContextStateSaver {
bool strictMode;
Lookup *lookups;
const QV4::Value *constantTable;
- CompiledData::CompilationUnit *compilationUnit;
+ CompiledData::CompilationUnitBase *compilationUnit;
int lineNumber;
ContextStateSaver(const Scope &scope, ExecutionContext *context)
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 72be11eca0..81f5c3566c 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -77,15 +77,15 @@ void Heap::StringObject::init()
{
Object::init();
Q_ASSERT(vtable() == QV4::StringObject::staticVTable());
- string = internalClass->engine->id_empty()->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0);
+ string.set(internalClass->engine, internalClass->engine->id_empty()->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0));
}
void Heap::StringObject::init(const QV4::String *str)
{
Object::init();
- string = str->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length());
+ string.set(internalClass->engine, str->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(length()));
}
Heap::String *Heap::StringObject::getIndex(uint index) const
@@ -145,13 +145,6 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name,
return Object::advanceIterator(m, it, name, index, p, attrs);
}
-void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- StringObject::Data *o = static_cast<StringObject::Data *>(that);
- o->string->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(StringCtor);
void Heap::StringCtor::init(QV4::ExecutionContext *scope)
@@ -563,7 +556,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
if (regExp->global())
- *regExp->lastIndexProperty() = Primitive::fromUInt32(0);
+ regExp->setLastIndex(0);
numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2);
numCaptures = regExp->value()->captureCount();
} else {
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index aed3bc1e28..5ccee3335e 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -60,14 +60,18 @@ namespace QV4 {
namespace Heap {
-struct StringObject : Object {
+#define StringObjectMembers(class, Member) \
+ Member(class, Pointer, String *, string)
+
+DECLARE_HEAP_OBJECT(StringObject, Object) {
+ DECLARE_MARK_TABLE(StringObject);
+
enum {
LengthPropertyIndex = 0
};
void init();
void init(const QV4::String *string);
- String *string;
Heap::String *getIndex(uint index) const;
uint length() const;
@@ -96,7 +100,6 @@ struct StringObject: Object {
protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct StringCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 5573a2e57f..a34a8922e1 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -229,8 +229,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
@@ -252,8 +252,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = destByteLength;
array->d()->byteOffset = 0;
@@ -311,8 +311,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
byteLength = (uint)l;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
scope.result = array.asReturnedValue();
@@ -335,8 +335,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = l * elementSize;
array->d()->byteOffset = 0;
@@ -375,12 +375,6 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type
return e->memoryManager->allocObject<TypedArray>(e->emptyClass, e->typedArrayPrototype + t, t);
}
-void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- static_cast<TypedArray::Data *>(that)->buffer->mark(e);
- Object::markObjects(that, e);
-}
-
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
{
Scope scope(static_cast<const Object *>(m)->engine());
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index fbf13c9815..96786c8231 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -72,7 +72,15 @@ struct TypedArrayOperations {
namespace Heap {
-struct TypedArray : Object {
+#define TypedArrayMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, const TypedArrayOperations *, type) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset) \
+ Member(class, NoMark, uint, arrayType)
+
+DECLARE_HEAP_OBJECT(TypedArray, Object) {
+ DECLARE_MARK_TABLE(TypedArray);
enum Type {
Int8Array,
UInt8Array,
@@ -87,12 +95,6 @@ struct TypedArray : Object {
};
void init(Type t);
-
- const TypedArrayOperations *type;
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
- Type arrayType;
};
struct TypedArrayCtor : FunctionObject {
@@ -128,10 +130,9 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
}
Heap::TypedArray::Type arrayType() const {
- return d()->arrayType;
+ return static_cast<Heap::TypedArray::Type>(d()->arrayType);
}
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
static bool putIndexed(Managed *m, uint index, const Value &value);
};
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 4ff0565f9b..11d75dde99 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -68,8 +68,6 @@ namespace Heap {
struct Base;
}
-typedef uint Bool;
-
struct Q_QML_PRIVATE_EXPORT Value
{
private:
@@ -708,7 +706,6 @@ inline unsigned int Value::toUInt32() const
return (unsigned int)toInt32();
}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 5cab4c5386..f2ff5d307e 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -84,7 +84,7 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other)
return false;
}
-void VariantObject::addVmePropertyReference()
+void VariantObject::addVmePropertyReference() const
{
if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
// remove from the ep->scarceResources list
@@ -94,7 +94,7 @@ void VariantObject::addVmePropertyReference()
}
}
-void VariantObject::removeVmePropertyReference()
+void VariantObject::removeVmePropertyReference() const
{
if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
// and add to the ep->scarceResources list
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index ef51b6632d..e281602bb5 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -96,8 +96,8 @@ struct VariantObject : Object
V4_PROTOTYPE(variantPrototype)
V4_NEEDS_DESTROY
- void addVmePropertyReference();
- void removeVmePropertyReference();
+ void addVmePropertyReference() const;
+ void removeVmePropertyReference() const;
static bool isEqualTo(Managed *m, Managed *other);
};
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index be2772c23f..8d523f17e9 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -249,10 +249,8 @@ int qt_v4DebuggerHook(const char *json)
return -NoSuchCommand; // Failure.
}
-static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scopes, int scopeDepth)
+static void qt_v4CheckForBreak(QV4::ExecutionContext *context)
{
- Q_UNUSED(scopes);
- Q_UNUSED(scopeDepth);
const int lineNumber = context->d()->lineNumber;
QV4::Function *function = qt_v4ExtractFunction(context);
QString engineName = function->sourceFile();
@@ -335,18 +333,24 @@ Param traceParam(const Param &param)
return param;
}
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index)
+# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index)
#else
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[param.scope] + param.index)
+# define VALUEPTR(param) (scopes[param.scope].values + param.index)
#endif
+// ### add write barrier here
#define STOREVALUE(param, value) { \
QV4::ReturnedValue tmp = (value); \
if (engine->hasException) \
goto catchException; \
- VALUE(param) = tmp; \
- }
+ if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \
+ VALUE(param) = tmp; \
+ } else { \
+ QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \
+ } \
+}
+
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
#undef CHECK_EXCEPTION
@@ -402,21 +406,29 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
}
}
- Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
+ struct Scopes {
+ QV4::Value *values;
+ QV4::Heap::Base *base; // non 0 if a write barrier is required
+ };
+ Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth));
{
- scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->constants);
+ scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->constants), 0 };
// stack gets setup in push instruction
- scopes[1] = 0;
+ scopes[1] = { 0, 0 };
QV4::Heap::ExecutionContext *scope = context->d();
int i = 0;
while (scope) {
- if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope);
+ scopes[2*i + 2] = { cc->callData->args, 0 };
+ scopes[2*i + 3] = { 0, 0 };
+ } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) {
QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope);
- scopes[2*i + 2] = cc->callData->args;
- scopes[2*i + 3] = cc->locals;
+ scopes[2*i + 2] = { cc->callData->args, cc };
+ scopes[2*i + 3] = { cc->locals.values, cc };
} else {
- scopes[2*i + 2] = 0;
- scopes[2*i + 3] = 0;
+ scopes[2*i + 2] = { 0, 0 };
+ scopes[2*i + 3] = { 0, 0 };
}
++i;
scope = scope->outer;
@@ -451,16 +463,16 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(LoadRegExp)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = context->d()->compilationUnit->runtimeRegularExpressions[instr.regExpId];
+ VALUE(instr.result) = static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->runtimeRegularExpressions[instr.regExpId];
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
- STOREVALUE(instr.result, engine->runtime.closure(engine, instr.value));
+ STOREVALUE(instr.result, Runtime::method_closure(engine, instr.value));
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- STOREVALUE(instr.result, engine->runtime.getActivationProperty(engine, instr.name));
+ STOREVALUE(instr.result, Runtime::method_getActivationProperty(engine, instr.name));
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(GetGlobalLookup)
@@ -470,32 +482,32 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(StoreName)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- engine->runtime.setActivationProperty(engine, instr.name, VALUE(instr.source));
+ Runtime::method_setActivationProperty(engine, instr.name, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreName)
MOTH_BEGIN_INSTR(LoadElement)
- STOREVALUE(instr.result, engine->runtime.getElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, Runtime::method_getElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(LoadElementLookup)
QV4::Lookup *l = context->d()->lookups + instr.lookup;
- STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
MOTH_BEGIN_INSTR(StoreElement)
- engine->runtime.setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ Runtime::method_setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(StoreElementLookup)
QV4::Lookup *l = context->d()->lookups + instr.lookup;
- l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
MOTH_BEGIN_INSTR(LoadProperty)
- STOREVALUE(instr.result, engine->runtime.getProperty(engine, VALUE(instr.base), instr.name));
+ STOREVALUE(instr.result, Runtime::method_getProperty(engine, VALUE(instr.base), instr.name));
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
@@ -504,7 +516,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
- engine->runtime.setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source));
+ Runtime::method_setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreProperty)
@@ -515,49 +527,49 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(SetLookup)
MOTH_BEGIN_INSTR(StoreQObjectProperty)
- engine->runtime.setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ Runtime::method_setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreQObjectProperty)
MOTH_BEGIN_INSTR(LoadQObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, Runtime::method_getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ Runtime::method_setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreScopeObjectProperty)
MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, Runtime::method_getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadScopeObjectProperty)
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ Runtime::method_setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreContextObjectProperty)
MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, Runtime::method_getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadContextObjectProperty)
MOTH_BEGIN_INSTR(LoadIdObject)
- STOREVALUE(instr.result, engine->runtime.getQmlIdObject(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, Runtime::method_getQmlIdObject(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(LoadIdObject)
MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex));
+ STOREVALUE(instr.result, Runtime::method_getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex));
MOTH_END_INSTR(LoadAttachedQObjectProperty)
MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty)
- STOREVALUE(instr.result, engine->runtime.getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STOREVALUE(instr.result, Runtime::method_getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadSingletonQObjectProperty)
MOTH_BEGIN_INSTR(Push)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
stack = scope.alloc(stackSize);
- scopes[1] = stack;
+ scopes[1].values = stack;
MOTH_END_INSTR(Push)
MOTH_BEGIN_INSTR(CallValue)
@@ -571,73 +583,73 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
}
}
#endif // DO_TRACE_INSTR
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, engine->runtime.callValue(engine, VALUE(instr.dest), callData));
+ STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData));
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.callProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData));
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.callPropertyLookup(engine, instr.lookupIndex, callData));
+ STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData));
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallScopeObjectProperty)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.callQmlScopeObjectProperty(engine, instr.index, callData));
+ STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData));
MOTH_END_INSTR(CallScopeObjectProperty)
MOTH_BEGIN_INSTR(CallContextObjectProperty)
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.callQmlContextObjectProperty(engine, instr.index, callData));
+ STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData));
MOTH_END_INSTR(CallContextObjectProperty)
MOTH_BEGIN_INSTR(CallElement)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.callElement(engine, VALUE(instr.index), callData));
+ STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData));
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallActivationProperty)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, engine->runtime.callActivationProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData));
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
@@ -650,141 +662,141 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(SetExceptionHandler)
MOTH_BEGIN_INSTR(CallBuiltinThrow)
- engine->runtime.throwException(engine, VALUE(instr.arg));
+ Runtime::method_throwException(engine, VALUE(instr.arg));
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinThrow)
MOTH_BEGIN_INSTR(CallBuiltinUnwindException)
- STOREVALUE(instr.result, engine->runtime.unwindException(engine));
+ STOREVALUE(instr.result, Runtime::method_unwindException(engine));
MOTH_END_INSTR(CallBuiltinUnwindException)
MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
- engine->runtime.pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
+ Runtime::method_pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPushCatchScope)
MOTH_BEGIN_INSTR(CallBuiltinPushScope)
- engine->runtime.pushWithScope(VALUE(instr.arg), static_cast<QV4::NoThrowEngine*>(engine));
+ Runtime::method_pushWithScope(VALUE(instr.arg), static_cast<QV4::NoThrowEngine*>(engine));
context = engine->currentContext;
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinPushScope)
MOTH_BEGIN_INSTR(CallBuiltinPopScope)
- engine->runtime.popScope(static_cast<QV4::NoThrowEngine*>(engine));
+ Runtime::method_popScope(static_cast<QV4::NoThrowEngine*>(engine));
context = engine->currentContext;
MOTH_END_INSTR(CallBuiltinPopScope)
MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject)
- STOREVALUE(instr.result, engine->runtime.foreachIterator(engine, VALUE(instr.arg)));
+ STOREVALUE(instr.result, Runtime::method_foreachIterator(engine, VALUE(instr.arg)));
MOTH_END_INSTR(CallBuiltinForeachIteratorObject)
MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName)
- STOREVALUE(instr.result, engine->runtime.foreachNextPropertyName(VALUE(instr.arg)));
+ STOREVALUE(instr.result, Runtime::method_foreachNextPropertyName(VALUE(instr.arg)));
MOTH_END_INSTR(CallBuiltinForeachNextPropertyName)
MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
- STOREVALUE(instr.result, engine->runtime.deleteMember(engine, VALUE(instr.base), instr.member));
+ STOREVALUE(instr.result, Runtime::method_deleteMember(engine, VALUE(instr.base), instr.member));
MOTH_END_INSTR(CallBuiltinDeleteMember)
MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
- STOREVALUE(instr.result, engine->runtime.deleteElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, Runtime::method_deleteElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(CallBuiltinDeleteSubscript)
MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
- STOREVALUE(instr.result, engine->runtime.deleteName(engine, instr.name));
+ STOREVALUE(instr.result, Runtime::method_deleteName(engine, instr.name));
MOTH_END_INSTR(CallBuiltinDeleteName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty)
- STOREVALUE(instr.result, engine->runtime.typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, Runtime::method_typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty)
- STOREVALUE(instr.result, engine->runtime.typeofContextObjectProperty(engine, VALUE(instr.base), instr.index));
+ STOREVALUE(instr.result, Runtime::method_typeofContextObjectProperty(engine, VALUE(instr.base), instr.index));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofMember)
- STOREVALUE(instr.result, engine->runtime.typeofMember(engine, VALUE(instr.base), instr.member));
+ STOREVALUE(instr.result, Runtime::method_typeofMember(engine, VALUE(instr.base), instr.member));
MOTH_END_INSTR(CallBuiltinTypeofMember)
MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript)
- STOREVALUE(instr.result, engine->runtime.typeofElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, Runtime::method_typeofElement(engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(CallBuiltinTypeofSubscript)
MOTH_BEGIN_INSTR(CallBuiltinTypeofName)
- STOREVALUE(instr.result, engine->runtime.typeofName(engine, instr.name));
+ STOREVALUE(instr.result, Runtime::method_typeofName(engine, instr.name));
MOTH_END_INSTR(CallBuiltinTypeofName)
MOTH_BEGIN_INSTR(CallBuiltinTypeofValue)
- STOREVALUE(instr.result, engine->runtime.typeofValue(engine, VALUE(instr.value)));
+ STOREVALUE(instr.result, Runtime::method_typeofValue(engine, VALUE(instr.value)));
MOTH_END_INSTR(CallBuiltinTypeofValue)
MOTH_BEGIN_INSTR(CallBuiltinDeclareVar)
- engine->runtime.declareVar(engine, instr.isDeletable, instr.varName);
+ Runtime::method_declareVar(engine, instr.isDeletable, instr.varName);
MOTH_END_INSTR(CallBuiltinDeclareVar)
MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, engine->runtime.arrayLiteral(engine, args, instr.argc));
+ STOREVALUE(instr.result, Runtime::method_arrayLiteral(engine, args, instr.argc));
MOTH_END_INSTR(CallBuiltinDefineArray)
MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, engine->runtime.objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
+ STOREVALUE(instr.result, Runtime::method_objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
- STOREVALUE(instr.result, engine->runtime.setupArgumentsObject(engine));
+ STOREVALUE(instr.result, Runtime::method_setupArgumentsObject(engine));
MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject)
- engine->runtime.convertThisToObject(engine);
+ Runtime::method_convertThisToObject(engine);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallBuiltinConvertThisToObject)
MOTH_BEGIN_INSTR(CreateValue)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, engine->runtime.constructValue(engine, VALUE(instr.func), callData));
+ STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData));
MOTH_END_INSTR(CreateValue)
MOTH_BEGIN_INSTR(CreateProperty)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.constructProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData));
MOTH_END_INSTR(CreateProperty)
MOTH_BEGIN_INSTR(ConstructPropertyLookup)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, engine->runtime.constructPropertyLookup(engine, instr.index, callData));
+ STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData));
MOTH_END_INSTR(ConstructPropertyLookup)
MOTH_BEGIN_INSTR(CreateActivationProperty)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, engine->runtime.constructActivationProperty(engine, instr.name, callData));
+ STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData));
MOTH_END_INSTR(CreateActivationProperty)
MOTH_BEGIN_INSTR(ConstructGlobalLookup)
- Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+ Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type_Internal;
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, engine->runtime.constructGlobalLookup(engine, instr.index, callData));
+ STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData));
MOTH_END_INSTR(ConstructGlobalLookup)
MOTH_BEGIN_INSTR(Jump)
@@ -806,7 +818,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(JumpNe)
MOTH_BEGIN_INSTR(UNot)
- STOREVALUE(instr.result, engine->runtime.uNot(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_uNot(VALUE(instr.source)));
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UNotBool)
@@ -815,15 +827,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(UNotBool)
MOTH_BEGIN_INSTR(UPlus)
- STOREVALUE(instr.result, engine->runtime.uPlus(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_uPlus(VALUE(instr.source)));
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- STOREVALUE(instr.result, engine->runtime.uMinus(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_uMinus(VALUE(instr.source)));
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
- STOREVALUE(instr.result, engine->runtime.complement(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_complement(VALUE(instr.source)));
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(UComplInt)
@@ -831,32 +843,32 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(UComplInt)
MOTH_BEGIN_INSTR(Increment)
- STOREVALUE(instr.result, engine->runtime.increment(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_increment(VALUE(instr.source)));
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- STOREVALUE(instr.result, engine->runtime.decrement(VALUE(instr.source)));
+ STOREVALUE(instr.result, Runtime::method_decrement(VALUE(instr.source)));
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Binop)
- QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime) + instr.alu);
+ QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu]));
STOREVALUE(instr.result, op(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Binop)
MOTH_BEGIN_INSTR(Add)
- STOREVALUE(instr.result, engine->runtime.add(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_add(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
- STOREVALUE(instr.result, engine->runtime.bitAnd(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_bitAnd(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitAnd)
MOTH_BEGIN_INSTR(BitOr)
- STOREVALUE(instr.result, engine->runtime.bitOr(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_bitOr(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitOr)
MOTH_BEGIN_INSTR(BitXor)
- STOREVALUE(instr.result, engine->runtime.bitXor(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_bitXor(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BitXor)
MOTH_BEGIN_INSTR(Shr)
@@ -891,15 +903,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(ShlConst)
MOTH_BEGIN_INSTR(Mul)
- STOREVALUE(instr.result, engine->runtime.mul(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_mul(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Sub)
- STOREVALUE(instr.result, engine->runtime.sub(VALUE(instr.lhs), VALUE(instr.rhs)));
+ STOREVALUE(instr.result, Runtime::method_sub(VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(BinopContext)
- QV4::Runtime::BinaryOperationContext op = *reinterpret_cast<QV4::Runtime::BinaryOperationContext *>(reinterpret_cast<char *>(&engine->runtime) + instr.alu);
+ QV4::Runtime::BinaryOperationContext op = *reinterpret_cast<QV4::Runtime::BinaryOperationContext *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu]));
STOREVALUE(instr.result, op(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
MOTH_END_INSTR(BinopContext)
@@ -915,13 +927,13 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
if (debugger && debugger->pauseAtNextOpportunity())
debugger->maybeBreakAtInstruction();
if (qt_v4IsDebugging)
- qt_v4CheckForBreak(context, scopes, scopeDepth);
+ qt_v4CheckForBreak(context);
MOTH_END_INSTR(Debug)
MOTH_BEGIN_INSTR(Line)
engine->current->lineNumber = instr.lineNumber;
if (qt_v4IsDebugging)
- qt_v4CheckForBreak(context, scopes, scopeDepth);
+ qt_v4CheckForBreak(context);
MOTH_END_INSTR(Line)
#endif // QT_NO_QML_DEBUGGER
@@ -930,15 +942,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_END_INSTR(LoadThis)
MOTH_BEGIN_INSTR(LoadQmlContext)
- VALUE(instr.result) = engine->runtime.getQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
+ VALUE(instr.result) = Runtime::method_getQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlContext)
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- VALUE(instr.result) = engine->runtime.getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
+ VALUE(instr.result) = Runtime::method_getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
MOTH_BEGIN_INSTR(LoadQmlSingleton)
- VALUE(instr.result) = engine->runtime.getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
+ VALUE(instr.result) = Runtime::method_getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
MOTH_END_INSTR(LoadQmlSingleton)
#ifdef MOTH_THREADED_INTERPRETER
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
index 38fadbf23f..7956e4a9a1 100644
--- a/src/qml/memory/memory.pri
+++ b/src/qml/memory/memory.pri
@@ -7,7 +7,8 @@ SOURCES += \
HEADERS += \
$$PWD/qv4mm_p.h \
- $$PWD/qv4mmdefs_p.h
+ $$PWD/qv4mmdefs_p.h \
+ $$PWD/qv4writebarrier_p.h
}
HEADERS += \
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 8285ef4de7..1347a9bd6e 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -72,6 +72,7 @@ namespace QV4 {
struct VTable
{
const VTable * const parent;
+ const quint64 markTable;
uint isExecutionContext : 1;
uint isString : 1;
uint isObject : 1;
@@ -91,6 +92,8 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
+ static Q_CONSTEXPR quint64 markTable = 0;
+
const VTable *vt;
inline ReturnedValue asReturnedValue() const;
@@ -110,6 +113,12 @@ struct Q_QML_EXPORT Base {
Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
return Chunk::setBit(c->blackBitmap, h - c->realBase());
}
+ inline void setGrayBit() {
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::setBit(c->grayBitmap, h - c->realBase());
+ }
inline bool inUse() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -133,7 +142,7 @@ struct Q_QML_EXPORT Base {
else if (_livenessStatus == Destroyed)
fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n",
vtable()->className);
- Q_ASSERT(_livenessStatus = Initialized);
+ Q_ASSERT(_livenessStatus == Initialized);
}
void _checkIsDestroyed() {
if (_livenessStatus == Initialized)
@@ -160,20 +169,12 @@ struct Q_QML_EXPORT Base {
#endif
};
V4_ASSERT_IS_TRIVIAL(Base)
-
-template <typename T>
-struct Pointer {
- T *operator->() const { return ptr; }
- operator T *() const { return ptr; }
-
- Pointer &operator =(T *t) { ptr = t; return *this; }
-
- template <typename Type>
- Type *cast() { return static_cast<Type *>(ptr); }
-
- T *ptr;
-};
-V4_ASSERT_IS_TRIVIAL(Pointer<void>)
+// This class needs to consist only of pointer sized members to allow
+// for a size/offset translation when cross-compiling between 32- and
+// 64-bit.
+Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
+Q_STATIC_ASSERT(offsetof(Base, vt) == 0);
+Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index a829e902fb..c025dd09a4 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -60,7 +60,11 @@
#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
-#define MM_DEBUG 0
+//#define MM_STATS
+
+#if !defined(MM_STATS) && !defined(QT_NO_DEBUG)
+#define MM_STATS
+#endif
#if MM_DEBUG
#define DEBUG qDebug() << "MM:"
@@ -113,14 +117,16 @@ struct MemorySegment {
pageReservation = PageReservation::reserve(size, OSAllocator::JSGCHeapPages);
base = reinterpret_cast<Chunk *>((reinterpret_cast<quintptr>(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1));
nChunks = NumChunks;
- if (base != pageReservation.base())
+ availableBytes = size - (reinterpret_cast<quintptr>(base) - reinterpret_cast<quintptr>(pageReservation.base()));
+ if (availableBytes < SegmentSize)
--nChunks;
}
MemorySegment(MemorySegment &&other) {
qSwap(pageReservation, other.pageReservation);
qSwap(base, other.base);
- qSwap(nChunks, other.nChunks);
qSwap(allocatedMap, other.allocatedMap);
+ qSwap(availableBytes, other.availableBytes);
+ qSwap(nChunks, other.nChunks);
}
~MemorySegment() {
@@ -150,7 +156,7 @@ struct MemorySegment {
void free(Chunk *chunk, size_t size) {
DEBUG << "freeing chunk" << chunk;
size_t index = static_cast<size_t>(chunk - base);
- size_t end = index + (size - 1)/Chunk::ChunkSize + 1;
+ size_t end = qMin(static_cast<size_t>(NumChunks), index + (size - 1)/Chunk::ChunkSize + 1);
while (index < end) {
Q_ASSERT(testBit(index));
clearBit(index);
@@ -169,11 +175,19 @@ struct MemorySegment {
PageReservation pageReservation;
Chunk *base = 0;
quint64 allocatedMap = 0;
+ size_t availableBytes = 0;
uint nChunks = 0;
};
Chunk *MemorySegment::allocate(size_t size)
{
+ if (!allocatedMap && size >= SegmentSize) {
+ // chunk allocated for one huge allocation
+ Q_ASSERT(availableBytes >= size);
+ pageReservation.commit(base, size);
+ allocatedMap = ~static_cast<quintptr>(0);
+ return base;
+ }
size_t requiredChunks = (size + sizeof(Chunk) - 1)/sizeof(Chunk);
uint sequence = 0;
Chunk *candidate = 0;
@@ -251,7 +265,9 @@ void Chunk::sweep()
// DEBUG << "sweeping chunk" << this << (*freeList);
HeapItem *o = realBase();
for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+#if WRITEBARRIER(none)
Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+#endif
quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
quintptr e = extendsBitmap[i];
@@ -280,7 +296,7 @@ void Chunk::sweep()
}
}
objectBitmap[i] = blackBitmap[i];
- blackBitmap[i] = 0;
+ grayBitmap[i] = 0;
extendsBitmap[i] = e;
o += Chunk::Bits;
}
@@ -319,13 +335,56 @@ void Chunk::freeAll()
}
}
objectBitmap[i] = 0;
- blackBitmap[i] = 0;
+ grayBitmap[i] = 0;
extendsBitmap[i] = e;
o += Chunk::Bits;
}
// DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
}
+void Chunk::resetBlackBits()
+{
+ memset(blackBitmap, 0, sizeof(blackBitmap));
+}
+
+#ifdef MM_STATS
+static uint nGrayItems = 0;
+#endif
+
+void Chunk::collectGrayItems(ExecutionEngine *engine)
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+#if WRITEBARRIER(none)
+ Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+#endif
+ quintptr toMark = blackBitmap[i] & grayBitmap[i]; // correct for a Steele type barrier
+ Q_ASSERT((toMark & objectBitmap[i]) == toMark); // check all black objects are marked as being used
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toMark) {
+ uint index = qCountTrailingZeroBits(toMark);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toMark ^= bit; // mask out marked slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ Q_ASSERT(b->inUse());
+ engine->pushForGC(b);
+#ifdef MM_STATS
+ ++nGrayItems;
+// qDebug() << "adding gray item" << b << "to mark stack";
+#endif
+ }
+ grayBitmap[i] = 0;
+ o += Chunk::Bits;
+ }
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+
+}
+
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
// qDebug() << "sortIntoBins:";
@@ -335,7 +394,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
#else
const int start = 1;
#endif
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
uint freeSlots = 0;
uint allocatedSlots = 0;
#endif
@@ -345,7 +404,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
if (!i)
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -362,7 +421,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
break;
}
usedSlots = (objectBitmap[i]|extendsBitmap[i]);
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -373,7 +432,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
usedSlots |= (quintptr(1) << index) - 1;
uint freeEnd = i*Bits + index;
uint nSlots = freeEnd - freeStart;
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
// qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots;
freeSlots += nSlots;
#endif
@@ -384,7 +443,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
bins[bin] = freeItem;
}
}
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr));
#endif
}
@@ -555,6 +614,19 @@ void BlockAllocator::freeAll()
}
}
+void BlockAllocator::resetBlackBits()
+{
+ for (auto c : chunks)
+ c->resetBlackBits();
+}
+
+void BlockAllocator::collectGrayItems(ExecutionEngine *engine)
+{
+ for (auto c : chunks)
+ c->collectGrayItems(engine);
+
+}
+
#if MM_DEBUG
void BlockAllocator::stats() {
DEBUG << "MM stats:";
@@ -607,7 +679,6 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato
void HugeItemAllocator::sweep() {
auto isBlack = [this] (const HugeChunk &c) {
bool b = c.chunk->first()->isBlack();
- Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
if (!b)
freeHugeChunk(chunkAllocator, c);
return !b;
@@ -617,6 +688,24 @@ void HugeItemAllocator::sweep() {
chunks.erase(newEnd, chunks.end());
}
+void HugeItemAllocator::resetBlackBits()
+{
+ for (auto c : chunks)
+ Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
+}
+
+void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine)
+{
+ for (auto c : chunks)
+ // Correct for a Steele type barrier
+ if (Chunk::testBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()) &&
+ Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) {
+ HeapItem *i = c.chunk->first();
+ Heap::Base *b = *i;
+ b->mark(engine);
+ }
+}
+
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
@@ -642,15 +731,17 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
#endif
}
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
+static int allocationCount = 0;
static size_t lastAllocRequestedSlots = 0;
#endif
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
const size_t stringSize = align(sizeof(Heap::String));
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift;
+ ++allocationCount;
#endif
bool didGCRun = false;
@@ -661,7 +752,8 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
unmanagedHeapSize += unmanagedSize;
if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
- runGC();
+ if (!didGCRun)
+ runGC();
if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize)
// more than 75% full, raise limit
@@ -679,14 +771,16 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
m = blockAllocator.allocate(stringSize, true);
}
+// qDebug() << "allocated string" << m;
memset(m, 0, stringSize);
return *m;
}
Heap::Base *MemoryManager::allocData(std::size_t size)
{
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
lastAllocRequestedSlots = size >> Chunk::SlotSizeShift;
+ ++allocationCount;
#endif
bool didRunGC = false;
@@ -703,8 +797,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
// qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
- if (size > Chunk::DataSize)
- return *hugeItemAllocator.allocate(size);
+ if (size > Chunk::DataSize) {
+ HeapItem *h = hugeItemAllocator.allocate(size);
+// qDebug() << "allocating huge item" << h;
+ return *h;
+ }
HeapItem *m = blockAllocator.allocate(size);
if (!m) {
@@ -714,39 +811,92 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
}
memset(m, 0, size);
+// qDebug() << "allocating data" << m;
return *m;
}
Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers)
{
- Heap::Object *o = static_cast<Heap::Object *>(allocData(size));
-
- // ### Could optimize this and allocate both in one go through the block allocator
- if (nMembers) {
+ Heap::Object *o;
+ if (!nMembers) {
+ o = static_cast<Heap::Object *>(allocData(size));
+ } else {
+ // Allocate both in one go through the block allocator
std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
-// qDebug() << "allocating member data for" << o << nMembers << memberSize;
- Heap::Base *m;
- if (memberSize > Chunk::DataSize)
- m = *hugeItemAllocator.allocate(memberSize);
- else
- m = *blockAllocator.allocate(memberSize, true);
- memset(m, 0, memberSize);
- o->memberData = static_cast<Heap::MemberData *>(m);
- o->memberData->setVtable(MemberData::staticVTable());
- o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
- o->memberData->init();
+ size_t totalSize = size + memberSize;
+ Heap::MemberData *m;
+ if (totalSize > Chunk::DataSize) {
+ o = static_cast<Heap::Object *>(allocData(size));
+ m = hugeItemAllocator.allocate(memberSize)->as<Heap::MemberData>();
+ } else {
+ HeapItem *mh = reinterpret_cast<HeapItem *>(allocData(totalSize));
+ Heap::Base *b = *mh;
+ o = static_cast<Heap::Object *>(b);
+ mh += (size >> Chunk::SlotSizeShift);
+ m = mh->as<Heap::MemberData>();
+ Chunk *c = mh->chunk();
+ size_t index = mh - c->realBase();
+ Chunk::setBit(c->objectBitmap, index);
+ Chunk::clearBit(c->extendsBitmap, index);
+ }
+ o->memberData.set(engine, m);
+ m->setVtable(MemberData::staticVTable());
+ m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.size = o->memberData->values.alloc;
+ m->init();
// qDebug() << " got" << o->memberData << o->memberData->size;
}
+// qDebug() << "allocating object with memberData" << o << o->memberData.operator->();
return o;
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+static uint markStackSize = 0;
+
+void MemoryManager::drainMarkStack(Value *markBase)
{
while (engine->jsStackTop > markBase) {
Heap::Base *h = engine->popForGC();
+ ++markStackSize;
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
+ if (h->vtable()->markObjects)
+ h->vtable()->markObjects(h, engine);
+ if (quint64 m = h->vtable()->markTable) {
+// qDebug() << "using mark table:" << hex << m << "for" << h;
+ void **mem = reinterpret_cast<void **>(h);
+ while (m) {
+ MarkFlags mark = static_cast<MarkFlags>(m & 3);
+ switch (mark) {
+ case Mark_NoMark:
+ break;
+ case Mark_Value:
+// qDebug() << "marking value at " << mem;
+ reinterpret_cast<Value *>(mem)->mark(engine);
+ break;
+ case Mark_Pointer: {
+// qDebug() << "marking pointer at " << mem;
+ Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem);
+ if (p)
+ p->mark(engine);
+ break;
+ }
+ case Mark_ValueArray: {
+ Q_ASSERT(m == Mark_ValueArray);
+// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
+ ValueArray<0> *a = reinterpret_cast<ValueArray<0> *>(mem);
+ Value *v = a->values;
+ const Value *end = v + a->alloc;
+ while (v < end) {
+ v->mark(engine);
+ ++v;
+ }
+ break;
+ }
+ }
+
+ m >>= 2;
+ ++mem;
+ }
+ }
}
}
@@ -754,12 +904,28 @@ void MemoryManager::mark()
{
Value *markBase = engine->jsStackTop;
- engine->markObjects();
+ markStackSize = 0;
+
+ if (nextGCIsIncremental) {
+ // need to collect all gray items and push them onto the mark stack
+ blockAllocator.collectGrayItems(engine);
+ hugeItemAllocator.collectGrayItems(engine);
+ }
+
+// qDebug() << ">>>> Mark phase:";
+// qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase);
+
+ engine->markObjects(nextGCIsIncremental);
+
+// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase);
collectFromJSStack();
+// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase);
m_persistentValues->mark(engine);
+// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase);
+
// Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
// keeps all of its children alive in JavaScript.
@@ -788,14 +954,20 @@ void MemoryManager::mark()
qobjectWrapper->mark(engine);
if (engine->jsStackTop >= engine->jsStackLimit)
- drainMarkStack(engine, markBase);
+ drainMarkStack(markBase);
}
- drainMarkStack(engine, markBase);
+ drainMarkStack(markBase);
}
void MemoryManager::sweep(bool lastSweep)
{
+ if (lastSweep && nextGCIsIncremental) {
+ // ensure we properly clean up on destruction even if the GC is in incremental mode
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
+ }
+
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
Managed *m = (*it).managed();
if (!m || m->markBit())
@@ -848,41 +1020,48 @@ void MemoryManager::sweep(bool lastSweep)
bool MemoryManager::shouldRunGC() const
{
size_t total = blockAllocator.totalSlots();
- size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
- if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100)
+ if (total > MinSlotsGCLimit && usedSlotsAfterLastFullSweep * GCOverallocation < total * 100)
return true;
return false;
}
size_t dumpBins(BlockAllocator *b, bool printOutput = true)
{
- size_t totalFragmentedSlots = 0;
+ size_t totalSlotMem = 0;
if (printOutput)
- qDebug() << "Fragmentation map:";
+ qDebug() << "Slot map:";
for (uint i = 0; i < BlockAllocator::NumBins; ++i) {
uint nEntries = 0;
HeapItem *h = b->freeBins[i];
while (h) {
++nEntries;
- totalFragmentedSlots += h->freeData.availableSlots;
+ totalSlotMem += h->freeData.availableSlots;
h = h->freeData.next;
}
if (printOutput)
qDebug() << " number of entries in slot" << i << ":" << nEntries;
}
if (printOutput)
- qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize;
- return totalFragmentedSlots*Chunk::SlotSize;
+ qDebug() << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
+ return totalSlotMem*Chunk::SlotSize;
}
-void MemoryManager::runGC()
+void MemoryManager::runGC(bool forceFullCollection)
{
if (gcBlocked) {
// qDebug() << "Not running GC.";
return;
}
+ if (forceFullCollection) {
+ // do a full GC
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
+ nextGCIsIncremental = false;
+ }
+
QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
+// qDebug() << "runGC";
if (!gcStats) {
// uint oldUsed = allocator.usedMem();
@@ -897,21 +1076,29 @@ void MemoryManager::runGC()
const size_t largeItemsBefore = getLargeItemsMem();
qDebug() << "========== GC ==========";
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
+ qDebug() << " Allocations since last GC" << allocationCount;
+ allocationCount = 0;
#endif
+ qDebug() << "Incremental:" << nextGCIsIncremental;
qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks";
qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
+#ifdef MM_STATS
+ nGrayItems = 0;
+#endif
+
QElapsedTimer t;
t.start();
mark();
- qint64 markTime = t.restart();
+ qint64 markTime = t.nsecsElapsed()/1000;
+ t.restart();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
- qint64 sweepTime = t.elapsed();
+ qint64 sweepTime = t.nsecsElapsed()/1000;
if (triggeredByUnmanagedHeap) {
qDebug() << "triggered by unmanaged heap:";
@@ -920,11 +1107,16 @@ void MemoryManager::runGC()
qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
}
size_t memInBins = dumpBins(&blockAllocator);
- qDebug() << "Marked object in" << markTime << "ms.";
- qDebug() << "Sweeped object in" << sweepTime << "ms.";
+#ifdef MM_STATS
+ if (nextGCIsIncremental)
+ qDebug() << " number of gray items:" << nGrayItems;
+#endif
+ qDebug() << "Marked object in" << markTime << "us.";
+ qDebug() << " " << markStackSize << "objects marked";
+ qDebug() << "Sweeped object in" << sweepTime << "us.";
qDebug() << "Used memory before GC:" << usedBefore;
- qDebug() << "Used memory after GC:" << usedAfter;
- qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
+ qDebug() << "Used memory after GC :" << usedAfter;
+ qDebug() << "Freed up bytes :" << (usedBefore - usedAfter);
size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
if (lost)
qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
@@ -940,6 +1132,37 @@ void MemoryManager::runGC()
// ensure we don't 'loose' any memory
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
}
+
+ if (!nextGCIsIncremental)
+ usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
+
+#if WRITEBARRIER(steele)
+ static int count = 0;
+ ++count;
+ if (aggressiveGC) {
+ nextGCIsIncremental = (count % 256);
+ } else {
+ size_t total = blockAllocator.totalSlots();
+ size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
+ if (!nextGCIsIncremental) {
+ // always try an incremental GC after a full one, unless there is anyway lots of memory pressure
+ nextGCIsIncremental = usedSlots * 4 < total * 3;
+ count = 0;
+ } else {
+ if (count > 16)
+ nextGCIsIncremental = false;
+ else
+ nextGCIsIncremental = usedSlots * 4 < total * 3; // less than 75% full
+ }
+ }
+#else
+ nextGCIsIncremental = false;
+#endif
+ if (!nextGCIsIncremental) {
+ // do a full GC
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
+ }
}
size_t MemoryManager::getUsedMem() const
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 00daf8a622..7f02a4f929 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -80,27 +80,28 @@ struct StackAllocator {
StackAllocator(ChunkAllocator *chunkAlloc);
T *allocate() {
- T *m = nextFree->as<T>();
+ HeapItem *m = nextFree;
if (Q_UNLIKELY(nextFree == lastInChunk)) {
nextChunk();
} else {
nextFree += requiredSlots;
}
-#if MM_DEBUG
+#if MM_DEBUG || !defined(QT_NO_DEBUG)
Chunk *c = m->chunk();
Chunk::setBit(c->objectBitmap, m - c->realBase());
#endif
- return m;
+ return m->as<T>();
}
void free() {
-#if MM_DEBUG
- Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase());
-#endif
if (Q_UNLIKELY(nextFree == firstInChunk)) {
prevChunk();
} else {
nextFree -= requiredSlots;
}
+#if MM_DEBUG || !defined(QT_NO_DEBUG)
+ Chunk *c = nextFree->chunk();
+ Chunk::clearBit(c->objectBitmap, nextFree - c->realBase());
+#endif
}
void nextChunk();
@@ -154,6 +155,8 @@ struct BlockAllocator {
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(ExecutionEngine *engine);
// bump allocations
HeapItem *nextFree = 0;
@@ -175,6 +178,8 @@ struct HugeItemAllocator {
HeapItem *allocate(size_t size);
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(ExecutionEngine *engine);
size_t usedMem() const {
size_t used = 0;
@@ -206,11 +211,11 @@ public:
Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size)
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
- QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4)
+ QV4::Heap::SimpleCallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4)
{
Heap::CallContext *ctxt = stackAllocator.allocate();
- memset(ctxt, 0, sizeof(Heap::CallContext));
- ctxt->setVtable(QV4::CallContext::staticVTable());
+ memset(ctxt, 0, sizeof(Heap::SimpleCallContext));
+ ctxt->setVtable(QV4::SimpleCallContext::staticVTable());
ctxt->init(v4);
return ctxt;
@@ -245,7 +250,7 @@ public:
o->setVtable(ObjectType::staticVTable());
Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
- o->prototype = prototype->d();
+ o->prototype.set(engine, prototype->d());
return static_cast<typename ObjectType::Data *>(o);
}
@@ -272,7 +277,7 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ t->d_unchecked()->prototype.set(engine, prototype->d());
t->d_unchecked()->init();
return t->d();
}
@@ -282,7 +287,7 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ t->d_unchecked()->prototype.set(engine, prototype->d());
t->d_unchecked()->init(arg1);
return t->d();
}
@@ -292,7 +297,7 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ t->d_unchecked()->prototype.set(engine, prototype->d());
t->d_unchecked()->init(arg1, arg2);
return t->d();
}
@@ -302,7 +307,7 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ t->d_unchecked()->prototype.set(engine, prototype->d());
t->d_unchecked()->init(arg1, arg2, arg3);
return t->d();
}
@@ -312,7 +317,7 @@ public:
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->prototype = prototype->d();
+ t->d_unchecked()->prototype.set(engine, prototype->d());
t->d_unchecked()->init(arg1, arg2, arg3, arg4);
return t->d();
}
@@ -417,7 +422,7 @@ public:
return t->d();
}
- void runGC();
+ void runGC(bool forceFullCollection = false);
void dumpStats() const;
@@ -427,6 +432,7 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+ void drainMarkStack(Value *markBase);
protected:
@@ -457,10 +463,12 @@ public:
std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
+ std::size_t usedSlotsAfterLastFullSweep = 0;
bool gcBlocked = false;
bool aggressiveGC = false;
bool gcStats = false;
+ bool nextGCIsIncremental = false;
};
}
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 588ae21ee0..1fc7b6a527 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -51,6 +51,7 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4runtimeapi_p.h>
#include <QtCore/qalgorithms.h>
#include <qdebug.h>
@@ -111,22 +112,29 @@ struct Chunk {
HeapItem *realBase();
HeapItem *first();
+ static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) {
+ return index >> BitShift;
+ }
+ static Q_ALWAYS_INLINE quintptr bitForIndex(size_t index) {
+ return static_cast<quintptr>(1) << (index & (Bits - 1));
+ }
+
static void setBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
*bitmap |= bit;
}
static void clearBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
*bitmap &= ~bit;
}
static bool testBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
return (*bitmap & bit);
}
static void setBits(quintptr *bitmap, size_t index, size_t nBits) {
@@ -176,6 +184,8 @@ struct Chunk {
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(ExecutionEngine *engine);
void sortIntoBins(HeapItem **bins, uint nBins);
};
@@ -255,6 +265,102 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+// Base class for the execution engine
+
+#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
+#pragma pack(push, 1)
+#endif
+struct EngineBase {
+ Heap::ExecutionContext *current = 0;
+
+ Value *jsStackTop = 0;
+ quint8 hasException = false;
+ quint8 writeBarrierActive = false;
+ quint16 unused = 0;
+#if QT_POINTER_SIZE == 8
+ quint8 padding[4];
+#endif
+ MemoryManager *memoryManager = 0;
+ Runtime runtime;
+};
+#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
+#pragma pack(pop)
+#endif
+
+Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value);
+Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0);
+Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
+
+// Some helper classes and macros to automate the generation of our
+// tables used for marking objects
+
+enum MarkFlags {
+ Mark_NoMark = 0,
+ Mark_Value = 1,
+ Mark_Pointer = 2,
+ Mark_ValueArray = 3
+};
+
+template <typename T>
+struct MarkFlagEvaluator {
+ static Q_CONSTEXPR quint64 value = 0;
+};
+template <typename T, size_t o>
+struct MarkFlagEvaluator<Heap::Pointer<T, o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Pointer) << (2*o / sizeof(quintptr));
+};
+template <size_t o>
+struct MarkFlagEvaluator<ValueArray<o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_ValueArray) << (2*o / sizeof(quintptr));
+};
+template <size_t o>
+struct MarkFlagEvaluator<HeapValue<o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Value) << (2 *o / sizeof(quintptr));
+};
+
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name) \
+ HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name)
+
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer<type, 0> name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name;
+
+#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \
+ HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name)
+
+#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) \
+ Pointer<type, offsetof(c##OffsetStruct, name) + baseOffset> name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) \
+ type name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \
+ HeapValue<offsetof(c##OffsetStruct, name) + baseOffset> name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \
+ type<offsetof(c##OffsetStruct, name) + baseOffset> name;
+
+#define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \
+ MarkFlagEvaluator<decltype(class::name)>::value |
+
+#define DECLARE_HEAP_OBJECT(name, base) \
+struct name##OffsetStruct { \
+ name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
+}; \
+struct name##SizeStruct : base, name##OffsetStruct {}; \
+struct name##Data { \
+ static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
+ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
+}; \
+Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
+static Q_CONSTEXPR quint64 name##_markTable = \
+ (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) | QV4::Heap::base::markTable; \
+ \
+struct name : base, name##Data
+
+#define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable
+
}
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
new file mode 100644
index 0000000000..a2f85822ca
--- /dev/null
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4WRITEBARRIER_P_H
+#define QV4WRITEBARRIER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+#include <private/qv4value_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define WRITEBARRIER_steele -1
+#define WRITEBARRIER_none 1
+
+#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
+
+namespace QV4 {
+
+namespace WriteBarrier {
+
+enum Type {
+ NoBarrier,
+ Barrier
+};
+
+enum NewValueType {
+ Primitive,
+ Object,
+ Unknown
+};
+
+// ### this needs to be filled with a real memory fence once marking is concurrent
+Q_ALWAYS_INLINE void fence() {}
+
+#if WRITEBARRIER(steele)
+
+template <NewValueType type>
+static Q_CONSTEXPR inline bool isRequired() {
+ return type != Primitive;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
+{
+ Q_UNUSED(engine);
+ *slot = value;
+ if (isRequired<Unknown>()) {
+ fence();
+ base->setGrayBit();
+ }
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ *slot = value;
+ if (isRequired<Object>()) {
+ fence();
+ base->setGrayBit();
+ }
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ *slot = value;
+ fence();
+ base->setGrayBit();
+}
+
+#elif WRITEBARRIER(none)
+
+template <NewValueType type>
+static Q_CONSTEXPR inline bool isRequired() {
+ return false;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+#endif
+
+}
+
+namespace Heap {
+
+template <typename T, size_t o>
+struct Pointer {
+ static Q_CONSTEXPR size_t offset = o;
+ T operator->() const { return ptr; }
+ operator T () const { return ptr; }
+
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(ExecutionEngine *e, T newVal) {
+ WriteBarrier::write(e, base(), reinterpret_cast<Heap::Base **>(&ptr), reinterpret_cast<Heap::Base *>(newVal));
+ }
+
+ template <typename Type>
+ Type *cast() { return static_cast<Type *>(ptr); }
+
+private:
+ T ptr;
+};
+typedef Pointer<char *, 0> V4PointerCheck;
+V4_ASSERT_IS_TRIVIAL(V4PointerCheck)
+
+}
+
+template <size_t offset>
+struct HeapValue : Value {
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(ExecutionEngine *e, const Value &newVal) {
+ WriteBarrier::write(e, base(), this, newVal);
+ }
+};
+
+template <size_t offset>
+struct ValueArray {
+ uint size;
+ uint alloc;
+ Value values[1];
+
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(ExecutionEngine *e, uint index, Value v) {
+ WriteBarrier::write(e, base(), values + index, v);
+ }
+ void set(ExecutionEngine *e, uint index, Heap::Base *b) {
+ WriteBarrier::write(e, base(), values + index, b);
+ }
+ inline const Value &operator[] (uint index) const {
+ Q_ASSERT(index < alloc);
+ return values[index];
+ }
+ inline const Value *data() const {
+ return values;
+ }
+
+ void insertData(ExecutionEngine *e, uint index, Value v) {
+ for (uint i = size - 1; i > index; --i) {
+ values[i] = values[i - 1];
+ }
+ set(e, index, v);
+ }
+ void removeData(ExecutionEngine *e, uint index, int n = 1) {
+ Q_UNUSED(e);
+ for (uint i = index; i < size - n; ++i) {
+ values[i] = values[i + n];
+ }
+ }
+};
+
+// It's really important that the offset of values in this structure is
+// constant across all architecture, otherwise JIT cross-compiled code will
+// have wrong offsets between host and target.
+Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index a04f47e6a4..75968ffc43 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1046,14 +1046,18 @@ namespace QV4 {
namespace Heap {
-struct QmlIncubatorObject : Object {
+#define QmlIncubatorObjectMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, valuemap) \
+ Member(class, HeapValue, HeapValue, statusChanged) \
+ Member(class, Pointer, QmlContext *, qmlContext) \
+ Member(class, NoMark, QQmlComponentIncubator *, incubator) \
+ Member(class, NoMark, QQmlQPointer<QObject>, parent)
+
+DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) {
+ DECLARE_MARK_TABLE(QmlIncubatorObject);
+
void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
inline void destroy();
- QQmlComponentIncubator *incubator;
- QQmlQPointer<QObject> parent;
- QV4::Value valuemap;
- QV4::Value statusChanged;
- Pointer<Heap::QmlContext> qmlContext;
};
}
@@ -1069,8 +1073,6 @@ struct QmlIncubatorObject : public QV4::Object
static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
-
void statusChanged(QQmlIncubator::Status);
void setInitialState(QObject *);
};
@@ -1374,8 +1376,8 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
r->setPrototype(p);
if (!valuemap->isUndefined())
- r->d()->valuemap = valuemap;
- r->d()->qmlContext = v4->qmlContext();
+ r->d()->valuemap.set(scope.engine, valuemap);
+ r->d()->qmlContext.set(scope.engine, v4->qmlContext());
r->d()->parent = parent;
QQmlIncubator *incubator = r->d()->incubator;
@@ -1459,7 +1461,7 @@ void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *,
if (!o || callData->argc < 1)
THROW_TYPE_ERROR();
- o->d()->statusChanged = callData->args[0];
+ o->d()->statusChanged.set(scope.engine, callData->args[0]);
RETURN_UNDEFINED();
}
@@ -1471,10 +1473,10 @@ QQmlComponentExtension::~QQmlComponentExtension()
void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
{
Object::init();
- valuemap = QV4::Primitive::undefinedValue();
- statusChanged = QV4::Primitive::undefinedValue();
+ valuemap.set(internalClass->engine, QV4::Primitive::undefinedValue());
+ statusChanged.set(internalClass->engine, QV4::Primitive::undefinedValue());
parent.init();
- qmlContext = nullptr;
+ qmlContext.set(internalClass->engine, nullptr);
incubator = new QQmlComponentIncubator(this, m);
}
@@ -1497,16 +1499,6 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
}
}
-void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e)
-{
- QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that);
- o->valuemap.mark(e);
- o->statusChanged.mark(e);
- if (o->qmlContext)
- o->qmlContext->mark(e);
- Object::markObjects(that, e);
-}
-
void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
QV4::Scope scope(engine());
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index e99335a117..d4d21583ba 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -791,7 +791,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
if (ddata->notifyList &&
- QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId) {
+ QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) {
if (!QObjectPrivate::get(object)->threadData->thread)
return;
@@ -1039,7 +1039,7 @@ QQmlEngine::~QQmlEngine()
/*! \fn void QQmlEngine::exit(int retCode)
This signal is emitted when the QML loaded by the engine would like to exit
- from the event loop with the specified return code.
+ from the event loop with the specified return code \a retCode.
\since 5.8
\sa quit()
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 1e1fbcf448..b70db5ed86 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -202,6 +202,7 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
*/
QQmlExpression::~QQmlExpression()
{
+ clearError();
}
/*!
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index c07d5c740a..ee5b38717b 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -210,7 +210,6 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR
} // namespace
-#if QT_CONFIG(library)
struct RegisteredPlugin {
QString uri;
QPluginLoader* loader;
@@ -221,21 +220,23 @@ struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
};
Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
+
void qmlClearEnginePlugins()
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
+#if QT_CONFIG(library)
for (auto &plugin : qAsConst(*plugins)) {
QPluginLoader* loader = plugin.loader;
if (loader && !loader->unload())
qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
delete loader;
}
+#endif
plugins->clear();
}
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
-#endif
/*!
\internal
@@ -332,10 +333,9 @@ public:
const QString &uri, const QString &url,
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
-#if QT_CONFIG(library)
- bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
+
+ bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors);
-#endif
};
/*!
@@ -959,7 +959,6 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
return result;
}
-#if QT_CONFIG(library)
static QVector<QStaticPlugin> makePlugins()
{
QVector<QStaticPlugin> plugins;
@@ -1009,7 +1008,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
return true;
}
-#endif
#if defined(QT_SHARED) || !QT_CONFIG(library)
static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
@@ -1030,7 +1028,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors)
{
-#if QT_CONFIG(library)
Q_ASSERT(qmldir);
if (qmlImportTrace())
@@ -1143,22 +1140,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
}
-
-#else
- Q_UNUSED(vmaj);
- Q_UNUSED(vmin);
- Q_UNUSED(database);
- Q_UNUSED(qmldir);
-
- if (errors) {
- QQmlError error;
- error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled")));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
-
- return false;
-#endif // library
return true;
}
@@ -2014,7 +1995,6 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b
bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath,
const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
{
-#if QT_CONFIG(library)
// Dynamic plugins are differentiated by their filepath. For static plugins we
// don't have that information so we use their address as key instead.
const QString uniquePluginID = QString::asprintf("%p", instance);
@@ -2050,15 +2030,6 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
}
return true;
-#else
- Q_UNUSED(instance);
- Q_UNUSED(basePath);
- Q_UNUSED(uri);
- Q_UNUSED(typeNamespace);
- Q_UNUSED(vmaj);
- Q_UNUSED(errors);
- return false;
-#endif
}
/*!
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index edd93ef03d..2c71293363 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -394,8 +394,9 @@ can be very useful while prototyping.
\fn QQmlListProperty::QQmlListProperty(QObject *object, void *data,
CountFunction count, AtFunction at)
-Construct a readonly QQmlListProperty from a set of operation functions. An opaque \a data handle
-may be passed which can be accessed from within the operation functions. The list property
+Construct a readonly QQmlListProperty from a set of operation functions
+\a count and \a at. An opaque \a data handle may be passed which can be
+accessed from within the operation functions. The list property
remains valid while \a object exists.
*/
@@ -404,8 +405,9 @@ remains valid while \a object exists.
CountFunction count, AtFunction at,
ClearFunction clear)
-Construct a QQmlListProperty from a set of operation functions. An opaque \a data handle
-may be passed which can be accessed from within the operation functions. The list property
+Construct a QQmlListProperty from a set of operation functions \a append,
+\a count, \a at, and \a clear. An opaque \a data handle may be passed which
+can be accessed from within the operation functions. The list property
remains valid while \a object exists.
Null pointers can be passed for any function. If any null pointers are passed in, the list
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index bd6b9a1599..bb9b69c479 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1971,7 +1971,9 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
const int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
if (lastSlash != -1)
typeName = typeName.mid(lastSlash + 1);
- } else {
+ }
+
+ if (typeName.isEmpty()) {
typeName = QString::fromUtf8(object->metaObject()->className());
int marker = typeName.indexOf(QLatin1String("_QMLTYPE_"));
if (marker != -1)
@@ -1982,10 +1984,12 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
typeName = typeName.leftRef(marker) + QLatin1Char('*');
type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
if (type) {
- typeName = type->qmlTypeName();
- const int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
+ QString qmlTypeName = type->qmlTypeName();
+ const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
if (lastSlash != -1)
- typeName = typeName.mid(lastSlash + 1);
+ qmlTypeName = qmlTypeName.mid(lastSlash + 1);
+ if (!qmlTypeName.isEmpty())
+ typeName = qmlTypeName;
}
}
}
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index 185f9687fb..538ca822ee 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -122,8 +122,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
disconnect();
Q_ASSERT(engine);
- if (QObjectPrivate::get(source)->threadData->threadId !=
- QObjectPrivate::get(engine)->threadData->threadId) {
+ if (QObjectPrivate::get(source)->threadData->threadId.load() !=
+ QObjectPrivate::get(engine)->threadData->threadId.load()) {
QString sourceName;
QDebug(&sourceName) << source;
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index df336f0803..ca522c29af 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -789,12 +789,12 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
QQmlAbstractBinding *
QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
{
+ findAliasTarget(object, index, &object, &index);
+
QQmlData *data = QQmlData::get(object);
if (!data)
return 0;
- findAliasTarget(object, index, &object, &index);
-
const int coreIndex = index.coreIndex();
const int valueTypeIndex = index.valueTypeIndex();
@@ -1399,9 +1399,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
}
/*!
- Sets the property value to \a value and returns true.
- Returns false if the property can't be set because the
- \a value is the wrong type, for example.
+ Sets the property value to \a value. Returns \c true on success, or
+ \c false if the property can't be set because the \a value is the
+ wrong type, for example.
*/
bool QQmlProperty::write(const QVariant &value) const
{
@@ -1416,6 +1416,8 @@ bool QQmlProperty::write(const QVariant &value) const
QQmlProperty p(object, name);
p.write(value);
\endcode
+
+ Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value)
{
@@ -1432,6 +1434,8 @@ bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &v
QQmlProperty p(object, name, ctxt);
p.write(value);
\endcode
+
+ Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object,
const QString &name,
@@ -1452,6 +1456,8 @@ bool QQmlProperty::write(QObject *object,
QQmlProperty p(object, name, engine);
p.write(value);
\endcode
+
+ Returns \c true on success, \c false otherwise.
*/
bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value,
QQmlEngine *engine)
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index f4f04e12c0..40bd2e5020 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -64,6 +64,7 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
+#include <QtCore/qcryptographichash.h>
#include <functional>
@@ -80,10 +81,6 @@
# define NAME_MAX _POSIX_SYMLINK_MAX
#endif
-// LSB has a broken version of qOffsetOf that can't be used at compile time
-// https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=3462
-#undef qOffsetOf
-#define qOffsetOf(TYPE, MEMBER) __builtin_qOffsetOf (TYPE, MEMBER)
#endif
// #define DATABLOB_DEBUG
@@ -1249,20 +1246,20 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
{
QML_MEMORY_SCOPE_URL(blob->url());
- QQmlDataBlob::Data d;
- d.d = &data;
+ QQmlDataBlob::SourceCodeData d;
+ d.inlineSourceCode = QString::fromUtf8(data);
setData(blob, d);
}
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
QML_MEMORY_SCOPE_URL(blob->url());
- QQmlDataBlob::Data d;
- d.d = &fileName;
+ QQmlDataBlob::SourceCodeData d;
+ d.fileInfo = QFileInfo(fileName);
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d)
+void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob);
@@ -1529,7 +1526,8 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
return false;
}
- *it = priority;
+ if (it != m_unresolvedImports.end())
+ *it = priority;
return true;
}
}
@@ -2009,6 +2007,16 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback()
{
}
+QString QQmlTypeData::TypeReference::qualifiedName() const
+{
+ QString result;
+ if (!prefix.isEmpty()) {
+ result = prefix + QLatin1Char('.');
+ }
+ result.append(type->qmlTypeName());
+ return result;
+}
+
QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
: QQmlTypeLoader::Blob(url, QmlFile, manager),
m_typesResolved(false), m_implicitImportLoaded(false)
@@ -2069,7 +2077,7 @@ bool QQmlTypeData::tryLoadFromDiskCache()
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
{
QString error;
- if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), v4->iselFactory.data(), &error)) {
qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error;
return false;
}
@@ -2154,6 +2162,23 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName
aliasCreator.appendAliasPropertiesToMetaObjects();
}
+static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+{
+ for (const auto &typeRef: typeRefs) {
+ if (typeRef.typeData) {
+ const auto unit = typeRef.typeData->compilationUnit();
+ hash->addData(unit->data->md5Checksum, sizeof(unit->data->md5Checksum));
+ } else if (typeRef.type) {
+ const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type->metaObject());
+ bool ok = false;
+ hash->addData(propertyCache->checksum(&ok));
+ if (!ok)
+ return false;
+ }
+ }
+ return true;
+}
+
void QQmlTypeData::done()
{
QDeferredCleanup cleanup([this]{
@@ -2234,18 +2259,24 @@ void QQmlTypeData::done()
QQmlEngine *const engine = typeLoader()->engine();
+ const auto dependencyHasher = [engine, resolvedTypeCache, this](QCryptographicHash *hash) {
+ if (!resolvedTypeCache.addToHash(hash, engine))
+ return false;
+ return ::addTypeReferenceChecksumsToHash(m_compositeSingletons, hash, engine);
+ };
+
// verify if any dependencies changed if we're using a cache
- if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) {
+ if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString();
if (!loadFromSource())
return;
- m_backupSourceCode.clear();
+ m_backupSourceCode = SourceCodeData();
m_compiledData = nullptr;
}
if (!m_document.isNull()) {
// Compile component
- compile(typeNameCache, resolvedTypeCache);
+ compile(typeNameCache, resolvedTypeCache, dependencyHasher);
} else {
createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
}
@@ -2346,13 +2377,9 @@ bool QQmlTypeData::loadImplicitImport()
return true;
}
-void QQmlTypeData::dataReceived(const Data &data)
+void QQmlTypeData::dataReceived(const SourceCodeData &data)
{
- QString error;
- m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp);
- // if we failed to read the source code, process it _after_ we've tried
- // to use the disk cache, in order to support scenarios where the source
- // was removed deliberately.
+ m_backupSourceCode = data;
if (tryLoadFromDiskCache())
return;
@@ -2360,8 +2387,8 @@ void QQmlTypeData::dataReceived(const Data &data)
if (isError())
return;
- if (!error.isEmpty()) {
- setError(error);
+ if (!m_backupSourceCode.exists()) {
+ setError(QQmlTypeLoader::tr("No such file or directory"));
return;
}
@@ -2380,12 +2407,19 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un
bool QQmlTypeData::loadFromSource()
{
- QString code = QString::fromUtf8(m_backupSourceCode);
m_document.reset(new QmlIR::Document(isDebugging()));
- m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp;
+ m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
QQmlEngine *qmlEngine = typeLoader()->engine();
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
- if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) {
+
+ QString sourceError;
+ const QString source = m_backupSourceCode.readAll(&sourceError);
+ if (!sourceError.isEmpty()) {
+ setError(sourceError);
+ return false;
+ }
+
+ if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
errors.reserve(compiler.errors.count());
for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
@@ -2407,6 +2441,7 @@ void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit>
m_document.reset(new QmlIR::Document(isDebugging()));
QmlIR::IRLoader loader(unit->data, m_document.data());
loader.load();
+ m_document->jsModule.setFileName(finalUrlString());
m_document->javaScriptCompilationUnit = unit;
continueLoadFromIR();
}
@@ -2503,24 +2538,27 @@ QString QQmlTypeData::stringAt(int index) const
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
Q_ASSERT(m_compiledData.isNull());
+ const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit && m_document->javaScriptCompilationUnit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation;
+
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache);
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
m_compiledData = compiler.compile();
if (!m_compiledData) {
setError(compiler.compilationErrors());
return;
}
- const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode;
+ const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation;
if (trySaveToDisk) {
QString errorString;
if (m_compiledData->saveToDisk(url(), &errorString)) {
QString error;
- if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) {
+ if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), enginePrivate->v4engine()->iselFactory.data(), &error)) {
// ignore error, keep using the in-memory compilation unit.
}
} else {
@@ -2580,6 +2618,10 @@ void QQmlTypeData::resolveTypes()
}
}
+ std::stable_sort(m_compositeSingletons.begin(), m_compositeSingletons.end(), [](const TypeReference &lhs, const TypeReference &rhs){
+ return lhs.qualifiedName() < rhs.qualifiedName();
+ });
+
for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
unresolvedRef != end; ++unresolvedRef) {
@@ -2873,14 +2915,14 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit
void linkBackendToEngine(QV4::ExecutionEngine *) override {}
};
-void QQmlScriptBlob::dataReceived(const Data &data)
+void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
if (!disableDiskCache() || forceDiskCache()) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
QString error;
- if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) {
+ if (unit->loadFromDisk(url(), data.sourceTimeStamp(), v4->iselFactory.data(), &error)) {
initializeFromCompilationUnit(unit);
return;
} else {
@@ -2891,8 +2933,9 @@ void QQmlScriptBlob::dataReceived(const Data &data)
QmlIR::Document irUnit(isDebugging());
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
QString error;
- QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp));
+ QString source = data.readAll(&error);
if (!error.isEmpty()) {
setError(error);
return;
@@ -2917,8 +2960,7 @@ void QQmlScriptBlob::dataReceived(const Data &data)
irUnit.jsModule.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary;
QmlIR::QmlUnitGenerator qmlGenerator;
- QV4::CompiledData::ResolvedTypeReferenceMap emptyDependencies;
- QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit, m_typeLoader->engine(), emptyDependencies);
+ QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit);
Q_ASSERT(!unit->data);
// The js unit owns the data and will free the qml unit.
unit->data = unitData;
@@ -3056,10 +3098,10 @@ void QQmlQmldirData::setPriority(int priority)
m_priority = priority;
}
-void QQmlQmldirData::dataReceived(const Data &data)
+void QQmlQmldirData::dataReceived(const SourceCodeData &data)
{
QString error;
- m_content = QString::fromUtf8(data.readAll(&error));
+ m_content = data.readAll(&error);
if (!error.isEmpty()) {
setError(error);
return;
@@ -3071,34 +3113,54 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *
Q_UNIMPLEMENTED();
}
-QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const
+QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
{
- Q_ASSERT(!d.isNull());
error->clear();
- if (d.isT1()) {
- if (sourceTimeStamp)
- *sourceTimeStamp = 0;
- return *d.asT1();
- }
- QFile f(*d.asT2());
+ if (!inlineSourceCode.isEmpty())
+ return inlineSourceCode;
+
+ QFile f(fileInfo.absoluteFilePath());
if (!f.open(QIODevice::ReadOnly)) {
*error = f.errorString();
- return QByteArray();
+ return QString();
}
- if (sourceTimeStamp) {
- QDateTime timeStamp = QFileInfo(f).lastModified();
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!timeStamp.isValid())
- timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
- *sourceTimeStamp = timeStamp.toMSecsSinceEpoch();
+
+ const qint64 fileSize = fileInfo.size();
+
+ if (uchar *mappedData = f.map(0, fileSize)) {
+ QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
+ f.unmap(mappedData);
+ return source;
}
- QByteArray data(f.size(), Qt::Uninitialized);
+
+ QByteArray data(fileSize, Qt::Uninitialized);
if (f.read(data.data(), data.length()) != data.length()) {
*error = f.errorString();
- return QByteArray();
+ return QString();
}
- return data;
+ return QString::fromUtf8(data);
+}
+
+QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
+{
+ if (!inlineSourceCode.isEmpty())
+ return QDateTime();
+
+ QDateTime timeStamp = fileInfo.lastModified();
+ if (timeStamp.isValid())
+ return timeStamp;
+
+ static QDateTime appTimeStamp;
+ if (!appTimeStamp.isValid())
+ appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+ return appTimeStamp;
+}
+
+bool QQmlDataBlob::SourceCodeData::exists() const
+{
+ if (!inlineSourceCode.isEmpty())
+ return true;
+ return fileInfo.exists();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 915b1bcc4c..48e7d5cba4 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -54,6 +54,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qobject.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qfileinfo.h>
#if QT_CONFIG(qml_network)
#include <QtNetwork/qnetworkreply.h>
#endif
@@ -130,16 +131,16 @@ public:
QList<QQmlError> errors() const;
- class Data {
+ class SourceCodeData {
public:
- QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const;
+ QString readAll(QString *error) const;
+ QDateTime sourceTimeStamp() const;
+ bool exists() const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
- inline Data();
- Data(const Data &);
- Data &operator=(const Data &);
- QBiPointer<const QByteArray, const QString> d;
+ QString inlineSourceCode;
+ QFileInfo fileInfo;
};
protected:
@@ -152,7 +153,7 @@ protected:
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
- virtual void dataReceived(const Data &) = 0;
+ virtual void dataReceived(const SourceCodeData &) = 0;
virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0;
virtual void done();
#if QT_CONFIG(qml_network)
@@ -339,7 +340,7 @@ private:
void setData(QQmlDataBlob *, const QByteArray &);
void setData(QQmlDataBlob *, const QString &fileName);
- void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
+ void setData(QQmlDataBlob *, const QQmlDataBlob::SourceCodeData &);
void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit);
template<typename T>
@@ -400,6 +401,7 @@ public:
int minorVersion;
QQmlTypeData *typeData;
QString prefix; // used by CompositeSingleton types
+ QString qualifiedName() const;
bool needsCreation;
};
@@ -436,7 +438,7 @@ public:
protected:
void done() override;
void completed() override;
- void dataReceived(const Data &) override;
+ void dataReceived(const SourceCodeData &) override;
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void allDependenciesDone() override;
void downloadProgressChanged(qreal) override;
@@ -454,7 +456,7 @@ private:
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true);
@@ -462,8 +464,7 @@ private:
void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- qint64 m_sourceTimeStamp = 0;
- QByteArray m_backupSourceCode; // used when cache verification fails.
+ SourceCodeData m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
QV4::CompiledData::TypeReferenceMap m_typeReferences;
@@ -547,7 +548,7 @@ public:
QQmlScriptData *scriptData() const;
protected:
- void dataReceived(const Data &) override;
+ void dataReceived(const SourceCodeData &) override;
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void done() override;
@@ -578,7 +579,7 @@ public:
void setPriority(int);
protected:
- void dataReceived(const Data &) override;
+ void dataReceived(const SourceCodeData &) override;
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) override;
private:
@@ -587,11 +588,6 @@ private:
int m_priority;
};
-QQmlDataBlob::Data::Data()
-{
-}
-
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index c4422afa9c..7b98096a7f 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -129,15 +129,20 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q
return w.asReturnedValue();
}
-static int enumForSingleton(String *name, QObject *qobjectSingleton)
+static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
+ QQmlType *type)
{
+ bool ok;
+ int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok)
+ return value;
+
// ### Optimize
QByteArray enumName = name->toQString().toUtf8();
const QMetaObject *metaObject = qobjectSingleton->metaObject();
for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
QMetaEnum e = metaObject->enumerator(ii);
- bool ok;
- int value = e.keyToValue(enumName.constData(), &ok);
+ value = e.keyToValue(enumName.constData(), &ok);
if (ok)
return value;
}
@@ -183,7 +188,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
// check for enum value
const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
- const int value = enumForSingleton(name, qobjectSingleton);
+ const int value = enumForSingleton(v4, name, qobjectSingleton, type);
if (value != -1)
return QV4::Primitive::fromInt32(value).asReturnedValue();
}
@@ -196,7 +201,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
// Warn when attempting to access a lowercased enum value, singleton case
if (!ok && includeEnums && !name->startsWithUpper()) {
- const int value = enumForSingleton(name, qobjectSingleton);
+ const int value = enumForSingleton(v4, name, qobjectSingleton, type);
if (value != -1)
return throwLowercaseEnumError(v4, name, type);
}
@@ -337,4 +342,44 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
return false;
}
+ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var)
+{
+ Q_ASSERT(typeObject->as<QV4::QmlTypeWrapper>());
+ const QV4::QmlTypeWrapper *typeWrapper = static_cast<const QV4::QmlTypeWrapper *>(typeObject);
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+ QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
+
+ // can only compare a QObject* against a QML type
+ const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
+ if (!wrapper)
+ return engine->throwTypeError();
+
+ // in case the wrapper outlived the QObject*
+ const QObject *wrapperObject = wrapper->object();
+ if (!wrapperObject)
+ return engine->throwTypeError();
+
+ const int myTypeId = typeWrapper->d()->type->typeId();
+ QQmlMetaObject myQmlType;
+ if (myTypeId == 0) {
+ // we're a composite type; a composite type cannot be equal to a
+ // non-composite object instance (Rectangle{} is never an instance of
+ // CustomRectangle)
+ QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false);
+ Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
+ if (!theirDData->compilationUnit)
+ return Encode(false);
+
+ QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type->sourceUrl());
+ CompiledData::CompilationUnit *cu = td->compilationUnit();
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ } else {
+ myQmlType = qenginepriv->metaObjectForType(myTypeId);
+ }
+
+ const QMetaObject *theirType = wrapperObject->metaObject();
+
+ return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index cfb6cb0ec9..c584458ed4 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -103,7 +103,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object
static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static bool isEqualTo(Managed *that, Managed *o);
-
+ static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
};
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 490a4e19ab..f464a099e0 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -104,8 +104,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
if (v4) {
QV4::Scope scope(v4);
QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
- if (sp)
- *(sp->data() + m_index) = QV4::Primitive::nullValue();
+ if (sp) {
+ QV4::MemberData::Index index{ sp->d(), static_cast<uint>(m_index) };
+ index.set(v4, QV4::Primitive::nullValue());
+ }
}
m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
@@ -329,7 +331,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (size) {
QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size);
propertyAndMethodStorage.set(v4, data);
- std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined());
}
// Need JS wrapper to ensure properties/methods are marked.
@@ -364,77 +366,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromInt32(v);
+ md->set(cache->engine, id, QV4::Primitive::fromInt32(v));
}
void QQmlVMEMetaObject::writeProperty(int id, bool v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromBoolean(v);
+ md->set(cache->engine, id, QV4::Primitive::fromBoolean(v));
}
void QQmlVMEMetaObject::writeProperty(int id, double v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromDouble(v);
+ md->set(cache->engine, id, QV4::Primitive::fromDouble(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newString(v);
+ md->set(cache->engine, id, cache->engine->newString(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v);
+ md->set(cache->engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(cache->engine, v)));
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
if (v && !guard) {
@@ -592,7 +594,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
QVariant variant(qVariantFromValue(QList<QObject*>()));
v = cache->engine->newVariantObject(variant);
- *(md->data() + id) = v;
+ md->set(cache->engine, id, v);
}
return static_cast<QList<QObject *> *>(v->d()->data().data());
}
@@ -742,7 +744,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
QVariant propertyAsVariant;
- if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
+ if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
propertyAsVariant = v->d()->data();
QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
}
@@ -815,9 +817,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
case QV4::CompiledData::Property::Quaternion:
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (!v) {
- *(md->data() + id) = cache->engine->newVariantObject(QVariant());
+ md->set(cache->engine, id, cache->engine->newVariantObject(QVariant()));
v = (md->data() + id)->as<QV4::VariantObject>();
QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
}
@@ -1028,7 +1030,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>();
if (oldVariant)
oldVariant->removeVmePropertyReference();
@@ -1054,7 +1056,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
guard->setGuardedValue(valueObject, this, id);
// Write the value and emit change signal as appropriate.
- *(md->data() + id) = value;
+ md->set(cache->engine, id, value);
activate(object, methodOffset() + id, 0);
}
@@ -1067,7 +1069,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>();
if (oldv)
oldv->removeVmePropertyReference();
@@ -1081,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// Write the value and emit change signal as appropriate.
QVariant currentValue = readPropertyAsVariant(id);
- *(md->data() + id) = newv;
+ md->set(cache->engine, id, newv);
if ((currentValue.userType() != value.userType() || currentValue != value))
activate(object, methodOffset() + id, 0);
} else {
@@ -1093,14 +1095,14 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
} else {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
- QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
needActivate = (!v ||
v->d()->data().userType() != value.userType() ||
v->d()->data() != value);
if (v)
v->removeVmePropertyReference();
- *(md->data() + id) = cache->engine->newVariantObject(value);
- v = static_cast<QV4::VariantObject *>(md->data() + id);
+ md->set(cache->engine, id, cache->engine->newVariantObject(value));
+ v = static_cast<const QV4::VariantObject *>(md->data() + id);
v->addVmePropertyReference();
}
}
@@ -1139,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function)
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
- *(md->data() + methodIndex + compiledObject->nProperties) = function;
+ md->set(cache->engine, methodIndex + compiledObject->nProperties, function);
}
QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index d0d9f080da..b18904fc73 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1597,10 +1597,12 @@ struct QQmlXMLHttpRequestWrapper : Object {
QQmlXMLHttpRequest *request;
};
-struct QQmlXMLHttpRequestCtor : FunctionObject {
- void init(ExecutionEngine *engine);
+#define QQmlXMLHttpRequestCtorMembers(class, Member) \
+ Member(class, Pointer, Object *, proto)
- Pointer<Object> proto;
+DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) {
+ DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor);
+ void init(ExecutionEngine *engine);
};
}
@@ -1614,12 +1616,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
- static void markObjects(Heap::Base *that, ExecutionEngine *e) {
- QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that);
- if (c->proto)
- c->proto->mark(e);
- FunctionObject::markObjects(that, e);
- }
+
static void construct(const Managed *that, Scope &scope, QV4::CallData *)
{
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
@@ -1686,7 +1683,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
ExecutionEngine *v4 = engine();
Scope scope(v4);
ScopedObject p(scope, v4->newObject());
- d()->proto = p->d();
+ d()->proto.set(scope.engine, p->d());
// Methods
p->defineDefaultProperty(QStringLiteral("open"), method_open);
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index d359a0f62f..68a64a28f0 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1885,7 +1885,7 @@ void GlobalExtensions::method_qsTr(const BuiltinFunction *, Scope &scope, CallDa
ExecutionContext *parentCtx = scope.engine->currentContext;
// The first non-empty source URL in the call stack determines the translation context.
while (!!parentCtx && context.isEmpty()) {
- if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) {
+ if (CompiledData::CompilationUnit *unit = static_cast<CompiledData::CompilationUnit*>(parentCtx->d()->compilationUnit)) {
QString fileName = unit->fileName();
QUrl url(unit->fileName());
if (url.isValid() && url.isRelative()) {
@@ -2019,7 +2019,7 @@ void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope,
void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *)
{
- scope.engine->memoryManager->runGC();
+ scope.engine->memoryManager->runGC(/* forceFullCollection = */ true);
scope.result = QV4::Encode::undefined();
}
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index a5878dcffd..34bc266cb5 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -837,10 +837,9 @@ void QQDMIncubationTask::statusChanged(Status status)
} else if (isDoneIncubating(status)) {
Q_ASSERT(incubating);
// The model was deleted from under our feet, cleanup ourselves
- if (incubating->object) {
- delete incubating->object;
-
- incubating->object = 0;
+ delete incubating->object;
+ incubating->object = 0;
+ if (incubating->contextData) {
incubating->contextData->destroy();
incubating->contextData = 0;
}
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
index 21205f4490..d926ecb6ce 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qml/types/qqmlobjectmodel.cpp
@@ -178,8 +178,8 @@ public:
\ingroup qtquick-models
\brief Defines a set of items to be used as a model
- A ObjectModel contains the visual items to be used in a view.
- When a ObjectModel is used in a view, the view does not require
+ An ObjectModel contains the visual items to be used in a view.
+ When an ObjectModel is used in a view, the view does not require
a delegate since the ObjectModel already contains the visual
delegate (items).
diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index 222690e4f2..b3d1b6fc0f 100644
--- a/src/quick/accessible/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -81,6 +81,14 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const
return 0;
}
+QAccessibleInterface *QAccessibleQuickWindow::focusChild() const
+{
+ QObject *focusObject = window()->focusObject();
+ if (focusObject)
+ return QAccessible::queryAccessibleInterface(focusObject);
+ return nullptr;
+}
+
QAccessible::Role QAccessibleQuickWindow::role() const
{
return QAccessible::Window; // FIXME
diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h
index 7c103380cb..39ffcaf39c 100644
--- a/src/quick/accessible/qaccessiblequickview_p.h
+++ b/src/quick/accessible/qaccessiblequickview_p.h
@@ -65,6 +65,7 @@ public:
QAccessibleInterface *parent() const override;
QAccessibleInterface *child(int index) const override;
+ QAccessibleInterface *focusChild() const override;
QAccessible::Role role() const override;
QAccessible::State state() const override;
diff --git a/src/quick/configure.json b/src/quick/configure.json
index 4ed11e8318..047fa8c948 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -51,6 +51,7 @@
"quick-canvas": {
"label": "Canvas item",
"purpose": "Provides the Qt Quick Canvas Item",
+ "condition": "features.quick-path",
"output": [
"privateFeature"
]
@@ -97,6 +98,14 @@
"privateFeature"
]
},
+ "quick-particles": {
+ "label": "Particle support",
+ "purpose": "Provides a particle system for Qt Quick",
+ "condition": "features.quick-shadereffect && features.quick-sprite && features.opengl",
+ "output": [
+ "privateFeature"
+ ]
+ },
"quick-path": {
"label": "Path support",
"purpose": "Provides Path elements in Qt Quick",
diff --git a/src/quick/doc/snippets/qml/localstorage/hello.qml b/src/quick/doc/snippets/qml/localstorage/hello.qml
new file mode 100644
index 0000000000..959895c82a
--- /dev/null
+++ b/src/quick/doc/snippets/qml/localstorage/hello.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ color: "white"
+ width: 200
+ height: 100
+
+ Text {
+ text: "?"
+ anchors.horizontalCenter: parent.horizontalCenter
+ function findGreetings() {
+ var db = openDatabaseSync("QDeclarativeExampleDB", "1.0", "The Example QML SQL!", 1000000);
+
+ db.transaction(
+ function(tx) {
+ // Create the database if it doesn't already exist
+ tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)');
+
+ // Add (another) greeting row
+ tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]);
+
+ // Show all added greetings
+ var rs = tx.executeSql('SELECT * FROM Greeting');
+
+ var r = ""
+ for (var i = 0; i < rs.rows.length; i++) {
+ r += rs.rows.item(i).salutation + ", " + rs.rows.item(i).salutee + "\n"
+ }
+ text = r
+ }
+ )
+ }
+ Component.onCompleted: findGreetings()
+ }
+}
+//![0]
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
index 20a6d131f5..e5834eb5c8 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
@@ -64,7 +64,7 @@
In addition to the above features, GridLayout adds these features:
\list
\li \l{Layout::row}{Grid coordinates} can be specified with the \l{Layout::row}{Layout.row} and
- \l{Layout::column}{Layout.column}.
+ \l{Layout::column}{Layout.column} properties.
\li \l{GridLayout::flow}{Automatic grid coordinates} used together with the
\l{GridLayout::flow}{flow}, \l{GridLayout::rows}{rows}, and
\l{GridLayout::columns}{columns} properties.
diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
index a764402c2f..12a107491a 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
@@ -36,10 +36,10 @@
Models can be defined in C++ and then made available to QML. This is useful
for exposing existing C++ data models or otherwise complex datasets to QML.
-A C++ model class can be defined as a \l QStringList, a QObjectList or a
-\l QAbstractItemModel. The first two are useful for exposing simpler datasets,
-while QAbstractItemModel provides a more flexible solution for more complex
-models.
+A C++ model class can be defined as a \l QStringList, a \l QVariantList, a
+QObjectList or a \l QAbstractItemModel. The first three are useful for exposing
+simpler datasets, while QAbstractItemModel provides a more flexible solution for
+more complex models.
\section2 QStringList-based Model
@@ -60,10 +60,20 @@ The complete source code for this example is available in
\l {models/stringlistmodel}{examples/quick/models/stringlistmodel}
within the Qt install directory.
-\b{Note:} There is no way for the view to know that the contents of a QStringList
-have changed. If the QStringList changes, it will be necessary to reset
+\note There is no way for the view to know that the contents of a QStringList
+have changed. If the QStringList changes, it will be necessary to reset
the model by calling QQmlContext::setContextProperty() again.
+\section2 QVariantList-based Model
+
+A model may be a single \l QVariantList, which provides the contents of the list
+via the \e modelData role.
+
+The API works just like with \l QStringList, as shown in the previous section.
+
+\note There is no way for the view to know that the contents of a QVariantList
+have changed. If the QVariantList changes, it will be necessary to reset
+the model.
\section2 QObjectList-based model
diff --git a/src/quick/doc/src/concepts/positioning/topic.qdoc b/src/quick/doc/src/concepts/positioning/topic.qdoc
index 92113ece54..b28acd1f89 100644
--- a/src/quick/doc/src/concepts/positioning/topic.qdoc
+++ b/src/quick/doc/src/concepts/positioning/topic.qdoc
@@ -112,7 +112,7 @@ them, and where possible, pristine Anchor layouts should be preferred.
\section1 Anchors
-Anchors allows an item to be placed either adjacent to or inside of another,
+Anchors allow an item to be placed either adjacent to or inside of another,
by attaching one or more of the item's anchor-points (boundaries) to an
anchor-point of the other. These anchors will remain even if the dimensions
or location of one of the items changes, allowing for highly dynamic
diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
index 3fd92177f9..d80c72e0f1 100644
--- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
@@ -31,18 +31,14 @@
\section1 Scene Graph Adaptations in Qt Quick
-Originally Qt Quick only had one available renderer for parsing the scene graph
-and rendering the results to a render target. This renderer is now the default
-OpenGL Renderer which supports rendering either using the OpenGL ES 2.0 or
-OpenGL 2.0 (with framebuffer object extensions) APIs. The Qt Quick APIs have
-originally been designed with the assumption that OpenGL is always available.
-However, it is now possible to use other graphics API's to render Qt Quick
-scenes using the scene graph APIs.
+Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing
+the scene graph and rendering the results to a render target. From Qt 5.8 onwards
+Qt Quick also supports rendering in software and with Direct3D 12.
\section1 Switching between the adaptation used by the application
-The default of the OpenGL, or - in Qt builds with disabled OpenGL support - the
-software adaptation, can be overridden either by using an environment variable
+The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support -
+the software renderer. This can be overridden either by using an environment variable
or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the
legacy \c{QMLSCENE_DEVICE} environment variable before launching applications.
The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the
diff --git a/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc b/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc
index fd5bf51307..f971043b58 100644
--- a/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc
@@ -125,7 +125,7 @@ the blue rectangle and beneath any of the blue rectangle's children.
Stacking order can be influenced with the \l Item::z property. Z values below 0 will stack below the parent, and if z
values are assigned then siblings will stack in z-order (with creation order used to break ties). Z values only affect
-stacking compared to siblings and the parent item. If you have an item who is obscured by a subtree rooted above its
+stacking compared to siblings and the parent item. If you have an item which is obscured by a subtree rooted above its
parent item, no z value on that item will increase its stacking order to stack above that subtree. To stack that item
above the other subtree you'll have to alter z values farther up in the hierarchy, or re-arrange the visual item
hierarchy.
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 1167f408f5..da9379e7af 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -44,8 +44,10 @@
#include <private/qquickcontext2d_p.h>
#include <private/qquickcontext2dtexture_p.h>
#include <private/qsgadaptationlayer_p.h>
+#include <qsgtextureprovider.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtGui/QGuiApplication>
+#include <qsgtextureprovider.h>
#include <qqmlinfo.h>
#include <private/qqmlengine_p.h>
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index b9b701313e..db9b1acbdf 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -42,13 +42,16 @@
#include "qquickcanvasitem_p.h"
#include <private/qquickcontext2dtexture_p.h>
#include <private/qquickitem_p.h>
+#if QT_CONFIG(quick_shadereffect)
#include <QtQuick/private/qquickshadereffectsource_p.h>
+#endif
#include <qsgrendererinterface.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquicksvgparser_p.h>
+#if QT_CONFIG(quick_path)
#include <private/qquickpath_p.h>
-
+#endif
#include <private/qquickimage_p_p.h>
#include <qqmlinfo.h>
@@ -126,8 +129,6 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
-#define DEGREES(t) ((t) * 180.0 / M_PI)
-
#define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
THROW_GENERIC_ERROR("Not a Context2D object");
@@ -567,9 +568,10 @@ struct QQuickJSContext2D : public QV4::Object
static void method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// should these two be on the proto?
+#if QT_CONFIG(quick_path)
static void method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
-
+#endif
static void method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
@@ -1639,7 +1641,7 @@ void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::Builtin
if (callData->argc >= 3) {
qreal x = callData->args[0].toNumber();
qreal y = callData->args[1].toNumber();
- qreal angle = DEGREES(callData->args[2].toNumber());
+ qreal angle = qRadiansToDegrees(callData->args[2].toNumber());
if (!qt_is_finite(x) || !qt_is_finite(y)) {
THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
}
@@ -2032,6 +2034,7 @@ void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, Q
RETURN_UNDEFINED();
}
+#if QT_CONFIG(quick_path)
void QQuickJSContext2D::method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
@@ -2058,6 +2061,7 @@ void QQuickJSContext2D::method_set_path(const QV4::BuiltinFunction *, QV4::Scope
r->d()->context->m_v4path.set(scope.engine, value);
RETURN_UNDEFINED();
}
+#endif // QT_CONFIG(quick_path)
//rects
/*!
@@ -3364,7 +3368,7 @@ void QQuickContext2D::rotate(qreal angle)
return;
QTransform newTransform =state.matrix;
- newTransform.rotate(DEGREES(angle));
+ newTransform.rotate(qRadiansToDegrees(angle));
if (!newTransform.isInvertible()) {
state.invertibleCTM = false;
@@ -3373,7 +3377,7 @@ void QQuickContext2D::rotate(qreal angle)
state.matrix = newTransform;
buffer()->updateMatrix(state.matrix);
- m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
+ m_path = QTransform().rotate(-qRadiansToDegrees(angle)).map(m_path);
}
void QQuickContext2D::shear(qreal h, qreal v)
@@ -3770,8 +3774,8 @@ void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear
antiClockWise = !antiClockWise;
//end hack
- float sa = DEGREES(sar);
- float ea = DEGREES(ear);
+ float sa = qRadiansToDegrees(sar);
+ float ea = qRadiansToDegrees(ear);
double span = 0;
@@ -4208,7 +4212,9 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4)
proto->defineAccessorProperty(QStringLiteral("fillStyle"), QQuickJSContext2D::method_get_fillStyle, QQuickJSContext2D::method_set_fillStyle);
proto->defineAccessorProperty(QStringLiteral("shadowColor"), QQuickJSContext2D::method_get_shadowColor, QQuickJSContext2D::method_set_shadowColor);
proto->defineAccessorProperty(QStringLiteral("textBaseline"), QQuickJSContext2D::method_get_textBaseline, QQuickJSContext2D::method_set_textBaseline);
+#if QT_CONFIG(quick_path)
proto->defineAccessorProperty(QStringLiteral("path"), QQuickJSContext2D::method_get_path, QQuickJSContext2D::method_set_path);
+#endif
proto->defineAccessorProperty(QStringLiteral("lineJoin"), QQuickJSContext2D::method_get_lineJoin, QQuickJSContext2D::method_set_lineJoin);
proto->defineAccessorProperty(QStringLiteral("lineWidth"), QQuickJSContext2D::method_get_lineWidth, QQuickJSContext2D::method_set_lineWidth);
proto->defineAccessorProperty(QStringLiteral("textAlign"), QQuickJSContext2D::method_get_textAlign, QQuickJSContext2D::method_set_textAlign);
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 38b5f054bf..d90f527486 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -48,6 +48,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLFunctions>
+#include <QtGui/private/qopenglextensions_p.h>
#endif
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
@@ -499,9 +500,9 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
static bool multisamplingSupported = false;
if (!extensionsChecked) {
- const QSet<QByteArray> extensions = QOpenGLContext::currentContext()->extensions();
- multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
- && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
+ QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
+ multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
+ && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
extensionsChecked = true;
}
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index b6c45c40a8..f1f82f9e0e 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -193,8 +193,8 @@ Item {
*/
/*!
- \qmlproperty int QtQuick::MouseEvent::x
- \qmlproperty int QtQuick::MouseEvent::y
+ \qmlproperty real QtQuick::MouseEvent::x
+ \qmlproperty real QtQuick::MouseEvent::y
These properties hold the coordinates of the position supplied by the mouse event.
*/
@@ -340,8 +340,8 @@ Item {
*/
/*!
- \qmlproperty int QtQuick::WheelEvent::x
- \qmlproperty int QtQuick::WheelEvent::y
+ \qmlproperty real QtQuick::WheelEvent::x
+ \qmlproperty real QtQuick::WheelEvent::y
These properties hold the coordinates of the position supplied by the wheel event.
*/
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 4ab604b30f..27d7072f03 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -642,8 +642,10 @@ is finished.
\section1 Limitations
- \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by
- \c id. Use \c parent instead.
+ \note Due to an implementation detail, items placed inside a Flickable
+ cannot anchor to the Flickable. Instead, use \l {Item::}{parent}, which
+ refers to the Flickable's \l contentItem. The size of the content item is
+ determined by \l contentWidth and \l contentHeight.
*/
/*!
@@ -2299,7 +2301,8 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool receiverDisabled = receiver && !receiver->isEnabled();
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || contains(localPos)) && (!receiver || !receiver->keepMouseGrab() || receiverDisabled)) {
+ bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
+ if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
mouseEvent->setAccepted(false);
@@ -2319,7 +2322,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
default:
break;
}
- if ((receiver && stealThisEvent && !receiver->keepMouseGrab() && receiver != this) || receiverDisabled) {
+ if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) {
d->clearDelayedPress();
grabMouse();
} else if (d->delayedPressEvent) {
@@ -2335,7 +2338,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
d->lastPosTime = -1;
returnToBounds();
}
- if (event->type() == QEvent::MouseButtonRelease || (receiver && receiver->keepMouseGrab() && !receiverDisabled)) {
+ if (event->type() == QEvent::MouseButtonRelease || (receiverKeepsGrab && !receiverDisabled)) {
// mouse released, or another item has claimed the grab
d->lastPosTime = -1;
d->clearDelayedPress();
@@ -2349,8 +2352,11 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
- if (!isVisible() || !isEnabled() || !isInteractive())
+ if (!isVisible() || !isEnabled() || !isInteractive()) {
+ d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
+ }
+
switch (e->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 22ee3f39e4..539a374dd9 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2911,14 +2911,15 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
childItems.append(child);
-#if QT_CONFIG(cursor)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
+#if QT_CONFIG(cursor)
// if the added child has a cursor and we do not currently have any children
// with cursors, bubble the notification up
if (childPrivate->subtreeCursorEnabled && !subtreeCursorEnabled)
setHasCursorInChild(true);
#endif
+
if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
setHasHoverInChild(true);
@@ -2939,13 +2940,14 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
childItems.removeOne(child);
Q_ASSERT(!childItems.contains(child));
-#if QT_CONFIG(cursor)
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
+#if QT_CONFIG(cursor)
// turn it off, if nothing else is using it
if (childPrivate->subtreeCursorEnabled && subtreeCursorEnabled)
setHasCursorInChild(false);
#endif
+
if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
setHasHoverInChild(false);
@@ -3807,10 +3809,10 @@ QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
/*!
This function is called when an item should release graphics
- resources which are not already managed by the nodes returend from
+ resources which are not already managed by the nodes returned from
QQuickItem::updatePaintNode().
- This happens when the item is about to be removed from window it
+ This happens when the item is about to be removed from the window it
was previously rendering to. The item is guaranteed to have a
\l {QQuickItem::window()}{window} when the function is called.
@@ -6744,8 +6746,27 @@ bool QQuickItem::heightValid() const
}
/*!
- \internal
- */
+ \since 5.10
+
+ Returns the size of the item.
+
+ \sa setSize, width, height
+ */
+
+QSizeF QQuickItem::size() const
+{
+ Q_D(const QQuickItem);
+ return QSizeF(d->width, d->height);
+}
+
+
+/*!
+ \since 5.10
+
+ Sets the size of the item to \a size.
+
+ \sa size, setWidth, setHeight
+ */
void QQuickItem::setSize(const QSizeF &size)
{
Q_D(QQuickItem);
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index c9494d91bd..f58946d01d 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -237,6 +237,7 @@ public:
void setImplicitHeight(qreal);
qreal implicitHeight() const;
+ QSizeF size() const;
void setSize(const QSizeF &size);
TransformOrigin transformOrigin() const;
diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp
index 9873622f41..874130b137 100644
--- a/src/quick/items/qquickitemanimation.cpp
+++ b/src/quick/items/qquickitemanimation.cpp
@@ -327,7 +327,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act
}
if (scale != 0)
- rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale));
else {
qmlWarning(this) << QQuickParentAnimation::tr("Unable to preserve appearance under scale of 0");
ok = false;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 43f4b88833..6c0539bcc1 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -274,7 +274,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickAnchorSet>();
qmlRegisterType<QQuickAnchorAnimation>(uri, major, minor,"AnchorAnimation");
qmlRegisterType<QQuickParentAnimation>(uri, major, minor,"ParentAnimation");
-#if QT_CONFIG(quick_canvas)
+#if QT_CONFIG(quick_path)
qmlRegisterType<QQuickPathAnimation>("QtQuick",2,0,"PathAnimation");
qmlRegisterType<QQuickPathInterpolator>("QtQuick",2,0,"PathInterpolator");
#endif
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index bb23b1fd54..c662efe40e 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -689,9 +689,10 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event)
#endif
setHovered(true);
d->startScene = event->windowPos();
- d->pressAndHoldTimer.start(pressAndHoldInterval(), this);
setKeepMouseGrab(d->stealMouse);
event->setAccepted(setPressed(event->button(), true, event->source()));
+ if (event->isAccepted())
+ d->pressAndHoldTimer.start(pressAndHoldInterval(), this);
}
}
@@ -738,23 +739,34 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
bool dragY = drag()->axis() & QQuickDrag::YAxis;
QPointF dragPos = d->drag->target()->position();
+ QPointF boundedDragPos = dragPos;
if (dragX) {
- dragPos.setX(qBound(
+ dragPos.setX(startPos.x() + curLocalPos.x() - startLocalPos.x());
+ boundedDragPos.setX(qBound(
d->drag->xmin(),
- startPos.x() + curLocalPos.x() - startLocalPos.x(),
+ dragPos.x(),
d->drag->xmax()));
}
if (dragY) {
- dragPos.setY(qBound(
+ dragPos.setY(startPos.y() + curLocalPos.y() - startLocalPos.y());
+ boundedDragPos.setY(qBound(
d->drag->ymin(),
- startPos.y() + curLocalPos.y() - startLocalPos.y(),
+ dragPos.y(),
d->drag->ymax()));
}
+
+ QPointF targetPos = d->drag->target()->position();
+
if (d->drag->active())
- d->drag->target()->setPosition(dragPos);
+ d->drag->target()->setPosition(boundedDragPos);
+
+ bool dragOverThresholdX = QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(),
+ Qt::XAxis, event, d->drag->threshold());
+ bool dragOverThresholdY = QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(),
+ Qt::YAxis, event, d->drag->threshold());
- if (!d->overThreshold && (QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), Qt::XAxis, event, d->drag->threshold())
- || QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold())))
+ if (!d->overThreshold && (((targetPos.x() != boundedDragPos.x()) && dragOverThresholdX) ||
+ ((targetPos.y() != boundedDragPos.y()) && dragOverThresholdY)))
{
d->overThreshold = true;
if (d->drag->smoothed())
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 42fcee3c0d..4f4c403483 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -256,10 +256,14 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item,
qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData());
} else {
auto *mapper = signalMappers[shaderType].at(i);
- mapper->setSignalIndex(pd->notifyIndex());
+ mapper->setSignalIndex(itemMetaObject->property(d.propertyIndex).notifySignal().methodIndex());
Q_ASSERT(item->metaObject() == itemMetaObject);
- QObjectPrivate::connectImpl(item, mapper->signalIndex(), item, nullptr, mapper,
- Qt::AutoConnection, nullptr, itemMetaObject);
+ bool ok = QObjectPrivate::connectImpl(item, pd->notifyIndex(), item, nullptr, mapper,
+ Qt::AutoConnection, nullptr, itemMetaObject);
+ if (!ok)
+ qWarning() << "Failed to connect to property" << itemMetaObject->property(d.propertyIndex).name()
+ << "(" << d.propertyIndex << ", signal index" << pd->notifyIndex()
+ << ") of item" << item;
}
} else {
// If the source is set via a dynamic property, like the layer is, then we need this
diff --git a/src/quick/items/qquickpainteditem_p.h b/src/quick/items/qquickpainteditem_p.h
index 742e786335..3e160ed55a 100644
--- a/src/quick/items/qquickpainteditem_p.h
+++ b/src/quick/items/qquickpainteditem_p.h
@@ -51,7 +51,9 @@
// We mean it.
//
+#include "qquickpainteditem.h"
#include "qquickitem_p.h"
+#include "qquickpainteditem.h"
#include <QtGui/qcolor.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index 8dc0d90a2f..cfe163b4c1 100644
--- a/src/quick/items/qquickpositioners_p.h
+++ b/src/quick/items/qquickpositioners_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
class QQuickBasePositionerPrivate;
-class QQuickPositionerAttached : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 7926607e33..d317c1d19b 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -873,4 +873,11 @@ void QQuickShaderEffectPrivate::updatePolish()
q->m_impl->maybeUpdateShaders();
}
+#if QT_CONFIG(opengl)
+bool QQuickShaderEffect::isOpenGLShaderEffect() const
+{
+ return m_glImpl != Q_NULLPTR;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 7885daffbb..30bd018098 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -117,6 +117,10 @@ public:
bool isComponentComplete() const;
QString parseLog();
+#if QT_CONFIG(opengl)
+ bool isOpenGLShaderEffect() const;
+#endif
+
Q_SIGNALS:
void fragmentShaderChanged();
void vertexShaderChanged();
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index b40a9e2843..a4ce13a199 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -101,7 +101,7 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s
}
if (scale != 0)
- rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale));
else {
qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under scale of 0");
ok = false;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 57810e4ec9..bd68f39e48 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -635,8 +635,8 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
// FIXME: make this work for mouse events too and get rid of the asTouchEvent in here.
Q_ASSERT(pointerEvent->asPointerTouchEvent());
- QTouchEvent *event = pointerEvent->asPointerTouchEvent()->touchEventForItem(item);
- if (!event)
+ QScopedPointer<QTouchEvent> event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item));
+ if (event.isNull())
return false;
// For each point, check if it is accepted, if not, try the next point.
@@ -653,7 +653,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
break;
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item;
- QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false));
+ QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false));
// Send a single press and see if that's accepted
QCoreApplication::sendEvent(item, mousePress.data());
@@ -667,7 +667,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
pointerEventPoint->setGrabber(item);
if (checkIfDoubleClicked(event->timestamp())) {
- QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
+ QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false));
QCoreApplication::sendEvent(item, mouseDoubleClick.data());
event->setAccepted(mouseDoubleClick->isAccepted());
if (!mouseDoubleClick->isAccepted()) {
@@ -684,7 +684,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
} else if (touchMouseDevice == device && p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
@@ -695,7 +695,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
// no grabber, check if we care about mouse hover
// FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
// hover for touch???
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item, false));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), item, false));
if (lastMousePosition.isNull())
lastMousePosition = me->windowPos();
QPointF last = lastMousePosition;
@@ -713,7 +713,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve
} else if (p.state() & Qt::TouchPointReleased) {
// currently handled point was released
if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event.data(), mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
if (item->acceptHoverEvents() && p.screenPos() != QGuiApplicationPrivate::lastCursorPosition) {
@@ -746,6 +746,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber;
QQuickItem *oldGrabber = q->mouseGrabberItem();
+ bool fromTouch = false;
if (grabber && touchMouseId != -1 && touchMouseDevice) {
// update the touch item for mouse touch id to the new grabber
@@ -753,6 +754,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId);
if (point)
point->setGrabber(grabber);
+ fromTouch = true;
} else {
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount() == 1);
@@ -762,8 +764,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
if (oldGrabber) {
QEvent e(QEvent::UngrabMouse);
QSet<QQuickItem *> hasFiltered;
- if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered))
+ if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) {
oldGrabber->mouseUngrabEvent();
+ if (fromTouch)
+ oldGrabber->touchUngrabEvent();
+ }
}
}
@@ -811,6 +816,10 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVector<int
void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool touch)
{
Q_Q(QQuickWindow);
+ if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) {
+ qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null";
+ setMouseGrabber(nullptr);
+ }
if (Q_LIKELY(touch)) {
const auto touchDevices = QQuickPointerDevice::touchDevices();
for (auto device : touchDevices) {
@@ -824,10 +833,6 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to
}
}
}
- if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) {
- qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null";
- setMouseGrabber(nullptr);
- }
}
/*!
@@ -2397,7 +2402,6 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
} else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
- moveEvent->setAccepted(true);
for (++grabItem; grabItem != grabber->end();) {
QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
if ((**grabItem)->contains(p)) {
@@ -2472,7 +2476,10 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
event->keyboardModifiers(),
event->type());
QQuickDropEventEx::copyActions(&translatedEvent, *event);
+ translatedEvent.setAccepted(event->isAccepted());
QCoreApplication::sendEvent(item, &translatedEvent);
+ event->setAccepted(translatedEvent.isAccepted());
+ event->setDropAction(translatedEvent.dropAction());
if (event->type() == QEvent::DragEnter) {
if (translatedEvent.isAccepted()) {
grabber->grab(item);
@@ -2583,23 +2590,39 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
break;
}
+ bool touchMouseUnset = (touchMouseId == -1);
// Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
- if (touchMouseId == -1 || touchMouseId == tp.id()) {
+ if (touchMouseUnset || touchMouseId == tp.id()) {
// targetEvent is already transformed wrt local position, velocity, etc.
// FIXME: remove asTouchEvent!!!
QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false));
+ // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should
+ // report the touchpoint's grabber. Whenever we send a synthetic mouse event,
+ // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed.
+ touchMouseId = tp.id();
+ touchMouseDevice = event->device();
if (target->childMouseEventFilter(item, mouseEvent.data())) {
qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
if (t != QEvent::MouseButtonRelease) {
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
- touchMouseId = tp.id();
- touchMouseDevice = event->device();
- touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target);
+ if (touchMouseUnset) {
+ // the point was grabbed as a pure touch point before, now it will be treated as mouse
+ // but the old receiver still needs to be informed
+ if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber())
+ oldGrabber->touchUngrabEvent();
+ }
+ touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
target->grabMouse();
}
filtered = true;
}
+ if (touchMouseUnset) {
+ // Now that we're done sending a synth mouse event, and it wasn't grabbed,
+ // the touchpoint is no longer acting as a synthetic mouse. Restore previous state.
+ touchMouseId = -1;
+ touchMouseDevice = nullptr;
+ }
// Only one event can be filtered as a mouse event.
break;
}
@@ -3392,6 +3415,11 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
The specified FBO must be created in the context of the window
or one that shares with it.
+ \note \a fboId can also be set to 0. In this case rendering will target the
+ default framebuffer of whichever surface is current when the scenegraph
+ renders. \a size must still be valid, specifying the dimensions of the
+ surface.
+
\note
This function only has an effect when using the default OpenGL scene
graph adaptation.
@@ -4495,8 +4523,8 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
\note The call to the function must happen before constructing the first
QQuickWindow in the application. It cannot be changed afterwards.
- If \a backend is invalid or an error occurs, the default backend (OpenGL or
- software, depending on the Qt configuration) is used.
+ If the selected backend is invalid or an error occurs, the default backend
+ (OpenGL or software, depending on the Qt configuration) is used.
\since 5.8
*/
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
index 6856d34616..b3b8274a73 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
@@ -101,7 +101,7 @@ void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window)
}
}
-void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
+void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
{
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
if (!m_windows.contains(window))
@@ -174,7 +174,10 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
if (alsoSwap && window->isVisible()) {
//Flush backingstore to window
- m_backingStores[window]->flush(softwareRenderer->flushRegion());
+ if (!isNewExpose)
+ m_backingStores[window]->flush(softwareRenderer->flushRegion());
+ else
+ m_backingStores[window]->flush(QRegion(QRect(QPoint(0,0), window->size())));
cd->fireFrameSwapped();
}
@@ -206,7 +209,7 @@ void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window)
{
if (window->isExposed()) {
m_windows[window].updatePending = true;
- renderWindow(window);
+ renderWindow(window, true);
}
}
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h
index 02dcf4eefa..c724d18298 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h
@@ -69,7 +69,7 @@ public:
void windowDestroyed(QQuickWindow *window) override;
- void renderWindow(QQuickWindow *window);
+ void renderWindow(QQuickWindow *window, bool isNewExpose = false);
void exposureChanged(QQuickWindow *window) override;
QImage grab(QQuickWindow *window) override;
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 9207fdbc55..bb2671f6c3 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -134,6 +134,7 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context)
, m_bindable(0)
, m_changed_emitted(false)
, m_is_rendering(false)
+ , m_is_preprocessing(false)
{
}
@@ -287,6 +288,8 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
void QSGRenderer::preprocess()
{
+ m_is_preprocessing = true;
+
QSGRootNode *root = rootNode();
Q_ASSERT(root);
@@ -298,6 +301,11 @@ void QSGRenderer::preprocess()
for (QSet<QSGNode *>::const_iterator it = items.constBegin();
it != items.constEnd(); ++it) {
QSGNode *n = *it;
+
+ // If we are currently preprocessing, check this node hasn't been
+ // deleted or something. we don't want a use-after-free!
+ if (m_nodes_dont_preprocess.contains(n)) // skip
+ continue;
if (!nodeUpdater()->isNodeBlocked(n, root)) {
n->preprocess();
}
@@ -315,8 +323,13 @@ void QSGRenderer::preprocess()
updatePassTime = frameTimer.nsecsElapsed();
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame,
QQuickProfiler::SceneGraphRendererUpdate);
+
+ m_is_preprocessing = false;
+ m_nodes_dont_preprocess.clear();
}
+
+
void QSGRenderer::addNodesToPreprocess(QSGNode *node)
{
for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
@@ -329,8 +342,13 @@ void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
{
for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
removeNodesToPreprocess(c);
- if (node->flags() & QSGNode::UsePreprocess)
+ if (node->flags() & QSGNode::UsePreprocess) {
m_nodes_to_preprocess.remove(node);
+
+ // If preprocessing *now*, mark the node as gone.
+ if (m_is_preprocessing)
+ m_nodes_dont_preprocess.insert(node);
+ }
}
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 4589685765..1ea2775e6f 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -118,11 +118,13 @@ private:
QSGNodeUpdater *m_node_updater;
QSet<QSGNode *> m_nodes_to_preprocess;
+ QSet<QSGNode *> m_nodes_dont_preprocess;
const QSGBindable *m_bindable;
uint m_changed_emitted : 1;
uint m_is_rendering : 1;
+ uint m_is_preprocessing : 1;
};
class Q_QUICK_PRIVATE_EXPORT QSGBindable
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 412023564f..f90706affe 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -40,7 +40,6 @@
#include "qsgadaptationlayer_p.h"
#include <qmath.h>
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qrawfont_p.h>
@@ -57,9 +56,8 @@ static QElapsedTimer qsg_render_timer;
QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
-QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
- : m_manager(man)
- , m_pendingGlyphs(64)
+QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font)
+ : m_pendingGlyphs(64)
{
Q_ASSERT(font.isValid());
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index a8e35b1ac1..ba146b884f 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -73,7 +73,6 @@ QT_BEGIN_NAMESPACE
class QSGNode;
class QImage;
class TextureReference;
-class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldGlyphNode;
class QOpenGLContext;
class QSGInternalImageNode;
@@ -409,7 +408,7 @@ public:
class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCache
{
public:
- QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
+ QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font);
virtual ~QSGDistanceFieldGlyphCache();
struct Metrics {
@@ -443,8 +442,6 @@ public:
bool operator == (const Texture &other) const { return textureId == other.textureId; }
};
- const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; }
-
const QRawFont &referenceFont() const { return m_referenceFont; }
qreal fontScale(qreal pixelSize) const
@@ -514,8 +511,6 @@ protected:
inline bool isCoreProfile() const { return m_coreProfile; }
private:
- QSGDistanceFieldGlyphCacheManager *m_manager;
-
QRawFont m_referenceFont;
int m_glyphCount;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index d52f69c7a3..ff2379ecb5 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -333,7 +333,6 @@ QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderCont
QSGRenderContext::QSGRenderContext(QSGContext *context)
: m_sg(context)
- , m_distanceFieldCacheManager(0)
{
}
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 2f5d5790ee..bd10453131 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -78,7 +78,6 @@ class QSGMaterial;
class QSGRenderLoop;
class QSGLayer;
class QQuickTextureFactory;
-class QSGDistanceFieldGlyphCacheManager;
class QSGContext;
class QQuickPaintedItem;
class QSGRendererInterface;
@@ -194,7 +193,7 @@ protected:
QMutex m_mutex;
QHash<QQuickTextureFactory *, QSGTexture *> m_textures;
QSet<QSGTexture *> m_texturesToDelete;
- QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager;
+ QHash<QRawFont, QSGDistanceFieldGlyphCache*> m_glyphCaches;
QSet<QFontEngine *> m_fontEnginesToClean;
};
diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp
index d31a7025e5..be5fec9dab 100644
--- a/src/quick/scenegraph/qsgdefaultcontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultcontext.cpp
@@ -39,7 +39,6 @@
#include "qsgdefaultcontext_p.h"
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h>
#include <QtQuick/private/qsgdefaultinternalimagenode_p.h>
#include <QtQuick/private/qsgdefaultpainternode_p.h>
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index f0a336e229..ba25172d2f 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -42,7 +42,6 @@
#include <QtGui/private/qdistancefield_p.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtQml/private/qqmlglobal_p.h>
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <qopenglfunctions.h>
#include <qopenglframebufferobject.h>
#include <qmath.h>
@@ -60,8 +59,8 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI
# define QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING 2
#endif
-QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
- : QSGDistanceFieldGlyphCache(man, c, font)
+QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font)
+ : QSGDistanceFieldGlyphCache(c, font)
, m_maxTextureSize(0)
, m_maxTextureCount(3)
, m_blitProgram(0)
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index 57dc4a5d07..fe365495c2 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -69,7 +69,7 @@ class QOpenGLFunctions_3_2_Core;
class Q_QUICK_PRIVATE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache
{
public:
- QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
+ QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font);
virtual ~QSGDefaultDistanceFieldGlyphCache();
void requestGlyphs(const QSet<glyph_t> &glyphs) override;
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
index b856d99bc1..0d42102f36 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
@@ -42,11 +42,33 @@
QT_BEGIN_NAMESPACE
+QSGDefaultGlyphNode::QSGDefaultGlyphNode()
+ : m_glyphNodeType(RootGlyphNode)
+ , m_dirtyGeometry(false)
+{
+ setFlag(UsePreprocess);
+}
+
+QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
+{
+ if (m_glyphNodeType == SubGlyphNode)
+ return;
+
+ qDeleteAll(m_nodesToDelete);
+ m_nodesToDelete.clear();
+}
+
void QSGDefaultGlyphNode::setMaterialColor(const QColor &color)
{
static_cast<QSGTextMaskMaterial *>(m_material)->setColor(color);
}
+void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
+{
+ QSGBasicGlyphNode::setGlyphs(position, glyphs);
+ m_dirtyGeometry = true;
+}
+
void QSGDefaultGlyphNode::update()
{
QRawFont font = m_glyphs.rawFont();
@@ -84,4 +106,110 @@ void QSGDefaultGlyphNode::update()
markDirty(DirtyGeometry);
}
+void QSGDefaultGlyphNode::preprocess()
+{
+ qDeleteAll(m_nodesToDelete);
+ m_nodesToDelete.clear();
+
+ if (m_dirtyGeometry)
+ updateGeometry();
+}
+
+void QSGDefaultGlyphNode::updateGeometry()
+{
+ // Remove previously created sub glyph nodes
+ // We assume all the children are sub glyph nodes
+ QSGNode *subnode = firstChild();
+ while (subnode) {
+ // We can't delete the node now as it might be in the preprocess list
+ // It will be deleted in the next preprocess
+ m_nodesToDelete.append(subnode);
+ subnode = subnode->nextSibling();
+ }
+ removeAllChildNodes();
+
+ GlyphInfo glyphInfo;
+
+ const QVector<quint32> indexes = m_glyphs.glyphIndexes();
+ const QVector<QPointF> positions = m_glyphs.positions();
+
+ const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384
+ const int maxVertices = maxGlyphs * 4; // 65536
+ const int maxIndexes = maxGlyphs * 6; // 98304
+
+ for (int i = 0; i < indexes.size(); ++i) {
+ const int glyphIndex = indexes.at(i);
+ const QPointF position = positions.at(i);
+
+ // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
+ // "glyphsInOtherNodes" concept as overflow for if there are more than
+ // 65536 (16384 * 4) vertices to render which would otherwise exceed
+ // the maximum index size. This will cause sub-nodes to be recursively
+ // created to handle any number of glyphs.
+ if (i >= maxGlyphs) {
+ glyphInfo.indexes.append(glyphIndex);
+ glyphInfo.positions.append(position);
+ continue;
+ }
+ }
+
+ if (!glyphInfo.indexes.isEmpty()) {
+ QGlyphRun subNodeGlyphRun(m_glyphs);
+ subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes);
+ subNodeGlyphRun.setPositions(glyphInfo.positions);
+
+ QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode();
+ subNode->setGlyphNodeType(SubGlyphNode);
+ subNode->setColor(m_color);
+ subNode->setStyle(m_style);
+ subNode->setStyleColor(m_styleColor);
+ subNode->setGlyphs(m_position, subNodeGlyphRun);
+ subNode->update();
+ subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
+ appendChildNode(subNode);
+
+ QSGGeometry *g = geometry();
+
+ QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D();
+ quint16 *indexData = g->indexDataAsUShort();
+
+ QVector<QSGGeometry::TexturedPoint2D> tempVertexData(maxVertices);
+ QVector<quint16> tempIndexData(maxIndexes);
+
+ for (int i = 0; i < maxGlyphs; i++) {
+ tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0];
+ tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1];
+ tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2];
+ tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3];
+
+ tempIndexData[i * 6 + 0] = indexData[i * 6 + 0];
+ tempIndexData[i * 6 + 1] = indexData[i * 6 + 1];
+ tempIndexData[i * 6 + 2] = indexData[i * 6 + 2];
+ tempIndexData[i * 6 + 3] = indexData[i * 6 + 3];
+ tempIndexData[i * 6 + 4] = indexData[i * 6 + 4];
+ tempIndexData[i * 6 + 5] = indexData[i * 6 + 5];
+ }
+
+ g->allocate(maxVertices, maxIndexes);
+ vertexData = g->vertexDataAsTexturedPoint2D();
+ indexData = g->indexDataAsUShort();
+
+ for (int i = 0; i < maxGlyphs; i++) {
+ vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0];
+ vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1];
+ vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2];
+ vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3];
+
+ indexData[i * 6 + 0] = tempIndexData[i * 6 + 0];
+ indexData[i * 6 + 1] = tempIndexData[i * 6 + 1];
+ indexData[i * 6 + 2] = tempIndexData[i * 6 + 2];
+ indexData[i * 6 + 3] = tempIndexData[i * 6 + 3];
+ indexData[i * 6 + 4] = tempIndexData[i * 6 + 4];
+ indexData[i * 6 + 5] = tempIndexData[i * 6 + 5];
+ }
+ }
+
+ m_dirtyGeometry = false;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h
index 0eb7a4e4bd..37a89c70b9 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h
@@ -59,8 +59,31 @@ QT_BEGIN_NAMESPACE
class QSGDefaultGlyphNode : public QSGBasicGlyphNode
{
public:
+ QSGDefaultGlyphNode();
+ ~QSGDefaultGlyphNode();
void setMaterialColor(const QColor &color) override;
+ void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override;
void update() override;
+ void preprocess() override;
+ void updateGeometry();
+
+private:
+ enum DefaultGlyphNodeType {
+ RootGlyphNode,
+ SubGlyphNode
+ };
+
+ void setGlyphNodeType(DefaultGlyphNodeType type) { m_glyphNodeType = type; }
+
+ DefaultGlyphNodeType m_glyphNodeType;
+ QLinkedList<QSGNode *> m_nodesToDelete;
+
+ struct GlyphInfo {
+ QVector<quint32> indexes;
+ QVector<QPointF> positions;
+ };
+
+ uint m_dirtyGeometry: 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp
index fc8040e67b..6fa9dd6359 100644
--- a/src/quick/scenegraph/qsgdefaultlayer.cpp
+++ b/src/quick/scenegraph/qsgdefaultlayer.cpp
@@ -44,6 +44,7 @@
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/private/qopenglextensions_p.h>
#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
@@ -330,9 +331,9 @@ void QSGDefaultLayer::grab()
if (effectiveSamples <= 1) {
m_multisampling = false;
} else {
- const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
- m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
- && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
+ QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(funcs);
+ m_multisampling = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
+ && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
}
m_multisamplingChecked = true;
}
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index aaf4635c0c..db0eea15df 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -45,7 +45,6 @@
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgatlastexture_p.h>
#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
QT_BEGIN_NAMESPACE
@@ -159,8 +158,8 @@ void QSGDefaultRenderContext::invalidate()
delete m_depthStencilManager;
m_depthStencilManager = 0;
- delete m_distanceFieldCacheManager;
- m_distanceFieldCacheManager = 0;
+ qDeleteAll(m_glyphCaches);
+ m_glyphCaches.clear();
if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
@@ -294,13 +293,10 @@ QT_END_NAMESPACE
QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font)
{
- if (!m_distanceFieldCacheManager)
- m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
-
- QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font);
+ QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(font, 0);
if (!cache) {
- cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font);
- m_distanceFieldCacheManager->insertCache(font, cache);
+ cache = new QSGDefaultDistanceFieldGlyphCache(openglContext(), font);
+ m_glyphCaches.insert(font, cache);
}
return cache;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index 456a197ba1..32eda2d142 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -39,7 +39,6 @@
#include "qsgdistancefieldglyphnode_p.h"
#include "qsgdistancefieldglyphnode_p_p.h"
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
@@ -76,9 +75,6 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
m_glyph_cache->unregisterGlyphNode(this);
m_glyph_cache->unregisterOwnerElement(ownerElement());
}
-
- while (m_nodesToDelete.count())
- delete m_nodesToDelete.takeLast();
}
void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
@@ -158,9 +154,6 @@ void QSGDistanceFieldGlyphNode::preprocess()
{
Q_ASSERT(m_glyph_cache);
- while (m_nodesToDelete.count())
- delete m_nodesToDelete.takeLast();
-
m_glyph_cache->processPendingGlyphs();
m_glyph_cache->update();
@@ -188,13 +181,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
// Remove previously created sub glyph nodes
// We assume all the children are sub glyph nodes
QSGNode *subnode = firstChild();
+ QSGNode *nextNode = 0;
while (subnode) {
- // We can't delete the node now as it might be in the preprocess list
- // It will be deleted in the next preprocess
- m_nodesToDelete.append(subnode);
- subnode = subnode->nextSibling();
+ nextNode = subnode->nextSibling();
+ delete subnode;
+ subnode = nextNode;
}
- removeAllChildNodes();
QSGGeometry *g = geometry();
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index fc66f2f2cc..a67c659c99 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qsgdistancefieldglyphnode_p_p.h"
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <QtGui/qopenglfunctions.h>
#include <QtGui/qsurface.h>
@@ -58,7 +57,7 @@ public:
protected:
void initialize() override;
- void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc);
+ void updateAlphaRange();
void updateColor(const QVector4D &c);
void updateTextureScale(const QVector2D &ts);
@@ -98,7 +97,31 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.frag"));
}
-void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc)
+static float qt_sg_envFloat(const char *name, float defaultValue)
+{
+ if (Q_LIKELY(!qEnvironmentVariableIsSet(name)))
+ return defaultValue;
+ bool ok = false;
+ const float value = qgetenv(name).toFloat(&ok);
+ return ok ? value : defaultValue;
+}
+
+static float thresholdFunc(float glyphScale)
+{
+ static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f);
+ static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f);
+ static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f);
+ static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f);
+ return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
+}
+
+static float spreadFunc(float glyphScale)
+{
+ static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f);
+ return range / glyphScale;
+}
+
+void QSGDistanceFieldTextMaterialShader::updateAlphaRange()
{
float combinedScale = m_fontScale * m_matrixScale;
float base = thresholdFunc(combinedScale);
@@ -169,8 +192,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
updateRange = true;
}
if (updateRange) {
- updateAlphaRange(material->glyphCache()->manager()->thresholdFunc(),
- material->glyphCache()->manager()->antialiasingSpreadFunc());
+ updateAlphaRange();
}
Q_ASSERT(material->glyphCache());
@@ -334,7 +356,7 @@ public:
protected:
void initialize() override;
- void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius);
+ void updateOutlineAlphaRange(int dfRadius);
int m_outlineAlphaMax0_id;
int m_outlineAlphaMax1_id;
@@ -355,9 +377,7 @@ void DistanceFieldOutlineTextMaterialShader::initialize()
m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1");
}
-void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(ThresholdFunc thresholdFunc,
- AntialiasingSpreadFunc spreadFunc,
- int dfRadius)
+void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius)
{
float combinedScale = m_fontScale * m_matrixScale;
float base = thresholdFunc(combinedScale);
@@ -381,9 +401,7 @@ void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &stat
if (oldMaterial == 0
|| material->fontScale() != oldMaterial->fontScale()
|| state.isMatrixDirty())
- updateOutlineAlphaRange(material->glyphCache()->manager()->thresholdFunc(),
- material->glyphCache()->manager()->antialiasingSpreadFunc(),
- material->glyphCache()->distanceFieldRadius());
+ updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
}
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index c0c6bda718..7008f20925 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -59,7 +59,6 @@
QT_BEGIN_NAMESPACE
class QSGRenderContext;
-class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldTextMaterial;
class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer
{
@@ -107,7 +106,6 @@ private:
AntialiasingMode m_antialiasingMode;
QRectF m_boundingRect;
const QSGDistanceFieldGlyphCache::Texture *m_texture;
- QLinkedList<QSGNode *> m_nodesToDelete;
struct GlyphInfo {
QVector<quint32> indexes;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 38c3b8dd85..c6db3df158 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -45,7 +45,6 @@ HEADERS += \
$$PWD/util/qsgtexture.h \
$$PWD/util/qsgtexture_p.h \
$$PWD/util/qsgtextureprovider.h \
- $$PWD/util/qsgdistancefieldutil_p.h \
$$PWD/util/qsgflatcolormaterial.h \
$$PWD/util/qsgsimplematerial.h \
$$PWD/util/qsgtexturematerial.h \
@@ -62,7 +61,6 @@ SOURCES += \
$$PWD/util/qsgsimpletexturenode.cpp \
$$PWD/util/qsgtexture.cpp \
$$PWD/util/qsgtextureprovider.cpp \
- $$PWD/util/qsgdistancefieldutil.cpp \
$$PWD/util/qsgflatcolormaterial.cpp \
$$PWD/util/qsgsimplematerial.cpp \
$$PWD/util/qsgtexturematerial.cpp \
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
index 389b9e0b4e..9ffd1b4b08 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
@@ -238,9 +238,9 @@ void QSGDefaultPainterNode::updateGeometry()
void QSGDefaultPainterNode::updateRenderTarget()
{
if (!m_extensionsChecked) {
- const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
- m_multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
- && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
+ QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
+ m_multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
+ && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
m_extensionsChecked = true;
}
diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
deleted file mode 100644
index 9ca9cdb107..0000000000
--- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsgdistancefieldutil_p.h"
-
-#include <private/qsgadaptationlayer_p.h>
-#if QT_CONFIG(opengl)
-# include <QtGui/private/qopenglengineshadersource_p.h>
-#endif
-#include <QtQuick/private/qsgcontext_p.h>
-
-QT_BEGIN_NAMESPACE
-
-static float qt_sg_envFloat(const char *name, float defaultValue)
-{
- if (Q_LIKELY(!qEnvironmentVariableIsSet(name)))
- return defaultValue;
- bool ok = false;
- const float value = qgetenv(name).toFloat(&ok);
- return ok ? value : defaultValue;
-}
-
-static float defaultThresholdFunc(float glyphScale)
-{
- static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f);
- static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f);
- static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f);
- static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f);
- return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
-}
-
-static float defaultAntialiasingSpreadFunc(float glyphScale)
-{
- static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f);
- return range / glyphScale;
-}
-
-QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager()
- : m_threshold_func(defaultThresholdFunc)
- , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc)
-{
-}
-
-QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager()
-{
- qDeleteAll(m_caches);
-}
-
-QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font)
-{
- return m_caches.value(font, 0);
-}
-
-void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache)
-{
- m_caches.insert(font, cache);
-}
-
-QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h
deleted file mode 100644
index ad366cb4d4..0000000000
--- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSGDISTANCEFIELDUTIL_H
-#define QSGDISTANCEFIELDUTIL_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qrawfont.h>
-#include <private/qfontengine_p.h>
-#include <private/qsgadaptationlayer_p.h>
-
-QT_BEGIN_NAMESPACE
-
-typedef float (*ThresholdFunc)(float glyphScale);
-typedef float (*AntialiasingSpreadFunc)(float glyphScale);
-
-class QOpenGLShaderProgram;
-class QSGDistanceFieldGlyphCache;
-class QSGContext;
-
-class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCacheManager
-{
-public:
- QSGDistanceFieldGlyphCacheManager();
- ~QSGDistanceFieldGlyphCacheManager();
-
- QSGDistanceFieldGlyphCache *cache(const QRawFont &font);
- void insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache);
-
- ThresholdFunc thresholdFunc() const { return m_threshold_func; }
- void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; }
-
- AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; }
- void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; }
-
-private:
- QHash<QRawFont, QSGDistanceFieldGlyphCache *> m_caches;
-
- ThresholdFunc m_threshold_func;
- AntialiasingSpreadFunc m_antialiasingSpread_func;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSGDISTANCEFIELDUTIL_H
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp
index 7214a255df..f29c58ad9e 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.cpp
+++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp
@@ -194,19 +194,15 @@
/*!
\fn const char *QSGSimpleMaterialShader::uniformMatrixName() const
- Reimplement this function to give a different name to the uniform for
- item transformation. The default value is \c qt_Matrix.
-
+ Returns the name for the transform matrix uniform of this item.
+ The default value is \c qt_Matrix.
*/
/*!
\fn const char *QSGSimpleMaterialShader::uniformOpacityName() const
- Reimplement this function to give a different name to the uniform for
- item opacity. The default value is \c qt_Opacity.
-
- If the shader program does not implement the item opacity, the
- implemented function should return a null pointer.
+ Returns the name for the opacity uniform of this item.
+ The default value is \c qt_Opacity.
*/
/*!
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h
index 0e7219d7bd..b5b8815b4a 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.h
+++ b/src/quick/scenegraph/util/qsgsimplematerial.h
@@ -71,6 +71,7 @@ public:
resolveUniforms();
}
+ // ### Qt 6: make both virtual and fix docs
const char *uniformMatrixName() const { return "qt_Matrix"; }
const char *uniformOpacityName() const { return "qt_Opacity"; }
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 5dd16407b8..89007cff1f 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -47,6 +47,7 @@
#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
# include <private/qquickopenglshadereffectnode_p.h>
# include <private/qquickopenglshadereffect_p.h>
+# include <private/qquickshadereffect_p.h>
#endif
#include <private/qanimationgroupjob_p.h>
@@ -344,12 +345,13 @@ void QQuickTransformAnimatorJob::postSync()
}
QQuickItemPrivate *d = QQuickItemPrivate::get(m_target);
+#if QT_CONFIG(quick_shadereffect)
if (d->extra.isAllocated()
&& d->extra->layer
&& d->extra->layer->enabled()) {
d = QQuickItemPrivate::get(d->extra->layer->m_effectSource);
}
-
+#endif
m_helper->node = d->itemNode();
}
@@ -625,7 +627,8 @@ QQuickUniformAnimatorJob::QQuickUniformAnimatorJob()
void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
{
- if (qobject_cast<QQuickOpenGLShaderEffect *>(target) != nullptr)
+ QQuickShaderEffect* effect = qobject_cast<QQuickShaderEffect*>(target);
+ if (effect && effect->isOpenGLShaderEffect())
m_target = target;
}
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index 7788635e3e..0ceed7f681 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -151,6 +151,8 @@ QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage
If you are using QRunnable as base for your QQuickImageResponse
ensure automatic deletion is disabled.
+ See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
+
\sa QQuickImageProvider
*/
@@ -181,7 +183,12 @@ QString QQuickImageResponse::errorString() const
It may be reimplemented to cancel a request in the provider side, however, it is not mandatory.
- A cancelled QQuickImageResponse still needs to emit finished().
+ A cancelled QQuickImageResponse still needs to emit finished() so that the
+ engine may clean up the QQuickImageResponse.
+
+ \note finished() should not be emitted until the response is complete,
+ regardless of whether or not cancel() was called. If it is called prematurely,
+ the engine may destroy the response while it is still active, leading to a crash.
*/
void QQuickImageResponse::cancel()
{
@@ -190,7 +197,12 @@ void QQuickImageResponse::cancel()
/*!
\fn void QQuickImageResponse::finished()
- Signals that the job execution has finished (be it successfully, because an error happened or because it was cancelled).
+ Signals that the job execution has finished (be it successfully, because an
+ error happened or because it was cancelled).
+
+ \note Emission of this signal must be the final action the response performs:
+ once the signal is received, the response will subsequently be destroyed by
+ the engine.
*/
/*!
@@ -466,6 +478,8 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi
\inmodule QtQuick
\brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests.
+ See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
+
\sa QQuickImageProvider
*/
QQuickAsyncImageProvider::QQuickAsyncImageProvider()
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 4ed41a0c6c..5d7fb04b9f 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -353,10 +353,9 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
return renderControl->grab();
}
-QObject *QQuickWidgetPrivate::focusObject()
-{
- return offscreenWindow ? offscreenWindow->focusObject() : 0;
-}
+// Intentionally not overriding the QQuickWindow's focusObject.
+// Key events should go to our key event handlers, and then to the
+// QQuickWindow, not any in-scene item.
/*!
\module QtQuickWidgets
@@ -1140,7 +1139,7 @@ QSize QQuickWidget::initialSize() const
/*!
Returns the view's root \l {QQuickItem} {item}. Can be null
- when setContents/setSource has not been called, if they were called with
+ when setSource() has not been called, if it was called with
broken QtQuick code or while the QtQuick contents are being created.
*/
QQuickItem *QQuickWidget::rootObject() const
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 559321cd51..6892e6e0b4 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -99,8 +99,6 @@ public:
void destroyContext();
void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs);
- QObject *focusObject() Q_DECL_OVERRIDE;
-
#if QT_CONFIG(opengl)
GLuint textureId() const Q_DECL_OVERRIDE;
QImage grabFramebuffer() Q_DECL_OVERRIDE;
diff --git a/src/src.pro b/src/src.pro
index c2a58c3757..3bb399acd4 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -5,12 +5,12 @@ QT_FOR_CONFIG += network quick-private
SUBDIRS += \
qml
-qtHaveModule(gui) {
+qtHaveModule(gui):qtConfig(animation) {
SUBDIRS += \
quick \
qmltest
- qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
+ qtConfig(quick-particles): \
SUBDIRS += particles
qtHaveModule(widgets): SUBDIRS += quickwidgets
}