aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2017-04-13 20:56:01 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2017-04-13 20:56:01 +0200
commit1fb1c6c4f8769250dffa375e3941738eb1fcc885 (patch)
tree4f4c4afae97b54a793a0589f8ca53b7c919de728
parentd0ce320646b7f852a24f6e0a9e9621ddcedef554 (diff)
parent9c1c471e54bb12e8740b76d1c048f2f916a6ab59 (diff)
Merge remote-tracking branch 'origin/dev' into wip/pointerhandler
-rw-r--r--.gitmodules5
-rw-r--r--examples/qml/doc/src/qml-extending.qdoc18
-rw-r--r--examples/qml/referenceexamples/properties/birthdayparty.cpp31
-rw-r--r--examples/qml/referenceexamples/properties/birthdayparty.h10
-rw-r--r--examples/quick/demos/demos.pro6
-rw-r--r--examples/quick/demos/stocqt/content/StockListModel.qml35
-rw-r--r--examples/quick/rendercontrol/window_singlethreaded.cpp46
-rw-r--r--examples/quick/rendercontrol/window_singlethreaded.h2
-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/masm-defs.pri7
-rw-r--r--src/3rdparty/masm/wtf/Assertions.h2
-rw-r--r--src/imports/builtins/builtins.qmltypes32
-rw-r--r--src/imports/imports.pro6
-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/TestCase.qml61
-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/particles/qquickparticlesystem.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp13
-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/compiler.pri6
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp26
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h2
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp348
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h84
-rw-r--r--src/qml/compiler/qv4codegen.cpp41
-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.cpp60
-rw-r--r--src/qml/compiler/qv4compileddata_p.h34
-rw-r--r--src/qml/compiler/qv4compiler.cpp6
-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/qv4isel_util_p.h76
-rw-r--r--src/qml/compiler/qv4jsir.cpp6
-rw-r--r--src/qml/compiler/qv4jsir_p.h31
-rw-r--r--src/qml/compiler/qv4jssimplifier.cpp384
-rw-r--r--src/qml/compiler/qv4jssimplifier_p.h154
-rw-r--r--src/qml/configure.json13
-rw-r--r--src/qml/debugger/qqmldebug.cpp10
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc2
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc13
-rw-r--r--src/qml/jit/qv4assembler.cpp98
-rw-r--r--src/qml/jit/qv4assembler_p.h455
-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.cpp153
-rw-r--r--src/qml/jit/qv4isel_masm_p.h20
-rw-r--r--src/qml/jit/qv4targetplatform_p.h6
-rw-r--r--src/qml/jit/qv4unop.cpp2
-rw-r--r--src/qml/jsapi/qjsvalue.h6
-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.cpp229
-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/qv4engine.cpp56
-rw-r--r--src/qml/jsruntime/qv4engine_p.h57
-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/qv4globalobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp30
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-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.h7
-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/qv4objectiterator.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp8
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp21
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-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.cpp39
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h37
-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.h4
-rw-r--r--src/qml/jsruntime/qv4script_p.h2
-rw-r--r--src/qml/jsruntime/qv4string.cpp6
-rw-r--r--src/qml/jsruntime/qv4string_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.h63
-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.cpp241
-rw-r--r--src/qml/memory/memory.pri3
-rw-r--r--src/qml/memory/qv4heap_p.h37
-rw-r--r--src/qml/memory/qv4mm.cpp330
-rw-r--r--src/qml/memory/qv4mm_p.h40
-rw-r--r--src/qml/memory/qv4mmdefs_p.h138
-rw-r--r--src/qml/memory/qv4writebarrier_p.h203
-rw-r--r--src/qml/parser/qqmljsglobal_p.h16
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/qqmlcomponent.cpp40
-rw-r--r--src/qml/qml/qqmldata_p.h8
-rw-r--r--src/qml/qml/qqmlengine.cpp36
-rw-r--r--src/qml/qml/qqmlimport.cpp39
-rw-r--r--src/qml/qml/qqmlmetatype.cpp12
-rw-r--r--src/qml/qml/qqmlnotifier.cpp4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlproperty.cpp2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp172
-rw-r--r--src/qml/qml/qqmltypeloader_p.h34
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp40
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp62
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp17
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp2
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp18
-rw-r--r--src/qml/types/types.pri10
-rw-r--r--src/quick/configure.json9
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp19
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp32
-rw-r--r--src/quick/items/qquickdrag_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp25
-rw-r--r--src/quick/items/qquickflickable.cpp123
-rw-r--r--src/quick/items/qquickflickable_p.h11
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickimage.cpp3
-rw-r--r--src/quick/items/qquickitem.cpp31
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitemanimation.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp4
-rw-r--r--src/quick/items/qquickpainteditem_p.h2
-rw-r--r--src/quick/items/qquickpositioners.cpp100
-rw-r--r--src/quick/items/qquickpositioners_p.h35
-rw-r--r--src/quick/items/qquickpositioners_p_p.h41
-rw-r--r--src/quick/items/qquickrendercontrol.cpp3
-rw-r--r--src/quick/items/qquickshadereffect.cpp2
-rw-r--r--src/quick/items/qquickshadereffect_p.h2
-rw-r--r--src/quick/items/qquickstateoperations.cpp2
-rw-r--r--src/quick/items/qquicktextcontrol.cpp46
-rw-r--r--src/quick/items/qquickwindow.cpp36
-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/qsgmaterial.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp2
-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/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/qsgrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-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/qsgengine.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.cpp12
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.h1
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp2
-rw-r--r--src/quick/util/qquickanimatorjob.cpp3
-rw-r--r--src/quick/util/qquickimageprovider.cpp59
-rw-r--r--src/quick/util/qquickimageprovider.h1
-rw-r--r--src/quick/util/qquickpixmapcache.cpp59
-rw-r--r--src/quick/util/qquickpixmapcache_p.h3
-rw-r--r--src/quickwidgets/qquickwidget.cpp23
-rw-r--r--src/quickwidgets/qquickwidget_p.h2
-rw-r--r--src/src.pro2
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml43
-rw-r--r--tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp7
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp118
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp71
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp181
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp1
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations (renamed from tests/manual/v4/TestExpectations)0
-rw-r--r--tests/auto/qml/ecmascripttests/ecmascripttests.pro20
m---------tests/auto/qml/ecmascripttests/test2620
-rwxr-xr-xtests/auto/qml/ecmascripttests/test262.py (renamed from tests/manual/v4/test262.py)19
-rw-r--r--tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp77
-rw-r--r--tests/auto/qml/qml.pro31
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro7
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp163
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp55
-rw-r--r--tests/auto/qml/qmlmin/tst_qmlmin.cpp9
-rw-r--r--tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp8
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceOf/qmldir2
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml26
-rw-r--r--tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml27
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp199
-rw-r--r--tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp28
-rw-r--r--tests/auto/qml/v4misc/tst_v4misc.cpp10
-rw-r--r--tests/auto/qmltest/BLACKLIST5
-rw-r--r--tests/auto/qmltest/selftests/tst_selftests.qml10
-rw-r--r--tests/auto/quick/examples/tst_examples.cpp1
-rw-r--r--tests/auto/quick/nokeywords/tst_nokeywords.cpp1
-rw-r--r--tests/auto/quick/qquickapplication/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickflickable/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickflickable/data/nestedSlider.qml36
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp328
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp2
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/BLACKLIST6
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp2
-rw-r--r--tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml12
-rw-r--r--tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml9
-rw-r--r--tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp44
-rw-r--r--tests/auto/quick/qquickwindow/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp258
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp76
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp28
-rw-r--r--tests/auto/toolsupport/tst_toolsupport.cpp4
-rw-r--r--tests/benchmarks/qml/holistic/testtypes.h1
-rw-r--r--tests/manual/scenegraph_lancelot/scenegrabber/main.cpp5
m---------tests/manual/v4/test2620
-rw-r--r--tests/manual/v4/tests.pro15
-rw-r--r--tools/qml/main.cpp6
-rw-r--r--tools/qmlcachegen/qmlcache.prf55
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp116
-rw-r--r--tools/qmlcachegen/qmlcachegen.pro18
-rw-r--r--tools/qmljs/qmljs.cpp2
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp9
-rw-r--r--tools/qmlscene/main.cpp86
-rw-r--r--tools/tools.pro9
289 files changed, 6727 insertions, 3721 deletions
diff --git a/.gitmodules b/.gitmodules
index 881629497e..c9561f396d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,3 @@
-[submodule "tests/manual/v4/test262"]
- path = tests/manual/v4/test262
+[submodule "tests/auto/qml/ecmascripttests/test262"]
+ path = tests/auto/qml/ecmascripttests/test262
url = ../qtdeclarative-testsuites.git
- update = none
diff --git a/examples/qml/doc/src/qml-extending.qdoc b/examples/qml/doc/src/qml-extending.qdoc
index b4174426a8..f99aca5457 100644
--- a/examples/qml/doc/src/qml-extending.qdoc
+++ b/examples/qml/doc/src/qml-extending.qdoc
@@ -73,24 +73,24 @@ This example builds on:
\li \l {Extending QML - Adding Types Example}
\endlist
-Shows how to use \l {QQmlEngine::}{qmlRegisterExtendedType()} to provide an \l {Registering
-Extension Objects}{extension object} to a \l QLineEdit without modifying or
-subclassing.
+Shows how to use \l {QQmlEngine::}{qmlRegisterExtendedType()} to provide an
+\l {Registering Extension Objects}{extension object} to a \l QLineEdit without modifying or
+subclassing it.
+
+Firstly, the LineEditExtension class is registered with the QML system as an extension of QLineEdit:
\snippet referenceexamples/extended/main.cpp 0
-The QML engine instantiates a \l QLineEdit
+The QML engine then instantiates a \l QLineEdit:
\snippet referenceexamples/extended/main.cpp 1
-and sets a property that oly exists on the extension type.
+In QML, a property is set on the line edit that only exists in the LineEditExtension class:
\snippet referenceexamples/extended/example.qml 0
-The QML engine instantiates a \l QLineEdit and sets a property that
-only exists on the extension type. The extension type performs calls on the
-\l QLineEdit that otherwise will not be accessible to the QML engine.
-
+The extension type performs calls on the \l QLineEdit that otherwise will
+not be accessible to the QML engine.
*/
/*!
diff --git a/examples/qml/referenceexamples/properties/birthdayparty.cpp b/examples/qml/referenceexamples/properties/birthdayparty.cpp
index b69b7c8a11..0b426fc00b 100644
--- a/examples/qml/referenceexamples/properties/birthdayparty.cpp
+++ b/examples/qml/referenceexamples/properties/birthdayparty.cpp
@@ -57,9 +57,18 @@ void BirthdayParty::setHost(Person *c)
QQmlListProperty<Person> BirthdayParty::guests()
{
- return QQmlListProperty<Person>(this, m_guests);
+ return QQmlListProperty<Person>(this, this,
+ &BirthdayParty::appendGuest,
+ &BirthdayParty::guestCount,
+ &BirthdayParty::guest,
+ &BirthdayParty::clearGuests);
}
+void BirthdayParty::appendGuest(Person* p) {
+ m_guests.append(p);
+}
+
+
int BirthdayParty::guestCount() const
{
return m_guests.count();
@@ -69,5 +78,25 @@ Person *BirthdayParty::guest(int index) const
{
return m_guests.at(index);
}
+
+void BirthdayParty::clearGuests() {
+ return m_guests.clear();
+}
+
// ![0]
+void BirthdayParty::appendGuest(QQmlListProperty<Person>* list, Person* p) {
+ reinterpret_cast< BirthdayParty* >(list->data)->appendGuest(p);
+}
+
+void BirthdayParty::clearGuests(QQmlListProperty<Person>* list) {
+ reinterpret_cast< BirthdayParty* >(list->data)->clearGuests();
+}
+
+Person* BirthdayParty::guest(QQmlListProperty<Person>* list, int i) {
+ return reinterpret_cast< BirthdayParty* >(list->data)->guest(i);
+}
+
+int BirthdayParty::guestCount(QQmlListProperty<Person>* list) {
+ return reinterpret_cast< BirthdayParty* >(list->data)->guestCount();
+}
diff --git a/examples/qml/referenceexamples/properties/birthdayparty.h b/examples/qml/referenceexamples/properties/birthdayparty.h
index d0a2cad285..df55df3e80 100644
--- a/examples/qml/referenceexamples/properties/birthdayparty.h
+++ b/examples/qml/referenceexamples/properties/birthdayparty.h
@@ -41,6 +41,7 @@
#define BIRTHDAYPARTY_H
#include <QObject>
+#include <QVector>
#include <QQmlListProperty>
#include "person.h"
@@ -63,12 +64,19 @@ public:
void setHost(Person *);
QQmlListProperty<Person> guests();
+ void appendGuest(Person*);
int guestCount() const;
Person *guest(int) const;
+ void clearGuests();
private:
+ static void appendGuest(QQmlListProperty<Person>*, Person*);
+ static int guestCount(QQmlListProperty<Person>*);
+ static Person* guest(QQmlListProperty<Person>*, int);
+ static void clearGuests(QQmlListProperty<Person>*);
+
Person *m_host;
- QList<Person *> m_guests;
+ QVector<Person *> m_guests;
};
// ![3]
diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro
index 0644b81a22..5a6fd52baf 100644
--- a/examples/quick/demos/demos.pro
+++ b/examples/quick/demos/demos.pro
@@ -7,5 +7,7 @@ SUBDIRS = samegame \
photosurface \
stocqt
-qtHaveModule(xmlpatterns): SUBDIRS += rssnews photoviewer
-
+qtHaveModule(xmlpatterns) {
+ SUBDIRS += rssnews
+ qtHaveModule(widgets): SUBDIRS += photoviewer
+}
diff --git a/examples/quick/demos/stocqt/content/StockListModel.qml b/examples/quick/demos/stocqt/content/StockListModel.qml
index 9b48124bda..02ece32a49 100644
--- a/examples/quick/demos/stocqt/content/StockListModel.qml
+++ b/examples/quick/demos/stocqt/content/StockListModel.qml
@@ -82,27 +82,28 @@ ListModel {
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.LOADING || xhr.readyState === XMLHttpRequest.DONE) {
var records = xhr.responseText.split('\n');
+ var unknown = "n/a";
+ set(index, {"value": unknown, "change": unknown, "changePercentage": unknown});
if (records.length > 0 && xhr.status == 200) {
var r = records[1].split(',');
var today = parseFloat(r[4]);
- setProperty(index, "value", today.toFixed(2));
+ if (!isNaN(today))
+ setProperty(index, "value", today.toFixed(2));
+ if (records.length > 2) {
+ r = records[2].split(',');
+ var yesterday = parseFloat(r[4]);
+ var change = today - yesterday;
+ if (change >= 0.0)
+ setProperty(index, "change", "+" + change.toFixed(2));
+ else
+ setProperty(index, "change", change.toFixed(2));
- r = records[2].split(',');
- var yesterday = parseFloat(r[4]);
- var change = today - yesterday;
- if (change >= 0.0)
- setProperty(index, "change", "+" + change.toFixed(2));
- else
- setProperty(index, "change", change.toFixed(2));
-
- var changePercentage = (change / yesterday) * 100.0;
- if (changePercentage >= 0.0)
- setProperty(index, "changePercentage", "+" + changePercentage.toFixed(2) + "%");
- else
- setProperty(index, "changePercentage", changePercentage.toFixed(2) + "%");
- } else {
- var unknown = "n/a";
- set(index, {"value": unknown, "change": unknown, "changePercentage": unknown});
+ var changePercentage = (change / yesterday) * 100.0;
+ if (changePercentage >= 0.0)
+ setProperty(index, "changePercentage", "+" + changePercentage.toFixed(2) + "%");
+ else
+ setProperty(index, "changePercentage", changePercentage.toFixed(2) + "%");
+ }
}
}
}
diff --git a/examples/quick/rendercontrol/window_singlethreaded.cpp b/examples/quick/rendercontrol/window_singlethreaded.cpp
index ef8f2fed43..bd4de9a7cb 100644
--- a/examples/quick/rendercontrol/window_singlethreaded.cpp
+++ b/examples/quick/rendercontrol/window_singlethreaded.cpp
@@ -82,6 +82,10 @@ WindowSingleThreaded::WindowSingleThreaded()
{
setSurfaceType(QSurface::OpenGLSurface);
+ // The rendercontrol does not necessarily need an FBO. Demonstrate this
+ // when requested.
+ m_onscreen = QCoreApplication::arguments().contains(QStringLiteral("--onscreen"));
+
QSurfaceFormat format;
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
format.setDepthBufferSize(16);
@@ -164,8 +168,14 @@ void WindowSingleThreaded::createFbo()
// The scene graph has been initialized. It is now time to create an FBO and associate
// it with the QQuickWindow.
m_dpr = devicePixelRatio();
- m_fbo = new QOpenGLFramebufferObject(size() * m_dpr, QOpenGLFramebufferObject::CombinedDepthStencil);
- m_quickWindow->setRenderTarget(m_fbo);
+ if (!m_onscreen) {
+ m_fbo = new QOpenGLFramebufferObject(size() * m_dpr, QOpenGLFramebufferObject::CombinedDepthStencil);
+ m_quickWindow->setRenderTarget(m_fbo);
+ } else {
+ // Special case: No FBO. Render directly to the window's default framebuffer.
+ m_onscreenSize = size() * m_dpr;
+ m_quickWindow->setRenderTarget(0, m_onscreenSize);
+ }
}
void WindowSingleThreaded::destroyFbo()
@@ -176,7 +186,10 @@ void WindowSingleThreaded::destroyFbo()
void WindowSingleThreaded::render()
{
- if (!m_context->makeCurrent(m_offscreenSurface))
+ QSurface *surface = m_offscreenSurface;
+ if (m_onscreen)
+ surface = this;
+ if (!m_context->makeCurrent(surface))
return;
// Polish, synchronize and render the next frame (into our fbo). In this example
@@ -195,7 +208,10 @@ void WindowSingleThreaded::render()
m_quickReady = true;
// Get something onto the screen.
- m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0);
+ if (!m_onscreen)
+ m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0);
+ else
+ m_context->swapBuffers(this);
}
void WindowSingleThreaded::requestUpdate()
@@ -237,7 +253,10 @@ void WindowSingleThreaded::run()
updateSizes();
// Initialize the render control and our OpenGL resources.
- m_context->makeCurrent(m_offscreenSurface);
+ QSurface *surface = m_offscreenSurface;
+ if (m_onscreen)
+ surface = this;
+ m_context->makeCurrent(surface);
m_renderControl->initialize(m_context);
m_quickInitialized = true;
}
@@ -266,7 +285,8 @@ void WindowSingleThreaded::exposeEvent(QExposeEvent *)
{
if (isExposed()) {
if (!m_quickInitialized) {
- m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0);
+ if (!m_onscreen)
+ m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0);
startQuick(QStringLiteral("qrc:/rendercontrol/demo.qml"));
}
}
@@ -274,7 +294,10 @@ void WindowSingleThreaded::exposeEvent(QExposeEvent *)
void WindowSingleThreaded::resizeFbo()
{
- if (m_rootItem && m_context->makeCurrent(m_offscreenSurface)) {
+ QSurface *surface = m_offscreenSurface;
+ if (m_onscreen)
+ surface = this;
+ if (m_rootItem && m_context->makeCurrent(surface)) {
delete m_fbo;
createFbo();
m_context->doneCurrent();
@@ -287,8 +310,13 @@ void WindowSingleThreaded::resizeEvent(QResizeEvent *)
{
// If this is a resize after the scene is up and running, recreate the fbo and the
// Quick item and scene.
- if (m_fbo && m_fbo->size() != size() * devicePixelRatio())
- resizeFbo();
+ if (!m_onscreen) {
+ if (m_fbo && m_fbo->size() != size() * devicePixelRatio())
+ resizeFbo();
+ } else {
+ if (m_onscreenSize != size() * devicePixelRatio())
+ resizeFbo();
+ }
}
void WindowSingleThreaded::handleScreenChange()
diff --git a/examples/quick/rendercontrol/window_singlethreaded.h b/examples/quick/rendercontrol/window_singlethreaded.h
index 534d6b9bc3..4736f036ad 100644
--- a/examples/quick/rendercontrol/window_singlethreaded.h
+++ b/examples/quick/rendercontrol/window_singlethreaded.h
@@ -97,6 +97,8 @@ private:
QTimer m_updateTimer;
CubeRenderer *m_cubeRenderer;
qreal m_dpr;
+ bool m_onscreen;
+ QSize m_onscreenSize;
};
#endif
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/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index fa0d3d3c55..c0c5f3d114 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -40,3 +40,10 @@ INCLUDEPATH += $$PWD/disassembler/udis86
INCLUDEPATH += $$_OUT_PWD
CONFIG(release, debug|release): DEFINES += NDEBUG
+
+!intel_icc:!clang:gcc {
+ greaterThan(QT_GCC_MAJOR_VERSION, 6) { # GCC 7
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-expansion-to-defined
+ QMAKE_CXXFLAGS += -Wno-expansion-to-defined
+ }
+}
diff --git a/src/3rdparty/masm/wtf/Assertions.h b/src/3rdparty/masm/wtf/Assertions.h
index 6263e50ed9..af65f5325c 100644
--- a/src/3rdparty/masm/wtf/Assertions.h
+++ b/src/3rdparty/masm/wtf/Assertions.h
@@ -233,7 +233,7 @@ WTF_EXPORT_PRIVATE void WTFInstallReportBacktraceOnCrashHook();
#define ASSERT_NOT_REACHED() ((void)0)
#define NO_RETURN_DUE_TO_ASSERT
-#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+#if COMPILER(RVCT)
template<typename T>
inline void assertUnused(T& x) { (void)x; }
#define ASSERT_UNUSED(variable, assertion) (assertUnused(variable))
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 544993c073..71c05c4b89 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -6,9 +6,9 @@ SUBDIRS += \
builtins \
qtqml \
folderlistmodel \
- localstorage \
models
+qtHaveModule(sql): SUBDIRS += localstorage
qtConfig(settings): SUBDIRS += settings
qtConfig(statemachine): SUBDIRS += statemachine
@@ -18,10 +18,10 @@ qtHaveModule(quick) {
layouts \
qtquick2 \
window \
- sharedimage \
testlib
- qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
+ qtConfig(systemsemaphore): SUBDIRS += sharedimage
+ qtConfig(quick-particles): \
SUBDIRS += particles
}
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 8679750842..40682dd6a8 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -770,6 +770,8 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
}
args->setReturnValue(db.asReturnedValue());
+#else
+ Q_UNUSED(args)
#endif // settings
}
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/TestCase.qml b/src/imports/testlib/TestCase.qml
index 18c70e1169..8c1744a2b2 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -38,6 +38,7 @@
****************************************************************************/
import QtQuick 2.0
+import QtQuick.Window 2.0 // used for qtest_verifyItem
import QtTest 1.1
import "testlogger.js" as TestLogger
import Qt.test.qtestroot 1.0
@@ -443,6 +444,9 @@ Item {
or \c{QVERIFY2(condition, message)} in C++.
*/
function verify(cond, msg) {
+ if (arguments.length > 2)
+ qtest_fail("More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?", 1)
+
if (msg === undefined)
msg = "";
if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine()))
@@ -1085,8 +1089,8 @@ Item {
function waitForRendering(item, timeout) {
if (timeout === undefined)
timeout = 5000
- if (!item)
- qtest_fail("No item given to waitForRendering", 1)
+ if (!qtest_verifyItem(item, "waitForRendering"))
+ return
return qtest_results.waitForRendering(item, timeout)
}
@@ -1198,8 +1202,8 @@ Item {
\sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mousePress(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mousePress", 1)
+ if (!qtest_verifyItem(item, "mousePress"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1232,8 +1236,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseRelease(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseRelease", 1)
+ if (!qtest_verifyItem(item, "mouseRelease"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1268,8 +1272,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel()
*/
function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDrag", 1)
+ if (!qtest_verifyItem(item, "mouseDrag"))
+ return
if (item.x === undefined || item.y === undefined)
return
@@ -1319,8 +1323,8 @@ Item {
\sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseClick(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseClick", 1)
+ if (!qtest_verifyItem(item, "mouseClick"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1353,8 +1357,8 @@ Item {
\sa mouseDoubleClickSequence(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseDoubleClick(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDoubleClick", 1)
+ if (!qtest_verifyItem(item, "mouseDoubleClick"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1394,8 +1398,8 @@ Item {
\sa mouseDoubleClick(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDoubleClickSequence", 1)
+ if (!qtest_verifyItem(item, "mouseDoubleClickSequence"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1426,8 +1430,8 @@ Item {
\sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel()
*/
function mouseMove(item, x, y, delay, buttons) {
- if (!item)
- qtest_fail("No item given to mouseMove", 1)
+ if (!qtest_verifyItem(item, "mouseMove"))
+ return
if (delay == undefined)
delay = -1
@@ -1454,8 +1458,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta()
*/
function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseWheel", 1)
+ if (!qtest_verifyItem(item, "mouseWheel"))
+ return
if (delay == undefined)
delay = -1
@@ -1515,8 +1519,8 @@ Item {
*/
function touchEvent(item) {
- if (!item)
- qtest_fail("No item given to touchEvent", 1)
+ if (!qtest_verifyItem(item, "touchEvent"))
+ return
return {
_defaultItem: item,
@@ -1625,6 +1629,23 @@ Item {
function cleanup() {}
/*! \internal */
+ function qtest_verifyItem(item, method) {
+ try {
+ if (!(item instanceof Item) &&
+ !(item instanceof Window)) {
+ // it's a QObject, but not a type
+ qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 2);
+ return false;
+ }
+ } catch (e) { // it's not a QObject
+ qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 3);
+ return false;
+ }
+
+ return true;
+ }
+
+ /*! \internal */
function qtest_runInternal(prop, arg) {
try {
qtest_testCaseResult = testCase[prop](arg)
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/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp
index 99e278238b..6f134f08df 100644
--- a/src/particles/qquickparticlesystem.cpp
+++ b/src/particles/qquickparticlesystem.cpp
@@ -668,8 +668,11 @@ void QQuickParticleSystem::setPaused(bool arg) {
if (m_animation && m_animation->state() != QAbstractAnimation::Stopped)
m_paused ? m_animation->pause() : m_animation->resume();
if (!m_paused) {
- foreach (QQuickParticlePainter *p, m_painters)
- p->update();
+ foreach (QQuickParticlePainter *p, m_painters) {
+ if (p) {
+ p->update();
+ }
+ }
}
emit pausedChanged(arg);
}
@@ -873,8 +876,11 @@ void QQuickParticleSystem::emittersChanged()
if (particleCount > bySysIdx.size())//New datum requests haven't updated it
bySysIdx.resize(particleCount);
- foreach (QQuickParticleAffector *a, m_affectors)//Groups may have changed
- a->m_updateIntSet = true;
+ foreach (QQuickParticleAffector *a, m_affectors) {//Groups may have changed
+ if (a) {
+ a->m_updateIntSet = true;
+ }
+ }
foreach (QQuickParticlePainter *p, m_painters)
loadPainter(p);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 151e44c4d4..3fb0522cd1 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -409,18 +409,7 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object)
rv.objectId = QQmlDebugService::idForObject(object);
rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
rv.parentId = QQmlDebugService::idForObject(object->parent());
- QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
- if (type) {
- QString typeName = type->qmlTypeName();
- int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
- rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
- } else {
- rv.objectType = QString::fromUtf8(object->metaObject()->className());
- int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
- if (marker != -1)
- rv.objectType = rv.objectType.left(marker);
- }
-
+ rv.objectType = QQmlMetaType::prettyTypeName(object);
return rv;
}
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/compiler.pri b/src/qml/compiler/compiler.pri
index fa66d3a6e3..871f28f2d0 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -10,7 +10,8 @@ HEADERS += \
$$PWD/qv4isel_util_p.h \
$$PWD/qv4ssa_p.h \
$$PWD/qqmlirbuilder_p.h \
- $$PWD/qqmltypecompiler_p.h
+ $$PWD/qqmltypecompiler_p.h \
+ $$PWD/qv4jssimplifier_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
@@ -19,7 +20,8 @@ SOURCES += \
$$PWD/qv4isel_p.cpp \
$$PWD/qv4jsir.cpp \
$$PWD/qv4ssa.cpp \
- $$PWD/qqmlirbuilder.cpp
+ $$PWD/qqmlirbuilder.cpp \
+ $$PWD/qv4jssimplifier.cpp
!qmldevtools_build {
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 b579a963a1..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;
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 109eb86c2e..d1d22be0ac 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -47,6 +47,7 @@
#include <private/qv4ssa_p.h>
#include "qqmlpropertycachecreator_p.h"
+#include "qv4jssimplifier_p.h"
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -58,10 +59,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)
{
@@ -143,7 +145,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
- QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
+ QQmlJavaScriptBindingExpressionSimplificationPass pass(document->objects, &document->jsModule, &document->jsGenerator);
pass.reduceTranslationBindings();
QV4::ExecutionEngine *v4 = engine->v4engine();
@@ -156,7 +158,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.
@@ -1428,344 +1430,4 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
}
}
-QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , jsModule(typeCompiler->jsIRModule())
-{
-
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings()
-{
- for (int i = 0; i < qmlObjects.count(); ++i)
- reduceTranslationBindings(i);
- if (!irFunctionsToRemove.isEmpty()) {
- QQmlIRFunctionCleanser cleanser(compiler, irFunctionsToRemove);
- cleanser.clean();
- }
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex)
-{
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
-
- const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
- QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
- if (simplifyBinding(irFunction, binding)) {
- irFunctionsToRemove.append(irFunctionIndex);
- jsModule->functions[irFunctionIndex] = 0;
- delete irFunction;
- }
- }
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move)
-{
- QV4::IR::Temp *target = move->target->asTemp();
- if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
-
- if (QV4::IR::Call *call = move->source->asCall()) {
- if (QV4::IR::Name *n = call->base->asName()) {
- if (n->builtin == QV4::IR::Name::builtin_invalid) {
- visitFunctionCall(n->id, call->args, target);
- return;
- }
- }
- discard();
- return;
- }
-
- if (QV4::IR::Name *n = move->source->asName()) {
- if (n->builtin == QV4::IR::Name::builtin_qml_context
- || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) {
- // these are free of side-effects
- return;
- }
- discard();
- return;
- }
-
- if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) {
- discard();
- return;
- }
-
- _temps[target->index] = move->source;
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target)
-{
- // more than one function call?
- if (_nameOfFunctionCalled) {
- discard();
- return;
- }
-
- _nameOfFunctionCalled = name;
-
- _functionParameters.clear();
- while (args) {
- int slot;
- if (QV4::IR::Temp *param = args->expr->asTemp()) {
- if (param->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
- slot = param->index;
- _functionParameters.append(slot);
- } else if (QV4::IR::Const *param = args->expr->asConst()) {
- slot = --_synthesizedConsts;
- Q_ASSERT(!_temps.contains(slot));
- _temps[slot] = param;
- _functionParameters.append(slot);
- }
- args = args->next;
- }
-
- _functionCallReturnValue = target->index;
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret)
-{
- // nothing initialized earlier?
- if (_returnValueOfBindingExpression != -1) {
- discard();
- return;
- }
- QV4::IR::Temp *target = ret->expr->asTemp();
- if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
- _returnValueOfBindingExpression = target->index;
-}
-
-bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding)
-{
- _canSimplify = true;
- _nameOfFunctionCalled = 0;
- _functionParameters.clear();
- _functionCallReturnValue = -1;
- _temps.clear();
- _returnValueOfBindingExpression = -1;
- _synthesizedConsts = 0;
-
- // It would seem unlikely that function with some many basic blocks (after optimization)
- // consists merely of a qsTr call or a constant value return ;-)
- if (function->basicBlockCount() > 10)
- return false;
-
- for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
- for (QV4::IR::Stmt *s : bb->statements()) {
- visit(s);
- if (!_canSimplify)
- return false;
- }
- }
-
- if (_returnValueOfBindingExpression == -1)
- return false;
-
- if (_nameOfFunctionCalled) {
- if (_functionCallReturnValue != _returnValueOfBindingExpression)
- return false;
- return detectTranslationCallAndConvertBinding(binding);
- }
-
- return false;
-}
-
-bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding)
-{
- if (*_nameOfFunctionCalled == QLatin1String("qsTr")) {
- QString translation;
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string
-
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- translation = *stringParam->value;
-
- ++param;
- if (param != end) {
- stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
- translationData.commentIndex = compiler->registerString(*stringParam->value);
- ++param;
-
- if (param != end) {
- QV4::IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != QV4::IR::SInt32Type)
- return false;
-
- translationData.number = int(constParam->value);
- ++param;
- }
- }
-
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_Translation;
- binding->stringIndex = compiler->registerString(translation);
- binding->value.translationData = translationData;
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) {
- QString id;
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string, but unused
-
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- id = *stringParam->value;
-
- ++param;
- if (param != end) {
- QV4::IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != QV4::IR::SInt32Type)
- return false;
-
- translationData.number = int(constParam->value);
- ++param;
- }
-
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_TranslationById;
- binding->stringIndex = compiler->registerString(id);
- binding->value.translationData = translationData;
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) {
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- ++param;
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = compiler->registerString(*stringParam->value);
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) {
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- ++param;
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- ++param;
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = compiler->registerString(*stringParam->value);
- return true;
- }
- return false;
-}
-
-QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove)
- : QQmlCompilePass(typeCompiler)
- , module(typeCompiler->jsIRModule())
- , functionsToRemove(functionsToRemove)
-{
-}
-
-void QQmlIRFunctionCleanser::clean()
-{
- QVector<QV4::IR::Function*> newFunctions;
- newFunctions.reserve(module->functions.count() - functionsToRemove.count());
-
- newFunctionIndices.resize(module->functions.count());
-
- for (int i = 0; i < module->functions.count(); ++i) {
- QV4::IR::Function *f = module->functions.at(i);
- Q_ASSERT(f || functionsToRemove.contains(i));
- if (f) {
- newFunctionIndices[i] = newFunctions.count();
- newFunctions << f;
- }
- }
-
- module->functions = newFunctions;
-
- for (QV4::IR::Function *function : qAsConst(module->functions)) {
- for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
- for (QV4::IR::Stmt *s : block->statements()) {
- visit(s);
- }
- }
- }
-
- for (QmlIR::Object *obj : qAsConst(*compiler->qmlObjects())) {
- for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
- obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
- }
-}
-
-void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
-{
-
- switch (s->stmtKind) {
- case QV4::IR::Stmt::PhiStmt:
- // nothing to do
- break;
- default:
- STMT_VISIT_ALL_KINDS(s);
- break;
- }
-}
-
-void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
-{
- switch (e->exprKind) {
- case QV4::IR::Expr::ClosureExpr: {
- auto closure = e->asClosure();
- closure->value = newFunctionIndices.at(closure->value);
- } break;
- default:
- EXPR_VISIT_ALL_KINDS(e);
- break;
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 2b59e7e42f..79fc073d8b 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)
@@ -343,86 +345,6 @@ private:
const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass
-{
-public:
- QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler);
-
- void reduceTranslationBindings();
-
-private:
- void reduceTranslationBindings(int objectIndex);
-
- void visit(QV4::IR::Stmt *s)
- {
- switch (s->stmtKind) {
- case QV4::IR::Stmt::MoveStmt:
- visitMove(s->asMove());
- break;
- case QV4::IR::Stmt::RetStmt:
- visitRet(s->asRet());
- break;
- case QV4::IR::Stmt::CJumpStmt:
- discard();
- break;
- case QV4::IR::Stmt::ExpStmt:
- discard();
- break;
- case QV4::IR::Stmt::JumpStmt:
- break;
- case QV4::IR::Stmt::PhiStmt:
- break;
- }
- }
-
- void visitMove(QV4::IR::Move *move);
- void visitRet(QV4::IR::Ret *ret);
-
- void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
-
- void discard() { _canSimplify = false; }
-
- bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
- bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- QV4::IR::Module *jsModule;
-
- bool _canSimplify;
- const QString *_nameOfFunctionCalled;
- QVector<int> _functionParameters;
- int _functionCallReturnValue;
-
- QHash<int, QV4::IR::Expr*> _temps;
- int _returnValueOfBindingExpression;
- int _synthesizedConsts;
-
- QVector<int> irFunctionsToRemove;
-};
-
-class QQmlIRFunctionCleanser : public QQmlCompilePass
-{
-public:
- QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove);
-
- void clean();
-
-private:
- virtual void visitMove(QV4::IR::Move *s) {
- visit(s->source);
- visit(s->target);
- }
-
- void visit(QV4::IR::Stmt *s);
- void visit(QV4::IR::Expr *e);
-
-private:
- QV4::IR::Module *module;
- const QVector<int> &functionsToRemove;
-
- QVector<int> newFunctionIndices;
-};
-
QT_END_NAMESPACE
#endif // QQMLTYPECOMPILER_P_H
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 0afc97e4bf..693a4230ba 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -92,6 +92,27 @@ static bool cjumpCanHandle(IR::AluOp op)
}
}
+static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body,
+ const SourceLocation &fallback)
+{
+ switch (body->kind) {
+ // Statements where we might never execute the last line.
+ // Use the fallback.
+ case Statement::Kind_ConditionalExpression:
+ case Statement::Kind_ForEachStatement:
+ case Statement::Kind_ForStatement:
+ case Statement::Kind_IfStatement:
+ case Statement::Kind_LocalForEachStatement:
+ case Statement::Kind_LocalForStatement:
+ case Statement::Kind_WhileStatement:
+ setLocation(s, fallback);
+ break;
+ default:
+ setLocation(s, body->lastSourceLocation());
+ break;
+ }
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
@@ -1497,7 +1518,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 +1529,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 +2290,7 @@ bool Codegen::visit(DoWhileStatement *ast)
_block = loopbody;
statement(ast->statement);
- _block->JUMP(loopcond);
+ setJumpOutLocation(_block->JUMP(loopcond), ast->statement, ast->semicolonToken);
_block = loopcond;
condition(ast->expression, loopbody, loopend);
@@ -2334,7 +2355,7 @@ bool Codegen::visit(ForEachStatement *ast)
return false;
move(*init, _block->TEMP(temp));
statement(ast->statement);
- _block->JUMP(foreachin);
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2373,7 +2394,7 @@ bool Codegen::visit(ForStatement *ast)
_block = forbody;
statement(ast->statement);
- _block->JUMP(forstep);
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2399,12 +2420,12 @@ bool Codegen::visit(IfStatement *ast)
_block = iftrue;
statement(ast->ok);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ok, ast->ifToken);
if (ast->ko) {
_block = iffalse;
statement(ast->ko);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ko, ast->elseToken);
}
_block = endif;
@@ -2473,7 +2494,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);
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2512,7 +2533,7 @@ bool Codegen::visit(LocalForStatement *ast)
_block = forbody;
statement(ast->statement);
- _block->JUMP(forstep);
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2813,7 +2834,7 @@ bool Codegen::visit(WhileStatement *ast)
_block = whilebody;
statement(ast->statement);
- _block->JUMP(whilecond);
+ setJumpOutLocation(_block->JUMP(whilecond), ast->statement, ast->whileToken);
_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 a8f065210b..9832e1c49b 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)
@@ -147,7 +140,8 @@ 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 (data->lookupTableSize) {
@@ -174,8 +168,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;
}
}
@@ -249,14 +241,14 @@ void CompilationUnit::unlink()
#endif
}
-void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
+void CompilationUnit::markObjects(QV4::MarkStack *markStack)
{
for (uint i = 0; i < data->stringTableSize; ++i)
if (runtimeStrings[i])
- runtimeStrings[i]->mark(e);
+ runtimeStrings[i]->mark(markStack);
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(e);
+ runtimeRegularExpressions[i].mark(markStack);
}
}
@@ -331,10 +323,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 +333,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 +341,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 +351,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,28 +399,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;
@@ -461,6 +453,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
#else
+ Q_UNUSED(outputFileName)
*errorString = QStringLiteral("features.temporaryfile is disabled.");
return false;
#endif // QT_CONFIG(temporaryfile)
@@ -485,10 +478,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.
@@ -551,6 +556,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;
@@ -732,7 +738,7 @@ static QByteArray ownLibraryChecksum()
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
if (library.open(QIODevice::ReadOnly)) {
- QCryptographicHash hash(QCryptographicHash::Sha1);
+ QCryptographicHash hash(QCryptographicHash::Md5);
hash.addData(&library);
libraryChecksum = hash.result();
}
@@ -769,7 +775,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..f4ba257cf5 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;
@@ -895,11 +897,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
- void markObjects(QV4::ExecutionEngine *e);
+ void markObjects(MarkStack *markStack);
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..f7e63437e1 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);
@@ -374,7 +376,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
- unit.architectureIndex = registerString(QSysInfo::buildAbi());
+ unit.architectureIndex = registerString(irModule->targetABI.isEmpty() ? QSysInfo::buildAbi() : irModule->targetABI);
unit.codeGeneratorIndex = registerString(codeGeneratorName);
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
@@ -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/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 1755193d32..e949e6f0ad 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -58,6 +58,59 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct TargetPrimitive32 {
+ static TargetPrimitive32 emptyValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Empty) << 32; return p; }
+ static TargetPrimitive32 nullValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Null) << 32; return p; }
+ static TargetPrimitive32 undefinedValue() { TargetPrimitive32 p; p._val = quint64(Value::Managed_Type_Internal_32) << 32; return p; }
+ static TargetPrimitive32 fromBoolean(bool b) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Boolean) << 32 | quint64(b); return p; }
+ static TargetPrimitive32 fromInt32(int v) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Integer) << 32 | quint32(v); return p; }
+ static TargetPrimitive32 fromDouble(double v) {
+ TargetPrimitive32 p;
+ memcpy(&p._val, &v, 8);
+ return p;
+ }
+ static TargetPrimitive32 fromUInt32(uint v) {
+ if (v < INT_MAX)
+ return fromInt32(qint32(v));
+ return fromDouble(double(v));
+ }
+
+ quint32 value() const { return _val & quint64(~quint32(0)); }
+ quint32 tag() const { return _val >> 32; }
+
+ quint64 rawValue() const { return _val; }
+
+private:
+ quint64 _val;
+};
+
+struct TargetPrimitive64 {
+ static TargetPrimitive64 emptyValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Empty) << 32; return p; }
+ static TargetPrimitive64 nullValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Null) << 32; return p; }
+ static TargetPrimitive64 undefinedValue() { TargetPrimitive64 p; p._val = 0; return p; }
+ static TargetPrimitive64 fromBoolean(bool b) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Boolean) << 32 | quint64(b); return p; }
+ static TargetPrimitive64 fromInt32(int v) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Integer) << 32 | quint32(v); return p; }
+ static TargetPrimitive64 fromDouble(double v) {
+ TargetPrimitive64 p;
+ memcpy(&p._val, &v, 8);
+ p._val ^= Value::NaNEncodeMask;
+ return p;
+ }
+ static TargetPrimitive64 fromUInt32(uint v) {
+ if (v < INT_MAX)
+ return fromInt32(qint32(v));
+ return fromDouble(double(v));
+ }
+
+ quint32 value() const { return _val & quint64(~quint32(0)); }
+ quint32 tag() const { return _val >> 32; }
+
+ quint64 rawValue() const { return _val; }
+
+private:
+ quint64 _val;
+};
+
inline bool canConvertToSignedInteger(double value)
{
int ival = (int) value;
@@ -72,36 +125,37 @@ inline bool canConvertToUnsignedInteger(double value)
return uval == value && !(value == 0 && isNegative(value));
}
-inline Primitive convertToValue(IR::Const *c)
+template <typename PrimitiveType = Primitive>
+inline PrimitiveType convertToValue(IR::Const *c)
{
switch (c->type) {
case IR::MissingType:
- return Primitive::emptyValue();
+ return PrimitiveType::emptyValue();
case IR::NullType:
- return Primitive::nullValue();
+ return PrimitiveType::nullValue();
case IR::UndefinedType:
- return Primitive::undefinedValue();
+ return PrimitiveType::undefinedValue();
case IR::BoolType:
- return Primitive::fromBoolean(c->value != 0);
+ return PrimitiveType::fromBoolean(c->value != 0);
case IR::SInt32Type:
- return Primitive::fromInt32(int(c->value));
+ return PrimitiveType::fromInt32(int(c->value));
case IR::UInt32Type:
- return Primitive::fromUInt32(unsigned(c->value));
+ return PrimitiveType::fromUInt32(unsigned(c->value));
case IR::DoubleType:
- return Primitive::fromDouble(c->value);
+ return PrimitiveType::fromDouble(c->value);
case IR::NumberType: {
int ival = (int)c->value;
if (canConvertToSignedInteger(c->value)) {
- return Primitive::fromInt32(ival);
+ return PrimitiveType::fromInt32(ival);
} else {
- return Primitive::fromDouble(c->value);
+ return PrimitiveType::fromDouble(c->value);
}
}
default:
Q_UNREACHABLE();
}
// unreachable, but the function must return something
- return Primitive::undefinedValue();
+ return PrimitiveType::undefinedValue();
}
class ConvertTemps
diff --git a/src/qml/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 23ebe0c962..35cf0fc174 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)
@@ -942,9 +943,10 @@ 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
+ QString targetABI; // fallback to QSysInfo::buildAbi() if empty
#ifdef QT_NO_QML_DEBUGGER
static const bool debugMode = false;
#else
@@ -955,7 +957,6 @@ struct Q_QML_PRIVATE_EXPORT Module {
Module(bool debugMode)
: rootFunction(0)
- , sourceTimeStamp(0)
, isQmlModule(false)
, unitFlags(0)
#ifndef QT_NO_QML_DEBUGGER
@@ -1352,6 +1353,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);
@@ -1420,6 +1446,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/qv4jssimplifier.cpp b/src/qml/compiler/qv4jssimplifier.cpp
new file mode 100644
index 0000000000..7d09218fe6
--- /dev/null
+++ b/src/qml/compiler/qv4jssimplifier.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "qv4jssimplifier_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator)
+ : qmlObjects(qmlObjects)
+ , jsModule(jsModule)
+ , unitGenerator(unitGenerator)
+{
+
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings()
+{
+ for (int i = 0; i < qmlObjects.count(); ++i)
+ reduceTranslationBindings(i);
+ if (!irFunctionsToRemove.isEmpty()) {
+ QQmlIRFunctionCleanser cleanser(jsModule, qmlObjects, irFunctionsToRemove);
+ cleanser.clean();
+ }
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex)
+{
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
+
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
+ QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
+ if (simplifyBinding(irFunction, binding)) {
+ irFunctionsToRemove.append(irFunctionIndex);
+ jsModule->functions[irFunctionIndex] = 0;
+ delete irFunction;
+ }
+ }
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move)
+{
+ QV4::IR::Temp *target = move->target->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+
+ if (QV4::IR::Call *call = move->source->asCall()) {
+ if (QV4::IR::Name *n = call->base->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_invalid) {
+ visitFunctionCall(n->id, call->args, target);
+ return;
+ }
+ }
+ discard();
+ return;
+ }
+
+ if (QV4::IR::Name *n = move->source->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_qml_context
+ || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) {
+ // these are free of side-effects
+ return;
+ }
+ discard();
+ return;
+ }
+
+ if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) {
+ discard();
+ return;
+ }
+
+ _temps[target->index] = move->source;
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target)
+{
+ // more than one function call?
+ if (_nameOfFunctionCalled) {
+ discard();
+ return;
+ }
+
+ _nameOfFunctionCalled = name;
+
+ _functionParameters.clear();
+ while (args) {
+ int slot;
+ if (QV4::IR::Temp *param = args->expr->asTemp()) {
+ if (param->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+ slot = param->index;
+ _functionParameters.append(slot);
+ } else if (QV4::IR::Const *param = args->expr->asConst()) {
+ slot = --_synthesizedConsts;
+ Q_ASSERT(!_temps.contains(slot));
+ _temps[slot] = param;
+ _functionParameters.append(slot);
+ }
+ args = args->next;
+ }
+
+ _functionCallReturnValue = target->index;
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret)
+{
+ // nothing initialized earlier?
+ if (_returnValueOfBindingExpression != -1) {
+ discard();
+ return;
+ }
+ QV4::IR::Temp *target = ret->expr->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+ _returnValueOfBindingExpression = target->index;
+}
+
+bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding)
+{
+ _canSimplify = true;
+ _nameOfFunctionCalled = 0;
+ _functionParameters.clear();
+ _functionCallReturnValue = -1;
+ _temps.clear();
+ _returnValueOfBindingExpression = -1;
+ _synthesizedConsts = 0;
+
+ // It would seem unlikely that function with some many basic blocks (after optimization)
+ // consists merely of a qsTr call or a constant value return ;-)
+ if (function->basicBlockCount() > 10)
+ return false;
+
+ for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
+ for (QV4::IR::Stmt *s : bb->statements()) {
+ visit(s);
+ if (!_canSimplify)
+ return false;
+ }
+ }
+
+ if (_returnValueOfBindingExpression == -1)
+ return false;
+
+ if (_nameOfFunctionCalled) {
+ if (_functionCallReturnValue != _returnValueOfBindingExpression)
+ return false;
+ return detectTranslationCallAndConvertBinding(binding);
+ }
+
+ return false;
+}
+
+bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding)
+{
+ if (*_nameOfFunctionCalled == QLatin1String("qsTr")) {
+ QString translation;
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+ translationData.commentIndex = 0; // empty string
+
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ translation = *stringParam->value;
+
+ ++param;
+ if (param != end) {
+ stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+ translationData.commentIndex = unitGenerator->registerString(*stringParam->value);
+ ++param;
+
+ if (param != end) {
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
+ return false;
+
+ translationData.number = int(constParam->value);
+ ++param;
+ }
+ }
+
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_Translation;
+ binding->stringIndex = unitGenerator->registerString(translation);
+ binding->value.translationData = translationData;
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) {
+ QString id;
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+ translationData.commentIndex = 0; // empty string, but unused
+
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ id = *stringParam->value;
+
+ ++param;
+ if (param != end) {
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
+ return false;
+
+ translationData.number = int(constParam->value);
+ ++param;
+ }
+
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_TranslationById;
+ binding->stringIndex = unitGenerator->registerString(id);
+ binding->value.translationData = translationData;
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = unitGenerator->registerString(*stringParam->value);
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ ++param;
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = unitGenerator->registerString(*stringParam->value);
+ return true;
+ }
+ return false;
+}
+
+QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object *> &qmlObjects, const QVector<int> &functionsToRemove)
+ : module(module)
+ , qmlObjects(qmlObjects)
+ , functionsToRemove(functionsToRemove)
+{
+}
+
+void QQmlIRFunctionCleanser::clean()
+{
+ QVector<QV4::IR::Function*> newFunctions;
+ newFunctions.reserve(module->functions.count() - functionsToRemove.count());
+
+ newFunctionIndices.resize(module->functions.count());
+
+ for (int i = 0; i < module->functions.count(); ++i) {
+ QV4::IR::Function *f = module->functions.at(i);
+ Q_ASSERT(f || functionsToRemove.contains(i));
+ if (f) {
+ newFunctionIndices[i] = newFunctions.count();
+ newFunctions << f;
+ }
+ }
+
+ module->functions = newFunctions;
+
+ for (QV4::IR::Function *function : qAsConst(module->functions)) {
+ for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
+ for (QV4::IR::Stmt *s : block->statements()) {
+ visit(s);
+ }
+ }
+ }
+
+ for (QmlIR::Object *obj : qmlObjects) {
+ for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
+ obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
+{
+
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::PhiStmt:
+ // nothing to do
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
+{
+ switch (e->exprKind) {
+ case QV4::IR::Expr::ClosureExpr: {
+ auto closure = e->asClosure();
+ closure->value = newFunctionIndices.at(closure->value);
+ } break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4jssimplifier_p.h b/src/qml/compiler/qv4jssimplifier_p.h
new file mode 100644
index 0000000000..ae8d74135c
--- /dev/null
+++ b/src/qml/compiler/qv4jssimplifier_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 QV4JSSIMPLIFIER
+#define QV4JSSIMPLIFIER
+
+//
+// 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 "qqmlirbuilder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlIR {
+struct Document;
+}
+
+namespace QV4 {
+namespace CompiledData {
+struct QmlUnit;
+struct Location;
+}
+}
+
+class QQmlJavaScriptBindingExpressionSimplificationPass
+{
+public:
+ QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator);
+
+ void reduceTranslationBindings();
+
+private:
+ void reduceTranslationBindings(int objectIndex);
+
+ void visit(QV4::IR::Stmt *s)
+ {
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::MoveStmt:
+ visitMove(s->asMove());
+ break;
+ case QV4::IR::Stmt::RetStmt:
+ visitRet(s->asRet());
+ break;
+ case QV4::IR::Stmt::CJumpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::ExpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::JumpStmt:
+ break;
+ case QV4::IR::Stmt::PhiStmt:
+ break;
+ }
+ }
+
+ void visitMove(QV4::IR::Move *move);
+ void visitRet(QV4::IR::Ret *ret);
+
+ void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
+
+ void discard() { _canSimplify = false; }
+
+ bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
+ bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
+
+ const QVector<QmlIR::Object*> &qmlObjects;
+ QV4::IR::Module *jsModule;
+ QV4::Compiler::JSUnitGenerator *unitGenerator;
+
+ bool _canSimplify;
+ const QString *_nameOfFunctionCalled;
+ QVector<int> _functionParameters;
+ int _functionCallReturnValue;
+
+ QHash<int, QV4::IR::Expr*> _temps;
+ int _returnValueOfBindingExpression;
+ int _synthesizedConsts;
+
+ QVector<int> irFunctionsToRemove;
+};
+
+class QQmlIRFunctionCleanser
+{
+public:
+ QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object*> &qmlObjects, const QVector<int> &functionsToRemove);
+
+ void clean();
+
+private:
+ virtual void visitMove(QV4::IR::Move *s) {
+ visit(s->source);
+ visit(s->target);
+ }
+
+ void visit(QV4::IR::Stmt *s);
+ void visit(QV4::IR::Expr *e);
+
+private:
+ QV4::IR::Module *module;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QVector<int> &functionsToRemove;
+
+ QVector<int> newFunctionIndices;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV4JSSIMPLIFIER
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/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 7d4a543089..32084bd308 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -687,7 +687,7 @@ class MessageBoard : public QObject
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
Q_CLASSINFO("DefaultProperty", "messages")
public:
- QQmlListProperty<Message> messages() const;
+ QQmlListProperty<Message> messages();
private:
QList<Message *> messages;
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 3bffd2eb6f..c4c58c2821 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -267,7 +267,7 @@ class MessageBoard : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
public:
- QQmlListProperty<Message> messages() const;
+ QQmlListProperty<Message> messages();
private:
static void append_message(QQmlListProperty<Message> *list, Message *msg);
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/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index e658977da1..d062f3bbb2 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;
@@ -150,9 +156,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
}
template <typename TargetConfiguration>
-const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
-
-template <typename TargetConfiguration>
Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
: _function(function)
, _nextBlock(0)
@@ -246,13 +249,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 +271,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,25 +317,25 @@ 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*));
+ return Pointer(reg, id * RegisterSize);
}
template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
{
- return loadConstant(convertToValue(c), baseReg);
+ return loadConstant(convertToValue<TargetPrimitive>(c), baseReg);
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg)
{
- loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
- loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
- const int index = _jsGenerator->registerConstant(v.asReturnedValue());
+ 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.rawValue());
return Address(baseReg, index * sizeof(QV4::Value));
}
@@ -328,10 +347,11 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString
}
template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
+void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination)
{
- Address addr = loadAddress(ScratchRegister, destination);
- storeValue(value, addr);
+ WriteBarrier::Type barrier;
+ Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier);
+ storeValue(value, addr, barrier);
}
template <typename TargetConfiguration>
@@ -420,25 +440,19 @@ 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);
// check if it's an int32:
Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
+ Assembler::TrustedImm32(quint32(ValueTypeInternal::Integer)));
convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest);
Assembler::Jump intDone = jump();
// not an int, check if it's a double:
isNoInt.link(this);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister);
- Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0));
-#else
- and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask));
-#endif
+ Assembler::Jump isNoDbl = RegisterSizeDependentOps::checkIfTagRegisterIsDouble(this, ScratchRegister);
toDoubleRegister(src, dest);
intDone.link(this);
@@ -507,7 +521,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo
} else if (IR::Temp *t = s->expr->asTemp()) {
RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
} else if (IR::Const *c = s->expr->asConst()) {
- QV4::Primitive retVal = convertToValue(c);
+ auto retVal = convertToValue<TargetPrimitive>(c);
RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
} else {
Q_UNREACHABLE();
@@ -518,15 +532,13 @@ 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();
exceptionReturnLabel = label();
- QV4::Primitive retVal = Primitive::undefinedValue();
+ auto retVal = TargetPrimitive::undefinedValue();
RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
jump(leaveStackFrame);
}
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 720c522e1d..9e38696d7a 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>
@@ -152,35 +153,86 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using TrustedImm64 = typename JITAssembler::TrustedImm64;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ using ValueTypeInternal = Value::ValueTypeInternal_32;
+ using TargetPrimitive = TargetPrimitive32;
+
+ 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(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, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
- as->store32(TrustedImm32(value.int_32()), destination);
+ as->store32(TrustedImm32(value.value()), 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 +245,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)
@@ -219,31 +273,31 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump done = as->jump();
intRange.link(as);
as->move(srcReg, lowReg);
- as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
done.link(as);
} break;
case IR::SInt32Type:
as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
break;
case IR::BoolType:
as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Boolean)), highReg);
break;
default:
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);
}
}
- static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
{
- as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister);
+ as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister);
as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
}
@@ -295,7 +349,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,21 +366,24 @@ 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);
// check if it's an int32:
Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)));
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);
+ as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, targetAddr);
} else {
as->load32(addr, (RegisterID) targetTemp->index);
}
@@ -335,17 +392,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)
@@ -367,6 +426,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
jump.linkTo(loop, as);
}
+
+ static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
+ {
+ as->and32(TrustedImm32(Value::NotDouble_Mask), tagRegister);
+ Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(Value::NotDouble_Mask));
+ return isNoDbl;
+ }
};
template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
@@ -383,6 +449,47 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using BranchTruncateType = typename JITAssembler::BranchTruncateType;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ using ValueTypeInternal = Value::ValueTypeInternal_64;
+ using TargetPrimitive = TargetPrimitive64;
+
+ 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(none)
+ static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
+#endif
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
{
@@ -391,19 +498,24 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
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->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->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ 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)
@@ -412,9 +524,11 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
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)
@@ -433,7 +547,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump done = as->jump();
intRange.link(as);
as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
- quint64 tag = QV4::Value::Integer_Type_Internal;
+ quint64 tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
as->or64(TrustedImm64(tag << 32),
TargetPlatform::ReturnValueRegister);
done.link(as);
@@ -442,10 +556,10 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
quint64 tag;
switch (t->type) {
case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
+ tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
break;
case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
+ tag = quint64(QV4::Value::ValueTypeInternal_64::Boolean);
break;
default:
tag = 31337; // bogus value
@@ -455,27 +569,29 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
TargetPlatform::ReturnValueRegister);
}
} else {
- as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier);
}
}
- static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
{
as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
}
- static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, 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)
@@ -501,7 +617,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Pointer addr = as->loadTempAddress(temp);
as->load64(addr, dest);
} else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
}
}
@@ -511,10 +627,10 @@ 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();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
}
}
@@ -523,7 +639,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
{
Q_UNUSED(argumentNumber);
- QV4::Value v = convertToValue(c);
+ auto v = convertToValue<TargetPrimitive64>(c);
as->move(TrustedImm64(v.rawValue()), dest);
}
@@ -532,7 +648,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNUSED(argumentNumber);
if (!expr) {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
} else if (IR::Temp *t = expr->asTemp()){
loadArgumentInRegister(as, t, dest, argumentNumber);
@@ -580,7 +696,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);
@@ -589,7 +705,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);
@@ -613,25 +729,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);
+ as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), 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)
@@ -651,6 +772,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
jump.linkTo(loop, as);
}
+
+ static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
+ {
+ as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagRegister);
+ Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(0));
+ return isNoDbl;
+ }
};
template <typename TargetConfiguration>
@@ -713,7 +841,11 @@ public:
using JITTargetPlatform::platformFinishEnteringStandardStackFrame;
using JITTargetPlatform::platformLeaveStandardStackFrame;
- using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+ static qint32 targetStructureOffset(qint32 hostOffset)
+ {
+ Q_ASSERT(hostOffset % QT_POINTER_SIZE == 0);
+ return (hostOffset * RegisterSize) / QT_POINTER_SIZE;
+ }
struct LookupCall {
Address addr;
@@ -728,7 +860,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; }
};
@@ -745,6 +877,10 @@ public:
{}
};
+ using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+ using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal;
+ using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive;
+
// V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage
// collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned
// by the garbage collector, so if any JS object needs to be retained, it should be put on the
@@ -962,12 +1098,19 @@ 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);
+ Address loadConstant(const TargetPrimitive &v, RegisterID baseReg);
void loadStringRef(RegisterID reg, const QString &string);
Pointer stackSlotPointer(IR::Temp *t) const
{
@@ -986,16 +1129,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();
@@ -1026,7 +1169,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);
}
}
@@ -1039,7 +1182,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);
}
@@ -1072,8 +1215,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);
}
@@ -1081,7 +1226,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);
}
@@ -1091,9 +1236,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)
@@ -1101,22 +1246,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);
}
}
@@ -1153,7 +1295,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);
@@ -1173,7 +1315,7 @@ public:
{
Q_ASSERT (temp.value);
- Pointer ptr = loadAddress(ScratchRegister, temp.value);
+ Pointer ptr = loadAddressForReading(ScratchRegister, temp.value);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
@@ -1184,7 +1326,7 @@ public:
moveDouble((FPRegisterID) sourceTemp->index, dest);
return;
}
- Pointer ptr = loadAddress(ScratchRegister, source);
+ Pointer ptr = loadAddressForReading(ScratchRegister, source);
loadDouble(ptr, dest);
}
@@ -1203,45 +1345,57 @@ 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 storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier)
+ {
+ TargetConfiguration::MacroAssembler::storeDouble(source, dest);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, dest);
}
- void storeValue(QV4::Primitive value, Address destination)
+ void storeValue(TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeValue(this, value, destination);
+ RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
}
- void storeValue(QV4::Primitive value, IR::Expr* temp);
+ void storeValue(TargetPrimitive 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);
@@ -1249,7 +1403,7 @@ public:
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);
@@ -1270,13 +1424,7 @@ public:
if (argumentNumber < RegisterArgumentCount)
loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber);
else
-#if OS(WINDOWS) && CPU(X86_64)
- loadArgumentOnStack<argumentNumber>(value, argumentNumber);
-#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms.
- loadArgumentOnStack<argumentNumber>(value, argumentNumber + 4);
-#else // Sanity:
- loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber);
-#endif
+ loadArgumentOnStack<argumentNumber - RegisterArgumentCount + (StackShadowSpace / RegisterSize)>(value, argumentNumber);
}
template <int argumentNumber>
@@ -1300,7 +1448,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>
@@ -1317,8 +1465,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)
@@ -1411,15 +1559,17 @@ 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;
tagAddr.offset += 4;
- QV4::Primitive v = convertToValue(c);
- store32(TrustedImm32(v.int_32()), addr);
+ auto v = convertToValue<TargetPrimitive>(c);
+ store32(TrustedImm32(v.value()), addr);
store32(TrustedImm32(v.tag()), tagAddr);
return Pointer(addr);
}
@@ -1428,14 +1578,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);
+ store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
void storeBool(RegisterID src, RegisterID dest)
@@ -1452,8 +1604,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) {
@@ -1475,25 +1628,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);
+ store32(TrustedImm32(TargetPrimitive::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);
}
}
@@ -1502,15 +1654,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);
}
@@ -1520,8 +1672,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);
}
}
@@ -1548,7 +1701,7 @@ public:
RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg)
{
if (IR::Const *c = e->asConst()) {
- move(TrustedImm32(convertToValue(c).int_32()), scratchReg);
+ move(TrustedImm32(convertToValue<Primitive>(c).int_32()), scratchReg);
return scratchReg;
}
@@ -1556,7 +1709,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)
@@ -1576,7 +1729,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)
@@ -1587,11 +1740,11 @@ public:
Pointer tagAddr = addr;
tagAddr.offset += 4;
load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
+ Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(quint32(ValueTypeInternal::Integer)));
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
- Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg);
+ Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg);
subDouble(inversionAddress, FPGpr0);
Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
canNeverHappen.link(this);
@@ -1616,9 +1769,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;
@@ -1647,40 +1800,44 @@ private:
};
template <typename TargetConfiguration>
+const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
+
+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);
+ auto v = convertToValue<TargetPrimitive>(c);
+ 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..599370f73d 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;
}
@@ -256,7 +256,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &na
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
{
- _as->storeValue(Primitive::fromBoolean(false), result);
+ _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result);
}
template <typename JITAssembler>
@@ -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(JITAssembler::TargetPrimitive::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(JITAssembler::TargetPrimitive::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>
@@ -486,7 +488,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E
_as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::BoolType) {
Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(TrustedImm32(convertToValue(sourceConst).int_32()),
+ _as->move(TrustedImm32(convertToValue<Primitive>(sourceConst).int_32()),
(RegisterID) targetTemp->index);
} else {
Q_UNREACHABLE();
@@ -495,7 +497,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E
}
}
- _as->storeValue(convertToValue(sourceConst), target);
+ _as->storeValue(convertToValue<typename JITAssembler::TargetPrimitive>(sourceConst), target);
}
template <typename JITAssembler>
@@ -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);
@@ -774,16 +781,17 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
quint32 tag;
switch (regTemp->type) {
case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
+ tag = quint32(JITAssembler::ValueTypeInternal::Boolean);
break;
case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
+ tag = quint32(JITAssembler::ValueTypeInternal::Integer);
break;
default:
tag = 31337; // bogus value
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,19 +921,19 @@ 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);
// check if it's an int32:
Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
convertIntToDouble(source, target);
Jump intDone = _as->jump();
@@ -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,20 +1004,20 @@ 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);
// checkif it's a bool:
Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Boolean_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
_as->load32(addr, JITTargetPlatform::ReturnValueRegister);
Jump boolDone = _as->jump();
// check if it's an int32:
notBool.link(_as);
Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
_as->load32(addr, JITTargetPlatform::ReturnValueRegister);
Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
TrustedImm32(0));
@@ -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);
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
+ 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,10 +1200,11 @@ 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));
+ Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag,
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
Address data = temp;
data.offset += QV4::Value::valueOffset();
@@ -1297,9 +1306,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 +1322,15 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
++argc;
}
- Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag));
- _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
- p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc));
+ Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag));
+ _as->store32(TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)), p);
+ 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(JITAssembler::TargetPrimitive::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 +1338,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,14 +1458,14 @@ 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);
RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
: RelationalCondition::NotEqual;
- const TrustedImm32 tag(QV4::Value::Null_Type_Internal);
+ const TrustedImm32 tag{quint32(JITAssembler::ValueTypeInternal::Null)};
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
@@ -1532,13 +1541,13 @@ 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'
_as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
if (binop->op == IR::OpStrictEqual)
_as->addPatch(falseBlock, noBool);
else
@@ -1581,14 +1590,14 @@ 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);
if (binop->op == IR::OpNotEqual)
qSwap(trueBlock, falseBlock);
- Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal)));
+ Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Null)));
Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
tagAddr.offset -= 4;
_as->load32(tagAddr, tagReg);
@@ -1640,18 +1649,18 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch
using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
- if (architecture == QLatin1String("armv7"))
+ if (architecture == QLatin1String("arm"))
return new ISelFactory<ARMv7CrossAssembler>;
- else if (architecture == QLatin1String("armv8"))
+ else if (architecture == QLatin1String("arm64"))
return new ISelFactory<ARM64CrossAssembler>;
QString hostArch;
#if CPU(ARM_THUMB2)
- hostArch = QStringLiteral("armv7");
+ hostArch = QStringLiteral("arm");
#elif CPU(MIPS)
hostArch = QStringLiteral("mips");
#elif CPU(X86)
- hostArch = QStringLiteral("x86");
+ hostArch = QStringLiteral("i386");
#elif CPU(X86_64)
hostArch = QStringLiteral("x86_64");
#endif
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 5c046cb397..7019a117a2 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -160,7 +160,7 @@ protected:
// FramePointerRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
- return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
+ return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * JITTargetPlatform::RegisterSize);
}
Pointer baseAddressForCallArguments()
@@ -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/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index d9f8034b1f..6d788f4a93 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -370,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
@@ -397,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)
@@ -405,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)
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/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index ab20a2607d..56bd64eec1 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -133,9 +133,9 @@ public:
bool deleteProperty(const QString &name);
bool isCallable() const;
- QJSValue call(const QJSValueList &args = QJSValueList());
- QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList());
- QJSValue callAsConstructor(const QJSValueList &args = QJSValueList());
+ QJSValue call(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
#ifdef QT_DEPRECATED
QT_DEPRECATED QJSEngine *engine() const;
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..02d3af619e 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -54,58 +54,49 @@
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 + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
+
+ 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 +120,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 +157,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 +212,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 +222,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 +233,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 +259,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 +266,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 +282,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 +290,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 +316,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 +335,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 +385,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 +396,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 +411,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 +435,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 +461,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 +472,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 +488,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 +511,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 +534,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/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 39b433e5f9..806a614e95 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -130,15 +130,13 @@ 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)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
+ , gcStack(new WTF::PageAllocation)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -151,6 +149,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_profiler(0)
#endif
{
+ memoryManager = new QV4::MemoryManager(this);
+
if (maxCallDepth == -1) {
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
@@ -189,18 +189,22 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
iselFactory.reset(factory);
// reserve space for the JS stack
- // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
- // and ScopedValues allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
+ // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
+ // allocated outside of JIT'ed methods.
+ *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
#endif
jsStackTop = jsStackBase;
+ *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false,
+ /* includesGuardPages */ true);
+
exceptionValue = jsAlloca(1);
globalObject = static_cast<Object *>(jsAlloca(1));
jsObjects = jsAlloca(NJSObjects);
@@ -398,7 +402,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());
@@ -494,6 +498,8 @@ ExecutionEngine::~ExecutionEngine()
delete executableAllocator;
jsStack->deallocate();
delete jsStack;
+ gcStack->deallocate();
+ delete gcStack;
delete [] argumentsAccessors;
}
@@ -518,7 +524,7 @@ void ExecutionEngine::initRootContext()
sizeof(GlobalContext::Data) + sizeof(CallData)));
r->d_unchecked()->init(this);
r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
- r->d()->callData->tag = QV4::Value::Integer_Type_Internal;
+ r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer);
r->d()->callData->argc = 0;
r->d()->callData->thisObject = globalObject;
r->d()->callData->args[0] = Encode::undefined();
@@ -600,12 +606,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 +894,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 +937,23 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
}
-void ExecutionEngine::markObjects()
+void ExecutionEngine::markObjects(MarkStack *markStack)
{
- identifierTable->mark(this);
+ identifierTable->mark(markStack);
for (int i = 0; i < nArgumentsAccessors; ++i) {
const Property &pd = argumentsAccessors[i];
if (Heap::FunctionObject *getter = pd.getter())
- getter->mark(this);
+ getter->mark(markStack);
if (Heap::FunctionObject *setter = pd.setter())
- setter->mark(this);
+ setter->mark(markStack);
}
- classPool->markObjects(this);
+ classPool->markObjects(markStack);
for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
it != end; ++it)
- (*it)->markObjects(this);
+ (*it)->markObjects(markStack);
}
ReturnedValue ExecutionEngine::throwError(const Value &value)
@@ -1563,12 +1571,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
-{
- Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
- Q_UNUSED(baseObject);
-}
-
void ExecutionEngine::failStackLimitCheck(Scope &scope)
{
scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 69aa389c44..a2c774c295 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,22 +106,16 @@ public:
Value *jsStackLimit;
- Runtime runtime;
-
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum { JSStackLimit = 4*1024*1024 };
+ enum {
+ JSStackLimit = 4*1024*1024,
+ GCStackLimit = 2*1024*1024
+ };
WTF::PageAllocation *jsStack;
Value *jsStackBase;
- void pushForGC(Heap::Base *m) {
- *jsStackTop = m;
- ++jsStackTop;
- }
- Heap::Base *popForGC() {
- --jsStackTop;
- return jsStackTop->heapObject();
- }
+ WTF::PageAllocation *gcStack;
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
Value *ptr = jsStackTop;
@@ -454,7 +442,7 @@ public:
void requireArgumentsAccessors(int n);
- void markObjects();
+ void markObjects(MarkStack *markStack);
void initRootContext();
@@ -491,8 +479,6 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
- void assertObjectBelongsToEngine(const Heap::Base &baseObject);
-
bool checkStackLimits(Scope &scope);
private:
@@ -551,23 +537,32 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex
}
inline
-void Heap::Base::mark(QV4::ExecutionEngine *engine)
+void Heap::Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
- if (isMarked())
- return;
-#ifndef QT_NO_DEBUG
- engine->assertObjectBelongsToEngine(*this);
-#endif
- setMarkBit();
- engine->pushForGC(this);
+ 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)) {
+ *bitmap |= bit;
+ markStack->push(this);
+ }
}
-inline void Value::mark(ExecutionEngine *e)
+inline void Value::mark(MarkStack *markStack)
{
Heap::Base *o = heapObject();
if (o)
- o->mark(e);
+ o->mark(markStack);
+}
+
+inline void Managed::mark(MarkStack *markStack)
+{
+ Q_ASSERT(m());
+ m()->mark(markStack);
}
#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
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/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 1bc91f832b..f0630660d4 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -394,6 +394,7 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c
// set the correct strict mode flag on the context
ctx->d()->strictMode = false;
ctx->d()->compilationUnit = function->compilationUnit;
+ ctx->d()->constantTable = function->compilationUnit->constants;
scope.result = Q_V4_PROFILE(ctx->engine(), function);
}
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 89af5db731..b0b08f1e54 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -93,14 +93,14 @@ public:
Heap::String *stringFromIdentifier(Identifier *i);
- void mark(ExecutionEngine *e) {
+ void mark(MarkStack *markStack) {
for (int i = 0; i < alloc; ++i) {
Heap::String *entry = entries[i];
if (!entry || entry->isMarked())
continue;
entry->setMarkBit();
Q_ASSERT(entry->vtable()->markObjects);
- entry->vtable()->markObjects(entry, e);
+ entry->vtable()->markObjects(entry, markStack);
}
}
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index bac71b4537..3d9a672f2f 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);
@@ -408,9 +388,9 @@ void InternalClass::destroy()
}
}
-void InternalClassPool::markObjects(ExecutionEngine *engine)
+void InternalClassPool::markObjects(MarkStack *markStack)
{
- Q_UNUSED(engine);
+ Q_UNUSED(markStack);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 1d8ef4b0fb..a29ce5b5ff 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -291,7 +291,7 @@ inline uint InternalClass::find(const String *string)
struct InternalClassPool : public QQmlJS::MemoryPool
{
- void markObjects(ExecutionEngine *engine);
+ void markObjects(MarkStack *markStack);
};
}
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..f97771831c 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 \
}
@@ -204,8 +207,10 @@ public:
bool inUse() const { return d()->inUse(); }
bool markBit() const { return d()->isMarked(); }
+ inline void mark(MarkStack *markStack);
static void destroy(Heap::Base *) {}
+ static void markObjects(Heap::Base *, MarkStack *) {}
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/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 59115dfe21..3427ee89fe 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -177,10 +177,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
-void ForEachIteratorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
+void ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that);
- o->workArea[0].mark(e);
- o->workArea[1].mark(e);
- Object::markObjects(that, e);
+ o->workArea[0].mark(markStack);
+ o->workArea[1].mark(markStack);
+ Object::markObjects(that, markStack);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 98e94a95ea..6168d59914 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -129,7 +129,7 @@ struct ForEachIteratorObject: Object {
ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
};
inline
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..0b31c971f9 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -215,26 +215,15 @@ void PersistentValueStorage::free(Value *v)
freePage(p);
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+void PersistentValueStorage::mark(MarkStack *markStack)
{
- 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;
-
Page *p = static_cast<Page *>(firstPage);
while (p) {
for (int i = 0; i < kEntriesPerPage; ++i) {
if (Managed *m = p->values[i].as<Managed>())
- m->mark(e);
+ m->mark(markStack);
}
- drainMarkStack(e, markBase);
+ markStack->drain();
p = p->header.next;
}
@@ -393,11 +382,11 @@ void WeakValue::allocVal(ExecutionEngine *engine)
val = engine->memoryManager->m_weakValues->allocate();
}
-void WeakValue::markOnce(ExecutionEngine *e)
+void WeakValue::markOnce(MarkStack *markStack)
{
if (!val)
return;
- val->mark(e);
+ val->mark(markStack);
}
void WeakValue::free()
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index c1cd1f34df..1f838f5531 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -65,7 +65,7 @@ struct Q_QML_EXPORT PersistentValueStorage
Value *allocate();
static void free(Value *e);
- void mark(ExecutionEngine *e);
+ void mark(MarkStack *markStack);
struct Iterator {
Iterator(void *p, int idx);
@@ -203,7 +203,7 @@ public:
bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); }
void clear() { free(); }
- void markOnce(ExecutionEngine *e);
+ void markOnce(MarkStack *markStack);
private:
Value *val;
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..2ac2b0b64d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -539,7 +539,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
-void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
+void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
return;
@@ -548,10 +548,10 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
if (!ddata)
return;
- if (ddata->jsEngineId == engine->m_engineId)
- ddata->jsWrapper.markOnce(engine);
- else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
- engine->m_multiplyWrappedQObjects->mark(object, engine);
+ if (ddata->jsEngineId == markStack->engine->m_engineId)
+ ddata->jsWrapper.markOnce(markStack);
+ else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
+ markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
}
ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
@@ -938,36 +938,36 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca
RETURN_UNDEFINED();
}
-static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
+static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack)
{
const QObjectList &children = parent->children();
for (int i = 0; i < children.count(); ++i) {
QObject *child = children.at(i);
if (!child)
continue;
- QObjectWrapper::markWrapper(child, e);
- markChildQObjectsRecursively(child, e);
+ QObjectWrapper::markWrapper(child, markStack);
+ markChildQObjectsRecursively(child, markStack);
}
}
-void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e)
+void QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QObject *o = This->object()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
- vme->mark(e);
+ vme->mark(markStack);
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
// _gets_ marked (we've been called here!) then we also need to
// propagate the marking down to the children recursively.
if (!o->parent())
- markChildQObjectsRecursively(o, e);
+ markChildQObjectsRecursively(o, markStack);
}
- QV4::Object::markObjects(that, e);
+ QV4::Object::markObjects(that, markStack);
}
void QObjectWrapper::destroyObject(bool lastCall)
@@ -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);
@@ -2075,12 +2066,12 @@ void MultiplyWrappedQObjectMap::remove(QObject *key)
erase(it);
}
-void MultiplyWrappedQObjectMap::mark(QObject *key, ExecutionEngine *engine)
+void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
{
Iterator it = find(key);
if (it == end())
return;
- it->markOnce(engine);
+ it->markOnce(markStack);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index d81ef2a680..55700d17c1 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 {
@@ -171,7 +171,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
- static void markWrapper(QObject *object, ExecutionEngine *engine);
+ static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
@@ -195,7 +195,7 @@ protected:
static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, QV4::MarkStack *markStack);
static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
@@ -209,13 +209,10 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
return QV4::Encode::null();
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
- if (Q_LIKELY(priv->declarativeData)) {
- auto ddata = static_cast<QQmlData *>(priv->declarativeData);
- if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
- // We own the JS object
- return ddata->jsWrapper.value();
- }
+ auto ddata = QQmlData::get(object);
+ if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
+ // We own the JS object
+ return ddata->jsWrapper.value();
}
return wrap_slowPath(engine, object);
@@ -243,8 +240,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);
};
@@ -297,7 +292,7 @@ public:
ReturnedValue value(QObject *key) const { return QHash<QObject*, QV4::WeakValue>::value(key).value(); }
Iterator erase(Iterator it);
void remove(QObject *key);
- void mark(QObject *key, ExecutionEngine *engine);
+ void mark(QObject *key, MarkStack *markStack);
private Q_SLOTS:
void removeDestroyedObject(QObject*);
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..e9dcc9172f 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -366,9 +366,9 @@ 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->tag = quint32(QV4::Value::ValueTypeInternal::Integer);
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/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index cde2131aab..71f85c2d71 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -54,12 +54,12 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(String);
-void String::markObjects(Heap::Base *that, ExecutionEngine *e)
+void String::markObjects(Heap::Base *that, MarkStack *markStack)
{
String::Data *s = static_cast<String::Data *>(that);
if (s->largestSubLength) {
- s->left->mark(e);
- s->right->mark(e);
+ s->left->mark(markStack);
+ s->right->mark(markStack);
}
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 5b0fd292d6..71e55cbcd4 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -204,7 +204,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
Identifier *identifier() const { return d()->identifier; }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
#endif
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..50cecb6598 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:
@@ -209,23 +207,23 @@ public:
}
QML_NEARLY_ALWAYS_INLINE void setInt_32(int i)
{
- setTagValue(Integer_Type_Internal, quint32(i));
+ setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
}
QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
QML_NEARLY_ALWAYS_INLINE void setEmpty()
{
- setTagValue(Empty_Type_Internal, value());
+ setTagValue(quint32(ValueTypeInternal::Empty), value());
}
QML_NEARLY_ALWAYS_INLINE void setEmpty(int i)
{
- setTagValue(Empty_Type_Internal, quint32(i));
+ setTagValue(quint32(ValueTypeInternal::Empty), quint32(i));
}
QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i)
{
- setTagValue(Empty_Type_Internal, i);
+ setTagValue(quint32(ValueTypeInternal::Empty), i);
}
QML_NEARLY_ALWAYS_INLINE quint32 emptyValue()
@@ -268,8 +266,17 @@ public:
IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
Managed_Type_Internal_64 = 0
};
+
static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+ enum class ValueTypeInternal_64 {
+ Empty = Immediate_Mask_64| 0,
+ ConvertibleToInt = Immediate_Mask_64| 0x10000u, // bit 48
+ Null = ConvertibleToInt | 0x08000u,
+ Boolean = ConvertibleToInt | 0x04000u,
+ Integer = ConvertibleToInt | 0x02000u
+ };
+
// Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
@@ -277,6 +284,14 @@ public:
};
static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
+ enum class ValueTypeInternal_32 {
+ Empty = Immediate_Mask_32| 0,
+ ConvertibleToInt = Immediate_Mask_32| 0x10000u, // bit 48
+ Null = ConvertibleToInt | 0x08000u,
+ Boolean = ConvertibleToInt | 0x04000u,
+ Integer = ConvertibleToInt | 0x02000u
+ };
+
enum {
Managed_Type_Internal_32 = NotDouble_Mask
};
@@ -286,28 +301,23 @@ public:
Managed_Type_Internal = Managed_Type_Internal_64
};
static const quint64 Immediate_Mask = Immediate_Mask_64;
+ using ValueTypeInternal = ValueTypeInternal_64;
#else
enum {
Managed_Type_Internal = Managed_Type_Internal_32
};
static const quint64 Immediate_Mask = Immediate_Mask_32;
+ using ValueTypeInternal = ValueTypeInternal_32;
#endif
enum {
NaN_Mask = 0x7ff80000,
};
- enum ValueTypeInternal {
- Empty_Type_Internal = Immediate_Mask | 0,
- ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
- Null_Type_Internal = ConvertibleToInt | 0x08000u,
- Boolean_Type_Internal = ConvertibleToInt | 0x04000u,
- Integer_Type_Internal = ConvertibleToInt | 0x02000u
- };
// used internally in property
- inline bool isEmpty() const { return tag() == Empty_Type_Internal; }
- inline bool isNull() const { return tag() == Null_Type_Internal; }
- inline bool isBoolean() const { return tag() == Boolean_Type_Internal; }
- inline bool isInteger() const { return tag() == Integer_Type_Internal; }
+ inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
+ inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
+ inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
+ inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
inline bool isNumber() const { return isDouble() || isInteger(); }
@@ -332,9 +342,9 @@ public:
inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); }
inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; }
- inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; }
+ inline bool integerCompatible() const { return (tag() & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); }
static inline bool integerCompatible(Value a, Value b) {
- return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt;
+ return ((a.tag() & b.tag()) & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt);
}
static inline bool bothDouble(Value a, Value b) {
return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
@@ -361,7 +371,7 @@ public:
inline bool isString() const;
inline bool isObject() const;
inline bool isInt32() {
- if (tag() == Integer_Type_Internal)
+ if (tag() == quint32(ValueTypeInternal::Integer))
return true;
if (isDouble()) {
double d = doubleValue();
@@ -374,7 +384,7 @@ public:
return false;
}
double asDouble() const {
- if (tag() == Integer_Type_Internal)
+ if (tag() == quint32(ValueTypeInternal::Integer))
return int_32();
return doubleValue();
}
@@ -429,7 +439,7 @@ public:
inline bool tryIntegerConversion() {
bool b = integerCompatible();
if (b)
- setTagValue(Integer_Type_Internal, value());
+ setTagValue(quint32(ValueTypeInternal::Integer), value());
return b;
}
@@ -477,7 +487,7 @@ public:
// Section 9.12
bool sameValue(Value other) const;
- inline void mark(ExecutionEngine *e);
+ inline void mark(MarkStack *markStack);
Value &operator =(const ScopedValue &v);
Value &operator=(ReturnedValue v) { _val = v; return *this; }
@@ -612,14 +622,14 @@ inline Primitive Primitive::emptyValue(uint e)
inline Primitive Primitive::nullValue()
{
Primitive v;
- v.setTagValue(Null_Type_Internal, 0);
+ v.setTagValue(quint32(ValueTypeInternal::Null), 0);
return v;
}
inline Primitive Primitive::fromBoolean(bool b)
{
Primitive v;
- v.setTagValue(Boolean_Type_Internal, b);
+ v.setTagValue(quint32(ValueTypeInternal::Boolean), b);
return v;
}
@@ -641,7 +651,7 @@ inline Primitive Primitive::fromUInt32(uint i)
{
Primitive v;
if (i < INT_MAX) {
- v.setTagValue(Integer_Type_Internal, i);
+ v.setTagValue(quint32(ValueTypeInternal::Integer), i);
} else {
v.setDouble(i);
}
@@ -708,7 +718,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..e16df8dc60 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -249,10 +249,11 @@ 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);
+ if (!qt_v4IsStepping && !qt_v4Breakpoints.size())
+ return;
+
const int lineNumber = context->d()->lineNumber;
QV4::Function *function = qt_v4ExtractFunction(context);
QString engineName = function->sourceFile();
@@ -335,18 +336,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 +409,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 +466,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 +485,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 +519,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 +530,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,75 +586,75 @@ 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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData));
@@ -650,141 +665,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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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->tag = quint32(Value::ValueTypeInternal::Integer);
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 +821,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 +830,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 +846,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 +906,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 +930,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 +945,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..a38a938588 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;
@@ -82,7 +83,7 @@ struct VTable
uint type : 8;
const char *className;
void (*destroy)(Heap::Base *);
- void (*markObjects)(Heap::Base *, ExecutionEngine *e);
+ void (*markObjects)(Heap::Base *, MarkStack *markStack);
bool (*isEqualTo)(Managed *m, Managed *other);
};
@@ -91,10 +92,12 @@ 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;
- inline void mark(QV4::ExecutionEngine *engine);
+ inline void mark(QV4::MarkStack *markStack);
void setVtable(const VTable *v) { vt = v; }
const VTable *vtable() const { return vt; }
@@ -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);
@@ -118,6 +127,8 @@ struct Q_QML_EXPORT Base {
return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
+ inline void markChildren(MarkStack *markStack);
+
void *operator new(size_t, Managed *m) { return m; }
void *operator new(size_t, Heap::Base *m) { return m; }
void operator delete(void *, Heap::Base *) {}
@@ -133,7 +144,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 +171,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..7c57b93d9b 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;
@@ -246,12 +260,73 @@ void ChunkAllocator::free(Chunk *chunk, size_t size)
}
+void Heap::Base::markChildren(MarkStack *markStack)
+{
+ if (vtable()->markObjects)
+ vtable()->markObjects(this, markStack);
+ if (quint64 m = vtable()->markTable) {
+// qDebug() << "using mark table:" << hex << m << "for" << h;
+ void **mem = reinterpret_cast<void **>(this);
+ 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(markStack);
+ break;
+ case Mark_Pointer: {
+// qDebug() << "marking pointer at " << mem;
+ Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem);
+ if (p)
+ p->mark(markStack);
+ 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;
+ if (a->alloc > 32*1024) {
+ // drain from time to time to avoid overflows in the js stack
+ Heap::Base **currentBase = markStack->top;
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ if (markStack->top >= currentBase + 32*1024) {
+ Heap::Base **oldBase = markStack->base;
+ markStack->base = currentBase;
+ markStack->drain();
+ markStack->base = oldBase;
+ }
+ }
+ } else {
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ }
+ }
+ break;
+ }
+ }
+
+ m >>= 2;
+ ++mem;
+ }
+ }
+}
+
+
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 +355,7 @@ void Chunk::sweep()
}
}
objectBitmap[i] = blackBitmap[i];
- blackBitmap[i] = 0;
+ grayBitmap[i] = 0;
extendsBitmap[i] = e;
o += Chunk::Bits;
}
@@ -319,13 +394,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(MarkStack *markStack)
+{
+ // 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());
+ markStack->push(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 +453,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 +463,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 +480,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 +491,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 +502,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 +673,19 @@ void BlockAllocator::freeAll()
}
}
+void BlockAllocator::resetBlackBits()
+{
+ for (auto c : chunks)
+ c->resetBlackBits();
+}
+
+void BlockAllocator::collectGrayItems(MarkStack *markStack)
+{
+ for (auto c : chunks)
+ c->collectGrayItems(markStack);
+
+}
+
#if MM_DEBUG
void BlockAllocator::stats() {
DEBUG << "MM stats:";
@@ -607,7 +738,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 +747,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(MarkStack *markStack)
+{
+ 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(markStack);
+ }
+}
+
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
@@ -642,15 +790,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 +811,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 +830,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 +856,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,51 +870,77 @@ 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;
+
+MarkStack::MarkStack(ExecutionEngine *engine)
+ : engine(engine)
+{
+ base = (Heap::Base **)engine->gcStack->base();
+ top = base;
+ limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4;
+}
+
+void MarkStack::drain()
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
+ while (top > base) {
+ Heap::Base *h = pop();
+ ++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);
+ h->markChildren(this);
}
}
-void MemoryManager::mark()
+void MemoryManager::collectRoots(MarkStack *markStack)
{
- Value *markBase = engine->jsStackTop;
+ engine->markObjects(markStack);
+
+// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase);
- engine->markObjects();
+ collectFromJSStack(markStack);
- collectFromJSStack();
+// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase);
+ m_persistentValues->mark(markStack);
- 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.
@@ -785,13 +967,21 @@ void MemoryManager::mark()
}
if (keepAlive)
- qobjectWrapper->mark(engine);
+ qobjectWrapper->mark(markStack);
- if (engine->jsStackTop >= engine->jsStackLimit)
- drainMarkStack(engine, markBase);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
}
+}
+
+void MemoryManager::mark()
+{
+ markStackSize = 0;
- drainMarkStack(engine, markBase);
+ MarkStack markStack(engine);
+ collectRoots(&markStack);
+
+ markStack.drain();
}
void MemoryManager::sweep(bool lastSweep)
@@ -848,31 +1038,30 @@ 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()
@@ -883,6 +1072,7 @@ void MemoryManager::runGC()
}
QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
+// qDebug() << "runGC";
if (!gcStats) {
// uint oldUsed = allocator.usedMem();
@@ -897,21 +1087,28 @@ 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() << "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 +1117,12 @@ 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.";
+ 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 +1138,12 @@ void MemoryManager::runGC()
// ensure we don't 'loose' any memory
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
}
+
+ usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
+
+ // reset all black bits
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
}
size_t MemoryManager::getUsedMem() const
@@ -1000,7 +1204,7 @@ void MemoryManager::willAllocate(std::size_t size)
#endif // DETAILED_MM_STATS
-void MemoryManager::collectFromJSStack() const
+void MemoryManager::collectFromJSStack(MarkStack *markStack) const
{
Value *v = engine->jsStackBase;
Value *top = engine->jsStackTop;
@@ -1008,7 +1212,7 @@ void MemoryManager::collectFromJSStack() const
Managed *m = v->managed();
if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
- m->mark(engine);
+ m->mark(markStack);
++v;
}
}
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 00daf8a622..76ffec42de 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(MarkStack *markStack);
// bump allocations
HeapItem *nextFree = 0;
@@ -175,6 +178,8 @@ struct HugeItemAllocator {
HeapItem *allocate(size_t size);
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(MarkStack *markStack);
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();
}
@@ -428,7 +433,6 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
-
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -440,10 +444,11 @@ protected:
#endif // DETAILED_MM_STATS
private:
- void collectFromJSStack() const;
+ void collectFromJSStack(MarkStack *markStack) const;
void mark();
void sweep(bool lastSweep = false);
bool shouldRunGC() const;
+ void collectRoots(MarkStack *markStack);
public:
QV4::ExecutionEngine *engine;
@@ -457,6 +462,7 @@ 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;
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 588ae21ee0..9512722782 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>
@@ -58,6 +59,8 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct MarkStack;
+
/*
* Chunks are the basic structure containing GC managed objects.
*
@@ -111,22 +114,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 +186,8 @@ struct Chunk {
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(QV4::MarkStack *markStack);
void sortIntoBins(HeapItem **bins, uint nBins);
};
@@ -255,6 +267,120 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+struct MarkStack {\
+ MarkStack(ExecutionEngine *engine);
+ Heap::Base **top = 0;
+ Heap::Base **base = 0;
+ Heap::Base **limit = 0;
+ ExecutionEngine *engine;
+ void push(Heap::Base *m) {
+ *top = m;
+ ++top;
+ }
+ Heap::Base *pop() {
+ --top;
+ return *top;
+ }
+ void drain();
+
+};
+
+// 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..e36ea0749a
--- /dev/null
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** 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_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(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/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index 933c8f5202..0e195994b4 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -67,13 +67,17 @@
#else // !QT_CREATOR
# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
-# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
- // QmlDevTools is a static library
-# define QML_PARSER_EXPORT
-# elif defined(QT_BUILD_QML_LIB)
-# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# ifndef QT_STATIC
+# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+ // QmlDevTools is a static library
+# define QML_PARSER_EXPORT
+# elif defined(QT_BUILD_QML_LIB)
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif
# else
-# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# define QML_PARSER_EXPORT
# endif
#endif // QT_CREATOR
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 8f9e4b7f83..be3956bb61 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -48,7 +48,9 @@ include(jit/jit.pri)
include(jsruntime/jsruntime.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
-include(animations/animations.pri)
+qtConfig(animation) {
+ include(animations/animations.pri)
+}
include(types/types.pri)
MODULE_PLUGIN_TYPES = \
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/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index e271598c2d..2083326cd5 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -201,7 +201,9 @@ public:
static QQmlData *get(const QObject *object, bool create = false) {
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
- if (priv->wasDeleted) {
+ // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
+ // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
+ if (priv->isDeletingChildren || priv->wasDeleted) {
Q_ASSERT(!create);
return 0;
} else if (priv->declarativeData) {
@@ -269,8 +271,8 @@ bool QQmlData::wasDeleted(QObject *object)
if (!priv || priv->wasDeleted)
return true;
- return priv->declarativeData &&
- static_cast<QQmlData *>(priv->declarativeData)->isQueuedForDeletion;
+ QQmlData *ddata = QQmlData::get(object);
+ return ddata && ddata->isQueuedForDeletion;
}
QQmlNotifierEndpoint *QQmlData::notify(int index)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index af94ece496..9ff76d7b24 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -82,7 +82,9 @@
#include <private/qqmllocale_p.h>
#include <private/qqmlbind_p.h>
#include <private/qqmlconnections_p.h>
+#if QT_CONFIG(animation)
#include <private/qqmltimer_p.h>
+#endif
#include <private/qqmllistmodel_p.h>
#include <private/qqmlplatform_p.h>
#include <private/qquickpackage_p.h>
@@ -218,7 +220,9 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3
qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections");
+#if QT_CONFIG(animation)
qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer");
+#endif
qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1
qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser);
qmlRegisterType<QQmlInstanceModel>();
@@ -709,9 +713,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
- QObjectPrivate *p = QObjectPrivate::get(o);
- if (p->declarativeData) {
- QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
+ if (QQmlData *d = QQmlData::get(o)) {
if (d->ownContext && d->context) {
d->context->destroy();
d->context = 0;
@@ -791,7 +793,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;
@@ -881,13 +883,10 @@ void QQmlData::markAsDeleted(QObject *o)
void QQmlData::setQueuedForDeletion(QObject *object)
{
if (object) {
- if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
- if (!priv->wasDeleted && priv->declarativeData) {
- QQmlData *ddata = QQmlData::get(object, false);
- if (ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
- ddata->isQueuedForDeletion = true;
- }
+ if (QQmlData *ddata = QQmlData::get(object)) {
+ if (ddata->ownContext && ddata->context)
+ ddata->context->emitDestruction();
+ ddata->isQueuedForDeletion = true;
}
}
}
@@ -1336,17 +1335,11 @@ QQmlContext *QQmlEngine::contextForObject(const QObject *object)
if(!object)
return 0;
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
-
- QQmlData *data =
- static_cast<QQmlData *>(priv->declarativeData);
-
- if (!data)
- return 0;
- else if (data->outerContext)
+ QQmlData *data = QQmlData::get(object);
+ if (data && data->outerContext)
return data->outerContext->asQQmlContext();
- else
- return 0;
+
+ return 0;
}
/*!
@@ -1881,6 +1874,7 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
{
Q_ASSERT(priv);
+ Q_ASSERT(!priv->isDeletingChildren);
priv->declarativeData = new QQmlData;
return static_cast<QQmlData *>(priv->declarativeData);
}
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/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/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 85fbd86dc4..2cbcfbbfb6 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1075,7 +1075,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
{
QQmlData *ddata = new (ddataMemory) QQmlData;
ddata->ownMemory = false;
- QObjectPrivate::get(instance)->declarativeData = ddata;
+ QObjectPrivate* p = QObjectPrivate::get(instance);
+ Q_ASSERT(!p->isDeletingChildren);
+ p->declarativeData = ddata;
}
const int parserStatusCast = type->parserStatusCast();
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index ca522c29af..9b5f7b0a06 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1627,7 +1627,7 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
*/
static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
{
- QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+ QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
: data->propertyCache->method(index);
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 49103ed653..7b98096a7f 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -342,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..9f86d1cae9 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
@@ -1168,16 +1170,16 @@ void QQmlVMEMetaObject::ensureQObjectWrapper()
QV4::QObjectWrapper::wrap(v4, object);
}
-void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
+void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
{
QV4::ExecutionEngine *v4 = cache ? cache->engine : 0;
- if (v4 != e)
+ if (v4 != markStack->engine)
return;
- propertyAndMethodStorage.markOnce(e);
+ propertyAndMethodStorage.markOnce(markStack);
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
- parent->mark(e);
+ parent->mark(markStack);
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index bb6fede7c8..031a9a9ddd 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -203,7 +203,7 @@ public:
void ensureQObjectWrapper();
- void mark(QV4::ExecutionEngine *e);
+ void mark(QV4::MarkStack *markStack);
void connectAlias(int aliasId);
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..8cc0b32168 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()) {
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index a5878dcffd..f26e5f6cdb 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;
}
@@ -1965,9 +1964,8 @@ void QQmlDelegateModelItem::destroyObject()
Q_ASSERT(object);
Q_ASSERT(contextData);
- QObjectPrivate *p = QObjectPrivate::get(object);
- Q_ASSERT(p->declarativeData);
- QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
+ QQmlData *data = QQmlData::get(object);
+ Q_ASSERT(data);
if (data->ownContext && data->context)
data->context->clearContext();
object->deleteLater();
@@ -1984,10 +1982,8 @@ void QQmlDelegateModelItem::destroyObject()
QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
{
- QObjectPrivate *p = QObjectPrivate::get(object);
- QQmlContextData *context = p->declarativeData
- ? static_cast<QQmlData *>(p->declarativeData)->context
- : 0;
+ QQmlData *d = QQmlData::get(object);
+ QQmlContextData *context = d ? d->context : 0;
for (context = context ? context->parent : 0; context; context = context->parent) {
if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
context->contextObject)) {
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index d2e5020738..e85ab5982b 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -7,7 +7,6 @@ SOURCES += \
$$PWD/qqmlmodelsmodule.cpp \
$$PWD/qqmlmodelindexvaluetype.cpp \
$$PWD/qqmlobjectmodel.cpp \
- $$PWD/qqmltimer.cpp \
$$PWD/qquickpackage.cpp \
$$PWD/qquickworkerscript.cpp \
$$PWD/qqmlinstantiator.cpp
@@ -23,8 +22,15 @@ HEADERS += \
$$PWD/qqmlmodelsmodule_p.h \
$$PWD/qqmlmodelindexvaluetype_p.h \
$$PWD/qqmlobjectmodel_p.h \
- $$PWD/qqmltimer_p.h \
$$PWD/qquickpackage_p.h \
$$PWD/qquickworkerscript_p.h \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h
+
+qtConfig(animation) {
+ SOURCES += \
+ $$PWD/qqmltimer.cpp
+
+ HEADERS += \
+ $$PWD/qqmltimer_p.h
+}
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/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 1167f408f5..dab35f2a54 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>
@@ -1102,14 +1104,17 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
QImage QQuickCanvasItem::toImage(const QRectF& rect) const
{
Q_D(const QQuickCanvasItem);
- if (d->context) {
- if (rect.isEmpty())
- return d->context->toImage(canvasWindow());
- else
- return d->context->toImage(rect);
- }
- return QImage();
+ if (!d->context)
+ return QImage();
+
+ const QRectF &rectSource = rect.isEmpty() ? canvasWindow() : rect;
+ const qreal dpr = window() ? window()->effectiveDevicePixelRatio() : qreal(1);
+ const QRectF rectScaled(rectSource.topLeft() * dpr, rectSource.size() * dpr);
+
+ QImage image = d->context->toImage(rectScaled);
+ image.setDevicePixelRatio(dpr);
+ return image;
}
static const char* mimeToType(const QString &mime)
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index b9b701313e..1a6f530bfa 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);
@@ -925,9 +927,9 @@ struct QQuickJSContext2DImageData : public QV4::Object
static void method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *engine) {
- static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(engine);
- QV4::Object::markObjects(that, engine);
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) {
+ static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(markStack);
+ QV4::Object::markObjects(that, markStack);
}
};
@@ -958,7 +960,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
*pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->d()->image->fill(0x00000000);
} else {
- Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h));
+ Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio()));
*pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
@@ -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/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 357f72b3e7..17e9d8c690 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -248,7 +248,7 @@ class QQuickDragAttached : public QObject
Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource)
Q_PROPERTY(QObject *target READ target NOTIFY targetChanged)
Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged)
- Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8)
+ Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged)
Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged)
Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged)
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 2671b9c9a2..19dd81b6fc 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -195,8 +195,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.
*/
@@ -342,8 +342,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.
*/
@@ -1225,9 +1225,24 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
auto p = m_touchPoints.at(i);
if (p->isAccepted())
continue;
+ // include points where item is the grabber
bool isGrabber = p->exclusiveGrabber() == item;
+ // include newly pressed points inside the bounds
bool isPressInside = p->state() == QQuickEventPoint::Pressed && item->contains(item->mapFromScene(p->scenePos()));
- if (!(isGrabber || isPressInside || isFiltering))
+
+ // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item
+ bool grabberIsChild = false;
+ auto parent = p->grabberItem();
+ while (isFiltering && parent) {
+ if (parent == item) {
+ grabberIsChild = true;
+ break;
+ }
+ parent = parent->parentItem();
+ }
+ bool filterRelevant = isFiltering && grabberIsChild;
+
+ if (!(isGrabber || isPressInside || filterRelevant))
continue;
const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 6306a48d48..40719c6324 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -255,6 +255,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
, rebound(0)
{
}
@@ -643,8 +644,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.
*/
/*!
@@ -1575,16 +1578,18 @@ void QQuickFlickablePrivate::replayDelayedPress()
void QQuickFlickablePrivate::setViewportX(qreal x)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- x = -Round(-x);
-
- contentItem->setX(x);
- if (contentItem->x() != x)
- return; // reentered
+ qreal effectiveX = pixelAligned ? -Round(-x) : x;
const qreal maxX = q->maxXExtent();
const qreal minX = q->minXExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveX = qBound(maxX, effectiveX, minX);
+
+ contentItem->setX(effectiveX);
+ if (contentItem->x() != effectiveX)
+ return; // reentered
+
qreal overshoot = 0.0;
if (x <= maxX)
overshoot = maxX - x;
@@ -1600,16 +1605,18 @@ void QQuickFlickablePrivate::setViewportX(qreal x)
void QQuickFlickablePrivate::setViewportY(qreal y)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- y = -Round(-y);
-
- contentItem->setY(y);
- if (contentItem->y() != y)
- return; // reentered
+ qreal effectiveY = pixelAligned ? -Round(-y) : y;
const qreal maxY = q->maxYExtent();
const qreal minY = q->minYExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveY = qBound(maxY, effectiveY, minY);
+
+ contentItem->setY(effectiveY);
+ if (contentItem->y() != effectiveY)
+ return; // reentered
+
qreal overshoot = 0.0;
if (y <= maxY)
overshoot = maxY - y;
@@ -1869,8 +1876,9 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
beyond the Flickable's boundaries, or overshoot the
Flickable's boundaries when flicked.
- This enables the feeling that the edges of the view are soft,
- rather than a hard physical boundary.
+ When the \l boundsMovement is \c Flickable.FollowBoundsBehavior, a value
+ other than \c Flickable.StopAtBounds will give a feeling that the edges of
+ the view are soft, rather than a hard physical boundary.
The \c boundsBehavior can be one of:
@@ -1886,7 +1894,7 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
boundary when flicked.
\endlist
- \sa horizontalOvershoot, verticalOvershoot
+ \sa horizontalOvershoot, verticalOvershoot, boundsMovement
*/
QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
{
@@ -2303,7 +2311,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);
@@ -2323,7 +2332,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) {
@@ -2339,7 +2348,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();
@@ -2696,7 +2705,11 @@ void QQuickFlickablePrivate::updateVelocity()
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa verticalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa verticalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::horizontalOvershoot() const
{
@@ -2713,7 +2726,11 @@ qreal QQuickFlickable::horizontalOvershoot() const
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa horizontalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa horizontalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::verticalOvershoot() const
{
@@ -2721,4 +2738,66 @@ qreal QQuickFlickable::verticalOvershoot() const
return d->vData.overshoot;
}
+/*!
+ \qmlproperty enumeration QtQuick::Flickable::boundsMovement
+ \since 5.10
+
+ This property holds whether the flickable will give a feeling that the edges of the
+ view are soft, rather than a hard physical boundary.
+
+ The \c boundsMovement can be one of:
+
+ \list
+ \li Flickable.StopAtBounds - this allows implementing custom edge effects where the
+ contents do not follow drags or flicks beyond the bounds of the flickable. The values
+ of \l horizontalOvershoot and \l verticalOvershoot can be utilized to implement custom
+ edge effects.
+ \li Flickable.FollowBoundsBehavior (default) - whether the contents follow drags or
+ flicks beyond the bounds of the flickable is determined by \l boundsBehavior.
+ \endlist
+
+ The following example keeps the contents within bounds and instead applies a flip
+ effect when flicked over horizontal bounds:
+ \code
+ Flickable {
+ id: flickable
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragAndOvershootBounds
+ transform: Rotation {
+ axis { x: 0; y: 1; z: 0 }
+ origin.x: flickable.width / 2
+ origin.y: flickable.height / 2
+ angle: Math.min(30, Math.max(-30, flickable.horizontalOvershoot))
+ }
+ }
+ \endcode
+
+ The following example keeps the contents within bounds and instead applies an opacity
+ effect when dragged over vertical bounds:
+ \code
+ Flickable {
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragOverBounds
+ opacity: Math.max(0.5, 1.0 - Math.abs(verticalOvershoot) / height)
+ }
+ \endcode
+
+ \sa boundsBehavior, verticalOvershoot, horizontalOvershoot
+*/
+QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement() const
+{
+ Q_D(const QQuickFlickable);
+ return d->boundsMovement;
+}
+
+void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
+{
+ Q_D(QQuickFlickable);
+ if (d->boundsMovement == movement)
+ return;
+
+ d->boundsMovement = movement;
+ emit boundsMovementChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index 52cade1472..7558ee7df8 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_p.h
@@ -80,6 +80,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem
Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged)
Q_PROPERTY(BoundsBehavior boundsBehavior READ boundsBehavior WRITE setBoundsBehavior NOTIFY boundsBehaviorChanged)
+ Q_PROPERTY(BoundsMovement boundsMovement READ boundsMovement WRITE setBoundsMovement NOTIFY boundsMovementChanged REVISION 10)
Q_PROPERTY(QQuickTransition *rebound READ rebound WRITE setRebound NOTIFY reboundChanged)
Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged)
Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
@@ -132,6 +133,15 @@ public:
BoundsBehavior boundsBehavior() const;
void setBoundsBehavior(BoundsBehavior);
+ enum BoundsMovement {
+ // StopAtBounds = 0x0,
+ FollowBoundsBehavior = 0x1
+ };
+ Q_ENUM(BoundsMovement)
+
+ BoundsMovement boundsMovement() const;
+ void setBoundsMovement(BoundsMovement movement);
+
QQuickTransition *rebound() const;
void setRebound(QQuickTransition *transition);
@@ -237,6 +247,7 @@ Q_SIGNALS:
void flickableDirectionChanged();
void interactiveChanged();
void boundsBehaviorChanged();
+ Q_REVISION(10) void boundsMovementChanged();
void reboundChanged();
void maximumFlickVelocityChanged();
void flickDecelerationChanged();
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 1ceff22dfc..8609a15fcd 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -247,6 +247,7 @@ public:
QQuickFlickableVisibleArea *visibleArea;
QQuickFlickable::FlickableDirection flickableDirection;
QQuickFlickable::BoundsBehavior boundsBehavior;
+ QQuickFlickable::BoundsMovement boundsMovement;
QQuickTransition *rebound;
void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index f3d7dc4b56..bf982117e8 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -559,7 +559,8 @@ void QQuickImage::updatePaintedGeometry()
void QQuickImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
QQuickImageBase::geometryChanged(newGeometry, oldGeometry);
- updatePaintedGeometry();
+ if (newGeometry.size() != oldGeometry.size())
+ updatePaintedGeometry();
}
QRectF QQuickImage::boundingRect() const
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 1edc54aca2..bfc4a59851 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -6780,8 +6780,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);
@@ -8456,19 +8475,19 @@ struct QQuickItemWrapper : public QObjectWrapper {
struct QQuickItemWrapper : public QV4::QObjectWrapper {
V4_OBJECT2(QQuickItemWrapper, QV4::QObjectWrapper)
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack);
};
DEFINE_OBJECT_VTABLE(QQuickItemWrapper);
-void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e)
+void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QQuickItem *item = static_cast<QQuickItem*>(This->object())) {
for (QQuickItem *child : qAsConst(QQuickItemPrivate::get(item)->childItems))
- QV4::QObjectWrapper::markWrapper(child, e);
+ QV4::QObjectWrapper::markWrapper(child, markStack);
}
- QV4::QObjectWrapper::markObjects(that, e);
+ QV4::QObjectWrapper::markObjects(that, markStack);
}
quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine)
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 279d052db9..1d174ca979 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 eeffe1ee48..13f23c918a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -273,7 +273,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
@@ -389,6 +389,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(quick_shadereffect)
qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
#endif
+
+ qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
}
static void initResources()
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.cpp b/src/quick/items/qquickpositioners.cpp
index 70fc5fa65f..05882d0464 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -48,19 +48,8 @@
QT_BEGIN_NAMESPACE
-// The default item change types that positioners are interested in.
-static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes =
- QQuickItemPrivate::Geometry
- | QQuickItemPrivate::SiblingOrder
- | QQuickItemPrivate::Visibility
- | QQuickItemPrivate::Destroyed;
-
-// The item change types for positioners that are only interested in the implicit
-// size of the items they manage. These are used if useImplicitSize is true.
-// useImplicitSize should be set in the constructor, before any items are added.
-static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes =
- QQuickItemPrivate::ImplicitWidth
- | QQuickItemPrivate::ImplicitHeight
+static const QQuickItemPrivate::ChangeTypes watchedChanges
+ = QQuickItemPrivate::Geometry
| QQuickItemPrivate::SiblingOrder
| QQuickItemPrivate::Visibility
| QQuickItemPrivate::Destroyed;
@@ -68,15 +57,13 @@ static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes =
void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->addItemChangeListener(this, useImplicitSize
- ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
+ otherPrivate->addItemChangeListener(this, watchedChanges);
}
void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->removeItemChangeListener(this, useImplicitSize
- ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
}
@@ -336,7 +323,7 @@ void QQuickBasePositioner::prePositioning()
if (wIdx < 0) {
d->watchChanges(child);
posItem.isNew = true;
- if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
+ if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
posItem.isVisible = false;
posItem.index = -1;
unpositionedItems.append(posItem);
@@ -358,7 +345,7 @@ void QQuickBasePositioner::prePositioning()
PositionedItem *item = &oldItems[wIdx];
// Items are only omitted from positioning if they are explicitly hidden
// i.e. their positioning is not affected if an ancestor is hidden.
- if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
+ if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
item->isVisible = false;
item->index = -1;
unpositionedItems.append(*item);
@@ -957,7 +944,6 @@ QQuickColumn::QQuickColumn(QQuickItem *parent)
void QQuickColumn::doPositioning(QSizeF *contentSize)
{
//Precondition: All items in the positioned list have a valid item pointer and should be positioned
- QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
qreal voffset = topPadding();
const qreal padding = leftPadding() + rightPadding();
contentSize->setWidth(qMax(contentSize->width(), padding));
@@ -966,9 +952,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize)
PositionedItem &child = positionedItems[ii];
positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
- contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding));
+ contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
- voffset += d->itemHeight(child.item);
+ voffset += child.item->height();
voffset += spacing();
}
@@ -1236,9 +1222,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
hoffsets << hoffset;
}
- contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding));
+ contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
- hoffset += d->itemWidth(child.item);
+ hoffset += child.item->width();
hoffset += spacing();
}
@@ -1259,7 +1245,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int ii = 0; ii < positionedItems.count(); ++ii) {
PositionedItem &child = positionedItems[ii];
- hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
+ hoffset = end - hoffsets[acc++] - child.item->width();
positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
}
@@ -1760,12 +1746,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
- if (childWidth > maxColWidth[j])
- maxColWidth[j] = childWidth;
- if (childHeight > maxRowHeight[i])
- maxRowHeight[i] = childHeight;
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
}
}
} else {
@@ -1780,12 +1764,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
- if (childWidth > maxColWidth[j])
- maxColWidth[j] = childWidth;
- if (childHeight > maxRowHeight[i])
- maxRowHeight[i] = childHeight;
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
}
}
}
@@ -1827,22 +1809,20 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
qreal childXOffset = xoffset;
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
if (effectiveHAlign() == AlignRight)
- childXOffset += maxColWidth[curCol] - childWidth;
+ childXOffset += maxColWidth[curCol] - child.item->width();
else if (hItemAlign() == AlignHCenter)
- childXOffset += (maxColWidth[curCol] - childWidth)/2.0;
+ childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
if (!d->isLeftToRight())
childXOffset -= maxColWidth[curCol];
qreal alignYOffset = yoffset;
if (m_vItemAlign == AlignVCenter)
- alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0;
+ alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
else if (m_vItemAlign == AlignBottom)
- alignYOffset += maxRowHeight[curRow] - childHeight;
+ alignYOffset += maxRowHeight[curRow] - child.item->height();
positionItem(childXOffset, alignYOffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
@@ -2160,17 +2140,15 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
if (d->flow == LeftToRight) {
- if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) {
+ if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
hoffset = hoffset1;
voffset += linemax + spacing();
linemax = 0;
}
} else {
- if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) {
+ if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
voffset = voffset1;
hoffset += linemax + spacing();
linemax = 0;
@@ -2187,17 +2165,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
child.bottomPadding = bottomPadding();
}
- contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2));
- contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding()));
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
if (d->flow == LeftToRight) {
- hoffset += childWidth;
+ hoffset += child.item->width();
hoffset += spacing();
- linemax = qMax(linemax, childHeight);
+ linemax = qMax(linemax, child.item->height());
} else {
- voffset += childHeight;
+ voffset += child.item->height();
voffset += spacing();
- linemax = qMax(linemax, childWidth);
+ linemax = qMax(linemax, child.item->width());
}
}
@@ -2212,7 +2190,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
- hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
+ hoffset = end - hoffsets[acc++] - child.item->width();
positionItemX(hoffset, &child);
child.leftPadding = leftPadding();
child.rightPadding = rightPadding();
@@ -2236,18 +2214,4 @@ void QQuickFlow::reportConflictingAnchors()
qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
}
-QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent)
- : QQuickRow(parent)
-{
- QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
- d->useImplicitSize = true;
-}
-
-QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent)
- : QQuickGrid(parent)
-{
- QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
- d->useImplicitSize = true;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index cfe163b4c1..9ae7029d69 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 Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject
+class QQuickPositionerAttached : public QObject
{
Q_OBJECT
@@ -132,11 +132,6 @@ public:
static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj);
- static QQuickBasePositionerPrivate* get(QQuickBasePositioner *positioner)
- {
- return positioner->d_func();
- }
-
void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const;
qreal padding() const;
@@ -187,7 +182,7 @@ protected:
virtual void doPositioning(QSizeF *contentSize)=0;
virtual void reportConflictingAnchors()=0;
- class Q_QUICK_PRIVATE_EXPORT PositionedItem
+ class PositionedItem
{
public :
PositionedItem(QQuickItem *i);
@@ -232,7 +227,7 @@ private:
Q_DECLARE_PRIVATE(QQuickBasePositioner)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickColumn : public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner
{
Q_OBJECT
public:
@@ -246,7 +241,7 @@ private:
};
class QQuickRowPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickRow: public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
@@ -271,7 +266,7 @@ private:
};
class QQuickGridPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickGrid : public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
@@ -358,7 +353,7 @@ private:
};
class QQuickFlowPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickFlow: public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
@@ -391,22 +386,6 @@ private:
Q_DECLARE_PRIVATE(QQuickFlow)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickImplicitRow : public QQuickRow
-{
- Q_OBJECT
-
-public:
- QQuickImplicitRow(QQuickItem *parent = nullptr);
-};
-
-class Q_QUICK_PRIVATE_EXPORT QQuickImplicitGrid : public QQuickGrid
-{
- Q_OBJECT
-
-public:
- QQuickImplicitGrid(QQuickItem *parent = nullptr);
-};
-
QT_END_NAMESPACE
@@ -414,8 +393,6 @@ QML_DECLARE_TYPE(QQuickColumn)
QML_DECLARE_TYPE(QQuickRow)
QML_DECLARE_TYPE(QQuickGrid)
QML_DECLARE_TYPE(QQuickFlow)
-QML_DECLARE_TYPE(QQuickImplicitRow)
-QML_DECLARE_TYPE(QQuickImplicitGrid)
QML_DECLARE_TYPE(QQuickBasePositioner)
QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES)
diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h
index 1a7051615c..0be4c56df6 100644
--- a/src/quick/items/qquickpositioners_p_p.h
+++ b/src/quick/items/qquickpositioners_p_p.h
@@ -89,14 +89,10 @@ public:
QLazilyAllocated<ExtraData> extra;
QQuickBasePositionerPrivate()
- : spacing(0)
- , type(QQuickBasePositioner::None)
- , transitioner(0)
- , positioningDirty(false)
- , doingPositioning(false)
- , anchorConflict(false)
- , useImplicitSize(false)
- , layoutDirection(Qt::LeftToRight)
+ : spacing(0), type(QQuickBasePositioner::None)
+ , transitioner(0), positioningDirty(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
+
{
}
@@ -123,7 +119,6 @@ public:
bool positioningDirty : 1;
bool doingPositioning : 1;
bool anchorConflict : 1;
- bool useImplicitSize : 1;
Qt::LayoutDirection layoutDirection;
@@ -179,34 +174,6 @@ public:
{
}
- void itemImplicitWidthChanged(QQuickItem *) override
- {
- Q_ASSERT(useImplicitSize);
- setPositioningDirty();
- }
-
- void itemImplicitHeightChanged(QQuickItem *) override
- {
- Q_ASSERT(useImplicitSize);
- setPositioningDirty();
- }
-
- qreal itemWidth(QQuickItem *item) const
- {
- if (Q_LIKELY(!useImplicitSize))
- return item->width();
-
- return item->implicitWidth();
- }
-
- qreal itemHeight(QQuickItem *item) const
- {
- if (Q_LIKELY(!useImplicitSize))
- return item->height();
-
- return item->implicitHeight();
- }
-
inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
void setTopPadding(qreal value, bool reset = false);
void setLeftPadding(qreal value, bool reset = false);
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 03d96aea1f..e2a20f9e7e 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -385,6 +385,9 @@ QImage QQuickRenderControl::grab()
cd->syncSceneGraph();
render();
grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
+ if (QQuickRenderControl::renderWindowFor(d->window)) {
+ grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
+ }
#endif
} else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 436d7b33ce..d317c1d19b 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -873,9 +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 d269dc5e50..30bd018098 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -117,7 +117,9 @@ public:
bool isComponentComplete() const;
QString parseLog();
+#if QT_CONFIG(opengl)
bool isOpenGLShaderEffect() const;
+#endif
Q_SIGNALS:
void fragmentShaderChanged();
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/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 555fd233b3..2dce3e9ec8 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -769,52 +769,8 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix)
case QEvent::ShortcutOverride:
if (d->interactionFlags & Qt::TextEditable) {
QKeyEvent* ke = static_cast<QKeyEvent *>(e);
- if (ke->modifiers() == Qt::NoModifier
- || ke->modifiers() == Qt::ShiftModifier
- || ke->modifiers() == Qt::KeypadModifier) {
- if (ke->key() < Qt::Key_Escape) {
- ke->accept();
- } else {
- switch (ke->key()) {
- case Qt::Key_Return:
- case Qt::Key_Enter:
- case Qt::Key_Delete:
- case Qt::Key_Home:
- case Qt::Key_End:
- case Qt::Key_Backspace:
- case Qt::Key_Left:
- case Qt::Key_Right:
- case Qt::Key_Up:
- case Qt::Key_Down:
- case Qt::Key_Tab:
- ke->accept();
- default:
- break;
- }
- }
-#if QT_CONFIG(shortcut)
- } else if (ke == QKeySequence::Copy
- || ke == QKeySequence::Paste
- || ke == QKeySequence::Cut
- || ke == QKeySequence::Redo
- || ke == QKeySequence::Undo
- || ke == QKeySequence::MoveToNextWord
- || ke == QKeySequence::MoveToPreviousWord
- || ke == QKeySequence::MoveToStartOfDocument
- || ke == QKeySequence::MoveToEndOfDocument
- || ke == QKeySequence::SelectNextWord
- || ke == QKeySequence::SelectPreviousWord
- || ke == QKeySequence::SelectStartOfLine
- || ke == QKeySequence::SelectEndOfLine
- || ke == QKeySequence::SelectStartOfBlock
- || ke == QKeySequence::SelectEndOfBlock
- || ke == QKeySequence::SelectStartOfDocument
- || ke == QKeySequence::SelectEndOfDocument
- || ke == QKeySequence::SelectAll
- ) {
+ if (isCommonTextEditShortcut(ke))
ke->accept();
-#endif
- }
}
break;
default:
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 0105e84cd6..888b0cde85 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -748,6 +748,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
QQuickItem *oldGrabber = q->mouseGrabberItem();
qCDebug(DBG_MOUSE_TARGET) << "grabber" << oldGrabber << "->" << grabber;
+ bool fromTouch = false;
if (grabber && touchMouseId != -1 && touchMouseDevice) {
// update the touch item for mouse touch id to the new grabber
@@ -758,6 +759,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
for (auto handler : point->passiveGrabbers())
point->cancelPassiveGrab(handler);
}
+ fromTouch = true;
} else {
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount() == 1);
@@ -771,8 +773,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();
+ }
}
}
@@ -2503,7 +2508,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)) {
@@ -2578,7 +2582,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);
@@ -2726,18 +2733,23 @@ bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQ
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()) {
// convert filteringParentTouchEvent (which is already transformed wrt local position, velocity, etc.)
// into a synthetic mouse event, and let childMouseEventFilter() have another chance with that
QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, filteringParentTouchEvent.data(), 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 (filteringParent->childMouseEventFilter(item, mouseEvent.data())) {
qCDebug(DBG_TOUCH) << "touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
if (t != QEvent::MouseButtonRelease) {
qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << tp.id() << "->" << filteringParent;
- touchMouseId = tp.id();
- touchMouseDevice = event->device();
touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabberItem(filteringParent);
+ touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
filteringParent->grabMouse();
auto pointerEventPoint = pte->pointById(tp.id());
for (auto handler : pointerEventPoint->passiveGrabbers()) {
@@ -2748,9 +2760,15 @@ bool QQuickWindowPrivate::sendFilteredPointerEvent(QQuickPointerEvent *event, QQ
}
ret = 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 touchpoint can be treated as a synthetic mouse, so after childMouseEventFilter
// has been called once, we're done with this loop over the touchpoints.
- break;
+ break;
}
}
}
@@ -3542,6 +3560,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.
@@ -3648,6 +3671,7 @@ QImage QQuickWindow::grabWindow()
bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255;
QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha);
+ image.setDevicePixelRatio(effectiveDevicePixelRatio());
d->cleanupNodesOnShutdown();
d->context->invalidate();
context.doneCurrent();
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/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 8d666d3d0b..07dc87a643 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -419,6 +419,10 @@ void QSGMaterialShader::compile()
\value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
\value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
+
+ \value DirtyCachedMaterialData Used to indicate that the cached material data have changed and must be updated.
+
+ \value DirtyAll Used to indicate that everything needs to be updated.
*/
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 7ef75d4b4c..7ac3914023 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -112,6 +112,7 @@ static void qt_print_node_count()
\value DirtyGeometry The geometry of a QSGGeometryNode has changed.
\value DirtyMaterial The material of a QSGGeometryNode has changed.
\value DirtyOpacity The opacity of a QSGOpacityNode has changed.
+ \value DirtySubtreeBlocked The subtree has been blocked.
\sa QSGNode::markDirty()
*/
@@ -146,6 +147,7 @@ static void qt_print_node_count()
\value TransformNodeType The type of QSGTransformNode
\value ClipNodeType The type of QSGClipNode
\value OpacityNodeType The type of QSGOpacityNode
+ \value RenderNodeType The type of QSGRenderNode
\sa type()
*/
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/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 2c5b4ff5c8..7542068a53 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/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index bb581c5e36..293a706c2e 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -423,6 +423,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (data.grabOnly) {
bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ grabContent.setDevicePixelRatio(window->effectiveDevicePixelRatio());
data.grabOnly = false;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 17a2c62a4e..560fddd580 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -432,6 +432,7 @@ bool QSGRenderThread::event(QEvent *e)
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result";
bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255;
*ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha);
+ ce->image->setDevicePixelRatio(ce->window->effectiveDevicePixelRatio());
}
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result";
waitCondition.wakeOne();
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index e944ddbc4f..eff6763a16 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -325,6 +325,7 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ image.setDevicePixelRatio(window->effectiveDevicePixelRatio());
return image;
}
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/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/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index 09e4cdf5a7..259e45c978 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE
will delete the GL texture when the texture object is deleted.
\value TextureCanUseAtlas The image can be uploaded into a texture atlas.
+
+ \value TextureIsOpaque The texture object is opaque.
*/
QSGEnginePrivate::QSGEnginePrivate()
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/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index bc59c49162..591b679ec4 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -256,6 +256,8 @@ static void qt_debug_remove_texture(QSGTexture* texture)
Specifies how the texture should treat texture coordinates.
+ \note Texture wrapping needs to be handled explicitly for atlas textures.
+
\value Repeat Only the factional part of the texture coordiante is
used, causing values above 1 and below 0 to repeat.
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 4aacb09c97..89007cff1f 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -345,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();
}
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index a026abe762..c4a98c69f9 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -183,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()
{
@@ -192,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.
*/
/*!
@@ -603,7 +613,6 @@ void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRa
d->preserveAspectRatioFit = preserveAspectRatioFit;
}
-
QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags)
: QQuickAsyncImageProvider()
{
@@ -660,5 +669,49 @@ QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const
return requestImageResponse(id, requestedSize);
}
+/*!
+ Returns the recommended scaled image size for loading and storage. This is
+ calculated according to the native pixel size of the image \a originalSize,
+ the requested sourceSize \a requestedSize, the image file format \a format,
+ and \a options. If the calculation otherwise concludes that scaled loading
+ is not recommended, an invalid size is returned.
+*/
+QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options)
+{
+ QSize res;
+ if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) || originalSize.isEmpty())
+ return res;
+
+ const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
+ const bool force_scale = (format == "svg" || format == "svgz");
+
+ qreal ratio = 0.0;
+ if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) {
+ ratio = qreal(requestedSize.width()) / originalSize.width();
+ }
+ if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) {
+ qreal hr = qreal(requestedSize.height()) / originalSize.height();
+ if (ratio == 0.0)
+ ratio = hr;
+ else if (!preserveAspectCropOrFit && (hr < ratio))
+ ratio = hr;
+ else if (preserveAspectCropOrFit && (hr > ratio))
+ ratio = hr;
+ }
+ if (ratio > 0.0) {
+ res.setHeight(qRound(originalSize.height() * ratio));
+ res.setWidth(qRound(originalSize.width() * ratio));
+ }
+ return res;
+}
+
+QQuickImageProviderWithOptions *QQuickImageProviderWithOptions::checkedCast(QQuickImageProvider *provider)
+{
+ if (provider && provider->d && provider->d->isProviderWithOptions)
+ return static_cast<QQuickImageProviderWithOptions *>(provider);
+
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h
index c77ff95f32..681de4b6c2 100644
--- a/src/quick/util/qquickimageprovider.h
+++ b/src/quick/util/qquickimageprovider.h
@@ -88,7 +88,6 @@ Q_SIGNALS:
class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
{
friend class QQuickImageProviderWithOptions; // ### Qt 6 Remove
- friend class QQuickPixmapReader; // ### Qt 6 Remove
public:
QQuickImageProvider(ImageType type, Flags flags = Flags());
virtual ~QQuickImageProvider();
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 395b89c784..7d88935402 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -141,6 +141,7 @@ public:
QUrl url;
bool loading;
+ QQuickImageProviderOptions providerOptions;
int redirectCount;
class Event : public QEvent {
@@ -204,7 +205,7 @@ protected:
private:
friend class QQuickPixmapReaderThreadObject;
void processJobs();
- void processJob(QQuickPixmapReply *, const QUrl &, const QString &, const QQuickImageProviderOptions &, QQuickImageProvider::ImageType, QQuickImageProvider *);
+ void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *);
#if QT_CONFIG(qml_network)
void networkRequestDone(QNetworkReply *);
#endif
@@ -386,37 +387,15 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
const QSize &requestSize, const QQuickImageProviderOptions &providerOptions,
QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr)
{
- const bool preserveAspectCropOrFit = providerOptions.preserveAspectRatioCrop() || providerOptions.preserveAspectRatioFit();
-
QImageReader imgio(dev);
if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform)
imgio.setAutoTransform(providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform);
else if (appliedTransform)
*appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform;
- const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz";
-
- if (requestSize.width() > 0 || requestSize.height() > 0) {
- QSize s = imgio.size();
- qreal ratio = 0.0;
- if (requestSize.width() && (preserveAspectCropOrFit || force_scale || requestSize.width() < s.width())) {
- ratio = qreal(requestSize.width())/s.width();
- }
- if (requestSize.height() && (preserveAspectCropOrFit || force_scale || requestSize.height() < s.height())) {
- qreal hr = qreal(requestSize.height())/s.height();
- if (ratio == 0.0)
- ratio = hr;
- else if (!preserveAspectCropOrFit && (hr < ratio))
- ratio = hr;
- else if (preserveAspectCropOrFit && (hr > ratio))
- ratio = hr;
- }
- if (ratio > 0.0) {
- s.setHeight(qRound(s.height() * ratio));
- s.setWidth(qRound(s.width() * ratio));
- imgio.setScaledSize(s);
- }
- }
+ QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions);
+ if (scSize.isValid())
+ imgio.setScaledSize(scSize);
if (impsize)
*impsize = imgio.size();
@@ -664,7 +643,7 @@ void QQuickPixmapReader::processJobs()
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
locker.unlock();
- processJob(job, url, localFile, job->data->providerOptions, imageType, provider);
+ processJob(job, url, localFile, imageType, provider);
locker.relock();
}
}
@@ -676,7 +655,6 @@ void QQuickPixmapReader::processJobs()
}
void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile,
- const QQuickImageProviderOptions &providerOptions,
QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider)
{
// fetch
@@ -693,8 +671,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
return;
}
- QQuickImageProviderWithOptions *providerV2 = provider->d->isProviderWithOptions ? static_cast<QQuickImageProviderWithOptions *>(provider)
- : nullptr;
+ QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider);
switch (imageType) {
case QQuickImageProvider::Invalid:
@@ -707,7 +684,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QImage image;
if (providerV2) {
- image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize);
}
@@ -728,7 +705,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QPixmap pixmap;
if (providerV2) {
- pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize);
}
@@ -749,7 +726,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QQuickTextureFactory *t;
if (providerV2) {
- t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize);
}
@@ -772,7 +749,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QQuickImageResponse *response;
if (providerV2) {
- response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, providerOptions);
+ response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions);
} else {
QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider);
response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize);
@@ -794,7 +771,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
QFile f(localFile);
QSize readSize;
if (f.open(QIODevice::ReadOnly)) {
- if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, providerOptions))
+ if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions))
errorCode = QQuickPixmapReply::Loading;
} else {
errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
@@ -1075,7 +1052,7 @@ void QQuickPixmap::purgeCache()
}
QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d)
-: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0)
+: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0)
{
if (finishedIndex == -1) {
finishedIndex = QMetaMethod::fromSignal(&QQuickPixmapReply::finished).methodIndex();
@@ -1196,6 +1173,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid;
QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)));
+ QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider);
if (provider)
imageType = provider->imageType();
@@ -1205,7 +1183,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()));
case QQuickImageProvider::Texture:
{
- QQuickTextureFactory *texture = provider->requestTexture(imageId(url), &readSize, requestSize);
+ QQuickTextureFactory *texture = providerV2 ? providerV2->requestTexture(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestTexture(imageId(url), &readSize, requestSize);
if (texture) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
@@ -1215,7 +1194,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
case QQuickImageProvider::Image:
{
- QImage image = provider->requestImage(imageId(url), &readSize, requestSize);
+ QImage image = providerV2 ? providerV2->requestImage(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestImage(imageId(url), &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
@@ -1224,7 +1204,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
}
case QQuickImageProvider::Pixmap:
{
- QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize);
+ QPixmap pixmap = providerV2 ? providerV2->requestPixmap(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestPixmap(imageId(url), &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 93d5a1cf56..91fb1ed3bb 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -204,6 +204,9 @@ public:
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options);
virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options);
virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options);
+
+ static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options);
+ static QQuickImageProviderWithOptions *checkedCast(QQuickImageProvider *provider);
};
QT_END_NAMESPACE
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 4ed41a0c6c..a2ea0f7af2 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -76,10 +76,6 @@
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(opengl)
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-#endif
-
class QQuickWidgetRenderControl : public QQuickRenderControl
{
public:
@@ -157,6 +153,16 @@ void QQuickWidgetPrivate::invalidateRenderControl()
#endif
renderControl->invalidate();
+
+ // Many things can happen inside the above invalidate() call, including a
+ // change of current context. Restore if needed since some code will rely
+ // on the fact that this function makes and leaves the context current.
+#if QT_CONFIG(opengl)
+ if (!useSoftwareRenderer && context) {
+ if (QOpenGLContext::currentContext() != context)
+ context->makeCurrent(offscreenSurface);
+ }
+#endif
}
void QQuickWidgetPrivate::handleWindowChange()
@@ -353,10 +359,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 +1145,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 4e2de8da14..3bb399acd4 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -10,7 +10,7 @@ qtHaveModule(gui):qtConfig(animation) {
quick \
qmltest
- qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \
+ qtConfig(quick-particles): \
SUBDIRS += particles
qtHaveModule(widgets): SUBDIRS += quickwidgets
}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 1e80f1bf65..f9c1fcce91 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -18,4 +18,7 @@ qtHaveModule(gui):qtConfig(opengl(es1|es2)?) {
# console applications not supported
uikit: SUBDIRS -= qmltest
+# Restricted sub-set for now
+boot2qt: SUBDIRS = qml
+
installed_cmake.depends = cmake
diff --git a/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml b/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml
new file mode 100644
index 0000000000..de105916a7
--- /dev/null
+++ b/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 reMarkable A/S
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Particles 2.0
+
+ParticleSystem {
+ running: false
+ Affector { Component.onCompleted: destroy() }
+ Emitter {
+ Timer { interval: 1; running: true; onTriggered: parent.lifeSpan = 1 }
+ }
+}
diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
index 5c82b946e5..5f9db12144 100644
--- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
+++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
@@ -42,6 +42,7 @@ public:
private slots:
void initTestCase();
void test_basic();
+ void test_affectorscrash();
};
void tst_qquickparticlesystem::initTestCase()
@@ -78,6 +79,12 @@ void tst_qquickparticlesystem::test_basic()
delete view;
QVERIFY(extremelyFuzzyCompare(stillAlive, 500, 5));//Small simulation variance is permissible.
}
+void tst_qquickparticlesystem::test_affectorscrash()
+{
+ QScopedPointer<QQuickView> view (createView(testFileUrl("crashaffectors.qml"), 600));
+
+ // This should have crashed by now
+}
QTEST_MAIN(tst_qquickparticlesystem);
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index 8be82c30f9..f193d3928a 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -135,7 +135,7 @@ void QQmlDebugMsgClient::messageReceived(const QByteArray &data)
QVERIFY(ds.atEnd());
QVERIFY(type >= QtDebugMsg);
- QVERIFY(type <= QtFatalMsg);
+ QVERIFY(type <= QtInfoMsg);
QVERIFY(timestamp > 0);
LogEntry entry((QtMsgType)type, QString::fromUtf8(message));
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
index 31b8d63ec2..d248cf9708 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -257,7 +257,7 @@ public:
stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
}
- void connect();
+ void connect(bool redundantRefs = false, bool namesAsObjects = false);
void interrupt();
void continueDebugging(StepAction stepAction);
@@ -304,9 +304,13 @@ public:
};
-void QJSDebugClient::connect()
+void QJSDebugClient::connect(bool redundantRefs, bool namesAsObjects)
{
- sendMessage(packMessage(CONNECT));
+ QJSValue jsonVal = parser.call(QJSValueList() << QLatin1String("{}"));
+ jsonVal.setProperty("redundantRefs", QJSValue(redundantRefs));
+ jsonVal.setProperty("namesAsObjects", QJSValue(namesAsObjects));
+ sendMessage(packMessage(CONNECT,
+ stringify.call(QJSValueList() << jsonVal).toString().toUtf8()));
}
void QJSDebugClient::interrupt()
@@ -870,8 +874,10 @@ void tst_QQmlDebugJS::interrupt()
//void connect()
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
client->interrupt();
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
@@ -882,8 +888,10 @@ void tst_QQmlDebugJS::getVersion()
//void version()
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
client->version();
@@ -894,9 +902,11 @@ void tst_QQmlDebugJS::getVersionWhenAttaching()
{
//void version()
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
client->version();
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
@@ -907,8 +917,10 @@ void tst_QQmlDebugJS::disconnect()
//void disconnect()
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
client->disconnect();
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
@@ -918,12 +930,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, ONCOMPLETED_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
QString jsonString(client->response);
@@ -939,12 +953,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, CREATECOMPONENT_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
QString jsonString(client->response);
@@ -959,10 +975,12 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
{
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 35;
init(qmlscene, TIMER_QMLFILE);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
//We can set the breakpoint after connect() here because the timer is repeating and if we miss
//its first iteration we can still catch the second one.
client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
@@ -981,12 +999,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 31;
init(qmlscene, LOADJSFILE_QMLFILE);
client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
QString jsonString(client->response);
@@ -1002,13 +1022,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComment()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
int actualLine = 36;
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
@@ -1025,13 +1047,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 35;
int actualLine = 36;
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
@@ -1048,12 +1072,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
{
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 39;
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
QString jsonString(client->response);
@@ -1068,11 +1094,13 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
{
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int out = 10;
int sourceLine = 37;
init(qmlscene, CONDITION_QMLFILE);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
//The breakpoint is in a timer loop so we can set it after connect().
client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
@@ -1105,12 +1133,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
{
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene, QUIT_QMLFILE);
int sourceLine = 36;
client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
QString jsonString(client->response);
@@ -1147,12 +1177,14 @@ void tst_QQmlDebugJS::clearBreakpoint()
{
//void clearBreakpoint(int breakpoint);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine1 = 37;
int sourceLine2 = 38;
init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
//The breakpoints are in a timer loop so we can set them after connect().
//Furthermore the breakpoints should be hit in the right order because setting of breakpoints
//can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
@@ -1195,10 +1227,12 @@ void tst_QQmlDebugJS::setExceptionBreak()
{
//void setExceptionBreak(QString type, bool enabled = false);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene, EXCEPTION_QMLFILE);
client->setExceptionBreak(QJSDebugClient::All,true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
}
@@ -1206,12 +1240,14 @@ void tst_QQmlDebugJS::stepNext()
{
//void continueDebugging(StepAction stepAction, int stepCount = 1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 37;
init(qmlscene, STEPACTION_QMLFILE);
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->continueDebugging(QJSDebugClient::Next);
@@ -1230,13 +1266,15 @@ void tst_QQmlDebugJS::stepIn()
{
//void continueDebugging(StepAction stepAction, int stepCount = 1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 41;
int actualLine = 37;
init(qmlscene, STEPACTION_QMLFILE);
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->continueDebugging(QJSDebugClient::In);
@@ -1255,13 +1293,15 @@ void tst_QQmlDebugJS::stepOut()
{
//void continueDebugging(StepAction stepAction, int stepCount = 1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 37;
int actualLine = 41;
init(qmlscene, STEPACTION_QMLFILE);
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->continueDebugging(QJSDebugClient::Out);
@@ -1280,6 +1320,8 @@ void tst_QQmlDebugJS::continueDebugging()
{
//void continueDebugging(StepAction stepAction, int stepCount = 1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine1 = 41;
int sourceLine2 = 38;
@@ -1287,7 +1329,7 @@ void tst_QQmlDebugJS::continueDebugging()
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->continueDebugging(QJSDebugClient::Continue);
@@ -1306,12 +1348,14 @@ void tst_QQmlDebugJS::backtrace()
{
//void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, ONCOMPLETED_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->backtrace();
@@ -1322,12 +1366,14 @@ void tst_QQmlDebugJS::getFrameDetails()
{
//void frame(int number = -1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, ONCOMPLETED_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->frame();
@@ -1338,12 +1384,14 @@ void tst_QQmlDebugJS::getScopeDetails()
{
//void scope(int number = -1, int frameNumber = -1);
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, ONCOMPLETED_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->scope();
@@ -1374,11 +1422,13 @@ void tst_QQmlDebugJS::evaluateInLocalScope()
//void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
int sourceLine = 34;
init(qmlscene, ONCOMPLETED_QMLFILE);
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->frame();
@@ -1461,10 +1511,12 @@ void tst_QQmlDebugJS::getScripts()
//void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
QFETCH(bool, qmlscene);
+ QFETCH(bool, redundantRefs);
+ QFETCH(bool, namesAsObjects);
init(qmlscene);
client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
- client->connect();
+ client->connect(redundantRefs, namesAsObjects);
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
client->scripts();
@@ -1482,8 +1534,16 @@ void tst_QQmlDebugJS::getScripts()
void tst_QQmlDebugJS::targetData()
{
QTest::addColumn<bool>("qmlscene");
- QTest::newRow("custom") << false;
- QTest::newRow("qmlscene") << true;
+ QTest::addColumn<bool>("redundantRefs");
+ QTest::addColumn<bool>("namesAsObjects");
+ QTest::newRow("custom / redundant / objects") << false << true << true;
+ QTest::newRow("qmlscene / redundant / objects") << true << true << true;
+ QTest::newRow("custom / redundant / strings") << false << true << false;
+ QTest::newRow("qmlscene / redundant / strings") << true << true << false;
+ QTest::newRow("custom / sparse / objects") << false << false << true;
+ QTest::newRow("qmlscene / sparse / objects") << true << false << true;
+ QTest::newRow("custom / sparse / strings") << false << false << false;
+ QTest::newRow("qmlscene / sparse / strings") << true << false << false;
}
QTEST_MAIN(tst_QQmlDebugJS)
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index 8c30a82317..d9a4777115 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -180,14 +180,9 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
{
const QMetaObject *meta = o->metaObject();
- QQmlType *type = QQmlMetaType::qmlType(meta);
- QString className = type ? QString(type->qmlTypeName())
- : QString(meta->className());
- className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1);
-
QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o));
QCOMPARE(oref.name, o->objectName());
- QCOMPARE(oref.className, className);
+ QCOMPARE(oref.className, QQmlMetaType::prettyTypeName(o));
QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject(
qmlContext(o)));
@@ -201,6 +196,7 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
QmlDebugObjectReference cref;
foreach (const QmlDebugObjectReference &ref, oref.children) {
+ QVERIFY(!ref.className.isEmpty());
if (ref.debugId == debugId) {
cref = ref;
break;
@@ -369,6 +365,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
{
bool success;
QmlDebugObjectReference obj = findRootObject(2);
+ QVERIFY(!obj.className.isEmpty());
QObject *root = m_components.at(2);
// Without args
@@ -410,6 +407,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
void tst_QQmlEngineDebugService::watch_property()
{
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
QmlDebugPropertyReference prop = findProperty(obj.properties, "width");
bool success;
@@ -454,6 +452,7 @@ void tst_QQmlEngineDebugService::watch_property()
void tst_QQmlEngineDebugService::watch_object()
{
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
bool success;
@@ -519,6 +518,7 @@ void tst_QQmlEngineDebugService::watch_expression()
int origWidth = m_rootItem->property("width").toInt();
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
bool success;
@@ -654,6 +654,7 @@ void tst_QQmlEngineDebugService::queryObject()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
@@ -665,6 +666,7 @@ void tst_QQmlEngineDebugService::queryObject()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
+ QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@@ -676,12 +678,15 @@ void tst_QQmlEngineDebugService::queryObject()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
+ }
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@@ -695,8 +700,10 @@ void tst_QQmlEngineDebugService::queryObject()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
+ }
}
}
@@ -715,6 +722,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
@@ -737,6 +745,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(m_dbg->objects().count(), 1);
QmlDebugObjectReference obj = m_dbg->objects().first();
+ QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@@ -748,12 +757,15 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
+ }
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@@ -767,8 +779,10 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
+ }
}
}
@@ -783,6 +797,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
int contextId = rootObject.contextDebugId;
QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
QQmlComponent component(context->engine());
@@ -809,6 +824,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
+ QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@@ -831,6 +847,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
+ QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@@ -846,6 +863,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
bool success;
QmlDebugObjectReference rootObject = findRootObject(4, true);
+ QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
unconnected->queryObject(rootObject, &success);
@@ -857,6 +875,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties, "modelIndex").value, QVariant());
}
@@ -950,6 +969,7 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
void tst_QQmlEngineDebugService::setBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@@ -967,6 +987,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(15));
@@ -982,6 +1003,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(20));
@@ -992,13 +1014,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
// set handler
//
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
QmlDebugObjectReference mouseAreaObject = rootObject.children.at(2);
+ QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
-
QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
QmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
@@ -1015,11 +1038,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
mouseAreaObject = rootObject.children.at(2);
+ QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
+ QVERIFY(!mouseAreaObject.className.isEmpty());
onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }"));
@@ -1028,6 +1054,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
void tst_QQmlEngineDebugService::resetBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@@ -1048,6 +1075,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(0));
@@ -1063,6 +1091,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QmlDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
QCOMPARE(boldPropertyRef.value.toBool(), false);
@@ -1076,7 +1105,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex);
-
+ QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
bool success;
@@ -1092,6 +1121,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),200);
@@ -1102,6 +1132,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
obj = findRootObject(sourceIndex, true);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@@ -1111,6 +1142,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
+ QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
m_dbg->setBindingForObject(propertyChange.debugId, "width",QVariant(300),true,
@@ -1120,6 +1152,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
// check properties changed in state
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@@ -1128,6 +1161,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
// check changing properties of base state from within a state
@@ -1141,6 +1175,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""), &success);
@@ -1148,6 +1183,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// reset binding while in a state
@@ -1156,6 +1192,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
m_dbg->resetBindingForObject(propertyChange.debugId, "width", &success);
@@ -1164,6 +1201,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// re-add binding
@@ -1174,6 +1212,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
}
@@ -1182,7 +1221,7 @@ void tst_QQmlEngineDebugService::queryObjectTree()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex, true);
-
+ QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
@@ -1192,16 +1231,16 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
+ QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
QmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value);
+ QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
-
-
// check transition
QmlDebugObjectReference transition = obj.children[0];
QCOMPARE(transition.className, QString("Transition"));
@@ -1210,12 +1249,14 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(transition.children.count() > 0);
QmlDebugObjectReference animation = transition.children[0];
+ QVERIFY(!animation.className.isEmpty());
QVERIFY(animation.debugId != -1);
QmlDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
QCOMPARE(animationTarget.objectDebugId, animation.debugId);
targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value);
+ QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width"));
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 6793596174..584bd10151 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -120,7 +120,6 @@ public:
typedef QV4DataCollector::Refs Refs;
typedef QV4DataCollector::Ref Ref;
struct NamedRefs {
- QJsonArray refs;
QJsonObject scope;
int size() const {
@@ -131,15 +130,6 @@ public:
return scope.contains(name);
}
- QJsonObject resolveRef(int ref) const {
- foreach (const QJsonValue &val, refs) {
- QJsonObject obj = val.toObject();
- if (obj.value(QLatin1String("handle")).toInt() == ref)
- return obj;
- }
- return QJsonObject();
- }
-
#define DUMP_JSON(x) {\
QJsonDocument doc(x);\
qDebug() << #x << "=" << doc.toJson(QJsonDocument::Indented);\
@@ -176,6 +166,7 @@ public:
, m_captureContextInfo(false)
, m_thrownValue(-1)
, collector(engine)
+ , m_resumeSpeed(QV4Debugger::FullThrottle)
, m_debugger(0)
{
}
@@ -208,13 +199,12 @@ public slots:
request.expression, &collector);
debugger->runInEngine(&job);
m_expressionResults << job.returnValue();
- m_expressionRefs << job.refs();
}
if (m_captureContextInfo)
captureContextInfo(debugger);
- debugger->resume(QV4Debugger::FullThrottle);
+ debugger->resume(m_resumeSpeed);
}
public:
@@ -234,24 +224,17 @@ public:
ScopeJob job(&collector, i, 0);
debugger->runInEngine(&job);
NamedRefs &refs = m_capturedScope.last();
- refs.refs = job.refs();
QJsonObject object = job.returnValue();
object = object.value(QLatin1String("object")).toObject();
- int ref = object.value(QLatin1String("ref")).toInt();
- object = refs.resolveRef(ref);
+ if (object.contains("ref") && !object.contains("properties")) {
+ QVERIFY(collector.redundantRefs());
+ object = collector.lookupRef(object.value("ref").toInt(), true);
+ QVERIFY(object.contains("properties"));
+ }
foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) {
QJsonObject property = value.toObject();
QString name = property.value(QLatin1String("name")).toString();
property.remove(QLatin1String("name"));
- if (property.contains(QLatin1String("ref"))) {
- int childRef = property.value(QLatin1String("ref")).toInt();
- if (childRef >= 0 && refs.refs.size() > childRef) {
- property.remove(QLatin1String("ref"));
- property.insert(QLatin1String("properties"),
- refs.resolveRef(childRef).value(
- QLatin1String("properties")).toArray());
- }
- }
refs.scope.insert(name, property);
}
}
@@ -280,8 +263,8 @@ public:
int context;
};
QVector<ExpressionRequest> m_expressionRequests;
+ QV4Debugger::Speed m_resumeSpeed;
QList<QJsonObject> m_expressionResults;
- QList<QJsonArray> m_expressionRefs;
QV4Debugger *m_debugger;
// Utility methods:
@@ -313,9 +296,13 @@ private slots:
void conditionalBreakPointInQml();
// context access:
+ void readArguments_data() { redundancy_data(); }
void readArguments();
+ void readLocals_data() { redundancy_data(); }
void readLocals();
+ void readObject_data() { redundancy_data(); }
void readObject();
+ void readContextInAllFrames_data() { redundancy_data(); }
void readContextInAllFrames();
// exceptions:
@@ -323,8 +310,13 @@ private slots:
void breakInCatch();
void breakInWith();
+ void evaluateExpression_data() { redundancy_data(); }
void evaluateExpression();
+ void stepToEndOfScript_data() { redundancy_data(); }
+ void stepToEndOfScript();
+ void lastLineOfConditional_data();
+ void lastLineOfConditional();
private:
QV4Debugger *debugger() const
{
@@ -338,6 +330,8 @@ private:
waitForSignal(m_engine, SIGNAL(evaluateFinished()), /*timeout*/0);
}
+ void redundancy_data();
+
TestEngine *m_engine;
QV4::ExecutionEngine *m_v4;
TestAgent *m_debuggerAgent;
@@ -532,6 +526,9 @@ void tst_qv4debugger::conditionalBreakPointInQml()
void tst_qv4debugger::readArguments()
{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
m_debuggerAgent->m_captureContextInfo = true;
QString script =
"function f(a, b, c, d) {\n"
@@ -555,6 +552,9 @@ void tst_qv4debugger::readArguments()
void tst_qv4debugger::readLocals()
{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
m_debuggerAgent->m_captureContextInfo = true;
QString script =
"function f(a, b) {\n"
@@ -578,6 +578,9 @@ void tst_qv4debugger::readLocals()
void tst_qv4debugger::readObject()
{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
m_debuggerAgent->m_captureContextInfo = true;
QString script =
"function f(a) {\n"
@@ -594,6 +597,12 @@ void tst_qv4debugger::readObject()
QVERIFY(frame0.contains("b"));
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
QJsonObject b = frame0.rawValue("b");
+ QVERIFY(b.contains(QStringLiteral("ref")));
+ QVERIFY(b.contains(QStringLiteral("value")));
+ QVERIFY(!b.contains(QStringLiteral("properties")));
+ QVERIFY(b.value("value").isDouble());
+ QCOMPARE(b.value("value").toInt(), 2);
+ b = m_debuggerAgent->collector.lookupRef(b.value("ref").toInt(), true);
QVERIFY(b.contains(QStringLiteral("properties")));
QVERIFY(b.value("properties").isArray());
QJsonArray b_props = b.value("properties").toArray();
@@ -609,7 +618,8 @@ void tst_qv4debugger::readObject()
QCOMPARE(b_tail.value("name").toString(), QStringLiteral("tail"));
QVERIFY(b_tail.contains("ref"));
- QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt());
+ QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt(),
+ true);
QCOMPARE(b_tail_value.value("type").toString(), QStringLiteral("object"));
QVERIFY(b_tail_value.contains("properties"));
QJsonArray b_tail_props = b_tail_value.value("properties").toArray();
@@ -626,6 +636,9 @@ void tst_qv4debugger::readObject()
void tst_qv4debugger::readContextInAllFrames()
{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
m_debuggerAgent->m_captureContextInfo = true;
QString script =
"function fact(n) {\n"
@@ -673,7 +686,8 @@ void tst_qv4debugger::pauseOnThrow()
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Throwing);
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
QVERIFY(m_debuggerAgent->m_thrownValue >= qint64(0));
- QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue);
+ QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue,
+ true);
// DUMP_JSON(exception);
QCOMPARE(exception.value("type").toString(), QStringLiteral("string"));
QCOMPARE(exception.value("value").toString(), QStringLiteral("hard"));
@@ -717,6 +731,9 @@ void tst_qv4debugger::breakInWith()
void tst_qv4debugger::evaluateExpression()
{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
QString script =
"function testFunction() {\n"
" var x = 10\n"
@@ -745,19 +762,119 @@ void tst_qv4debugger::evaluateExpression()
evaluateJavaScript(script, "evaluateExpression");
- QCOMPARE(m_debuggerAgent->m_expressionRefs.count(), 4);
- QCOMPARE(m_debuggerAgent->m_expressionRefs[0].size(), 1);
- QJsonObject result0 = m_debuggerAgent->m_expressionRefs[0].first().toObject();
+ QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 4);
+ QJsonObject result0 = m_debuggerAgent->m_expressionResults[0];
QCOMPARE(result0.value("type").toString(), QStringLiteral("number"));
QCOMPARE(result0.value("value").toInt(), 10);
for (int i = 1; i < 4; ++i) {
- QCOMPARE(m_debuggerAgent->m_expressionRefs[i].size(), 1);
- QJsonObject result1 = m_debuggerAgent->m_expressionRefs[1].first().toObject();
+ QJsonObject result1 = m_debuggerAgent->m_expressionResults[i];
QCOMPARE(result1.value("type").toString(), QStringLiteral("number"));
QCOMPARE(result1.value("value").toInt(), 20);
}
}
+void tst_qv4debugger::stepToEndOfScript()
+{
+ QFETCH(bool, redundantRefs);
+ m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
+
+ QString script =
+ "var ret = 0;\n"
+ "ret += 4;\n"
+ "ret += 1;\n"
+ "ret += 5;\n";
+
+ debugger()->addBreakPoint("toEnd", 1);
+ m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
+ evaluateJavaScript(script, "toEnd");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Step);
+ QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 5);
+ for (int i = 0; i < 4; ++i) {
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(i);
+ QCOMPARE(state.fileName, QString("toEnd"));
+ QCOMPARE(state.lineNumber, i + 1);
+ }
+
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(4);
+ QCOMPARE(state.fileName, QString("toEnd"));
+ QCOMPARE(state.lineNumber, -4); // A return instruction without proper line number.
+}
+
+void tst_qv4debugger::lastLineOfConditional_data()
+{
+ QTest::addColumn<QString>("head");
+ QTest::addColumn<QString>("tail");
+ QTest::addColumn<int>("breakPoint");
+ QTest::addColumn<int>("lastLine");
+
+ QTest::newRow("for {block}") << "for (var i = 0; i < 10; ++i) {\n" << "}" << 4 << 7;
+ QTest::newRow("for..in {block}") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}" << 4 << 7;
+ QTest::newRow("while {block}") << "while (ret < 10) {\n" << "}" << 4 << 7;
+ QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7;
+
+ QTest::newRow("if true {block}") << "if (true) {\n" << "}"
+ << 4 << 7;
+ QTest::newRow("if false {block}") << "if (false) {\n" << "}"
+ << 2 << 8;
+ QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}"
+ << 4 << 7;
+ QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}"
+ << 8 << 9;
+
+ QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2;
+ QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2;
+ QTest::newRow("while statement") << "while (ret < 10)\n" << "" << 4 << 2;
+ QTest::newRow("do..while statement") << "do\n" << "while (ret < 10);" << 4 << 7;
+
+ // For two nested if statements without blocks, we need to map the jump from the inner to the
+ // outer one on the outer "if". There is just no better place.
+ QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2;
+ QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8;
+
+ // Also two nested ifs without blocks.
+ QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2;
+ QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9;
+}
+
+void tst_qv4debugger::lastLineOfConditional()
+{
+ QFETCH(QString, head);
+ QFETCH(QString, tail);
+ QFETCH(int, breakPoint);
+ QFETCH(int, lastLine);
+
+ QString script =
+ "var ret = 2;\n"
+ + head +
+ " if (ret == 2)\n"
+ " ret += 4;\n" // breakpoint, then step over
+ " else\n"
+ " ret += 1;\n"
+ + tail + "\n" +
+ "ret -= 5;";
+
+ debugger()->addBreakPoint("trueBranch", breakPoint);
+ m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
+ evaluateJavaScript(script, "trueBranch");
+ QVERIFY(m_debuggerAgent->m_wasPaused);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Step);
+ QVERIFY(m_debuggerAgent->m_statesWhenPaused.count() > 1);
+ QV4Debugger::ExecutionState firstState = m_debuggerAgent->m_statesWhenPaused.first();
+ QCOMPARE(firstState.fileName, QString("trueBranch"));
+ QCOMPARE(firstState.lineNumber, breakPoint);
+ QV4Debugger::ExecutionState secondState = m_debuggerAgent->m_statesWhenPaused.at(1);
+ QCOMPARE(secondState.fileName, QString("trueBranch"));
+ QCOMPARE(secondState.lineNumber, lastLine);
+}
+
+void tst_qv4debugger::redundancy_data()
+{
+ QTest::addColumn<bool>("redundantRefs");
+ QTest::addRow("redundant") << true;
+ QTest::addRow("sparse") << false;
+}
+
QTEST_MAIN(tst_qv4debugger)
#include "tst_qv4debugger.moc"
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
index 3e27951d78..c0252a0290 100644
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
@@ -386,6 +386,7 @@ void QQmlEngineDebugClient::decode(QPacket &ds,
{
QmlDebugObjectReference obj;
obj.debugId = prop.value.toInt();
+ obj.className = prop.valueTypeName;
prop.value = qVariantFromValue(obj);
break;
}
diff --git a/tests/manual/v4/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 27498de473..27498de473 100644
--- a/tests/manual/v4/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
diff --git a/tests/auto/qml/ecmascripttests/ecmascripttests.pro b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
new file mode 100644
index 0000000000..6d3ee12307
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
@@ -0,0 +1,20 @@
+CONFIG += testcase
+TARGET = tst_ecmascripttests
+QT += testlib
+macos:CONFIG -= app_bundle
+SOURCES += tst_ecmascripttests.cpp
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+TESTSCRIPT=$$PWD/test262.py
+isEmpty(V4CMD): V4CMD = qmljs
+
+checkjittarget.target = check-jit
+checkjittarget.commands = python $$TESTSCRIPT --command=$$V4CMD --parallel --with-test-expectations --update-expectations
+checkjittarget.depends = all
+QMAKE_EXTRA_TARGETS += checkjittarget
+
+checkmothtarget.target = check-interpreter
+checkmothtarget.commands = python $$TESTSCRIPT --command=\"$$V4CMD --interpret\" --parallel --with-test-expectations
+checkmothtarget.depends = all
+QMAKE_EXTRA_TARGETS += checkmothtarget
+
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
new file mode 160000
+Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8
diff --git a/tests/manual/v4/test262.py b/tests/auto/qml/ecmascripttests/test262.py
index 3b5bfa119a..99f029cffd 100755
--- a/tests/manual/v4/test262.py
+++ b/tests/auto/qml/ecmascripttests/test262.py
@@ -555,6 +555,7 @@ class TestSuite(object):
print
if update_expectations:
self.expectations.update(progress)
+ return progress.failed == 0
def Print(self, tests):
cases = self.EnumerateTests(tests)
@@ -567,6 +568,7 @@ def Main():
# Uncomment the next line for more logging info.
#logging.basicConfig(level=logging.DEBUG)
os.environ["TZ"] = "PST8PDT"
+ os.environ["LANG"] = "en_US.UTF-8"
parser = BuildOptions()
(options, args) = parser.parse_args()
ValidateOptions(options)
@@ -578,18 +580,21 @@ def Main():
test_suite.Validate()
if options.cat:
test_suite.Print(args)
+ return 0
else:
- test_suite.Run(options.command, args,
- options.summary or options.full_summary,
- options.full_summary,
- options.parallel,
- options.update_expectations)
+ if test_suite.Run(options.command, args,
+ options.summary or options.full_summary,
+ options.full_summary,
+ options.parallel,
+ options.update_expectations):
+ return 0
+ else:
+ return 1
if __name__ == '__main__':
try:
- Main()
- sys.exit(0)
+ sys.exit(Main())
except Test262Error, e:
print "Error: %s" % e.message
sys.exit(1)
diff --git a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
new file mode 100644
index 0000000000..5d7009e7c8
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QProcess>
+#include <QLibraryInfo>
+
+class tst_EcmaScriptTests : public QObject
+{
+ Q_OBJECT
+private slots:
+ void runTests_data();
+ void runTests();
+};
+
+void tst_EcmaScriptTests::runTests_data()
+{
+ QTest::addColumn<QString>("qmljsParameter");
+
+ QTest::newRow("jit") << QStringLiteral("--jit");
+ // Not passing yet: QTest::newRow("interpreter") << QStringLiteral("--interpret");
+}
+
+void tst_EcmaScriptTests::runTests()
+{
+#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_X86_64)
+ QFETCH(QString, qmljsParameter);
+
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ForwardedChannels);
+ process.setWorkingDirectory(QLatin1String(SRCDIR));
+ process.setProgram("python");
+ process.setArguments(QStringList() << "test262.py" << "--command=" + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs " + qmljsParameter << "--parallel" << "--with-test-expectations");
+
+ qDebug() << "Going to run" << process.program() << process.arguments() << "in" << process.workingDirectory();
+
+ process.start();
+ QVERIFY(process.waitForStarted());
+ const int timeoutInMSecs = 20 * 60 * 1000;
+ QVERIFY2(process.waitForFinished(timeoutInMSecs), "Tests did not terminate in time -- see output above for details");
+ QVERIFY2(process.exitStatus() == QProcess::NormalExit, "Running the test harness failed -- see output above for details");
+ QVERIFY2(process.exitCode() == 0, "Tests failed -- see output above for details");
+#else
+ QSKIP("Currently the ecmascript tests are only run on Linux/x86-64");
+#endif
+}
+
+QTEST_GUILESS_MAIN(tst_EcmaScriptTests)
+
+#include "tst_ecmascripttests.moc"
+
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 7d182b7255..59566ad927 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -7,6 +7,9 @@ PUBLICTESTS += \
parserstress \
qjsvalueiterator \
qjsonbinding \
+
+!boot2qt {
+PUBLICTESTS += \
qmlmin \
qqmlcomponent \
qqmlconsole \
@@ -25,15 +28,22 @@ PUBLICTESTS += \
qquickfolderlistmodel \
qqmlapplicationengine \
qqmlsettings \
- qqmlstatemachine
+ qqmlstatemachine \
+ qmldiskcache
+}
PRIVATETESTS += \
- animation \
qqmlcpputils \
+ qqmldirparser \
+ v4misc \
+ qmlcachegen
+
+!boot2qt {
+PRIVATETESTS += \
+ animation \
qqmlecmascript \
qqmlcontext \
qqmlexpression \
- qqmldirparser \
qqmlglobal \
qqmllanguage \
qqmlopenmetaobject \
@@ -57,12 +67,12 @@ PRIVATETESTS += \
qqmltimer \
qqmlinstantiator \
qqmlenginecleanup \
- v4misc \
qqmltranslation \
qqmlimport \
qqmlobjectmodel \
- qmldiskcache \
- qv4mm
+ qv4mm \
+ ecmascripttests
+}
qtHaveModule(widgets) {
PUBLICTESTS += \
@@ -70,14 +80,17 @@ qtHaveModule(widgets) {
qjsvalue
}
-SUBDIRS += $$PUBLICTESTS \
- qqmlextensionplugin
+SUBDIRS += $$PUBLICTESTS
SUBDIRS += $$METATYPETESTS
-qtConfig(process) {
+qtConfig(process):!boot2qt {
!contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
SUBDIRS += qmllint qmlplugindump
}
+qtConfig(library) {
+ SUBDIRS += qqmlextensionplugin
+}
+
qtConfig(private_tests): \
SUBDIRS += $$PRIVATETESTS
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
new file mode 100644
index 0000000000..8d8b37be15
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qmlcachegen
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmlcachegen.cpp
+
+QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
new file mode 100644
index 0000000000..b7e616a050
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QProcess>
+#include <QLibraryInfo>
+#include <QSysInfo>
+
+class tst_qmlcachegen: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void loadGeneratedFile();
+ void translationExpressionSupport();
+};
+
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
+static bool generateCache(const QString &qmlFileName)
+{
+ QProcess proc;
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
+ proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
+ proc.start();
+ if (!proc.waitForFinished())
+ return false;
+ if (proc.exitStatus() != QProcess::NormalExit)
+ return false;
+ return proc.exitCode() == 0;
+}
+
+void tst_qmlcachegen::initTestCase()
+{
+ qputenv("QML_FORCE_DISK_CACHE", "1");
+}
+
+void tst_qmlcachegen::loadGeneratedFile()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n"
+ "QtObject {\n"
+ " property int value: Math.min(100, 42);\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+}
+
+void tst_qmlcachegen::translationExpressionSupport()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml.Models 2.2\n"
+ "import QtQml 2.2\n"
+ "QtObject {\n"
+ " property ListModel model: ListModel {\n"
+ " ListElement {\n"
+ " text: qsTr(\"All\")\n"
+ " }\n"
+ " ListElement {\n"
+ " text: QT_TR_NOOP(\"Ok\")\n"
+ " }\n"
+ " }\n"
+ " property string text: model.get(0).text + \" \" + model.get(1).text\n"
+ "}");
+
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("text").toString(), QString("All Ok"));
+}
+
+QTEST_GUILESS_MAIN(tst_qmlcachegen)
+
+#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index b265607fd1..3402aeebc1 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -58,6 +58,7 @@ private slots:
void localAliases();
void cacheResources();
void stableOrderOfDependentCompositeTypes();
+ void singletonDependency();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -174,7 +175,7 @@ struct TestCompiler
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading();
- return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString);
+ return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), v4->iselFactory.data(), &lastErrorString);
}
void closeMapping()
@@ -737,6 +738,58 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes()
}
}
+void tst_qmldiskcache::singletonDependency()
+{
+ QScopedPointer<QQmlEngine> engine(new QQmlEngine);
+
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }");
+ writeTempFile("qmldir", "singleton MySingleton 1.0 MySingleton.qml");
+ const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport \".\"\nQtObject {\n"
+ " property int value: MySingleton.value\n"
+ "}");
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+ }
+
+ const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+
+ engine.reset(new QQmlEngine);
+ waitForFileSystem();
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }");
+ waitForFileSystem();
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 100);
+ }
+
+ {
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+ QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString()));
+ }
+}
+
QTEST_MAIN(tst_qmldiskcache)
#include "tst_qmldiskcache.moc"
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
index 3ed0aa7446..171c2bda8a 100644
--- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -29,7 +29,9 @@
#include <qtest.h>
#include <QLibraryInfo>
#include <QDir>
+#if QT_CONFIG(process)
#include <QProcess>
+#endif
#include <QDebug>
#include <QQmlError>
#include <cstdlib>
@@ -42,7 +44,7 @@ public:
private slots:
void initTestCase();
-#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
void qmlMinify_data();
void qmlMinify();
#endif
@@ -82,6 +84,7 @@ void tst_qmlmin::initTestCase()
excludedDirs << "doc/src/snippets/qtquick1/qtbinding";
excludedDirs << "doc/src/snippets/qtquick1/imports";
excludedDirs << "tests/manual/v4";
+ excludedDirs << "tests/auto/qml/ecmascripttests";
excludedDirs << "tests/auto/qml/qmllint";
// Add invalid files (i.e. files with syntax errors)
@@ -166,7 +169,7 @@ Examples are any .qml files under the examples/ directory that start
with a lower case letter.
*/
-#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
void tst_qmlmin::qmlMinify_data()
{
QTest::addColumn<QString>("file");
@@ -183,7 +186,7 @@ void tst_qmlmin::qmlMinify_data()
}
#endif
-#if !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
+#if QT_CONFIG(process) && !defined(QTEST_CROSS_COMPILED) // sources not available when cross compiled
void tst_qmlmin::qmlMinify()
{
QFETCH(QString, file);
diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
index 838966e2a0..68e11e3551 100644
--- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
+++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
@@ -105,12 +105,12 @@ void tst_qmlplugindump::singleton()
args << QLatin1String("tests.dumper.CompositeSingleton") << QLatin1String("1.0")
<< QLatin1String(".");
dumper.start(qmlplugindumpPath, args);
- dumper.waitForFinished();
+ QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
+ QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
const QString &result = dumper.readAllStandardOutput();
- qDebug() << "result: " << result;
- QVERIFY(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]")));
- QVERIFY(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")));
+ QVERIFY2(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]")), qPrintable(result));
+ QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result));
}
QTEST_MAIN(tst_qmlplugindump)
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index 74add85cb0..f7748b2da9 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -29,7 +29,9 @@
#include "../../shared/util.h"
#include <QQmlApplicationEngine>
#include <QSignalSpy>
+#if QT_CONFIG(process)
#include <QProcess>
+#endif
#include <QDebug>
class tst_qqmlapplicationengine : public QQmlDataTest
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 91ceed7697..6c9cb331a2 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -8170,6 +8170,8 @@ void tst_qqmlecmascript::stringify_qtbug_50592()
QCOMPARE(obj->property("source").toString(), QString::fromLatin1("http://example.org/some_nonexistant_image.png"));
}
+// Tests for the JS-only instanceof. Tests for the QML extensions for
+// instanceof belong in tst_qqmllanguage!
void tst_qqmlecmascript::instanceof_data()
{
QTest::addColumn<QString>("setupCode");
diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml
new file mode 100644
index 0000000000..f6ec5848c1
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.6
+
+MouseArea {
+
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml
new file mode 100644
index 0000000000..b3fa43a671
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.6
+
+Rectangle {
+}
diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml
new file mode 100644
index 0000000000..cf566b9315
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.6
+
+Rectangle {
+ property int somethingCustom: 0
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir
new file mode 100644
index 0000000000..144c93d8e3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir
@@ -0,0 +1,2 @@
+CustomRectangle 1.0 CustomRectangle.qml
+CustomMouseArea 1.0 CustomMouseArea.qml
diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml
new file mode 100644
index 0000000000..d74b172cf8
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml
@@ -0,0 +1,13 @@
+import QtQml 2.0
+
+QtObject {
+ id: qtobjectInstance
+
+ property Timer aTimer: Timer {
+ id: timerInstance
+ }
+
+ property Connections aConnections: Connections {
+ id: connectionsInstance
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml
new file mode 100644
index 0000000000..a8e303363e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml
@@ -0,0 +1,13 @@
+import QtQml 2.0 as QmlImport
+
+QmlImport.QtObject {
+ id: qtobjectInstance
+
+ property QmlImport.Timer aTimer: QmlImport.Timer {
+ id: timerInstance
+ }
+
+ property QmlImport.Connections aConnections: QmlImport.Connections {
+ id: connectionsInstance
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml
new file mode 100644
index 0000000000..9c1808d515
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ id: itemInstance
+
+ Rectangle {
+ id: rectangleInstance
+ }
+
+ MouseArea {
+ id: mouseAreaInstance
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml
new file mode 100644
index 0000000000..78fc112805
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+import "instanceOf"
+
+Item {
+ id: itemInstance
+
+ Rectangle {
+ id: rectangleInstance
+ }
+
+ MouseArea {
+ id: mouseAreaInstance
+ }
+
+ CustomRectangle {
+ id: customRectangleInstance
+ }
+ CustomRectangleWithProp {
+ id: customRectangleWithPropInstance
+ }
+ CustomMouseArea {
+ id: customMouseAreaInstance
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml
new file mode 100644
index 0000000000..97361b7334
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0 as QuickImport
+import "instanceOf" as CustomImport
+
+QuickImport.Item {
+ id: itemInstance
+
+ QuickImport.Rectangle {
+ id: rectangleInstance
+ }
+
+ QuickImport.MouseArea {
+ id: mouseAreaInstance
+ }
+
+ CustomImport.CustomRectangle {
+ id: customRectangleInstance
+ }
+ CustomImport.CustomRectangleWithProp {
+ id: customRectangleWithPropInstance
+ }
+ CustomImport.CustomMouseArea {
+ id: customMouseAreaInstance
+ }
+}
+
+
+
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 750c32cc3c..e67fa18309 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -263,6 +263,9 @@ private slots:
void qmlTypeCanBeResolvedByName_data();
void qmlTypeCanBeResolvedByName();
+ void instanceof_data();
+ void instanceof();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -309,7 +312,7 @@ private:
if (!errorfile) { \
if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \
qWarning() << "Unexpected Errors:" << component.errors(); \
- QVERIFY(!component.isError()); \
+ QVERIFY2(!component.isError(), qPrintable(component.errorString())); \
QVERIFY(component.errors().isEmpty()); \
} else { \
DETERMINE_ERRORS(errorfile,expected,actual);\
@@ -4338,6 +4341,200 @@ void tst_qqmllanguage::qmlTypeCanBeResolvedByName()
QVERIFY(!o.isNull());
}
+// Tests for the QML-only extensions of instanceof. Tests for the regular JS
+// instanceof belong in tst_qqmlecmascript!
+void tst_qqmllanguage::instanceof_data()
+{
+ QTest::addColumn<QUrl>("documentToTestIn");
+ QTest::addColumn<QVariant>("expectedValue");
+
+ // so the way this works is that the name of the test tag defines the test
+ // to run.
+ //
+ // the expectedValue is either a boolean true or false for whether the two
+ // operands are indeed an instanceof each other, or a string for the
+ // expected error message.
+
+ // assert that basic types don't convert to QObject
+ QTest::newRow("1 instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+ QTest::newRow("true instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+ QTest::newRow("\"foobar\" instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+
+ // assert that Managed don't either
+ QTest::newRow("new String(\"foobar\") instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+ QTest::newRow("new Object() instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+ QTest::newRow("new Date() instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant("TypeError: Type error");
+
+ // test that simple QtQml comparisons work
+ QTest::newRow("qtobjectInstance instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(true);
+ QTest::newRow("qtobjectInstance instanceof Timer")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(false);
+ QTest::newRow("timerInstance instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(true);
+ QTest::newRow("timerInstance instanceof Timer")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(true);
+ QTest::newRow("connectionsInstance instanceof QtObject")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(true);
+ QTest::newRow("connectionsInstance instanceof Timer")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(false);
+ QTest::newRow("connectionsInstance instanceof Connections")
+ << testFileUrl("instanceof_qtqml.qml")
+ << QVariant(true);
+
+ // make sure they still work when imported with a qualifier
+ QTest::newRow("qtobjectInstance instanceof QmlImport.QtObject")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("qtobjectInstance instanceof QmlImport.Timer")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(false);
+ QTest::newRow("timerInstance instanceof QmlImport.QtObject")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("timerInstance instanceof QmlImport.Timer")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("connectionsInstance instanceof QmlImport.QtObject")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("connectionsInstance instanceof QmlImport.Timer")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(false);
+ QTest::newRow("connectionsInstance instanceof QmlImport.Connections")
+ << testFileUrl("instanceof_qtqml_qualified.qml")
+ << QVariant(true);
+
+ // test that Quick C++ types work ok
+ QTest::newRow("itemInstance instanceof QtObject")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(true);
+ QTest::newRow("itemInstance instanceof Timer")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(false);
+ QTest::newRow("itemInstance instanceof Rectangle")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(false);
+ QTest::newRow("rectangleInstance instanceof Item")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(true);
+ QTest::newRow("rectangleInstance instanceof Rectangle")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(true);
+ QTest::newRow("rectangleInstance instanceof MouseArea")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(false);
+ QTest::newRow("mouseAreaInstance instanceof Item")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(true);
+ QTest::newRow("mouseAreaInstance instanceof Rectangle")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(false);
+ QTest::newRow("mouseAreaInstance instanceof MouseArea")
+ << testFileUrl("instanceof_qtquick.qml")
+ << QVariant(true);
+
+ // test that unqualified quick composite types work ok
+ QTest::newRow("rectangleInstance instanceof CustomRectangle")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(false);
+ QTest::newRow("customRectangleInstance instanceof Rectangle")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleInstance instanceof Item")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangleWithProp")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangle")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(false); // ### XXX: QTBUG-58477
+ QTest::newRow("customRectangleWithPropInstance instanceof Rectangle")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleInstance instanceof MouseArea")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(false);
+ QTest::newRow("customMouseAreaInstance instanceof MouseArea")
+ << testFileUrl("instanceof_qtquick_composite.qml")
+ << QVariant(true);
+
+ // test that they still work when qualified
+ QTest::newRow("rectangleInstance instanceof CustomImport.CustomRectangle")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(false);
+ QTest::newRow("customRectangleInstance instanceof QuickImport.Rectangle")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleInstance instanceof QuickImport.Item")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangleWithProp")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(false); // ### XXX: QTBUG-58477
+ QTest::newRow("customRectangleWithPropInstance instanceof QuickImport.Rectangle")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(true);
+ QTest::newRow("customRectangleInstance instanceof QuickImport.MouseArea")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(false);
+ QTest::newRow("customMouseAreaInstance instanceof QuickImport.MouseArea")
+ << testFileUrl("instanceof_qtquick_composite_qualified.qml")
+ << QVariant(true);
+}
+
+void tst_qqmllanguage::instanceof()
+{
+ QFETCH(QUrl, documentToTestIn);
+ QFETCH(QVariant, expectedValue);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, documentToTestIn);
+ VERIFY_ERRORS(0);
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o != 0);
+
+ QQmlExpression expr(engine.contextForObject(o.data()), 0, QString::fromLatin1(QTest::currentDataTag()));
+ QVariant ret = expr.evaluate();
+
+ if (expectedValue.type() == QVariant::Bool) {
+ // no error expected
+ QVERIFY2(!expr.hasError(), qPrintable(expr.error().description()));
+ bool returnValue = ret.toBool();
+
+ if (QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomRectangle") ||
+ QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle"))
+ QEXPECT_FAIL("", "QTBUG-58477: QML type rules are a little lax", Continue);
+ QCOMPARE(returnValue, expectedValue.toBool());
+ } else {
+ QVERIFY(expr.hasError());
+ QCOMPARE(expr.error().description(), expectedValue.toString());
+ }
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
index 9fbd719d7b..30e517c8f9 100644
--- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
+++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp
@@ -52,6 +52,7 @@ private slots:
void qmlPropertyValueInterceptorCast();
void qmlType();
void invalidQmlTypeName();
+ void prettyTypeName();
void registrationType();
void compositeType();
void externalEnums();
@@ -72,6 +73,16 @@ public:
};
QML_DECLARE_TYPE(TestType);
+class TestType2 : public QObject
+{
+ Q_OBJECT
+};
+
+class TestType3 : public QObject
+{
+ Q_OBJECT
+};
+
class ExternalEnums : public QObject
{
Q_OBJECT
@@ -214,13 +225,28 @@ void tst_qqmlmetatype::invalidQmlTypeName()
{
QStringList currFailures = QQmlMetaType::typeRegistrationFailures();
QCOMPARE(qmlRegisterType<TestType>("TestNamespace", 1, 0, "Test$Type"), -1); // should fail due to invalid QML type name.
+ QCOMPARE(qmlRegisterType<TestType>("Test", 1, 0, "EndingInSlash/"), -1);
QStringList nowFailures = QQmlMetaType::typeRegistrationFailures();
foreach (const QString &f, currFailures)
nowFailures.removeOne(f);
- QCOMPARE(nowFailures.size(), 1);
+ QCOMPARE(nowFailures.size(), 2);
QCOMPARE(nowFailures.at(0), QStringLiteral("Invalid QML element name \"Test$Type\""));
+ QCOMPARE(nowFailures.at(1), QStringLiteral("Invalid QML element name \"EndingInSlash/\""));
+}
+
+void tst_qqmlmetatype::prettyTypeName()
+{
+ TestType2 obj2;
+ QCOMPARE(QQmlMetaType::prettyTypeName(&obj2), QString("TestType2"));
+ QVERIFY(qmlRegisterType<TestType2>("Test", 1, 0, "") >= 0);
+ QCOMPARE(QQmlMetaType::prettyTypeName(&obj2), QString("TestType2"));
+
+ TestType3 obj3;
+ QCOMPARE(QQmlMetaType::prettyTypeName(&obj3), QString("TestType3"));
+ QVERIFY(qmlRegisterType<TestType3>("Test", 1, 0, "OtherName") >= 0);
+ QCOMPARE(QQmlMetaType::prettyTypeName(&obj3), QString("OtherName"));
}
void tst_qqmlmetatype::isList()
diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp
index 88b6ae92a8..55a1f65608 100644
--- a/tests/auto/qml/v4misc/tst_v4misc.cpp
+++ b/tests/auto/qml/v4misc/tst_v4misc.cpp
@@ -26,6 +26,7 @@
**
****************************************************************************/
+#include <qhashfunctions.h>
#include <qtest.h>
#define V4_AUTOTEST
@@ -46,17 +47,12 @@ private slots:
void moveMapping_2();
};
-QT_BEGIN_NAMESPACE
-// Avoid QHash randomization so that the temp numbering is stable.
-extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed; // from qhash.cpp
-QT_END_NAMESPACE
-
using namespace QT_PREPEND_NAMESPACE(QV4::IR);
void tst_v4misc::initTestCase()
{
- qt_qhash_seed.store(0);
- QCOMPARE(qt_qhash_seed.load(), 0);
+ qSetGlobalQHashSeed(0);
+ QCOMPARE(qGlobalQHashSeed(), 0);
}
// split between two ranges
diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/BLACKLIST
index c38347b42a..e0a4ce1743 100644
--- a/tests/auto/qmltest/BLACKLIST
+++ b/tests/auto/qmltest/BLACKLIST
@@ -9,3 +9,8 @@ linux
linux
[ListView::test_listInteractiveCurrentIndexEnforce]
linux
+macos-10.12
+[TextEdit::test_textentry]
+macos-10.12
+[TextEdit::test_textentry_char]
+macos-10.12
diff --git a/tests/auto/qmltest/selftests/tst_selftests.qml b/tests/auto/qmltest/selftests/tst_selftests.qml
index 439ea7a70d..5555876014 100644
--- a/tests/auto/qmltest/selftests/tst_selftests.qml
+++ b/tests/auto/qmltest/selftests/tst_selftests.qml
@@ -167,6 +167,16 @@ TestCase {
caught = true
}
verify(caught)
+
+ caught = false;
+ try {
+ testCase.verify(true, "foo", "bar")
+ } catch (e) {
+ compare(e.message, "QtQuickTest::fail")
+ compare(functions.failmsg, "More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?")
+ caught = true
+ }
+ verify(caught)
}
function test_compare() {
diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp
index d5c9aaeb90..b6742b9efe 100644
--- a/tests/auto/quick/examples/tst_examples.cpp
+++ b/tests/auto/quick/examples/tst_examples.cpp
@@ -29,7 +29,6 @@
#include <qtest.h>
#include <QLibraryInfo>
#include <QDir>
-#include <QProcess>
#include <QDebug>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
index ad77743ddd..e6655589a3 100644
--- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp
+++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
@@ -55,7 +55,6 @@
#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h>
#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
#endif
#include <QtQuick/private/qsggeometry_p.h>
#include <QtQuick/private/qsgnode_p.h>
diff --git a/tests/auto/quick/qquickapplication/BLACKLIST b/tests/auto/quick/qquickapplication/BLACKLIST
new file mode 100644
index 0000000000..81592db56f
--- /dev/null
+++ b/tests/auto/quick/qquickapplication/BLACKLIST
@@ -0,0 +1,2 @@
+[active]
+osx-10.11
diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST
index 647bf819a5..f35397f119 100644
--- a/tests/auto/quick/qquickflickable/BLACKLIST
+++ b/tests/auto/quick/qquickflickable/BLACKLIST
@@ -17,3 +17,5 @@ osx
osx-10.10
[flickVelocity]
osx-10.10
+[nestedSliderUsingTouch:keepNeither]
+ubuntu-16.04
diff --git a/tests/auto/quick/qquickflickable/data/nestedSlider.qml b/tests/auto/quick/qquickflickable/data/nestedSlider.qml
new file mode 100644
index 0000000000..2fd0cbfcc8
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/nestedSlider.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+import Test 1.0
+
+Flickable {
+ width: 240
+ height: 320
+ contentWidth: width * 1.5
+ contentHeight: height * 1.5
+ contentY: height * 0.25
+
+ Rectangle {
+ id: slider
+ width: 50
+ height: 200
+ color: "lightgray"
+ border.color: drag.active ? "green" : "black"
+ anchors.centerIn: parent
+ radius: 4
+
+ TouchDragArea {
+ id: drag
+ objectName: "drag"
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ width: parent.width - 2
+ height: 20
+ radius: 5
+ color: "darkgray"
+ border.color: "black"
+ x: 1
+ y: Math.min(slider.height - height, Math.max(0, drag.pos.y - height / 2))
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 9ead271bfe..ef6e444580 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -46,12 +46,107 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
+// an abstract Slider which only handles touch events
+class TouchDragArea : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QPointF pos READ pos NOTIFY posChanged)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged)
+ Q_PROPERTY(bool keepMouseGrab READ keepMouseGrab WRITE setKeepMouseGrab NOTIFY keepMouseGrabChanged)
+ Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged)
+
+public:
+ TouchDragArea(QQuickItem *parent = 0)
+ : QQuickItem(parent)
+ , touchEvents(0)
+ , touchUpdates(0)
+ , touchReleases(0)
+ , ungrabs(0)
+ , m_active(false)
+ { }
+
+ QPointF pos() const { return m_pos; }
+
+ bool active() const { return m_active; }
+
+ void setKeepMouseGrab(bool keepMouseGrab)
+ {
+ QQuickItem::setKeepMouseGrab(keepMouseGrab);
+ emit keepMouseGrabChanged();
+ }
+
+ void setKeepTouchGrab(bool keepTouchGrab)
+ {
+ QQuickItem::setKeepTouchGrab(keepTouchGrab);
+ emit keepTouchGrabChanged();
+ }
+
+ int touchEvents;
+ int touchUpdates;
+ int touchReleases;
+ int ungrabs;
+ QVector<Qt::TouchPointState> touchPointStates;
+
+protected:
+ void touchEvent(QTouchEvent *ev) override
+ {
+ QCOMPARE(ev->touchPoints().count(), 1);
+ auto touchpoint = ev->touchPoints().first();
+ switch (touchpoint.state()) {
+ case Qt::TouchPointPressed:
+ QVERIFY(!m_active);
+ m_active = true;
+ emit activeChanged();
+ grabTouchPoints(QVector<int>() << touchpoint.id());
+ break;
+ case Qt::TouchPointMoved:
+ ++touchUpdates;
+ break;
+ case Qt::TouchPointReleased:
+ QVERIFY(m_active);
+ m_active = false;
+ ++touchReleases;
+ emit activeChanged();
+ case Qt::TouchPointStationary:
+ break;
+ }
+ touchPointStates << touchpoint.state();
+ ++touchEvents;
+ m_pos = touchpoint.pos();
+ emit posChanged();
+ }
+
+ void touchUngrabEvent() override
+ {
+ ++ungrabs;
+ QVERIFY(m_active);
+ emit ungrabbed();
+ m_active = false;
+ emit activeChanged();
+ }
+
+signals:
+ void ungrabbed();
+ void posChanged();
+ void keepMouseGrabChanged();
+ void keepTouchGrabChanged();
+ void activeChanged();
+
+private:
+ QPointF m_pos;
+ bool m_active;
+};
+
class tst_qquickflickable : public QQmlDataTest
{
Q_OBJECT
public:
+ tst_qquickflickable()
+ : touchDevice(QTest::createTouchDevice())
+ {}
private slots:
+ void initTestCase() override;
void create();
void horizontalViewportSize();
void verticalViewportSize();
@@ -89,6 +184,8 @@ private slots:
void stopAtBounds();
void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
+ void nestedSliderUsingTouch();
+ void nestedSliderUsingTouch_data();
void pressDelayWithLoader();
void movementFromProgrammaticFlick();
void cleanup();
@@ -101,9 +198,16 @@ private slots:
void overshoot_reentrant();
private:
- void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to);
+ void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
+ QTouchDevice *touchDevice;
};
+void tst_qquickflickable::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea");
+}
+
void tst_qquickflickable::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
@@ -1530,12 +1634,6 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
void tst_qquickflickable::flickTwiceUsingTouches()
{
- QTouchDevice *touchDevice = new QTouchDevice;
- touchDevice->setName("Fake Touchscreen");
- touchDevice->setType(QTouchDevice::TouchScreen);
- touchDevice->setCapabilities(QTouchDevice::Position);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
-
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
@@ -1548,7 +1646,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QVERIFY(flickable != 0);
QCOMPARE(flickable->contentY(), 0.0f);
- flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240));
+ flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240));
qreal contentYAfterFirstFlick = flickable->contentY();
qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick;
@@ -1556,7 +1654,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
// Wait until view stops moving
QTRY_VERIFY(!flickable->isMoving());
- flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240));
+ flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240));
// In the original bug, that second flick would cause Flickable to halt immediately
qreal contentYAfterSecondFlick = flickable->contentY();
@@ -1564,7 +1662,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f));
}
-void tst_qquickflickable::flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to)
+void tst_qquickflickable::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to)
{
QTest::touchEvent(window, touchDevice).press(0, from, window);
QQuickTouchUtils::flush(window);
@@ -1869,12 +1967,6 @@ void tst_qquickflickable::stopAtBounds()
void tst_qquickflickable::nestedMouseAreaUsingTouch()
{
- QTouchDevice *touchDevice = new QTouchDevice;
- touchDevice->setName("Fake Touchscreen");
- touchDevice->setType(QTouchDevice::TouchScreen);
- touchDevice->setCapabilities(QTouchDevice::Position);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
-
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedmousearea.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
@@ -1887,7 +1979,7 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(flickable != 0);
QCOMPARE(flickable->contentY(), 50.0f);
- flickWithTouch(window.data(), touchDevice, QPoint(100, 300), QPoint(100, 200));
+ flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200));
// flickable should not have moved
QCOMPARE(flickable->contentY(), 50.0);
@@ -1897,6 +1989,65 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(nested->y() < 100.0);
}
+void tst_qquickflickable::nestedSliderUsingTouch_data()
+{
+ QTest::addColumn<bool>("keepMouseGrab");
+ QTest::addColumn<bool>("keepTouchGrab");
+ QTest::addColumn<int>("updates");
+ QTest::addColumn<int>("releases");
+ QTest::addColumn<int>("ungrabs");
+
+ QTest::newRow("keepBoth") << true << true << 8 << 1 << 0;
+ QTest::newRow("keepMouse") << true << false << 8 << 1 << 0;
+ QTest::newRow("keepTouch") << false << true << 8 << 1 << 0;
+ QTest::newRow("keepNeither") << false << false << 6 << 0 << 1;
+}
+
+void tst_qquickflickable::nestedSliderUsingTouch()
+{
+ QFETCH(bool, keepMouseGrab);
+ QFETCH(bool, keepTouchGrab);
+ QFETCH(int, updates);
+ QFETCH(int, releases);
+ QFETCH(int, ungrabs);
+
+ QQuickView *window = new QQuickView;
+ QScopedPointer<QQuickView> windowPtr(window);
+ windowPtr->setSource(testFileUrl("nestedSlider.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickViewTestUtil::centerOnScreen(window);
+ QQuickViewTestUtil::moveMouseAway(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable);
+
+ TouchDragArea *tda = flickable->findChild<TouchDragArea*>("drag");
+ QVERIFY(tda);
+
+ // Drag down and a little to the right: flickable will steal the grab only if tda allows it
+ const int dragThreshold = qApp->styleHints()->startDragDistance();
+ tda->setKeepMouseGrab(keepMouseGrab);
+ tda->setKeepTouchGrab(keepTouchGrab);
+ QPoint p0 = tda->mapToScene(QPoint(20, 20)).toPoint();
+ QTest::touchEvent(window, touchDevice).press(0, p0, window);
+ QQuickTouchUtils::flush(window);
+ for (int i = 0; i < 8; ++i) {
+ p0 += QPoint(dragThreshold / 6, dragThreshold / 4);
+ QTest::touchEvent(window, touchDevice).move(0, p0, window);
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(tda->active(), !ungrabs);
+ QTest::touchEvent(window, touchDevice).release(0, p0, window);
+ QQuickTouchUtils::flush(window);
+ QTRY_COMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
+ QTRY_COMPARE(tda->touchUpdates, updates);
+ QTRY_COMPARE(tda->touchReleases, releases);
+ QTRY_COMPARE(tda->ungrabs, ungrabs);
+}
+
// QTBUG-31328
void tst_qquickflickable::pressDelayWithLoader()
{
@@ -2065,6 +2216,7 @@ Q_DECLARE_METATYPE(QQuickFlickable::BoundsBehavior)
void tst_qquickflickable::overshoot()
{
QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior);
+ QFETCH(int, boundsMovement);
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("overshoot.qml"));
@@ -2081,6 +2233,7 @@ void tst_qquickflickable::overshoot()
QCOMPARE(flickable->contentHeight(), 400.0);
flickable->setBoundsBehavior(boundsBehavior);
+ flickable->setBoundsMovement(QQuickFlickable::BoundsMovement(boundsMovement));
// drag past the beginning
QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10, 10));
@@ -2089,23 +2242,30 @@ void tst_qquickflickable::overshoot()
QTest::mouseMove(window.data(), QPoint(40, 40));
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 50));
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QVERIFY(flickable->property("minContentX").toReal() < 0.0);
+ QVERIFY(flickable->property("minContentY").toReal() < 0.0);
+ } else {
+ QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
+ }
if (boundsBehavior & QQuickFlickable::DragOverBounds) {
- QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0);
- QCOMPARE(flickable->property("minContentY").toReal(),
- flickable->property("minVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("minContentX").toReal(),
- flickable->property("minHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
} else {
- QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
- QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ }
+ if (bool(boundsMovement == QQuickFlickable::FollowBoundsBehavior) == bool(boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QCOMPARE(flickable->property("minContentX").toReal(),
+ flickable->property("minHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("minContentY").toReal(),
+ flickable->property("minVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("maxContentY").toReal(), 0.0);
QCOMPARE(flickable->property("maxContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(20.0);
flickable->setContentY(20.0);
@@ -2115,23 +2275,30 @@ void tst_qquickflickable::overshoot()
flick(window.data(), QPoint(10, 10), QPoint(50, 50), 100);
QTRY_VERIFY(!flickable->property("flicking").toBool());
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QVERIFY(flickable->property("minContentX").toReal() < 0.0);
+ QVERIFY(flickable->property("minContentY").toReal() < 0.0);
+ } else {
+ QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
+ }
if (boundsBehavior & QQuickFlickable::OvershootBounds) {
- QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0);
- QCOMPARE(flickable->property("minContentY").toReal(),
- flickable->property("minVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("minContentX").toReal(),
- flickable->property("minHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
} else {
- QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
- QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QCOMPARE(flickable->property("minContentX").toReal(),
+ flickable->property("minHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("minContentY").toReal(),
+ flickable->property("minVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("maxContentY").toReal(), 20.0);
QCOMPARE(flickable->property("maxContentX").toReal(), 20.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 20.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(200.0);
flickable->setContentY(200.0);
@@ -2144,23 +2311,30 @@ void tst_qquickflickable::overshoot()
QTest::mouseMove(window.data(), QPoint(20, 20));
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10, 10));
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ } else {
+ QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
+ }
if (boundsBehavior & QQuickFlickable::DragOverBounds) {
- QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0);
- QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
- flickable->property("maxVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
- flickable->property("maxHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
} else {
- QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
- QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
+ flickable->property("maxHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
+ flickable->property("maxVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("minContentY").toReal(), 200.0);
QCOMPARE(flickable->property("minContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 200.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(180.0);
flickable->setContentY(180.0);
@@ -2170,37 +2344,59 @@ void tst_qquickflickable::overshoot()
flick(window.data(), QPoint(50, 50), QPoint(10, 10), 100);
QTRY_VERIFY(!flickable->property("flicking").toBool());
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ QVERIFY(flickable->property("maxContentY").toReal() > 200.0);
+ } else {
+ QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
+ }
if (boundsBehavior & QQuickFlickable::OvershootBounds) {
- QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0);
- QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
- flickable->property("maxVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
- flickable->property("maxHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
} else {
- QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
- QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
+ flickable->property("maxHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
+ flickable->property("maxVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("minContentY").toReal(), 180.0);
QCOMPARE(flickable->property("minContentX").toReal(), 180.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 180.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
}
void tst_qquickflickable::overshoot_data()
{
QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior");
-
- QTest::newRow("StopAtBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds);
- QTest::newRow("DragOverBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds);
- QTest::newRow("OvershootBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds);
- QTest::newRow("DragAndOvershootBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
+ QTest::addColumn<int>("boundsMovement");
+
+ QTest::newRow("StopAtBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("DragOverBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("OvershootBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+
+ QTest::newRow("DragOverBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::StopAtBounds);
+ QTest::newRow("OvershootBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::StopAtBounds);
+ QTest::newRow("DragAndOvershootBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::StopAtBounds);
}
void tst_qquickflickable::overshoot_reentrant()
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 2681f1a966..36d99ad48d 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -375,7 +375,7 @@ void tst_qquickimage::mirror()
}
QImage img = expected.toImage();
- QCOMPARE(screenshots[fillMode], img);
+ QCOMPARE(screenshots[fillMode].convertToFormat(img.format()), img);
}
}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
index 1777af9e0c..cab6e2f7bf 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
+++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
@@ -1,2 +1,4 @@
-[inFlickable]
-*
+[nonOverlapping]
+ubuntu-16.04
+[nested]
+ubuntu-16.04
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
index 2872556a94..87acd67f6a 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
+++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
@@ -800,7 +800,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable2()
QVERIFY(flickable->contentY() < 0);
QVERIFY(flickable->isMoving());
- QCOMPARE(point11->pressed(), true);
+ QCOMPARE(point11->pressed(), false);
QTest::touchEvent(window.data(), device).release(0, p1);
QQuickTouchUtils::flush(window.data());
diff --git a/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml
deleted file mode 100644
index 8da9fc270d..0000000000
--- a/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml
+++ /dev/null
@@ -1,12 +0,0 @@
-import QtQuick 2.9
-import PositionerTest 1.0
-
-ImplicitGrid {
- columns: 2
- rows: 1
-
- Text {
- text: "Text"
- width: parent.width
- }
-}
diff --git a/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml
deleted file mode 100644
index 25a287cf31..0000000000
--- a/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml
+++ /dev/null
@@ -1,9 +0,0 @@
-import QtQuick 2.9
-import PositionerTest 1.0
-
-ImplicitRow {
- Text {
- text: "Text"
- width: parent.width
- }
-}
diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
index 4c4afb7a7b..1b3939401a 100644
--- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
+++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
@@ -98,8 +98,6 @@ private slots:
void test_attachedproperties();
void test_attachedproperties_data();
void test_attachedproperties_dynamic();
- void test_useImplicitSize_oneItem_data();
- void test_useImplicitSize_oneItem();
void populateTransitions_row();
void populateTransitions_row_data();
@@ -306,8 +304,6 @@ void tst_qquickpositioners::moveTransitions_flow_data()
tst_qquickpositioners::tst_qquickpositioners()
{
- qmlRegisterType<QQuickImplicitRow>("PositionerTest", 1, 0, "ImplicitRow");
- qmlRegisterType<QQuickImplicitGrid>("PositionerTest", 1, 0, "ImplicitGrid");
}
void tst_qquickpositioners::test_horizontal()
@@ -4008,46 +4004,6 @@ void tst_qquickpositioners::test_attachedproperties_dynamic()
}
-void tst_qquickpositioners::test_useImplicitSize_oneItem_data()
-{
- QTest::addColumn<QString>("positionerType");
-
- QTest::newRow("Grid") << "Grid";
- QTest::newRow("Row") << "Row";
-}
-
-void tst_qquickpositioners::test_useImplicitSize_oneItem()
-{
- QFETCH(QString, positionerType);
-
- QQuickView view;
- view.setSource(testFileUrl(QString::fromLatin1("implicit%1OneItem.qml").arg(positionerType)));
- QCOMPARE(view.status(), QQuickView::Ready);
- view.show();
- QVERIFY(QTest::qWaitForWindowExposed(&view));
-
- QQuickItem *positioner = view.rootObject();
- QVERIFY(positioner);
- const qreal oldPositionerImplicitWidth = positioner->implicitWidth();
-
- QQuickText *text = qobject_cast<QQuickText*>(positioner->childItems().first());
- QVERIFY(text);
- const qreal oldTextImplicitWidth = text->implicitWidth();
- QCOMPARE(positioner->implicitWidth(), text->implicitWidth());
-
- // Ensure that the implicit size of the positioner changes when the implicit size
- // of one of its children changes.
- text->setText(QLatin1String("Even More Text"));
- const qreal textImplicitWidthIncrease = text->implicitWidth() - oldTextImplicitWidth;
- QVERIFY(textImplicitWidthIncrease > 0);
- QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease);
-
- // Ensure that the implicit size of the positioner does not change when the
- // explicit size of one of its children changes.
- text->setWidth(10);
- QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease);
-}
-
QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait)
{
QQuickView *window = new QQuickView(0);
diff --git a/tests/auto/quick/qquickwindow/BLACKLIST b/tests/auto/quick/qquickwindow/BLACKLIST
new file mode 100644
index 0000000000..157808fdbf
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/BLACKLIST
@@ -0,0 +1,4 @@
+[requestActivate]
+osx-10.11
+[attachedProperty]
+osx-10.11
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 578f737c4d..4fea13eb49 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QDebug>
+#include <QMimeData>
#include <QTouchEvent>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
@@ -385,6 +386,8 @@ private slots:
void grabContentItemToImage();
+ void testDragEventPropertyPropagation();
+
private:
QTouchDevice *touchDevice;
QTouchDevice *touchDeviceWithVelocity;
@@ -2617,6 +2620,261 @@ void tst_qquickwindow::grabContentItemToImage()
QTRY_COMPARE(created->property("success").toInt(), 1);
}
+class TestDropTarget : public QQuickItem
+{
+ Q_OBJECT
+public:
+ TestDropTarget(QQuickItem *parent = 0)
+ : QQuickItem(parent)
+ , enterDropAction(Qt::CopyAction)
+ , moveDropAction(Qt::CopyAction)
+ , dropDropAction(Qt::CopyAction)
+ , enterAccept(true)
+ , moveAccept(true)
+ , dropAccept(true)
+ {
+ setFlags(ItemAcceptsDrops);
+ }
+
+ void reset()
+ {
+ enterDropAction = Qt::CopyAction;
+ moveDropAction = Qt::CopyAction;
+ dropDropAction = Qt::CopyAction;
+ enterAccept = true;
+ moveAccept = true;
+ dropAccept = true;
+ }
+
+ void dragEnterEvent(QDragEnterEvent *event)
+ {
+ event->setAccepted(enterAccept);
+ event->setDropAction(enterDropAction);
+ }
+
+ void dragMoveEvent(QDragMoveEvent *event)
+ {
+ event->setAccepted(moveAccept);
+ event->setDropAction(moveDropAction);
+ }
+
+ void dropEvent(QDropEvent *event)
+ {
+ event->setAccepted(dropAccept);
+ event->setDropAction(dropDropAction);
+ }
+
+ Qt::DropAction enterDropAction;
+ Qt::DropAction moveDropAction;
+ Qt::DropAction dropDropAction;
+ bool enterAccept;
+ bool moveAccept;
+ bool dropAccept;
+};
+
+class DragEventTester {
+public:
+ DragEventTester()
+ : pos(60, 60)
+ , actions(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)
+ , buttons(Qt::LeftButton)
+ , modifiers(Qt::NoModifier)
+ {
+ }
+
+ ~DragEventTester() {
+ qDeleteAll(events);
+ events.clear();
+ enterEvent = 0;
+ moveEvent = 0;
+ dropEvent = 0;
+ leaveEvent = 0;
+ }
+
+ void addEnterEvent()
+ {
+ enterEvent = new QDragEnterEvent(pos, actions, &data, buttons, modifiers);
+ events.append(enterEvent);
+ }
+
+ void addMoveEvent()
+ {
+ moveEvent = new QDragMoveEvent(pos, actions, &data, buttons, modifiers, QEvent::DragMove);
+ events.append(moveEvent);
+ }
+
+ void addDropEvent()
+ {
+ dropEvent = new QDropEvent(pos, actions, &data, buttons, modifiers, QEvent::Drop);
+ events.append(dropEvent);
+ }
+
+ void addLeaveEvent()
+ {
+ leaveEvent = new QDragLeaveEvent();
+ events.append(leaveEvent);
+ }
+
+ void sendDragEventSequence(QQuickWindow *window) const {
+ for (int i = 0; i < events.size(); ++i) {
+ QCoreApplication::sendEvent(window, events[i]);
+ }
+ }
+
+ // Used for building events.
+ QMimeData data;
+ QPoint pos;
+ Qt::DropActions actions;
+ Qt::MouseButtons buttons;
+ Qt::KeyboardModifiers modifiers;
+
+ // Owns events.
+ QList<QEvent *> events;
+
+ // Non-owner pointers for easy acccess.
+ QDragEnterEvent *enterEvent;
+ QDragMoveEvent *moveEvent;
+ QDropEvent *dropEvent;
+ QDragLeaveEvent *leaveEvent;
+};
+
+void tst_qquickwindow::testDragEventPropertyPropagation()
+{
+ QQuickWindow window;
+ TestDropTarget dropTarget(window.contentItem());
+
+ // Setting the size is important because the QQuickWindow checks if the drag happened inside
+ // the drop target.
+ dropTarget.setSize(QSizeF(100, 100));
+
+ // Test enter events property propagation.
+ // For enter events, only isAccepted gets propagated.
+ {
+ DragEventTester builder;
+ dropTarget.enterAccept = false;
+ dropTarget.enterDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragEnterEvent* enterEvent = builder.enterEvent;
+ QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.enterAccept = false;
+ dropTarget.enterDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragEnterEvent* enterEvent = builder.enterEvent;
+ QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.enterAccept = true;
+ dropTarget.enterDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragEnterEvent* enterEvent = builder.enterEvent;
+ QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.enterAccept = true;
+ dropTarget.enterDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragEnterEvent* enterEvent = builder.enterEvent;
+ QCOMPARE(enterEvent->isAccepted(), dropTarget.enterAccept);
+ }
+
+ // Test move events property propagation.
+ // For move events, both isAccepted and dropAction get propagated.
+ dropTarget.reset();
+ {
+ DragEventTester builder;
+ dropTarget.moveAccept = false;
+ dropTarget.moveDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragMoveEvent* moveEvent = builder.moveEvent;
+ QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
+ QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.moveAccept = false;
+ dropTarget.moveDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragMoveEvent* moveEvent = builder.moveEvent;
+ QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
+ QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.moveAccept = true;
+ dropTarget.moveDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragMoveEvent* moveEvent = builder.moveEvent;
+ QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
+ QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.moveAccept = true;
+ dropTarget.moveDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addLeaveEvent();
+ builder.sendDragEventSequence(&window);
+ QDragMoveEvent* moveEvent = builder.moveEvent;
+ QCOMPARE(moveEvent->isAccepted(), dropTarget.moveAccept);
+ QCOMPARE(moveEvent->dropAction(), dropTarget.moveDropAction);
+ }
+
+ // Test drop events property propagation.
+ // For drop events, both isAccepted and dropAction get propagated.
+ dropTarget.reset();
+ {
+ DragEventTester builder;
+ dropTarget.dropAccept = false;
+ dropTarget.dropDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
+ builder.sendDragEventSequence(&window);
+ QDropEvent* dropEvent = builder.dropEvent;
+ QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
+ QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.dropAccept = false;
+ dropTarget.dropDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
+ builder.sendDragEventSequence(&window);
+ QDropEvent* dropEvent = builder.dropEvent;
+ QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
+ QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.dropAccept = true;
+ dropTarget.dropDropAction = Qt::IgnoreAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
+ builder.sendDragEventSequence(&window);
+ QDropEvent* dropEvent = builder.dropEvent;
+ QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
+ QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
+ }
+ {
+ DragEventTester builder;
+ dropTarget.dropAccept = true;
+ dropTarget.dropDropAction = Qt::CopyAction;
+ builder.addEnterEvent(); builder.addMoveEvent(); builder.addDropEvent();
+ builder.sendDragEventSequence(&window);
+ QDropEvent* dropEvent = builder.dropEvent;
+ QCOMPARE(dropEvent->isAccepted(), dropTarget.dropAccept);
+ QCOMPARE(dropEvent->dropAction(), dropTarget.dropDropAction);
+ }
+}
+
QTEST_MAIN(tst_qquickwindow)
#include "tst_qquickwindow.moc"
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
index b02d60d0c5..6e7fce6189 100644
--- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -71,7 +71,7 @@ Q_SIGNALS:
public:
EventItem(QQuickItem *parent = 0)
- : QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1)
+ : QQuickItem(parent), touchUngrabCount(0), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1)
{
setAcceptedMouseButtons(Qt::LeftButton);
}
@@ -111,11 +111,17 @@ public:
eventList.append(Event(QEvent::UngrabMouse, QPoint(0,0), QPoint(0,0)));
}
+ void touchUngrabEvent()
+ {
+ ++touchUngrabCount;
+ }
+
bool event(QEvent *event) {
return QQuickItem::event(event);
}
QList<Event> eventList;
+ int touchUngrabCount;
bool acceptMouse;
bool acceptTouch;
bool filterTouch; // when used as event filter
@@ -158,6 +164,7 @@ private slots:
void mouseOverTouch();
void buttonOnFlickable();
+ void touchButtonOnFlickable();
void buttonOnDelayedPressFlickable_data();
void buttonOnDelayedPressFlickable();
void buttonOnTouch();
@@ -568,9 +575,10 @@ void tst_TouchMouse::buttonOnFlickable()
QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1);
QCOMPARE(window->mouseGrabberItem(), eventItem1);
- p1 += QPoint(0, -10);
- QPoint p2 = p1 + QPoint(0, -10);
- QPoint p3 = p2 + QPoint(0, -10);
+ int dragDelta = -qApp->styleHints()->startDragDistance();
+ p1 += QPoint(0, dragDelta);
+ QPoint p2 = p1 + QPoint(0, dragDelta);
+ QPoint p3 = p2 + QPoint(0, dragDelta);
QQuickTouchUtils::flush(window.data());
QTest::touchEvent(window.data(), device).move(0, p1, window.data());
QQuickTouchUtils::flush(window.data());
@@ -593,6 +601,66 @@ void tst_TouchMouse::buttonOnFlickable()
QQuickTouchUtils::flush(window.data());
}
+void tst_TouchMouse::touchButtonOnFlickable()
+{
+ // flickable - height 500 / 1000
+ // - eventItem1 y: 100, height 100
+ // - eventItem2 y: 300, height 100
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("buttononflickable.qml"));
+ window->show();
+ QQuickViewTestUtil::centerOnScreen(window.data());
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+ QVERIFY(window->rootObject() != 0);
+
+ QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable);
+
+ EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+ QCOMPARE(eventItem2->eventList.size(), 0);
+ eventItem2->acceptTouch = true;
+
+ // press via touch, then drag: check that flickable moves and that the button gets ungrabbed
+ QCOMPARE(eventItem2->eventList.size(), 0);
+ QPoint p1 = QPoint(10, 310);
+ QTest::touchEvent(window.data(), device).press(0, p1, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QCOMPARE(eventItem2->eventList.size(), 1);
+ QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
+
+ QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data());
+ QVERIFY(windowPriv->touchMouseId == -1);
+ auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent();
+ QCOMPARE(pointerEvent->point(0)->grabberItem(), eventItem2);
+ QCOMPARE(window->mouseGrabberItem(), nullptr);
+
+ int dragDelta = qApp->styleHints()->startDragDistance() * -0.7;
+ p1 += QPoint(0, dragDelta);
+ QPoint p2 = p1 + QPoint(0, dragDelta);
+ QPoint p3 = p2 + QPoint(0, dragDelta);
+
+ QQuickTouchUtils::flush(window.data());
+ QTest::touchEvent(window.data(), device).move(0, p1, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QTest::touchEvent(window.data(), device).move(0, p2, window.data());
+ QQuickTouchUtils::flush(window.data());
+ QTest::touchEvent(window.data(), device).move(0, p3, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ QVERIFY(eventItem2->eventList.size() > 2);
+ QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
+ QCOMPARE(eventItem2->touchUngrabCount, 1);
+ QCOMPARE(window->mouseGrabberItem(), flickable);
+ QVERIFY(windowPriv->touchMouseId != -1);
+ QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable);
+ QVERIFY(flickable->isMovingVertically());
+
+ QTest::touchEvent(window.data(), device).release(0, p3, window.data());
+ QQuickTouchUtils::flush(window.data());
+}
+
void tst_TouchMouse::buttonOnDelayedPressFlickable_data()
{
QTest::addColumn<bool>("scrollBeforeDelayIsOver");
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 5e8f762e23..bd051ec990 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -58,6 +58,7 @@ private slots:
void grabBeforeShow();
void reparentToNewWindow();
void nullEngine();
+ void keyEvents();
};
@@ -337,6 +338,33 @@ void tst_qquickwidget::nullEngine()
QVERIFY(widget.engine());
}
+class KeyHandlingWidget : public QQuickWidget
+{
+public:
+ void keyPressEvent(QKeyEvent *e) override {
+ if (e->key() == Qt::Key_A)
+ ok = true;
+ }
+
+ bool ok = false;
+};
+
+void tst_qquickwidget::keyEvents()
+{
+ // A QQuickWidget should behave like a normal widget when it comes to event handling.
+ // Verify that key events actually reach the widget. (QTBUG-45757)
+ KeyHandlingWidget widget;
+ widget.setSource(testFileUrl("rectangle.qml"));
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(widget.window(), 5000));
+
+ // Note: send the event to the QWindow, not the QWidget, in order
+ // to simulate the full event processing chain.
+ QTest::keyClick(widget.window()->windowHandle(), Qt::Key_A);
+
+ QTRY_VERIFY(widget.ok);
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"
diff --git a/tests/auto/toolsupport/tst_toolsupport.cpp b/tests/auto/toolsupport/tst_toolsupport.cpp
index 9a11a67e65..6ee1db805a 100644
--- a/tests/auto/toolsupport/tst_toolsupport.cpp
+++ b/tests/auto/toolsupport/tst_toolsupport.cpp
@@ -101,7 +101,7 @@ void tst_toolsupport::offsets_data()
= QTest::newRow("CompiledData::CompilationUnit::data")
<< pmm_to_offsetof(&QV4::CompiledData::CompilationUnit::data);
- data << 8 << 16;
+ data << 12 << 24;
}
{
@@ -109,7 +109,7 @@ void tst_toolsupport::offsets_data()
= QTest::newRow("CompiledData::CompilationUnit::runtimeStrings")
<< pmm_to_offsetof(&QV4::CompiledData::CompilationUnit::runtimeStrings);
- data << 16 << 32;
+ data << 0 << 0;
}
{
diff --git a/tests/benchmarks/qml/holistic/testtypes.h b/tests/benchmarks/qml/holistic/testtypes.h
index 0736982373..a752a8585b 100644
--- a/tests/benchmarks/qml/holistic/testtypes.h
+++ b/tests/benchmarks/qml/holistic/testtypes.h
@@ -43,6 +43,7 @@
#include <QtQml/qjsvalue.h>
#include <QtQml/qqmlscriptstring.h>
#include <QtQml/qqmlcomponent.h>
+#include <QtCore/qregexp.h>
class MyQmlAttachedObject : public QObject
{
diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
index 886cfc6599..6da0799bbc 100644
--- a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
+++ b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp
@@ -29,6 +29,7 @@
#include <QtCore/QTimer>
#include <QtCore/QDebug>
#include <QtCore/QFileInfo>
+#include <QtCore/QHashFunctions>
#include <QtGui/QGuiApplication>
#include <QtGui/QImage>
@@ -134,11 +135,9 @@ private:
};
-Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed;
-
int main(int argc, char *argv[])
{
- qt_qhash_seed = 0;
+ qSetGlobalQHashSeed(0);
QGuiApplication a(argc, argv);
diff --git a/tests/manual/v4/test262 b/tests/manual/v4/test262
deleted file mode 160000
-Subproject 9741ac4655808ac46c127e3d1d8ba3d27ada618
diff --git a/tests/manual/v4/tests.pro b/tests/manual/v4/tests.pro
deleted file mode 100644
index ce4a34f7a0..0000000000
--- a/tests/manual/v4/tests.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-TEMPLATE = aux
-
-TESTSCRIPT=$$PWD/test262.py
-isEmpty(V4CMD): V4CMD = qmljs
-
-checktarget.target = check
-checktarget.commands = python $$TESTSCRIPT --command=$$V4CMD --parallel --with-test-expectations --update-expectations
-checktarget.depends = all
-QMAKE_EXTRA_TARGETS += checktarget
-
-checkmothtarget.target = check-interpreter
-checkmothtarget.commands = python $$TESTSCRIPT --command=\"$$V4CMD --interpret\" --parallel --with-test-expectations
-checkmothtarget.depends = all
-QMAKE_EXTRA_TARGETS += checkmothtarget
-
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 1699d3d81b..3b20fba5d4 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -55,7 +55,9 @@
#include <QLibraryInfo>
#include <qqml.h>
#include <qqmldebug.h>
+#if QT_CONFIG(animation)
#include <private/qabstractanimation_p.h>
+#endif
#include <cstdio>
#include <cstring>
@@ -476,10 +478,12 @@ int main(int argc, char *argv[])
break;
else if (arg == QLatin1String("-verbose"))
verboseMode = true;
+#if QT_CONFIG(animation)
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
QUnifiedTimer::instance()->setConsistentTiming(true);
+#endif
else if (arg == QLatin1String("-I")) {
if (i+1 == argList.count())
continue;//Invalid usage, but just ignore it
@@ -567,7 +571,7 @@ int main(int argc, char *argv[])
loadDummyDataFiles(e, dummyDir);
for (const QString &path : qAsConst(files)) {
- QUrl url = QUrl::fromUserInput(path, QDir::currentPath());
+ QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile);
if (verboseMode)
printf("qml: loading %s\n", qPrintable(url.toString()));
QByteArray strippedFile;
diff --git a/tools/qmlcachegen/qmlcache.prf b/tools/qmlcachegen/qmlcache.prf
index fed9f0d2f3..4470db0d09 100644
--- a/tools/qmlcachegen/qmlcache.prf
+++ b/tools/qmlcachegen/qmlcache.prf
@@ -1,12 +1,55 @@
-qtPrepareTool(QML_CACHEGEN, qmlcachegen)
+static {
+ message("QML cache generation ahead of time is not supported in static builds")
+ return()
+}
+
+qtPrepareTool(QML_CACHEGEN, qmlcachegen, _ARCH_CHECK)
+
+isEmpty(TARGETPATH): error("Must set TARGETPATH (QML import name) for ahead-of-time QML cache generation")
!isEmpty(QT_TARGET_ARCH):QML_CACHEGEN_ARCH=$$QT_TARGET_ARCH
else:QML_CACHEGEN_ARCH=$$QT_ARCH
-qmlcachegen.input = QML_FILES
-qmlcachegen.output = ${QMAKE_FILE_IN}c
-qmlcachegen.commands = $$QML_CACHEGEN --target-architecture=$$QML_CACHEGEN_ARCH ${QMAKE_FILE_IN}
+!isEmpty(QT_TARGET_BUILDABI):QML_CACHEGEN_ABI=$$QT_TARGET_BUILDABI
+else:QML_CACHEGEN_ABI=$$QT_BUILDABI
+
+QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH --target-abi=$$QML_CACHEGEN_ABI
+
+!system($$QML_CACHEGEN_ARCH_CHECK $$QML_CACHEGEN_ARGS --check-if-supported) {
+ message("QML cache generation requested but target architecture $$QML_CACHEGEN_ARCH is not supported.")
+ return()
+}
+
+load(qt_build_paths)
+
+prefix_build: QMLCACHE_DESTDIR = $$MODULE_BASE_OUTDIR/qml/$$TARGETPATH
+else: QMLCACHE_DESTDIR = $$[QT_INSTALL_QML]/$$TARGETPATH
+
+CACHEGEN_FILES=
+qmlcacheinst.files =
+for(qmlf, QML_FILES) {
+ contains(qmlf,.*\\.js$)|contains(qmlf,.*\\.qml$) {
+ CACHEGEN_FILES += $$absolute_path($$qmlf, $$_PRO_FILE_PWD_)
+ qmlcacheinst.files += $$QMLCACHE_DESTDIR/$$relative_path($$qmlf, $$_PRO_FILE_PWD_)c
+ }
+}
+
+defineReplace(qmlCacheOutputFileName) {
+ return($$relative_path($$QMLCACHE_DESTDIR/$$relative_path($$1, $$_PRO_FILE_PWD_)c, $$OUT_PWD))
+}
+
+qmlcacheinst.base = $$QMLCACHE_DESTDIR
+qmlcacheinst.path = $$[QT_INSTALL_QML]/$$TARGETPATH
+qmlcacheinst.CONFIG = no_check_exist
+
+qmlcachegen.input = CACHEGEN_FILES
+qmlcachegen.output = ${QMAKE_FUNC_FILE_IN_qmlCacheOutputFileName}
+qmlcachegen.CONFIG = no_link target_predeps
+qmlcachegen.commands = $$QML_CACHEGEN $$QML_CACHEGEN_ARGS -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
qmlcachegen.name = Generate QML Cache ${QMAKE_FILE_IN}
-qmlcachegen.variable_out = AUX_QML_FILES
+qmlcachegen.variable_out = GENERATED_FILES
-QMAKE_EXTRA_COMPILERS += qmlcachegen
+!debug_and_release|!build_all|CONFIG(release, debug|release) {
+ QMAKE_EXTRA_COMPILERS += qmlcachegen
+ INSTALLS += qmlcacheinst
+}
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index 977c5b6ff1..b201176d5e 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -32,13 +32,14 @@
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
+#include <QHashFunctions>
#include <private/qqmlirbuilder_p.h>
#include <private/qv4isel_moth_p.h>
#include <private/qqmljsparser_p.h>
+#include <private/qv4jssimplifier_p.h>
QT_BEGIN_NAMESPACE
-extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
namespace QV4 { namespace JIT {
Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture);
@@ -80,9 +81,43 @@ QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::Diagnostic
return message;
}
-static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+// Ensure that ListElement objects keep all property assignments in their string form
+static void annotateListElements(QmlIR::Document *document)
+{
+ QStringList listElementNames;
+
+ foreach (const QV4::CompiledData::Import *import, document->imports) {
+ const QString uri = document->stringAt(import->uriIndex);
+ if (uri != QStringLiteral("QtQml.Models") && uri != QStringLiteral("QtQuick"))
+ continue;
+
+ QString listElementName = QStringLiteral("ListElement");
+ const QString qualifier = document->stringAt(import->qualifierIndex);
+ if (!qualifier.isEmpty()) {
+ listElementName.prepend(QLatin1Char('.'));
+ listElementName.prepend(qualifier);
+ }
+ listElementNames.append(listElementName);
+ }
+
+ if (listElementNames.isEmpty())
+ return;
+
+ foreach (QmlIR::Object *object, document->objects) {
+ if (!listElementNames.contains(document->stringAt(object->inheritedTypeNameIndex)))
+ continue;
+ for (QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+ binding->stringIndex = document->registerString(object->bindingAsString(document, binding->value.compiledScriptIndex));
+ }
+ }
+}
+
+static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
+ irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@@ -96,7 +131,6 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
return false;
}
- irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
}
{
@@ -112,8 +146,10 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
}
}
+ annotateListElements(&irDocument);
+
{
- QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
+ QmlIR::JSCodeGen v4CodeGen(/*empty input file name*/QString(), irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0)
continue;
@@ -139,21 +175,22 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
QmlIR::QmlUnitGenerator generator;
- // ### translation binding simplification
+ {
+ QQmlJavaScriptBindingExpressionSimplificationPass pass(irDocument.objects, &irDocument.jsModule, &irDocument.jsGenerator);
+ pass.reduceTranslationBindings();
+ }
QV4::ExecutableAllocator allocator;
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
// Disable lookups in non-standalone (aka QML) mode
isel->setUseFastLookups(false);
irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
- // ###
- QV4::CompiledData::ResolvedTypeReferenceMap dummyDependencies;
- QV4::CompiledData::Unit *unit = generator.generate(irDocument, /*engine*/nullptr, dummyDependencies);
+ QV4::CompiledData::Unit *unit = generator.generate(irDocument);
unit->flags |= QV4::CompiledData::Unit::StaticData;
unit->flags |= QV4::CompiledData::Unit::PendingTypeCompilation;
irDocument.javaScriptCompilationUnit->data = unit;
- if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message))
+ if (!irDocument.javaScriptCompilationUnit->saveToDisk(outputFileName, &error->message))
return false;
free(unit);
@@ -161,9 +198,10 @@ static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *i
return true;
}
-static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
+ irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@@ -177,7 +215,6 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
return false;
}
- irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
}
QQmlJS::Engine *engine = &irDocument.jsParserEngine;
@@ -217,7 +254,7 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
{
QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
- v4CodeGen.generateFromProgram(inputFileName, sourceCode, program, &irDocument.jsModule, QQmlJS::Codegen::GlobalCode);
+ v4CodeGen.generateFromProgram(/*empty input file name*/QString(), sourceCode, program, &irDocument.jsModule, QQmlJS::Codegen::GlobalCode);
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
if (!jsErrors.isEmpty()) {
for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
@@ -231,19 +268,16 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
QmlIR::QmlUnitGenerator generator;
- // ### translation binding simplification
-
- QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, /*executable allocator*/nullptr, &irDocument.jsModule, &irDocument.jsGenerator));
+ QV4::ExecutableAllocator allocator;
+ QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
// Disable lookups in non-standalone (aka QML) mode
isel->setUseFastLookups(false);
irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
- // ###
- QV4::CompiledData::ResolvedTypeReferenceMap dummyDependencies;
- QV4::CompiledData::Unit *unit = generator.generate(irDocument, /*engine*/nullptr, dummyDependencies);
+ QV4::CompiledData::Unit *unit = generator.generate(irDocument);
unit->flags |= QV4::CompiledData::Unit::StaticData;
irDocument.javaScriptCompilationUnit->data = unit;
- if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message)) {
+ if (!irDocument.javaScriptCompilationUnit->saveToDisk(outputFileName, &error->message)) {
engine->setDirectives(oldDirs);
return false;
}
@@ -257,7 +291,7 @@ static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *is
int main(int argc, char **argv)
{
// Produce reliably the same output for the same input by disabling QHash's random seeding.
- qt_qhash_seed.testAndSetRelaxed(-1, 0);
+ qSetGlobalQHashSeed(0);
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName(QStringLiteral("qmlcachegen"));
@@ -270,37 +304,65 @@ int main(int argc, char **argv)
QCommandLineOption targetArchitectureOption(QStringLiteral("target-architecture"), QCoreApplication::translate("main", "Target architecture"), QCoreApplication::translate("main", "architecture"));
parser.addOption(targetArchitectureOption);
+ QCommandLineOption targetABIOption(QStringLiteral("target-abi"), QCoreApplication::translate("main", "Target architecture binary interface"), QCoreApplication::translate("main", "abi"));
+ parser.addOption(targetABIOption);
+
+ QCommandLineOption outputFileOption(QStringLiteral("o"), QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
+ parser.addOption(outputFileOption);
+
+ QCommandLineOption checkIfSupportedOption(QStringLiteral("check-if-supported"), QCoreApplication::translate("main", "Check if cache generate is supported on the specified target architecture"));
+ parser.addOption(checkIfSupportedOption);
+
parser.addPositionalArgument(QStringLiteral("[qml file]"),
QStringLiteral("QML source file to generate cache for."));
parser.process(app);
- const QStringList sources = parser.positionalArguments();
- if (sources.isEmpty()){
+ if (!parser.isSet(targetArchitectureOption)) {
+ fprintf(stderr, "Target architecture not specified. Please specify with --target-architecture=<arch>\n");
parser.showHelp();
- } else if (sources.count() > 1) {
- fprintf(stderr, "%s\n", qPrintable(QStringLiteral("Too many input files specified: '") + sources.join(QStringLiteral("' '")) + QLatin1Char('\'')));
return EXIT_FAILURE;
}
- const QString inputFile = sources.first();
QScopedPointer<QV4::EvalISelFactory> isel;
const QString targetArchitecture = parser.value(targetArchitectureOption);
isel.reset(QV4::JIT::createISelForArchitecture(targetArchitecture));
+ if (parser.isSet(checkIfSupportedOption)) {
+ if (isel.isNull())
+ return EXIT_FAILURE;
+ else
+ return EXIT_SUCCESS;
+ }
+
+ const QStringList sources = parser.positionalArguments();
+ if (sources.isEmpty()){
+ parser.showHelp();
+ } else if (sources.count() > 1) {
+ fprintf(stderr, "%s\n", qPrintable(QStringLiteral("Too many input files specified: '") + sources.join(QStringLiteral("' '")) + QLatin1Char('\'')));
+ return EXIT_FAILURE;
+ }
+ const QString inputFile = sources.first();
+
if (!isel)
isel.reset(new QV4::Moth::ISelFactory);
Error error;
+ QString outputFileName = inputFile + QLatin1Char('c');
+ if (parser.isSet(outputFileOption))
+ outputFileName = parser.value(outputFileOption);
+
+ const QString targetABI = parser.value(targetABIOption);
+
if (inputFile.endsWith(QLatin1String(".qml"))) {
- if (!compileQmlFile(inputFile, isel.data(), &error)) {
+ if (!compileQmlFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
} else if (inputFile.endsWith(QLatin1String(".js"))) {
- if (!compileJSFile(inputFile, isel.data(), &error)) {
+ if (!compileJSFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
diff --git a/tools/qmlcachegen/qmlcachegen.pro b/tools/qmlcachegen/qmlcachegen.pro
index 81783d0396..25afc2860d 100644
--- a/tools/qmlcachegen/qmlcachegen.pro
+++ b/tools/qmlcachegen/qmlcachegen.pro
@@ -6,19 +6,9 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
SOURCES = qmlcachegen.cpp
TARGET = qmlcachegen
-BUILD_INTEGRATION = qmlcache.prf
-!force_independent {
- qmake_integration.input = BUILD_INTEGRATION
- qmake_integration.output = $$[QT_HOST_DATA]/mkspecs/features/${QMAKE_FILE_BASE}.prf
- qmake_integration.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
- qmake_integration.name = COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
- qmake_integration.CONFIG = no_clean no_link
- !contains(TEMPLATE, vc.*): qmake_integration.variable_out = GENERATED_FILES
- QMAKE_EXTRA_COMPILERS += qmake_integration
-}
-
-qmake_integration_installs.files = $$BUILD_INTEGRATION
-qmake_integration_installs.path = $$[QT_HOST_DATA]/mkspecs/features
-INSTALLS += qmake_integration_installs
+build_integration.files = qmlcache.prf
+build_integration.path = $$[QT_HOST_DATA]/mkspecs/features
+prefix_build: INSTALLS += build_integration
+else: COPIES += build_integration
load(qt_tool)
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index 081e0660d5..182547490d 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -157,7 +157,7 @@ int main(int argc, char *argv[])
if (cache && QFile::exists(fn + QLatin1Char('c'))) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = iSelFactory->createUnitForLoading();
QString error;
- if (unit->loadFromDisk(QUrl::fromLocalFile(fn), iSelFactory, &error)) {
+ if (unit->loadFromDisk(QUrl::fromLocalFile(fn), QFileInfo(fn).lastModified(), iSelFactory, &error)) {
script.reset(new QV4::Script(&vm, nullptr, unit));
} else {
std::cout << "Error loading" << qPrintable(fn) << "from disk cache:" << qPrintable(error) << std::endl;
diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp
index 668cb3ce2d..bcda0bb7fe 100644
--- a/tools/qmlprofiler/qmlprofilerdata.cpp
+++ b/tools/qmlprofiler/qmlprofilerdata.cpp
@@ -33,6 +33,7 @@
#include <QHash>
#include <QFile>
#include <QXmlStreamReader>
+#include <QRegularExpression>
#include <limits>
@@ -231,10 +232,10 @@ void QmlProfilerData::addQmlEvent(QQmlProfilerDefinitions::RangeType type,
if (!data.isEmpty()) {
details = data.join(QLatin1Char(' ')).replace(
QLatin1Char('\n'), QLatin1Char(' ')).simplified();
- QRegExp rewrite(QStringLiteral("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)"));
- bool match = rewrite.exactMatch(details);
- if (match) {
- details = rewrite.cap(1) +QLatin1String(": ") + rewrite.cap(3);
+ QRegularExpression rewrite(QStringLiteral("^\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)$"));
+ QRegularExpressionMatch match = rewrite.match(details);
+ if (match.hasMatch()) {
+ details = match.captured(1) +QLatin1String(": ") + match.captured(3);
}
if (details.startsWith(QLatin1String("file://")))
details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1);
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 1e8d91a95b..6ce676456c 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -33,6 +33,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/qregularexpression.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFunctions>
@@ -132,6 +133,17 @@ void RenderStatistics::printTotalStats()
struct Options
{
+ enum QmlApplicationType
+ {
+ QmlApplicationTypeGui,
+ QmlApplicationTypeWidget,
+#ifdef QT_WIDGETS_LIB
+ DefaultQmlApplicationType = QmlApplicationTypeWidget
+#else
+ DefaultQmlApplicationType = QmlApplicationTypeGui
+#endif
+ };
+
Options()
: originalQml(false)
, originalQmlRaster(false)
@@ -145,6 +157,7 @@ struct Options
, resizeViewToRootItem(false)
, multisample(false)
, verbose(false)
+ , applicationType(DefaultQmlApplicationType)
{
// QtWebEngine needs a shared context in order for the GPU thread to
// upload textures.
@@ -166,6 +179,7 @@ struct Options
bool verbose;
QVector<Qt::ApplicationAttribute> applicationAttributes;
QString translationFile;
+ QmlApplicationType applicationType;
};
#if defined(QMLSCENE_BUNDLE)
@@ -258,8 +272,8 @@ static bool checkVersion(const QUrl &url)
return false;
}
- QRegExp quick1("^\\s*import +QtQuick +1\\.\\w*");
- QRegExp qt47("^\\s*import +Qt +4\\.7");
+ QRegularExpression quick1("^\\s*import +QtQuick +1\\.\\w*");
+ QRegularExpression qt47("^\\s*import +Qt +4\\.7");
QTextStream stream(&f);
bool codeFound= false;
@@ -269,10 +283,11 @@ static bool checkVersion(const QUrl &url)
codeFound = true;
} else {
QString import;
- if (quick1.indexIn(line) >= 0)
- import = quick1.cap(0).trimmed();
- else if (qt47.indexIn(line) >= 0)
- import = qt47.cap(0).trimmed();
+ QRegularExpressionMatch match = quick1.match(line);
+ if (match.hasMatch())
+ import = match.captured(0).trimmed();
+ else if ((match = qt47.match(line)).hasMatch())
+ import = match.captured(0).trimmed();
if (!import.isNull()) {
fprintf(stderr, "qmlscene: '%s' is no longer supported.\n"
@@ -290,15 +305,17 @@ static bool checkVersion(const QUrl &url)
static void displayFileDialog(Options *options)
{
#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
- QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
- if (!fileName.isEmpty()) {
- QFileInfo fi(fileName);
- options->url = QUrl::fromLocalFile(fi.canonicalFilePath());
+ if (options->applicationType == Options::QmlApplicationTypeWidget) {
+ QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ options->url = QUrl::fromLocalFile(fi.canonicalFilePath());
+ }
+ return;
}
-#else
+#endif // QT_WIDGETS_LIB && QT_CONFIG(filedialog)
Q_UNUSED(options);
puts("No filename specified...");
-#endif
}
#if QT_CONFIG(translation)
@@ -354,6 +371,9 @@ static void usage()
puts(" --scaling..........................Enable High DPI scaling (AA_EnableHighDpiScaling)");
puts(" --no-scaling.......................Disable High DPI scaling (AA_DisableHighDpiScaling)");
puts(" --verbose..........................Print version and graphical diagnostics for the run-time");
+#ifdef QT_WIDGETS_LIB
+ puts(" --apptype [gui|widgets] ...........Select which application class to use. Default is widgets.");
+#endif
puts(" -I <path> ........................ Add <path> to the list of import paths");
puts(" -P <path> ........................ Add <path> to the list of plugin paths");
puts(" -translation <translationfile> ... Set the language to run in");
@@ -443,30 +463,38 @@ int main(int argc, char ** argv)
// Parse arguments for application attributes to be applied before Q[Gui]Application creation.
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
- if (!qstrcmp(arg, "--disable-context-sharing"))
+ if (!qstrcmp(arg, "--disable-context-sharing")) {
options.applicationAttributes.removeAll(Qt::AA_ShareOpenGLContexts);
- else if (!qstrcmp(arg, "--gles"))
+ } else if (!qstrcmp(arg, "--gles")) {
options.applicationAttributes.append(Qt::AA_UseOpenGLES);
- else if (!qstrcmp(arg, "--software"))
+ } else if (!qstrcmp(arg, "--software")) {
options.applicationAttributes.append(Qt::AA_UseSoftwareOpenGL);
- else if (!qstrcmp(arg, "--desktop"))
+ } else if (!qstrcmp(arg, "--desktop")) {
options.applicationAttributes.append(Qt::AA_UseDesktopOpenGL);
- else if (!qstrcmp(arg, "--scaling"))
+ } else if (!qstrcmp(arg, "--scaling")) {
options.applicationAttributes.append(Qt::AA_EnableHighDpiScaling);
- else if (!qstrcmp(arg, "--no-scaling"))
+ } else if (!qstrcmp(arg, "--no-scaling")) {
options.applicationAttributes.append(Qt::AA_DisableHighDpiScaling);
+ } else if (!qstrcmp(arg, "--apptype")) {
+ if (++i >= argc)
+ usage();
+ if (!qstrcmp(argv[i], "gui"))
+ options.applicationType = Options::QmlApplicationTypeGui;
+ }
}
for (Qt::ApplicationAttribute a : qAsConst(options.applicationAttributes))
QCoreApplication::setAttribute(a);
+ QScopedPointer<QGuiApplication> app;
#ifdef QT_WIDGETS_LIB
- QApplication app(argc, argv);
-#else
- QGuiApplication app(argc, argv);
+ if (options.applicationType == Options::QmlApplicationTypeWidget)
+ app.reset(new QApplication(argc, argv));
#endif
- app.setApplicationName("QtQmlViewer");
- app.setOrganizationName("QtProject");
- app.setOrganizationDomain("qt-project.org");
+ if (app.isNull())
+ app.reset(new QGuiApplication(argc, argv));
+ QCoreApplication::setApplicationName(QStringLiteral("QtQmlViewer"));
+ QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
+ QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
const QStringList arguments = QCoreApplication::arguments();
@@ -501,6 +529,8 @@ int main(int argc, char ** argv)
imports.append(arguments.at(++i));
else if (lowerArgument == QLatin1String("-p") && i + 1 < size)
pluginPaths.append(arguments.at(++i));
+ else if (lowerArgument == QLatin1String("--apptype"))
+ ++i; // Consume previously parsed argument
else if (lowerArgument == QLatin1String("--help")
|| lowerArgument == QLatin1String("-help")
|| lowerArgument == QLatin1String("--h")
@@ -514,14 +544,14 @@ int main(int argc, char ** argv)
QTranslator qtTranslator;
QString sysLocale = QLocale::system().name();
if (qtTranslator.load(QLatin1String("qt_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- app.installTranslator(&qtTranslator);
+ app->installTranslator(&qtTranslator);
if (translator.load(QLatin1String("qmlscene_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- app.installTranslator(&translator);
+ app->installTranslator(&translator);
QTranslator qmlTranslator;
if (!options.translationFile.isEmpty()) {
if (qmlTranslator.load(options.translationFile)) {
- app.installTranslator(&qmlTranslator);
+ app->installTranslator(&qmlTranslator);
} else {
fprintf(stderr, "Could not load the translation file \"%s\"\n",
qPrintable(options.translationFile));
@@ -629,7 +659,7 @@ int main(int argc, char ** argv)
// Now would be a good time to inform the debug service to start listening.
- exitCode = app.exec();
+ exitCode = app->exec();
#ifdef QML_RUNTIME_TESTING
RenderStatistics::printTotalStats();
diff --git a/tools/tools.pro b/tools/tools.pro
index bf39a649df..20a3600fb8 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -2,15 +2,16 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += qml-private
SUBDIRS += \
qmlmin \
- qmlimportscanner \
- qmlcachegen
+ qmlimportscanner
+
+qtConfig(commandlineparser): SUBDIRS += qmlcachegen
!android|android_app {
SUBDIRS += \
qml \
qmllint
- qtConfig(qml-network):!contains(QT_CONFIG, no-qml-debug): SUBDIRS += qmlprofiler
+ qtConfig(qml-profiler): SUBDIRS += qmlprofiler
qtHaveModule(quick) {
!static: {
@@ -18,7 +19,7 @@ SUBDIRS += \
qmlscene \
qmltime
- qtConfig(regularexpression) {
+ qtConfig(regularexpression):qtConfig(process) {
SUBDIRS += \
qmlplugindump
}