aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h1
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp72
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h58
-rw-r--r--src/3rdparty/masm/disassembler/UDis86Disassembler.cpp2
-rw-r--r--src/3rdparty/masm/wtf/Platform.h3
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp2
-rw-r--r--src/imports/imports.pro3
-rw-r--r--src/imports/localstorage/plugin.cpp193
-rw-r--r--src/imports/statemachine/childrenprivate.h108
-rw-r--r--src/imports/statemachine/finalstate.cpp85
-rw-r--r--src/imports/statemachine/finalstate.h73
-rw-r--r--src/imports/statemachine/plugin.cpp77
-rw-r--r--src/imports/statemachine/plugins.qmltypes163
-rw-r--r--src/imports/statemachine/qmldir4
-rw-r--r--src/imports/statemachine/signaltransition.cpp238
-rw-r--r--src/imports/statemachine/signaltransition.h86
-rw-r--r--src/imports/statemachine/statebase.cpp244
-rw-r--r--src/imports/statemachine/statebase.h77
-rw-r--r--src/imports/statemachine/statemachine.cpp223
-rw-r--r--src/imports/statemachine/statemachine.h91
-rw-r--r--src/imports/statemachine/statemachine.pro24
-rw-r--r--src/imports/statemachine/timeouttransition.cpp114
-rw-r--r--src/imports/statemachine/timeouttransition.h76
-rw-r--r--src/imports/testlib/TestCase.qml15
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp2
-rw-r--r--src/particles/qquickimageparticle.cpp2
-rw-r--r--src/particles/qquickv4particledata.cpp92
-rw-r--r--src/plugins/accessible/accessible.pro2
-rw-r--r--src/plugins/accessible/quick/accessible.json3
-rw-r--r--src/plugins/accessible/quick/quick.pro23
-rw-r--r--src/plugins/accessible/shared/qaccessiblebase.pri3
-rw-r--r--src/plugins/plugins.pro3
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp2
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h4
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp12
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h3
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp37
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h10
-rw-r--r--src/qml/compiler/qv4codegen.cpp289
-rw-r--r--src/qml/compiler/qv4codegen_p.h22
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp230
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h88
-rw-r--r--src/qml/compiler/qv4isel_p.cpp119
-rw-r--r--src/qml/compiler/qv4isel_p.h84
-rw-r--r--src/qml/compiler/qv4isel_util_p.h1
-rw-r--r--src/qml/compiler/qv4jsir.cpp748
-rw-r--r--src/qml/compiler/qv4jsir_p.h226
-rw-r--r--src/qml/compiler/qv4ssa.cpp2542
-rw-r--r--src/qml/compiler/qv4ssa_p.h100
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h3
-rw-r--r--src/qml/debugger/qv4debugservice.cpp91
-rw-r--r--src/qml/debugger/qv4profileradapter.cpp39
-rw-r--r--src/qml/debugger/qv4profileradapter_p.h5
-rw-r--r--src/qml/doc/images/statemachine-button-history.pngbin0 -> 8074 bytes
-rw-r--r--src/qml/doc/images/statemachine-button-nested.pngbin0 -> 7051 bytes
-rw-r--r--src/qml/doc/images/statemachine-button.pngbin0 -> 4233 bytes
-rw-r--r--src/qml/doc/images/statemachine-finished.pngbin0 -> 5518 bytes
-rw-r--r--src/qml/doc/images/statemachine-nonparallel.pngbin0 -> 5350 bytes
-rw-r--r--src/qml/doc/images/statemachine-parallel.pngbin0 -> 8631 bytes
-rw-r--r--src/qml/doc/qtqml.qdocconf5
-rw-r--r--src/qml/doc/snippets/qml/statemachine/Button.qml88
-rw-r--r--src/qml/doc/snippets/qml/statemachine/basicstate.qml55
-rw-r--r--src/qml/doc/snippets/qml/statemachine/finalstate.qml63
-rw-r--r--src/qml/doc/snippets/qml/statemachine/historystate.qml85
-rw-r--r--src/qml/doc/snippets/qml/statemachine/signaltransition.qml77
-rw-r--r--src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml62
-rw-r--r--src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml68
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml150
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml135
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml127
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button.qml100
-rw-r--r--src/qml/doc/snippets/qml/statemachine/timeouttransition.qml69
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc38
-rw-r--r--src/qml/doc/src/qtqml.qdoc5
-rw-r--r--src/qml/doc/src/statemachine.qdoc317
-rw-r--r--src/qml/jit/jit.pri2
-rw-r--r--src/qml/jit/qv4assembler.cpp131
-rw-r--r--src/qml/jit/qv4assembler_p.h373
-rw-r--r--src/qml/jit/qv4binop.cpp50
-rw-r--r--src/qml/jit/qv4binop_p.h8
-rw-r--r--src/qml/jit/qv4isel_masm.cpp440
-rw-r--r--src/qml/jit/qv4isel_masm_p.h139
-rw-r--r--src/qml/jit/qv4regalloc.cpp1292
-rw-r--r--src/qml/jit/qv4regalloc_p.h51
-rw-r--r--src/qml/jit/qv4registerinfo_p.h99
-rw-r--r--src/qml/jit/qv4targetplatform_p.h390
-rw-r--r--src/qml/jit/qv4unop.cpp35
-rw-r--r--src/qml/jit/qv4unop_p.h8
-rw-r--r--src/qml/jsapi/qjsengine.cpp42
-rw-r--r--src/qml/jsapi/qjsengine.h2
-rw-r--r--src/qml/jsapi/qjsvalue.cpp24
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp16
-rw-r--r--src/qml/jsruntime/jsruntime.pri7
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp123
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h56
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp486
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h93
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp191
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h11
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp24
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4context.cpp341
-rw-r--r--src/qml/jsruntime/qv4context_p.h169
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp268
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h42
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp114
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h4
-rw-r--r--src/qml/jsruntime/qv4engine.cpp294
-rw-r--r--src/qml/jsruntime/qv4engine_p.h19
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp204
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h141
-rw-r--r--src/qml/jsruntime/qv4function.cpp5
-rw-r--r--src/qml/jsruntime/qv4function_p.h4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp322
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h130
-rw-r--r--src/qml/jsruntime/qv4global_p.h14
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp111
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h7
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp4
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp36
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h12
-rw-r--r--src/qml/jsruntime/qv4include.cpp53
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp63
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h3
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp72
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h14
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp236
-rw-r--r--src/qml/jsruntime/qv4managed.cpp35
-rw-r--r--src/qml/jsruntime/qv4managed_p.h243
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp110
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h7
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp30
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h20
-rw-r--r--src/qml/jsruntime/qv4mm.cpp90
-rw-r--r--src/qml/jsruntime/qv4mm_p.h59
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp66
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h9
-rw-r--r--src/qml/jsruntime/qv4object.cpp359
-rw-r--r--src/qml/jsruntime/qv4object_p.h213
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp80
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h31
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp195
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h10
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h2
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp23
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h43
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp212
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h61
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp43
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h95
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp179
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h59
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp251
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h45
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h113
-rw-r--r--src/qml/jsruntime/qv4script.cpp135
-rw-r--r--src/qml/jsruntime/qv4script_p.h52
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp219
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp8
-rw-r--r--src/qml/jsruntime/qv4string.cpp136
-rw-r--r--src/qml/jsruntime/qv4string_p.h107
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp234
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h24
-rw-r--r--src/qml/jsruntime/qv4value.cpp6
-rw-r--r--src/qml/jsruntime/qv4value_inl_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h12
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp68
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h24
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp54
-rw-r--r--src/qml/qml.pro6
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h2
-rw-r--r--src/qml/qml/qqml.h77
-rw-r--r--src/qml/qml/qqmlbinding.cpp38
-rw-r--r--src/qml/qml/qqmlbinding_p.h2
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp2
-rw-r--r--src/qml/qml/qqmlcompiler_p.h16
-rw-r--r--src/qml/qml/qqmlcomponent.cpp116
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp77
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h43
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp46
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h10
-rw-r--r--src/qml/qml/qqmlengine.cpp8
-rw-r--r--src/qml/qml/qqmlerror.cpp11
-rw-r--r--src/qml/qml/qqmlexpression.cpp2
-rw-r--r--src/qml/qml/qqmlfileselector.cpp8
-rw-r--r--src/qml/qml/qqmlfileselector_p.h2
-rw-r--r--src/qml/qml/qqmlincubator.cpp4
-rw-r--r--src/qml/qml/qqmlinfo.cpp2
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp56
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h28
-rw-r--r--src/qml/qml/qqmllocale.cpp298
-rw-r--r--src/qml/qml/qqmllocale_p.h24
-rw-r--r--src/qml/qml/qqmlmetatype.cpp5
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp33
-rw-r--r--src/qml/qml/qqmlproperty.cpp9
-rw-r--r--src/qml/qml/qqmltypeloader.cpp23
-rw-r--r--src/qml/qml/qqmltypeloader_p.h1
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp84
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h34
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp214
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h22
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp589
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp659
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h31
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h6
-rw-r--r--src/qml/qml/v8/qv8engine.cpp43
-rw-r--r--src/qml/qml/v8/qv8engine_p.h10
-rw-r--r--src/qml/types/qqmlconnections.cpp53
-rw-r--r--src/qml/types/qqmlconnections_p.h4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp250
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h25
-rw-r--r--src/qml/types/qqmlinstantiator.cpp4
-rw-r--r--src/qml/types/qqmllistmodel.cpp272
-rw-r--r--src/qml/types/qqmllistmodel_p.h33
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h16
-rw-r--r--src/qml/types/qqmltimer.cpp43
-rw-r--r--src/qml/types/qqmltimer_p.h2
-rw-r--r--src/qml/types/qquickworkerscript.cpp12
-rw-r--r--src/qml/util/qqmladaptormodel.cpp62
-rw-r--r--src/qml/util/qqmlchangeset.cpp112
-rw-r--r--src/qml/util/qqmlchangeset_p.h35
-rw-r--r--src/qml/util/qqmllistcompositor.cpp44
-rw-r--r--src/qml/util/qqmllistcompositor_p.h10
-rw-r--r--src/qmltest/qmltest.pro2
-rw-r--r--src/qmltest/quicktestresult.cpp6
-rw-r--r--src/qmltest/quicktestresult_p.h2
-rw-r--r--src/quick/accessible/accessible.pri16
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp (renamed from src/plugins/accessible/quick/qaccessiblequickitem.cpp)8
-rw-r--r--src/quick/accessible/qaccessiblequickitem_p.h (renamed from src/plugins/accessible/quick/qaccessiblequickitem.h)4
-rw-r--r--src/quick/accessible/qaccessiblequickview.cpp (renamed from src/plugins/accessible/quick/qaccessiblequickview.cpp)8
-rw-r--r--src/quick/accessible/qaccessiblequickview_p.h (renamed from src/plugins/accessible/quick/qaccessiblequickview.h)2
-rw-r--r--src/quick/accessible/qqmlaccessible.cpp (renamed from src/plugins/accessible/shared/qqmlaccessible.cpp)6
-rw-r--r--src/quick/accessible/qqmlaccessible_p.h (renamed from src/plugins/accessible/shared/qqmlaccessible.h)0
-rw-r--r--src/quick/accessible/qquickaccessiblefactory.cpp (renamed from src/plugins/accessible/quick/main.cpp)51
-rw-r--r--src/quick/accessible/qquickaccessiblefactory_p.h55
-rw-r--r--src/quick/doc/qtquick.qdocconf2
-rw-r--r--src/quick/doc/snippets/qml/itemGrab.qml87
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc42
-rw-r--r--src/quick/doc/src/concepts/visualtypes/topic.qdoc8
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc279
-rw-r--r--src/quick/doc/src/qtquick.qdoc23
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp8
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h1
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp1404
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp3
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp32
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h5
-rw-r--r--src/quick/items/items.pri15
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp40
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h6
-rw-r--r--src/quick/items/qquickanimatedimage.cpp40
-rw-r--r--src/quick/items/qquickanimatedimage_p_p.h3
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp2
-rw-r--r--src/quick/items/qquickdrag.cpp14
-rw-r--r--src/quick/items/qquickdrag_p.h6
-rw-r--r--src/quick/items/qquickflickable.cpp3
-rw-r--r--src/quick/items/qquickframebufferobject.cpp2
-rw-r--r--src/quick/items/qquickgridview.cpp4
-rw-r--r--src/quick/items/qquickimage.cpp46
-rw-r--r--src/quick/items/qquickimage_p.h4
-rw-r--r--src/quick/items/qquickimage_p_p.h1
-rw-r--r--src/quick/items/qquickitem.cpp247
-rw-r--r--src/quick/items/qquickitem.h11
-rw-r--r--src/quick/items/qquickitem_p.h8
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp399
-rw-r--r--src/quick/items/qquickitemgrabresult.h89
-rw-r--r--src/quick/items/qquickitemsmodule.cpp10
-rw-r--r--src/quick/items/qquickitemview.cpp16
-rw-r--r--src/quick/items/qquickitemview_p_p.h8
-rw-r--r--src/quick/items/qquicklistview.cpp169
-rw-r--r--src/quick/items/qquicklistview_p.h15
-rw-r--r--src/quick/items/qquickmousearea.cpp42
-rw-r--r--src/quick/items/qquickmousearea_p.h3
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp1
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h3
-rw-r--r--src/quick/items/qquickopenglinfo.cpp200
-rw-r--r--src/quick/items/qquickopenglinfo_p.h122
-rw-r--r--src/quick/items/qquickpathview.cpp4
-rw-r--r--src/quick/items/qquickpincharea.cpp84
-rw-r--r--src/quick/items/qquickpincharea_p.h1
-rw-r--r--src/quick/items/qquickpositioners.cpp4
-rw-r--r--src/quick/items/qquickrendercontrol.cpp236
-rw-r--r--src/quick/items/qquickrendercontrol.h84
-rw-r--r--src/quick/items/qquickrendercontrol_p.h67
-rw-r--r--src/quick/items/qquickrepeater.cpp4
-rw-r--r--src/quick/items/qquickshadereffect.cpp123
-rw-r--r--src/quick/items/qquickshadereffect_p.h7
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp3
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h4
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp69
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h4
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp91
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquickspriteengine.cpp3
-rw-r--r--src/quick/items/qquicktext.cpp1
-rw-r--r--src/quick/items/qquicktextinput.cpp150
-rw-r--r--src/quick/items/qquicktextinput_p.h10
-rw-r--r--src/quick/items/qquicktextinput_p_p.h3
-rw-r--r--src/quick/items/qquickview.cpp11
-rw-r--r--src/quick/items/qquickview_p.h18
-rw-r--r--src/quick/items/qquickwindow.cpp717
-rw-r--r--src/quick/items/qquickwindow.h24
-rw-r--r--src/quick/items/qquickwindow_p.h30
-rw-r--r--src/quick/items/qquickwindowattached.cpp110
-rw-r--r--src/quick/items/qquickwindowattached_p.h84
-rw-r--r--src/quick/items/qquickwindowmodule.cpp7
-rw-r--r--src/quick/qtquick2.cpp5
-rw-r--r--src/quick/qtquickglobal_p.h7
-rw-r--r--src/quick/quick.pro3
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp318
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer.h103
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h77
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp245
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h25
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp18
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader_p.h5
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp20
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h22
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp20
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp497
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h102
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp77
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h59
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp94
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h14
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp189
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp26
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp15
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp79
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h3
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp522
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h15
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp90
-rw-r--r--src/quick/scenegraph/scenegraph.pri6
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp113
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp204
-rw-r--r--src/quick/scenegraph/util/qsgengine.h80
-rw-r--r--src/quick/scenegraph/util/qsgengine_p.h66
-rw-r--r--src/quick/scenegraph/util/qsgpainternode.cpp18
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp38
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.h4
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp125
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp6
-rw-r--r--src/quick/util/qquickanimatorjob.cpp12
-rw-r--r--src/quick/util/qquickapplication.cpp55
-rw-r--r--src/quick/util/qquickapplication_p.h4
-rw-r--r--src/quick/util/qquickfontmetrics.cpp350
-rw-r--r--src/quick/util/qquickfontmetrics_p.h114
-rw-r--r--src/quick/util/qquickglobal.cpp22
-rw-r--r--src/quick/util/qquickpixmapcache.cpp45
-rw-r--r--src/quick/util/qquickpixmapcache_p.h3
-rw-r--r--src/quick/util/qquickprofiler.cpp6
-rw-r--r--src/quick/util/qquickprofiler_p.h10
-rw-r--r--src/quick/util/qquickpropertychanges.cpp197
-rw-r--r--src/quick/util/qquickpropertychanges_p.h6
-rw-r--r--src/quick/util/qquicksystempalette.cpp54
-rw-r--r--src/quick/util/qquicksystempalette_p.h5
-rw-r--r--src/quick/util/qquicktextmetrics.cpp268
-rw-r--r--src/quick/util/qquicktextmetrics_p.h111
-rw-r--r--src/quick/util/qquickutilmodule.cpp5
-rw-r--r--src/quick/util/util.pri8
-rw-r--r--src/quickwidgets/qquickwidget.cpp78
-rw-r--r--src/quickwidgets/qquickwidget.h4
-rw-r--r--src/quickwidgets/qquickwidget_p.h1
371 files changed, 20800 insertions, 11857 deletions
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index f492cc8c94..2be073e314 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -35,6 +35,7 @@
namespace JSC {
class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
+protected: // the YarrJIT needs know about addressTempRegister in order to push it.
// FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
// - dTR is likely used more than aTR, and we'll get better instruction
// encoding if it's in the low 8 registers.
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
index ae7b0859ed..d9afdd447a 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -120,6 +120,9 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = {
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVADDVSUB),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMUL),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCVT),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCMP),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink),
@@ -1579,6 +1582,75 @@ const char* ARMv7DOpcodeVADDVSUB::format()
return m_formatBuffer;
}
+const char* ARMv7DOpcodeVMUL::format()
+{
+ char regPrefix = sz() ? 'd' : 's';
+ appendInstructionName("vmul");
+ appendFPRegisterName(regPrefix, vd());
+ appendSeparator();
+ appendFPRegisterName(regPrefix, vn());
+ appendSeparator();
+ appendFPRegisterName(regPrefix, vm());
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeVCVT::format()
+{
+ char dregPrefix;
+ char mregPrefix;
+ const char *n1, *n2;
+
+ switch (opc2()) {
+ case 5:
+ n1 = op() ? "vcvtr.s32." : "vcvt.s32.";
+ n2 = sz() ? "f64" : "f32";
+ dregPrefix = 's';
+ mregPrefix = sz() ? 'd' : 's';
+ break;
+ case 4:
+ n1 = op() ? "vcvtr.u32." : "vcvt.u32.";
+ n2 = sz() ? "f64" : "f32";
+ dregPrefix = 's';
+ mregPrefix = sz() ? 'd' : 's';
+ break;
+ case 0:
+ n1 = sz() ? "vcvt.f64." : "vcvt.f32.";
+ n2 = op() ? "s32" : "u32";
+ dregPrefix = sz() ? 'd' : 's';
+ mregPrefix = 's';
+ break;
+ default:
+ n1 = "vcvt.?";
+ n2 = ".?";
+ break;
+ }
+
+ char buf[42];
+ snprintf(buf, 42, "%s%s", n1, n2);
+ appendInstructionName(buf);
+
+ appendFPRegisterName(dregPrefix, vd());
+ appendSeparator();
+ appendFPRegisterName(mregPrefix, vm());
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeVCMP::format()
+{
+ char regPrefix = sz() ? 'd' : 's';
+ appendInstructionName(e() ? "vcmpe" : "vcmp");
+ appendFPRegisterName(regPrefix, vd());
+ appendSeparator();
+ if (zero())
+ appendString("#0.0");
+ else
+ appendFPRegisterName(regPrefix, vm());
+
+ return m_formatBuffer;
+}
+
const char* ARMv7DOpcodeVLDRVSTR::format()
{
appendInstructionName(opName());
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
index 5bcb6b15b9..051d05525a 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
@@ -1146,6 +1146,8 @@ public:
protected:
const char* format();
+ // FIXME: the register encoding for single precision is not correct.
+
unsigned sz() { return (m_opcode >> 8) & 0x1; }
unsigned isSub() { return (m_opcode >> 6) & 0x1; }
unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
@@ -1153,6 +1155,62 @@ protected:
unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
};
+class ARMv7DOpcodeVMUL : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0xffb00e50;
+ static const uint32_t s_pattern = 0xee200a00;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMUL, thisObj);
+
+protected:
+ const char* format();
+
+ // FIXME: the register encoding for single precision is not correct.
+
+ unsigned sz() { return (m_opcode >> 8) & 0x1; }
+ unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
+ unsigned vn() { return ((m_opcode >> 16) & 0xf) | ((m_opcode >> 3) & 0x10); }
+ unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
+};
+
+class ARMv7DOpcodeVCVT : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0xffb80a50;
+ static const uint32_t s_pattern = 0xeeb80a40;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCVT, thisObj);
+
+protected:
+ const char* format();
+
+ // FIXME: the register encoding for single precision is not correct.
+
+ unsigned sz() { return (m_opcode >> 8) & 0x1; }
+ unsigned op() { return (m_opcode >> 7) & 0x1; }
+ unsigned opc2() { return (m_opcode >> 16) & 0x7; }
+ unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
+ unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
+};
+
+class ARMv7DOpcodeVCMP : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0xffbf0e50;
+ static const uint32_t s_pattern = 0xeeb40a40;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCMP, thisObj);
+
+protected:
+ const char* format();
+
+ // FIXME: the register encoding for single precision is not correct.
+
+ unsigned sz() { return (m_opcode >> 8) & 0x1; }
+ unsigned e() { return (m_opcode >> 7) & 0x1; }
+ unsigned zero() { return (m_opcode >> 16) & 0x1; }
+ unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
+ unsigned vd() { return ((m_opcode >> 12) & 0xf) | ((m_opcode >> 18) & 0x10); }
+};
+
class ARMv7DOpcodeVLDRVSTR : public ARMv7D32BitOpcode {
public:
static const uint32_t s_mask = 0xff200a00;
diff --git a/src/3rdparty/masm/disassembler/UDis86Disassembler.cpp b/src/3rdparty/masm/disassembler/UDis86Disassembler.cpp
index 395d43008f..ce901eaeaf 100644
--- a/src/3rdparty/masm/disassembler/UDis86Disassembler.cpp
+++ b/src/3rdparty/masm/disassembler/UDis86Disassembler.cpp
@@ -41,7 +41,7 @@ template <> struct helper<4> {
};
template <> struct helper<8> {
static void hex(char *str, size_t len, uint64_t pc)
- { snprintf(str, len, "0x%lx", pc); }
+ { snprintf(str, len, "0x%llx", static_cast<unsigned long long>(pc)); }
};
inline void print(char *str, size_t len, uint64_t pc)
{ helper<sizeof(void*)>::hex(str, len, pc); }
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index c845f5e23c..3e2a51379c 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -288,7 +288,8 @@
/* Only one of these will be defined. */
#if !defined(WTF_CPU_ARM_TRADITIONAL) && !defined(WTF_CPU_ARM_THUMB2)
# if defined(thumb2) || defined(__thumb2__) \
- || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4)
+ || ((defined(__thumb) || defined(__thumb__)) && WTF_THUMB_ARCH_VERSION == 4) \
+ || (defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2)
# define WTF_CPU_ARM_TRADITIONAL 0
# define WTF_CPU_ARM_THUMB2 1
# elif WTF_ARM_ARCH_AT_LEAST(4)
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 5dc4332d69..1f28d8009e 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -446,7 +446,7 @@ void QQuickFolderListModel::setFolder(const QUrl &folder)
/*!
- \qmlproperty url QQuickFolderListModel::rootFolder
+ \qmlproperty url FolderListModel::rootFolder
When the rootFolder is set, then this folder will
be threated as the root in the file system, so that
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index f1d262a6c3..d0d47aa38c 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -4,7 +4,8 @@ SUBDIRS += \
folderlistmodel \
localstorage \
models \
- settings
+ settings \
+ statemachine
qtHaveModule(quick) {
SUBDIRS += \
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 5fe445758b..659c19917a 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -64,23 +64,23 @@
using namespace QV4;
#define V4THROW_SQL(error, desc) { \
- QV4::Scoped<String> v(scope, ctx->engine->newString(desc)); \
- QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
+ QV4::Scoped<String> v(scope, scope.engine->newString(desc)); \
+ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
ctx->throwError(ex); \
return Encode::undefined(); \
}
#define V4THROW_SQL2(error, desc) { \
- QV4::Scoped<String> v(scope, ctx->engine->newString(desc)); \
- QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
+ QV4::Scoped<String> v(scope, scope.engine->newString(desc)); \
+ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \
args->setReturnValue(ctx->throwError(ex)); \
return; \
}
#define V4THROW_REFERENCE(string) { \
- QV4::Scoped<String> v(scope, ctx->engine->newString(string)); \
+ QV4::Scoped<String> v(scope, scope.engine->newString(string)); \
ctx->throwReferenceError(v); \
return Encode::undefined(); \
}
@@ -101,14 +101,33 @@ V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)
class QQmlSqlDatabaseWrapper : public Object
{
- V4_OBJECT
-
public:
enum Type { Database, Query, Rows };
- QQmlSqlDatabaseWrapper(QV8Engine *e)
- : Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false)
+ struct Data : Object::Data {
+ Data(ExecutionEngine *e)
+ : Object::Data(e)
+ {
+ setVTable(staticVTable());
+ type = Database;
+ }
+
+ Type type;
+ QSqlDatabase database;
+
+ QString version; // type == Database
+
+ bool inTransaction; // type == Query
+ bool readonly; // type == Query
+
+ QSqlQuery sqlQuery; // type == Rows
+ bool forwardOnly; // type == Rows
+ };
+ V4_OBJECT(Object)
+
+ static QQmlSqlDatabaseWrapper *create(QV8Engine *engine)
{
- setVTable(staticVTable());
+ QV4::ExecutionEngine *e = QV8Engine::getV4(engine);
+ return e->memoryManager->alloc<QQmlSqlDatabaseWrapper>(e);
}
~QQmlSqlDatabaseWrapper() {
@@ -118,44 +137,32 @@ public:
static void destroy(Managed *that) {
static_cast<QQmlSqlDatabaseWrapper *>(that)->~QQmlSqlDatabaseWrapper();
}
-
- Type type;
- QSqlDatabase database;
-
- QString version; // type == Database
-
- bool inTransaction; // type == Query
- bool readonly; // type == Query
-
- QSqlQuery sqlQuery; // type == Rows
- bool forwardOnly; // type == Rows
};
-DEFINE_REF(QQmlSqlDatabaseWrapper, Object);
DEFINE_OBJECT_VTABLE(QQmlSqlDatabaseWrapper);
static ReturnedValue qmlsqldatabase_version(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Database)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Database)
V4THROW_REFERENCE("Not a SQLDatabase object");
- return Encode(ctx->engine->newString(r->version));
+ return Encode(scope.engine->newString(r->d()->version));
}
static ReturnedValue qmlsqldatabase_rows_length(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows)
V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- int s = r->sqlQuery.size();
+ int s = r->d()->sqlQuery.size();
if (s < 0) {
// Inefficient
- if (r->sqlQuery.last()) {
- s = r->sqlQuery.at() + 1;
+ if (r->d()->sqlQuery.last()) {
+ s = r->d()->sqlQuery.at() + 1;
} else {
s = 0;
}
@@ -166,22 +173,22 @@ static ReturnedValue qmlsqldatabase_rows_length(CallContext *ctx)
static ReturnedValue qmlsqldatabase_rows_forwardOnly(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows)
V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- return Encode(r->sqlQuery.isForwardOnly());
+ return Encode(r->d()->sqlQuery.isForwardOnly());
}
static ReturnedValue qmlsqldatabase_rows_setForwardOnly(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows)
V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- if (ctx->callData->argc < 1)
+ if (ctx->d()->callData->argc < 1)
return ctx->throwTypeError();
- r->sqlQuery.setForwardOnly(ctx->callData->args[0].toBoolean());
+ r->d()->sqlQuery.setForwardOnly(ctx->d()->callData->args[0].toBoolean());
return Encode::undefined();
}
@@ -207,20 +214,20 @@ static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Eng
return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
}
-static ReturnedValue qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapperRef r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
+static ReturnedValue qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0)
{
Scope scope(v4);
QV8Engine *v8 = v4->v8Engine;
- if (r->sqlQuery.at() == (int)index || r->sqlQuery.seek(index)) {
- QSqlRecord record = r->sqlQuery.record();
+ if (r->d()->sqlQuery.at() == (int)index || r->d()->sqlQuery.seek(index)) {
+ QSqlRecord record = r->d()->sqlQuery.record();
// XXX optimize
Scoped<Object> row(scope, v4->newObject());
for (int ii = 0; ii < record.count(); ++ii) {
QVariant v = record.value(ii);
ScopedString s(scope, v4->newIdentifier(record.fieldName(ii)));
ScopedValue val(scope, v.isNull() ? Encode::null() : v8->fromVariant(v));
- row->put(s, val);
+ row->put(s.getPointer(), val);
}
if (hasProperty)
*hasProperty = true;
@@ -236,7 +243,7 @@ ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(Managed *m, uint index, bool *h
{
QV4::Scope scope(m->engine());
QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, m->as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows)
return Object::getIndexed(m, index, hasProperty);
return qmlsqldatabase_rows_index(r, m->engine(), index, hasProperty);
@@ -245,30 +252,30 @@ ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(Managed *m, uint index, bool *h
static ReturnedValue qmlsqldatabase_rows_item(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Rows)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows)
V4THROW_REFERENCE("Not a SQLDatabase::Rows object");
- return qmlsqldatabase_rows_index(r, ctx->engine, ctx->callData->argc ? ctx->callData->args[0].toUInt32() : 0);
+ return qmlsqldatabase_rows_index(r, scope.engine, ctx->d()->callData->argc ? ctx->d()->callData->args[0].toUInt32() : 0);
}
static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Query)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Query)
V4THROW_REFERENCE("Not a SQLDatabase::Query object");
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (!r->inTransaction)
+ if (!r->d()->inTransaction)
V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()"));
- QSqlDatabase db = r->database;
+ QSqlDatabase db = r->d()->database;
- QString sql = ctx->callData->argc ? ctx->callData->args[0].toQString() : QString();
+ QString sql = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toQString() : QString();
- if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
+ if (r->d()->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction"));
}
@@ -278,8 +285,8 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
ScopedValue result(scope, Primitive::undefinedValue());
if (query.prepare(sql)) {
- if (ctx->callData->argc > 1) {
- ScopedValue values(scope, ctx->callData->args[1]);
+ if (ctx->d()->callData->argc > 1) {
+ ScopedValue values(scope, ctx->d()->callData->args[1]);
if (values->asArrayObject()) {
ScopedArrayObject array(scope, values);
quint32 size = array->getLength();
@@ -308,21 +315,21 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx)
}
}
if (query.exec()) {
- QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine));
+ QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, QQmlSqlDatabaseWrapper::create(engine));
QV4::ScopedObject p(scope, databaseData(engine)->rowsProto.value());
rows->setPrototype(p.getPointer());
- rows->type = QQmlSqlDatabaseWrapper::Rows;
- rows->database = db;
- rows->sqlQuery = query;
+ rows->d()->type = QQmlSqlDatabaseWrapper::Rows;
+ rows->d()->database = db;
+ rows->d()->sqlQuery = query;
- Scoped<Object> resultObject(scope, ctx->engine->newObject());
+ Scoped<Object> resultObject(scope, scope.engine->newObject());
result = resultObject.asReturnedValue();
// XXX optimize
ScopedString s(scope);
ScopedValue v(scope);
- resultObject->put((s = ctx->engine->newIdentifier("rowsAffected")), (v = Primitive::fromInt32(query.numRowsAffected())));
- resultObject->put((s = ctx->engine->newIdentifier("insertId")), (v = engine->toString(query.lastInsertId().toString())));
- resultObject->put((s = ctx->engine->newIdentifier("rows")), rows);
+ resultObject->put((s = scope.engine->newIdentifier("rowsAffected")).getPointer(), (v = Primitive::fromInt32(query.numRowsAffected())));
+ resultObject->put((s = scope.engine->newIdentifier("insertId")).getPointer(), (v = engine->toString(query.lastInsertId().toString())));
+ resultObject->put((s = scope.engine->newIdentifier("rows")).getPointer(), rows);
} else {
err = true;
}
@@ -366,31 +373,31 @@ struct TransactionRollback {
static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
{
- if (ctx->callData->argc < 2)
+ if (ctx->d()->callData->argc < 2)
return Encode::undefined();
Scope scope(ctx);
- Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject);
- if (!r || r->type != QQmlSqlDatabaseWrapper::Database)
+ Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject);
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Database)
V4THROW_REFERENCE("Not a SQLDatabase object");
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- QSqlDatabase db = r->database;
- QString from_version = ctx->callData->args[0].toQString();
- QString to_version = ctx->callData->args[1].toQString();
+ QSqlDatabase db = r->d()->database;
+ QString from_version = ctx->d()->callData->args[0].toQString();
+ QString to_version = ctx->d()->callData->args[1].toQString();
Scoped<FunctionObject> callback(scope, ctx->argument(2));
- if (from_version != r->version)
- V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version));
+ if (from_version != r->d()->version)
+ V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->d()->version));
- Scoped<QQmlSqlDatabaseWrapper> w(scope, new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine));
+ Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(engine));
ScopedObject p(scope, databaseData(engine)->queryProto.value());
w->setPrototype(p.getPointer());
- w->type = QQmlSqlDatabaseWrapper::Query;
- w->database = db;
- w->version = r->version;
+ w->d()->type = QQmlSqlDatabaseWrapper::Query;
+ w->d()->database = db;
+ w->d()->version = r->d()->version;
bool ok = true;
if (!!callback) {
@@ -401,7 +408,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
callData->thisObject = engine->global();
callData->args[0] = w;
- TransactionRollback rollbackOnException(&db, &w->inTransaction);
+ TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
callback->call(callData);
rollbackOnException.clear();
if (!db.commit()) {
@@ -413,7 +420,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
}
if (ok) {
- w->version = to_version;
+ w->d()->version = to_version;
#ifndef QT_NO_SETTINGS
QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
ini.setValue(QLatin1String("Version"), to_version);
@@ -426,32 +433,32 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx)
static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool readOnly)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
- if (!r || r->type != QQmlSqlDatabaseWrapper::Database)
+ QV4::Scoped<QQmlSqlDatabaseWrapper> r(scope, ctx->d()->callData->thisObject.as<QQmlSqlDatabaseWrapper>());
+ if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Database)
V4THROW_REFERENCE("Not a SQLDatabase object");
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- FunctionObject *callback = ctx->callData->argc ? ctx->callData->args[0].asFunctionObject() : 0;
+ FunctionObject *callback = ctx->d()->callData->argc ? ctx->d()->callData->args[0].asFunctionObject() : 0;
if (!callback)
V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback"));
- QSqlDatabase db = r->database;
+ QSqlDatabase db = r->d()->database;
- Scoped<QQmlSqlDatabaseWrapper> w(scope, new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine));
+ Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(engine));
QV4::ScopedObject p(scope, databaseData(engine)->queryProto.value());
w->setPrototype(p.getPointer());
- w->type = QQmlSqlDatabaseWrapper::Query;
- w->database = db;
- w->version = r->version;
- w->readonly = readOnly;
+ w->d()->type = QQmlSqlDatabaseWrapper::Query;
+ w->d()->database = db;
+ w->d()->version = r->d()->version;
+ w->d()->readonly = readOnly;
db.transaction();
if (callback) {
ScopedCallData callData(scope, 1);
callData->thisObject = engine->global();
callData->args[0] = w;
- TransactionRollback rollbackOnException(&db, &w->inTransaction);
+ TransactionRollback rollbackOnException(&db, &w->d()->inTransaction);
callback->call(callData);
rollbackOnException.clear();
@@ -716,11 +723,11 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
database.open();
}
- QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine));
+ QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, QQmlSqlDatabaseWrapper::create(engine));
QV4::ScopedObject p(scope, databaseData(engine)->databaseProto.value());
db->setPrototype(p.getPointer());
- db->database = database;
- db->version = version;
+ db->d()->database = database;
+ db->d()->version = version;
if (created && dbcreationCallback) {
Scope scope(ctx);
diff --git a/src/imports/statemachine/childrenprivate.h b/src/imports/statemachine/childrenprivate.h
new file mode 100644
index 0000000000..7e7b7f37ef
--- /dev/null
+++ b/src/imports/statemachine/childrenprivate.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCHILDRENPRIVATE_H
+#define QQMLCHILDRENPRIVATE_H
+
+#include <QAbstractState>
+#include <QAbstractTransition>
+#include <QStateMachine>
+#include <QQmlInfo>
+#include <QQmlListProperty>
+
+template <class T>
+class ChildrenPrivate
+{
+public:
+ ChildrenPrivate()
+ {}
+
+ static void append(QQmlListProperty<QObject> *prop, QObject *item)
+ {
+ QAbstractState *state = qobject_cast<QAbstractState*>(item);
+ if (state) {
+ if (qobject_cast<QStateMachine*>(item))
+ qmlInfo(static_cast<T *>(prop->object)) << "StateMachines should not be nested.";
+
+ item->setParent(prop->object);
+ } else {
+ QAbstractTransition *trans = qobject_cast<QAbstractTransition*>(item);
+ if (trans)
+ static_cast<T *>(prop->object)->addTransition(trans);
+ }
+ static_cast<ChildrenPrivate<T>*>(prop->data)->children.append(item);
+ emit static_cast<T *>(prop->object)->childrenChanged();
+ }
+
+ static void appendNoTransition(QQmlListProperty<QObject> *prop, QObject *item)
+ {
+ QAbstractState *state = qobject_cast<QAbstractState*>(item);
+ if (state) {
+ if (qobject_cast<QStateMachine*>(item))
+ qmlInfo(static_cast<T *>(prop->object)) << "StateMachines should not be nested.";
+
+ item->setParent(prop->object);
+ }
+ static_cast<ChildrenPrivate<T>*>(prop->data)->children.append(item);
+ emit static_cast<T *>(prop->object)->childrenChanged();
+ }
+
+ static int count(QQmlListProperty<QObject> *prop)
+ {
+ return static_cast<ChildrenPrivate<T>*>(prop->data)->children.count();
+ }
+
+ static QObject *at(QQmlListProperty<QObject> *prop, int index)
+ {
+ return static_cast<ChildrenPrivate<T>*>(prop->data)->children.at(index);
+ }
+
+ static void clear(QQmlListProperty<QObject> *prop)
+ {
+ static_cast<ChildrenPrivate<T>*>(prop->data)->children.clear();
+ emit static_cast<T *>(prop->object)->childrenChanged();
+ }
+
+private:
+ QList<QObject *> children;
+};
+
+#endif
diff --git a/src/imports/statemachine/finalstate.cpp b/src/imports/statemachine/finalstate.cpp
new file mode 100644
index 0000000000..1852a533c6
--- /dev/null
+++ b/src/imports/statemachine/finalstate.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "finalstate.h"
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+FinalState::FinalState(QState *parent)
+ : QFinalState(parent)
+{
+}
+
+QQmlListProperty<QObject> FinalState::children()
+{
+ return QQmlListProperty<QObject>(this, &m_children, m_children.appendNoTransition, m_children.count, m_children.at, m_children.clear);
+}
+
+/*!
+ \qmltype FinalState
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QAbstractState
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief Provides a final state.
+
+
+ A final state is used to communicate that (part of) a StateMachine has
+ finished its work. When a final top-level state is entered, the state
+ machine's \l{StateBase::finished}{finished}() signal is emitted. In
+ general, when a final substate (a child of a State) is entered, the parent
+ state's \l{StateBase::finished}{finished}() signal is emitted. FinalState
+ is part of \l{The Declarative State Machine Framework}.
+
+ To use a final state, you create a FinalState object and add a transition
+ to it from another state.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/finalstate.qml document
+
+ \clearfloat
+
+ \sa StateMachine, StateBase
+*/
diff --git a/src/imports/statemachine/finalstate.h b/src/imports/statemachine/finalstate.h
new file mode 100644
index 0000000000..6086b1b8a2
--- /dev/null
+++ b/src/imports/statemachine/finalstate.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLFINALSTATE_H
+#define QQMLFINALSTATE_H
+
+#include "childrenprivate.h"
+#include "statemachine.h"
+
+#include <QtCore/QFinalState>
+#include <QtQml/QQmlListProperty>
+
+
+QT_BEGIN_NAMESPACE
+
+class FinalState : public QFinalState
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged)
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ explicit FinalState(QState *parent = 0);
+
+ QQmlListProperty<QObject> children();
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ ChildrenPrivate<FinalState> m_children;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp
new file mode 100644
index 0000000000..2a266f9dfb
--- /dev/null
+++ b/src/imports/statemachine/plugin.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "finalstate.h"
+#include "signaltransition.h"
+#include "statebase.h"
+#include "statemachine.h"
+#include "timeouttransition.h"
+
+#include <QHistoryState>
+#include <QQmlExtensionPlugin>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QtQmlStateMachinePlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.org.Qt.QtQml.StateMachine/1.0")
+
+public:
+ void registerTypes(const char *uri)
+ {
+ qmlRegisterType<StateBase>(uri, 1, 0, "StateBase");
+ qmlRegisterType<StateMachine>(uri, 1, 0, "StateMachine");
+ qmlRegisterType<QHistoryState>(uri, 1, 0, "HistoryState");
+ qmlRegisterType<FinalState>(uri, 1, 0, "FinalState");
+ qmlRegisterUncreatableType<QState>(uri, 1, 0, "QState", "Don't use this, use StateBase instead");
+ qmlRegisterUncreatableType<QAbstractState>(uri, 1, 0, "QAbstractState", "Don't use this, use StateBase instead");
+ qmlRegisterUncreatableType<QSignalTransition>(uri, 1, 0, "QSignalTransition", "Don't use this, use SignalTransition instead");
+ qmlRegisterType<SignalTransition>(uri, 1, 0, "SignalTransition");
+ qmlRegisterType<TimeoutTransition>(uri, 1, 0, "TimeoutTransition");
+ qmlProtectModule(uri, 1);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/statemachine/plugins.qmltypes b/src/imports/statemachine/plugins.qmltypes
new file mode 100644
index 0000000000..a53d68f8e8
--- /dev/null
+++ b/src/imports/statemachine/plugins.qmltypes
@@ -0,0 +1,163 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQml.StateMachine 1.0'
+
+Module {
+ Component {
+ name: "FinalState"
+ defaultProperty: "children"
+ prototype: "QFinalState"
+ exports: ["QtQml.StateMachine/FinalState 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
+ }
+ Component {
+ name: "QAbstractState"
+ prototype: "QObject"
+ exports: ["QtQml.StateMachine/QAbstractState 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "active"; type: "bool"; isReadonly: true }
+ Signal { name: "entered" }
+ Signal { name: "exited" }
+ Signal {
+ name: "activeChanged"
+ Parameter { name: "active"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QAbstractTransition"
+ prototype: "QObject"
+ Property { name: "sourceState"; type: "QState"; isReadonly: true; isPointer: true }
+ Property { name: "targetState"; type: "QAbstractState"; isPointer: true }
+ Property { name: "targetStates"; type: "QList<QAbstractState*>" }
+ Signal { name: "triggered" }
+ }
+ Component { name: "QFinalState"; prototype: "QAbstractState" }
+ Component {
+ name: "QHistoryState"
+ prototype: "QAbstractState"
+ exports: ["QtQml.StateMachine/HistoryState 1.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "HistoryType"
+ values: {
+ "ShallowHistory": 0,
+ "DeepHistory": 1
+ }
+ }
+ Property { name: "defaultState"; type: "QAbstractState"; isPointer: true }
+ Property { name: "historyType"; type: "HistoryType" }
+ }
+ Component {
+ name: "QSignalTransition"
+ prototype: "QAbstractTransition"
+ exports: ["QtQml.StateMachine/QSignalTransition 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "senderObject"; type: "QObject"; isPointer: true }
+ Property { name: "signal"; type: "QByteArray" }
+ }
+ Component {
+ name: "QState"
+ prototype: "QAbstractState"
+ exports: ["QtQml.StateMachine/QState 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "ChildMode"
+ values: {
+ "ExclusiveStates": 0,
+ "ParallelStates": 1
+ }
+ }
+ Enum {
+ name: "RestorePolicy"
+ values: {
+ "DontRestoreProperties": 0,
+ "RestoreProperties": 1
+ }
+ }
+ Property { name: "initialState"; type: "QAbstractState"; isPointer: true }
+ Property { name: "errorState"; type: "QAbstractState"; isPointer: true }
+ Property { name: "childMode"; type: "ChildMode" }
+ Signal { name: "finished" }
+ Signal { name: "propertiesAssigned" }
+ }
+ Component {
+ name: "QStateMachine"
+ prototype: "QState"
+ Property { name: "errorString"; type: "string"; isReadonly: true }
+ Property { name: "globalRestorePolicy"; type: "QState::RestorePolicy" }
+ Property { name: "running"; type: "bool" }
+ Property { name: "animated"; type: "bool" }
+ Signal { name: "started" }
+ Signal { name: "stopped" }
+ Signal {
+ name: "runningChanged"
+ Parameter { name: "running"; type: "bool" }
+ }
+ Method { name: "start" }
+ Method { name: "stop" }
+ Method {
+ name: "setRunning"
+ Parameter { name: "running"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QTimer"
+ prototype: "QObject"
+ Property { name: "singleShot"; type: "bool" }
+ Property { name: "interval"; type: "int" }
+ Property { name: "remainingTime"; type: "int"; isReadonly: true }
+ Property { name: "timerType"; type: "Qt::TimerType" }
+ Property { name: "active"; type: "bool"; isReadonly: true }
+ Signal { name: "timeout" }
+ Method {
+ name: "start"
+ Parameter { name: "msec"; type: "int" }
+ }
+ Method { name: "start" }
+ Method { name: "stop" }
+ }
+ Component {
+ name: "SignalTransition"
+ prototype: "QSignalTransition"
+ exports: ["QtQml.StateMachine/SignalTransition 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "signal"; type: "QJSValue" }
+ Property { name: "guard"; type: "bool" }
+ Signal { name: "invokeYourself" }
+ Signal { name: "qmlSignalChanged" }
+ Method { name: "invoke" }
+ }
+ Component {
+ name: "StateBase"
+ defaultProperty: "children"
+ prototype: "QState"
+ exports: ["QtQml.StateMachine/StateBase 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
+ }
+ Component {
+ name: "StateMachine"
+ defaultProperty: "children"
+ prototype: "QStateMachine"
+ exports: ["QtQml.StateMachine/StateMachine 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "running"; type: "bool" }
+ Signal { name: "qmlRunningChanged" }
+ }
+ Component {
+ name: "TimeoutTransition"
+ prototype: "QSignalTransition"
+ exports: ["QtQml.StateMachine/TimeoutTransition 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "timeout"; type: "int" }
+ }
+}
diff --git a/src/imports/statemachine/qmldir b/src/imports/statemachine/qmldir
new file mode 100644
index 0000000000..8bc3831208
--- /dev/null
+++ b/src/imports/statemachine/qmldir
@@ -0,0 +1,4 @@
+module QtQml.StateMachine
+plugin qtqmlstatemachine
+classname QtQmlStateMachinePlugin
+typeinfo plugins.qmltypes
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
new file mode 100644
index 0000000000..c3dc183472
--- /dev/null
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "signaltransition.h"
+
+#include <QStateMachine>
+#include <QMetaProperty>
+#include <QQmlInfo>
+#include <QQmlEngine>
+#include <QQmlContext>
+
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qv4scopedvalue_p.h>
+
+SignalTransition::SignalTransition(QState *parent)
+ : QSignalTransition(this, SIGNAL(invokeYourself()), parent)
+ , m_guard(true)
+{
+ connect(this, SIGNAL(signalChanged()), SIGNAL(qmlSignalChanged()));
+}
+
+bool SignalTransition::eventTest(QEvent *event)
+{
+ Q_ASSERT(event);
+ if (!QSignalTransition::eventTest(event))
+ return false;
+
+ return m_guard;
+}
+
+const QJSValue& SignalTransition::signal()
+{
+ return m_signal;
+}
+
+void SignalTransition::setSignal(const QJSValue &signal)
+{
+ if (m_signal.strictlyEquals(signal))
+ return;
+
+ m_signal = signal;
+
+ QV4::ExecutionEngine *jsEngine = QV8Engine::getV4(QQmlEngine::contextForObject(this)->engine());
+ QV4::Scope scope(jsEngine);
+
+ QV4::Scoped<QV4::FunctionObject> function(scope, QJSValuePrivate::get(m_signal)->getValue(jsEngine));
+ Q_ASSERT(function);
+
+ QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, function->as<QV4::QObjectMethod>());
+ Q_ASSERT(qobjectSignal);
+
+ QObject *sender = qobjectSignal->object();
+ Q_ASSERT(sender);
+ QMetaMethod metaMethod = sender->metaObject()->method(qobjectSignal->methodIndex());
+
+ QSignalTransition::setSenderObject(sender);
+ QSignalTransition::setSignal(metaMethod.methodSignature());
+}
+
+bool SignalTransition::guard() const
+{
+ return m_guard;
+}
+
+void SignalTransition::setGuard(bool guard)
+{
+ if (guard != m_guard) {
+ m_guard = guard;
+ emit guardChanged();
+ }
+}
+
+void SignalTransition::invoke()
+{
+ emit invokeYourself();
+}
+
+/*!
+ \qmltype QAbstractTransition
+ \inqmlmodule QtStateMachine 1.0
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The QAbstractTransition type is the base type of transitions between QAbstractState objects.
+
+ The QAbstractTransition type is the abstract base type of transitions
+ between states (QAbstractState objects) of a StateMachine.
+ QAbstractTransition is part of \l{The Declarative State Machine Framework}.
+
+ The sourceState() property has the source of the transition. The
+ targetState and targetStates properties return the target(s) of the
+ transition.
+
+ The triggered() signal is emitted when the transition has been triggered.
+
+ Do not use QAbstractTransition directly; use SignalTransition or
+ TimeoutTransition instead.
+
+ \sa SignalTransition, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty bool QAbstractTransition::sourceState
+ \readonly sourceState
+
+ \brief The source state (parent) of this transition.
+*/
+
+/*!
+ \qmlproperty QAbstractState QAbstractTransition::targetState
+
+ \brief The target state of this transition.
+
+ If a transition has no target state, the transition may still be
+ triggered, but this will not cause the state machine's configuration to
+ change (i.e. the current state will not be exited and re-entered).
+*/
+
+/*!
+ \qmlproperty list<QAbstractState> QAbstractTransition::targetStates
+
+ \brief The target states of this transition.
+
+ If multiple states are specified, they all must be descendants of the
+ same parallel group state.
+*/
+
+/*!
+ \qmlsignal QAbstractTransition::triggered()
+
+ This signal is emitted when the transition has been triggered.
+
+ The corresponding handler is \c onTriggered.
+*/
+
+/*!
+ \qmltype QSignalTransition
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QAbstractTransition
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The QSignalTransition type provides a transition based on a Qt signal.
+
+ Do not use QSignalTransition directly; use SignalTransition or
+ TimeoutTransition instead.
+
+ \sa SignalTransition, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty string QSignalTransition::signal
+
+ \brief The signal which is associated with this signal transition.
+*/
+
+/*!
+ \qmlproperty QObject QSignalTransition::senderObject
+
+ \brief The sender object which is associated with this signal transition.
+*/
+
+
+/*!
+ \qmltype SignalTransition
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QSignalTransition
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The SignalTransition type provides a transition based on a Qt signal.
+
+ SignalTransition is part of \l{The Declarative State Machine Framework}.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/signaltransition.qml document
+
+ \clearfloat
+
+ \sa StateMachine, FinalState, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty signal SignalTransition::signal
+
+ \brief The signal which is associated with this signal transition.
+
+ \snippet qml/statemachine/signaltransitionsignal.qml document
+*/
+
+/*!
+ \qmlproperty bool SignalTransition::guard
+
+ Guard conditions affect the behavior of a state machine by enabling
+ transitions only when they evaluate to true and disabling them when
+ they evaluate to false.
+*/
diff --git a/src/imports/statemachine/signaltransition.h b/src/imports/statemachine/signaltransition.h
new file mode 100644
index 0000000000..614a6064a5
--- /dev/null
+++ b/src/imports/statemachine/signaltransition.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIGNALTRANSITION_H
+#define SIGNALTRANSITION_H
+
+#include <QtCore/QSignalTransition>
+#include <QtCore/QVariant>
+#include <QtQml/QJSValue>
+
+QT_BEGIN_NAMESPACE
+
+class SignalTransition : public QSignalTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QJSValue signal READ signal WRITE setSignal NOTIFY qmlSignalChanged)
+ Q_PROPERTY(bool guard READ guard WRITE setGuard NOTIFY guardChanged)
+
+public:
+ explicit SignalTransition(QState *parent = Q_NULLPTR);
+
+ bool guard() const;
+ void setGuard(bool guard);
+
+ bool eventTest(QEvent *event);
+
+ const QJSValue &signal();
+ void setSignal(const QJSValue &signal);
+
+ Q_INVOKABLE void invoke();
+
+Q_SIGNALS:
+ void guardChanged();
+ void invokeYourself();
+ /*!
+ * \internal
+ */
+ void qmlSignalChanged();
+
+private:
+ QByteArray m_data;
+ QJSValue m_signal;
+ bool m_guard;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/statemachine/statebase.cpp b/src/imports/statemachine/statebase.cpp
new file mode 100644
index 0000000000..fa475df604
--- /dev/null
+++ b/src/imports/statemachine/statebase.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "statebase.h"
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+StateBase::StateBase(QState *parent)
+ : QState(parent)
+{
+}
+
+void StateBase::componentComplete()
+{
+ if (this->machine() == NULL) {
+ static bool once = false;
+ if (!once) {
+ once = true;
+ qmlInfo(this) << "No top level StateMachine found. Nothing will run without a StateMachine.";
+ }
+ }
+}
+
+QQmlListProperty<QObject> StateBase::children()
+{
+ return QQmlListProperty<QObject>(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear);
+}
+
+/*!
+ \qmltype QAbstractState
+ \inqmlmodule QtStateMachine 1.0
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The QAbstractState type is the base type of States of a StateMachine.
+
+ Do not use QAbstractState directly; use StateBase, FinalState or
+ StateMachine instead.
+
+ \sa StateMachine, StateBase
+*/
+
+/*!
+ \qmlproperty bool QAbstractState::active
+ \readonly active
+
+ The active property of this state. A state is active between
+ entered() and exited() signals. This property is readonly.
+
+ \sa entered, exited
+*/
+
+/*!
+ \qmlsignal QAbstractState::entered()
+
+ This signal is emitted when the State becomes active.
+
+ The corresponding handler is \c onEntered.
+
+ \sa active, exited
+*/
+
+/*!
+ \qmlsignal QAbstractState::exited()
+
+ This signal is emitted when the State becomes inactive.
+
+ The corresponding handler is \c onExited.
+
+ \sa active, entered
+*/
+
+/*!
+ \qmltype StateBase
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QAbstractState
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief Provides a general-purpose state for StateMachine.
+
+
+ StateBase objects can have child states as well as transitions to other
+ states. StateBase is part of \l{The Declarative State Machine Framework}.
+
+ \section1 States with Child States
+
+ The childMode property determines how child states are treated. For
+ non-parallel state groups, the initialState property must be used to
+ set the initial state. The child states are mutually exclusive states,
+ and the state machine needs to know which child state to enter when the
+ parent state is the target of a transition.
+
+ The state emits the StateBase::finished() signal when a final child state
+ (FinalState) is entered.
+
+ The errorState sets the state's error state. The error state is the state
+ that the state machine will transition to if an error is detected when
+ attempting to enter the state (e.g. because no initial state has been set).
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/basicstate.qml document
+
+ \clearfloat
+
+ \sa StateMachine, FinalState
+*/
+
+/*!
+ \qmlproperty enumeration StateBase::childMode
+
+ \brief The child mode of this state
+
+ The default value of this property is QState.ExclusiveStates.
+
+ This enum specifies how a state's child states are treated:
+ \list
+ \li QState.ExclusiveStates The child states are mutually exclusive and an initial state must be set by setting initialState property.
+ \li QState.ParallelStates The child states are parallel. When the parent state is entered, all its child states are entered in parallel.
+ \endlist
+*/
+
+/*!
+ \qmlproperty QAbstractState StateBase::errorState
+
+ \brief The error state of this state.
+*/
+
+/*!
+ \qmlproperty QAbstractState StateBase::initialState
+
+ \brief The initial state of this state (one of its child states).
+*/
+
+/*!
+ \qmlsignal StateBase::finished()
+
+ This signal is emitted when a final child state of this state is entered.
+
+ The corresponding handler is \c onFinished.
+
+ \sa QAbstractState::active, QAbstractState::entered, QAbstractState::exited
+*/
+
+/*!
+ \qmltype HistoryState
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QAbstractState
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The HistoryState type provides a means of returning to a previously active substate.
+
+ A history state is a pseudo-state that represents the child state that the
+ parent state was in the last time the parent state was exited. A transition
+ with a history state as its target is in fact a transition to one of the
+ other child states of the parent state.
+ HistoryState is part of \l{The Declarative State Machine Framework}.
+
+ Use the defaultState property to set the state that should be entered
+ if the parent state has never been entered.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/historystate.qml document
+
+ \clearfloat
+
+ By default, a history state is shallow, meaning that it will not remember
+ nested states. This can be configured through the historyType property.
+
+ \sa StateMachine, StateBase
+*/
+
+/*!
+ \qmlproperty QAbstractState HistoryState::defaultState
+
+ \brief The default state of this history state.
+
+ The default state indicates the state to transition to if the parent
+ state has never been entered before.
+*/
+
+/*!
+ \qmlproperty enumeration HistoryState::historyType
+
+ \brief The type of history that this history state records.
+
+ The default value of this property is QHistoryState.ShallowHistory.
+
+ This enum specifies the type of history that a QHistoryState records.
+ \list
+ \li QHistoryState.ShallowHistory Only the immediate child states of the
+ parent state are recorded. In this case, a transition with the history
+ state as its target will end up in the immediate child state that the
+ parent was in the last time it was exited. This is the default.
+ \li QHistoryState.DeepHistory Nested states are recorded. In this case
+ a transition with the history state as its target will end up in the
+ most deeply nested descendant state the parent was in the last time
+ it was exited.
+ \endlist
+*/
+
diff --git a/src/imports/statemachine/statebase.h b/src/imports/statemachine/statebase.h
new file mode 100644
index 0000000000..e3084238ef
--- /dev/null
+++ b/src/imports/statemachine/statebase.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef STATE_H
+#define STATE_H
+
+#include "childrenprivate.h"
+
+#include <QtCore/QState>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+class StateBase : public QState, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged)
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ explicit StateBase(QState *parent = 0);
+
+ void classBegin() {}
+ void componentComplete();
+
+ QQmlListProperty<QObject> children();
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ ChildrenPrivate<StateBase> m_children;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/statemachine/statemachine.cpp b/src/imports/statemachine/statemachine.cpp
new file mode 100644
index 0000000000..31d98b7094
--- /dev/null
+++ b/src/imports/statemachine/statemachine.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "statemachine.h"
+
+#include <QAbstractTransition>
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+#include <private/qqmlopenmetaobject_p.h>
+#include <private/qqmlengine_p.h>
+
+StateMachine::StateMachine(QObject *parent)
+ : QStateMachine(parent), m_completed(false), m_running(false)
+{
+ connect(this, SIGNAL(runningChanged(bool)), SIGNAL(qmlRunningChanged()));
+}
+
+bool StateMachine::isRunning() const
+{
+ return QStateMachine::isRunning();
+}
+
+void StateMachine::setRunning(bool running)
+{
+ if (m_completed)
+ QStateMachine::setRunning(running);
+ else
+ m_running = running;
+}
+
+void StateMachine::componentComplete()
+{
+ if (QStateMachine::initialState() == NULL && childMode() == QState::ExclusiveStates)
+ qmlInfo(this) << "No initial state set for StateMachine";
+
+ // Everything is proper setup, now start the state-machine if we got
+ // asked to do so.
+ m_completed = true;
+ if (m_running)
+ setRunning(true);
+}
+
+QQmlListProperty<QObject> StateMachine::children()
+{
+ return QQmlListProperty<QObject>(this, &m_children, m_children.append, m_children.count, m_children.at, m_children.clear);
+}
+
+/*!
+ \qmltype StateMachine
+ \inqmlmodule QtStateMachine 1.0
+ \inherits StateBase
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief Provides a hierarchical finite state machine.
+
+ StateMachine is based on the concepts and notation of
+ \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}{Statecharts}.
+ StateMachine is part of \l{The Declarative State Machine Framework}.
+
+ A state machine manages a set of states and transitions between those
+ states; these states and transitions define a state graph. Once a state
+ graph has been built, the state machine can execute it. StateMachine's
+ execution algorithm is based on the \l{http://www.w3.org/TR/scxml/}{State Chart XML (SCXML)}
+ algorithm. The framework's \l{The Declarative State Machine Framework}{overview}
+ gives several state graphs and the code to build them.
+
+ Before the machine can be started, the \l{StateBase::initialState}{initialState}
+ must be set. The initial state is the state that the
+ machine enters when started. You can then set running property to true
+ or start() the state machine. The started signal is emitted when the
+ initial state is entered.
+
+ The state machine processes events and takes transitions until a
+ top-level final state is entered; the state machine then emits the
+ finished() signal. You can also stop() the state machine
+ explicitly (you can also set running property to false).
+ The stopped signal is emitted in this case.
+
+ \section1 Example Usage
+ The following snippet shows a state machine that will finish when a button
+ is clicked:
+
+ \snippet qml/statemachine/simplestatemachine.qml document
+
+ If an error is encountered, the machine will look for an
+ \l{StateBase::errorState}{errorState}, and if one is available, it will
+ enter this state. After the error state is entered, the type of the error
+ can be retrieved with error(). The execution of the state graph will not
+ stop when the error state is entered. If no error state applies to the
+ erroneous state, the machine will stop executing and an error message will
+ be printed to the console.
+
+ \clearfloat
+
+ \sa QAbstractState, StateBase, SignalTransition, TimeoutTransition, HistoryState {The Declarative State Machine Framework}
+*/
+
+/*!
+ \qmlproperty enumeration StateMachine::globalRestorePolicy
+
+ \brief The restore policy for states of this state machine.
+
+ The default value of this property is QState.DontRestoreProperties.
+
+ This enum specifies the restore policy type. The restore policy
+ takes effect when the machine enters a state which sets one or more
+ properties. If the restore policy is set to QState.RestoreProperties,
+ the state machine will save the original value of the property before the
+ new value is set.
+
+ Later, when the machine either enters a state which does not set a
+ value for the given property, the property will automatically be restored
+ to its initial value.
+
+ Only one initial value will be saved for any given property. If a value
+ for a property has already been saved by the state machine, it will not be
+ overwritten until the property has been successfully restored.
+
+ \list
+ \li QState.DontRestoreProperties The state machine should not save the initial values of properties and restore them later.
+ \li QState.RestoreProperties The state machine should save the initial values of properties and restore them later.
+ \endlist
+*/
+
+/*!
+ \qmlproperty bool StateMachine::running
+
+ \brief The running state of this state machine.
+ \sa start(), stop()
+*/
+
+/*!
+ \qmlproperty string StateMachine::errorString
+ \readonly errorString
+
+ \brief The error string of this state machine.
+*/
+
+
+/*!
+ \qmlmethod StateMachine::start()
+
+ Starts this state machine. The machine will reset its configuration and
+ transition to the initial state. When a final top-level state (FinalState)
+ is entered, the machine will emit the finished() signal.
+
+ \note A state machine will not run without a running event loop, such as
+ the main application event loop started with QCoreApplication::exec() or
+ QApplication::exec().
+
+ \sa started, StateBase::finished, stop(), StateBase::initialState, running
+*/
+
+/*!
+ \qmlsignal StateMachine::started()
+
+ This signal is emitted when the state machine has entered its initial state
+ (StateBase::initialState).
+
+ The corresponding handler is \c onStarted.
+
+ \sa running, start(), StateBase::finished
+*/
+
+/*!
+ \qmlmethod StateMachine::stop()
+
+ Stops this state machine. The state machine will stop processing events
+ and then emit the stopped signal.
+
+ \sa stopped, start(), running
+*/
+
+/*!
+ \qmlsignal StateMachine::stopped()
+
+ This signal is emitted when the state machine has stopped.
+
+ The corresponding handler is \c onStopped.
+
+ \sa running, stop(), StateBase::finished
+*/
diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h
new file mode 100644
index 0000000000..5bce986230
--- /dev/null
+++ b/src/imports/statemachine/statemachine.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef STATEMACHINE_H
+#define STATEMACHINE_H
+
+#include "childrenprivate.h"
+
+#include <QtCore/QStateMachine>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlOpenMetaObject;
+
+class StateMachine : public QStateMachine, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged)
+
+ // Override to delay execution after componentComplete()
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY qmlRunningChanged)
+
+ Q_CLASSINFO("DefaultProperty", "children")
+
+public:
+ explicit StateMachine(QObject *parent = 0);
+
+ void classBegin() {}
+ void componentComplete();
+ QQmlListProperty<QObject> children();
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+Q_SIGNALS:
+ void childrenChanged();
+ /*!
+ * \internal
+ */
+ void qmlRunningChanged();
+
+private:
+ ChildrenPrivate<StateMachine> m_children;
+ bool m_completed;
+ bool m_running;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/statemachine/statemachine.pro b/src/imports/statemachine/statemachine.pro
new file mode 100644
index 0000000000..4cc7089a32
--- /dev/null
+++ b/src/imports/statemachine/statemachine.pro
@@ -0,0 +1,24 @@
+CXX_MODULE = qml
+TARGET = qtqmlstatemachine
+TARGETPATH = QtQml/StateMachine
+IMPORT_VERSION = 1.0
+
+QT = core-private qml-private
+
+SOURCES = \
+ $$PWD/finalstate.cpp \
+ $$PWD/signaltransition.cpp \
+ $$PWD/statebase.cpp \
+ $$PWD/statemachine.cpp \
+ $$PWD/timeouttransition.cpp \
+ $$PWD/plugin.cpp
+
+HEADERS = \
+ $$PWD/childrenprivate.h \
+ $$PWD/finalstate.h \
+ $$PWD/signaltransition.h \
+ $$PWD/statebase.h \
+ $$PWD/statemachine.h \
+ $$PWD/timeouttransition.h
+
+load(qml_plugin)
diff --git a/src/imports/statemachine/timeouttransition.cpp b/src/imports/statemachine/timeouttransition.cpp
new file mode 100644
index 0000000000..eb946e38ad
--- /dev/null
+++ b/src/imports/statemachine/timeouttransition.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "timeouttransition.h"
+
+#include <QQmlInfo>
+#include <QTimer>
+#include <QState>
+
+TimeoutTransition::TimeoutTransition(QState* parent)
+ : QSignalTransition((m_timer = new QTimer), SIGNAL(timeout()), parent)
+{
+ m_timer->setSingleShot(true);
+ m_timer->setInterval(1000);
+}
+
+TimeoutTransition::~TimeoutTransition()
+{
+ delete m_timer;
+}
+
+int TimeoutTransition::timeout() const
+{
+ return m_timer->interval();
+}
+
+void TimeoutTransition::setTimeout(int timeout)
+{
+ if (timeout != m_timer->interval()) {
+ m_timer->setInterval(timeout);
+ emit timeoutChanged();
+ }
+}
+
+void TimeoutTransition::componentComplete()
+{
+ QState *state = qobject_cast<QState*>(parent());
+ if (!state) {
+ qmlInfo(this) << "Parent needs to be a State";
+ return;
+ }
+
+ connect(state, SIGNAL(entered()), m_timer, SLOT(start()));
+ connect(state, SIGNAL(exited()), m_timer, SLOT(stop()));
+ if (state->active())
+ m_timer->start();
+}
+
+/*!
+ \qmltype TimeoutTransition
+ \inqmlmodule QtStateMachine 1.0
+ \inherits QSignalTransition
+ \ingroup qmlstatemachine
+ \since 5.4
+
+ \brief The TimeoutTransition type provides a transition based on a timer.
+
+ \l{Timer} type can be combined with SignalTransition to enact more complex
+ timeout based transitions.
+
+ TimeoutTransition is part of \l{The Declarative State Machine Framework}.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/timeouttransition.qml document
+
+ \clearfloat
+
+ \sa StateMachine, SignalTransition, FinalState, HistoryState
+*/
+
+/*!
+ \qmlproperty int TimeoutTransition::timeout
+
+ \brief The timeout interval in milliseconds.
+*/
diff --git a/src/imports/statemachine/timeouttransition.h b/src/imports/statemachine/timeouttransition.h
new file mode 100644
index 0000000000..9b166f8886
--- /dev/null
+++ b/src/imports/statemachine/timeouttransition.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TIMEOUTTRANSITION_H
+#define TIMEOUTTRANSITION_H
+
+#include <QtCore/QSignalTransition>
+#include <QtQml/QQmlParserStatus>
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+
+class TimeoutTransition : public QSignalTransition, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged)
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ TimeoutTransition(QState *parent = Q_NULLPTR);
+ ~TimeoutTransition();
+
+ int timeout() const;
+ void setTimeout(int timeout);
+
+ void classBegin() {}
+ void componentComplete();
+
+Q_SIGNALS:
+ void timeoutChanged();
+
+private:
+ QTimer *m_timer;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 37addd1d7d..f946a4eef3 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -638,6 +638,21 @@ Item {
}
/*!
+ \since 5.4
+ \qmlmethod QtObject TestCase::findChild(parent, objectName)
+
+ Returns the first child of \a parent with \a objectName,
+ or \c null if no such item exists. Children are searched recursively.
+
+ \code
+ compare(findChild(item, "childObject"), expectedChildObject);
+ \endcode
+ */
+ function findChild(parent, objectName) {
+ return qtest_results.findChild(parent, objectName);
+ }
+
+ /*!
\qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000, message = "")
Fails the current test case if the specified \a property on \a obj
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index d5be42c06d..5cc97f0909 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -934,7 +934,7 @@ QQmlV4Handle QQuickXmlListModel::get(int index) const
for (int ii = 0; ii < d->roleObjects.count(); ++ii) {
name = v4engine->newIdentifier(d->roleObjects[ii]->name());
value = v8engine->fromVariant(d->data.value(ii).value(index));
- o->insertMember(name, value);
+ o->insertMember(name.getPointer(), value);
}
return QQmlV4Handle(o);
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index 5efa7b4cca..fdfefb83f5 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -1416,7 +1416,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
g->setDrawingMode(GL_POINTS);
if (m_debugMode){
GLfloat pointSizeRange[2];
- glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
+ QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
}
}else
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index 1d7b7abd9c..bd73509eeb 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -273,18 +273,16 @@ QT_BEGIN_NAMESPACE
//### Particle data handles are not locked to within certain scopes like QQuickContext2D, but there's no way to reload either...
struct QV4ParticleData : public QV4::Object
{
- V4_OBJECT
- QV4ParticleData(QV4::ExecutionEngine *engine, QQuickParticleData *datum)
- : Object(engine)
- {
- setVTable(staticVTable());
- this->datum = datum;
- }
-
- QQuickParticleData* datum;//TODO: Guard needed?
-
- static void destroy(Managed *that)
- { that->as<QV4ParticleData>()->~QV4ParticleData(); }
+ struct Data : QV4::Object::Data {
+ Data(QV4::ExecutionEngine *engine, QQuickParticleData *datum)
+ : Object::Data(engine)
+ , datum(datum)
+ {
+ setVTable(QV4ParticleData::staticVTable());
+ }
+ QQuickParticleData* datum;//TODO: Guard needed?
+ };
+ V4_OBJECT(QV4::Object)
};
DEFINE_OBJECT_VTABLE(QV4ParticleData);
@@ -301,55 +299,55 @@ public:
static QV4::ReturnedValue particleData_discard(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject);
- if (!r || !r->datum)
+ if (!r || !r->d()->datum)
return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
- r->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created
+ r->d()->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created
return QV4::Encode::undefined();
}
static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject);
- if (!r || !r->datum)
+ if (!r || !r->d()->datum)
return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
- return QV4::Encode(r->datum->lifeLeft());
+ return QV4::Encode(r->d()->datum->lifeLeft());
}
static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject);
- if (!r || !r->datum)
+ if (!r || !r->d()->datum)
return ctx->throwError(QStringLiteral("Not a valid ParticleData object"));
- return QV4::Encode(r->datum->curSize());
+ return QV4::Encode(r->d()->datum->curSize());
}
#define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum) \
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum) \
ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \
\
- return QV4::Encode((r->datum->color. VAR )/255.0);\
+ return QV4::Encode((r->d()->datum->color. VAR )/255.0);\
}\
\
static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum)\
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum)\
ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\
\
- double d = ctx->callData->argc ? ctx->callData->args[0].toNumber() : 0; \
- r->datum->color. VAR = qMin(255, qMax(0, (int)floor(d * 255.0)));\
+ double d = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : 0; \
+ r->d()->datum->color. VAR = qMin(255, qMax(0, (int)floor(d * 255.0)));\
return QV4::Encode::undefined(); \
}
@@ -357,63 +355,63 @@ static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\
#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum) \
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum) \
ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \
\
- return QV4::Encode(r->datum-> VARIABLE);\
+ return QV4::Encode(r->d()->datum-> VARIABLE);\
}\
\
static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum)\
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum)\
ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\
\
- r->datum-> VARIABLE = (ctx->callData->argc && ctx->callData->args[0].toBoolean()) ? 1.0 : 0.0;\
+ r->d()->datum-> VARIABLE = (ctx->d()->callData->argc && ctx->d()->callData->args[0].toBoolean()) ? 1.0 : 0.0;\
return QV4::Encode::undefined(); \
}
#define FLOAT_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum) \
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum) \
ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \
\
- return QV4::Encode(r->datum-> VARIABLE);\
+ return QV4::Encode(r->d()->datum-> VARIABLE);\
}\
\
static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum)\
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum)\
ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\
\
- r->datum-> VARIABLE = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();\
+ r->d()->datum-> VARIABLE = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();\
return QV4::Encode::undefined(); \
}
#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \
{ \
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum) \
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum) \
ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \
\
- return QV4::Encode(r->datum-> GETTER ());\
+ return QV4::Encode(r->d()->datum-> GETTER ());\
}\
\
static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\
{\
QV4::Scope scope(ctx); \
- QV4::Scoped<QV4ParticleData> r(scope, ctx->callData->thisObject); \
- if (!r || !r->datum)\
+ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \
+ if (!r || !r->d()->datum)\
ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\
\
- r->datum-> SETTER (ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN());\
+ r->d()->datum-> SETTER (ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN());\
return QV4::Encode::undefined(); \
}
@@ -518,7 +516,7 @@ QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData
QV8ParticleDataDeletable *d = particleV8Data(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, new (v4->memoryManager) QV4ParticleData(v4, datum));
+ QV4::ScopedObject o(scope, v4->memoryManager->alloc<QV4ParticleData>(v4, datum));
QV4::ScopedObject p(scope, d->proto.value());
o->setPrototype(p.getPointer());
m_v4Value = o;
diff --git a/src/plugins/accessible/accessible.pro b/src/plugins/accessible/accessible.pro
deleted file mode 100644
index b97d323a08..0000000000
--- a/src/plugins/accessible/accessible.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-TEMPLATE = subdirs
-qtHaveModule(quick): SUBDIRS += quick
diff --git a/src/plugins/accessible/quick/accessible.json b/src/plugins/accessible/quick/accessible.json
deleted file mode 100644
index b21218f19c..0000000000
--- a/src/plugins/accessible/quick/accessible.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "QQuickWindow", "QQuickItem" ]
-}
diff --git a/src/plugins/accessible/quick/quick.pro b/src/plugins/accessible/quick/quick.pro
deleted file mode 100644
index 115f9bebad..0000000000
--- a/src/plugins/accessible/quick/quick.pro
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGET = qtaccessiblequick
-
-PLUGIN_TYPE = accessible
-PLUGIN_EXTENDS = quick
-PLUGIN_CLASS_NAME = AccessibleQuickFactory
-load(qt_plugin)
-
-include ($$PWD/../shared/qaccessiblebase.pri)
-
-QT += core-private gui-private qml-private quick-private
-
-#DEFINES+=Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION
-
-SOURCES += \
- main.cpp \
- qaccessiblequickview.cpp \
- qaccessiblequickitem.cpp
-
-HEADERS += \
- qaccessiblequickview.h \
- qaccessiblequickitem.h
-
-OTHERFILES += accessible.json
diff --git a/src/plugins/accessible/shared/qaccessiblebase.pri b/src/plugins/accessible/shared/qaccessiblebase.pri
deleted file mode 100644
index 827df0f132..0000000000
--- a/src/plugins/accessible/shared/qaccessiblebase.pri
+++ /dev/null
@@ -1,3 +0,0 @@
-INCLUDEPATH += $$PWD
-SOURCES += $$PWD/qqmlaccessible.cpp
-HEADERS += $$PWD/qqmlaccessible.h
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 9ef8c7ab72..664a457608 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,5 +1,2 @@
TEMPLATE = subdirs
SUBDIRS += qmltooling
-contains(QT_CONFIG, accessibility) {
- SUBDIRS += accessible
-}
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 991b1fad5c..512d9c2914 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -147,6 +147,8 @@ void QQmlAnimationTimer::restartAnimationTimer()
void QQmlAnimationTimer::startAnimations()
{
+ if (!startAnimationPending)
+ return;
startAnimationPending = false;
//force timer to update, which prevents large deltas for our newly added animations
QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index c905fca0d7..994311ced0 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -215,7 +215,9 @@ public:
//useful for profiling/debugging
int runningAnimationCount() { return animations.count(); }
-private Q_SLOTS:
+ bool hasStartAnimationPending() const { return startAnimationPending; }
+
+public Q_SLOTS:
void startAnimations();
void stopTimer();
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 28a4e23a37..b61297ee09 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -558,9 +558,8 @@ IRBuilder::IRBuilder(const QSet<QString> &illegalNames)
{
}
-bool IRBuilder::generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output)
+bool IRBuilder::generateFromQml(const QString &code, const QString &url, Document *output)
{
- this->url = url;
QQmlJS::AST::UiProgram *program = 0;
{
QQmlJS::Lexer lexer(&output->jsParserEngine);
@@ -574,7 +573,7 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, const Q
foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(urlString), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
continue;
}
@@ -1821,6 +1820,13 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe
tdata->release();
resolver->flags |= AllPropertiesAreFinal;
return resolver->resolveMember(qmlEngine, resolver, member);
+ } else if (type->isSingleton()) {
+ const QMetaObject *singletonMeta = type->singletonInstanceInfo()->instanceMetaObject;
+ if (singletonMeta) { // QJSValue-based singletons cannot be accelerated
+ initMetaObjectResolver(resolver, qmlEngine->cache(singletonMeta));
+ member->kind = QV4::IR::Member::MemberOfSingletonObject;
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ }
} else if (const QMetaObject *attachedMeta = type->attachedPropertiesType()) {
QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
initMetaObjectResolver(resolver, cache);
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 3438af425c..1aac878776 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -343,7 +343,7 @@ struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
IRBuilder(const QSet<QString> &illegalNames);
- bool generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output);
+ bool generateFromQml(const QString &code, const QString &url, Document *output);
static bool isSignalPropertyName(const QString &name);
@@ -420,7 +420,6 @@ public:
QQmlJS::MemoryPool *pool;
QString sourceCode;
- QString url;
QV4::Compiler::JSUnitGenerator *jsGenerator;
};
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index f5cb5db369..a4130cb45f 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -298,7 +298,7 @@ bool QQmlTypeCompiler::compile()
void QQmlTypeCompiler::recordError(const QQmlError &error)
{
QQmlError e = error;
- e.setUrl(compiledData->url);
+ e.setUrl(url());
errors << e;
}
@@ -378,9 +378,9 @@ QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent()
return &compiledData->objectIndexToIdPerComponent;
}
-QHash<int, QQmlCompiledData::CustomParserData> *QQmlTypeCompiler::customParserData()
+QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings()
{
- return &compiledData->customParserData;
+ return &compiledData->customParserBindings;
}
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
@@ -398,11 +398,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
return &document->jsGenerator.stringTable;
}
-void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
-{
- compiledData->customParserBindings = bindings;
-}
-
void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject)
{
compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
@@ -1722,7 +1717,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
, customParsers(typeCompiler->customParserCache())
, propertyCaches(typeCompiler->propertyCaches())
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
- , customParserData(typeCompiler->customParserData())
+ , customParserBindingsPerObject(typeCompiler->customParserBindings())
, _seenObjectWithId(false)
{
}
@@ -1731,7 +1726,6 @@ bool QQmlPropertyValidator::validate()
{
if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
return false;
- compiler->setCustomParserBindings(customParserBindings);
compiler->setDeferredBindingsPerObject(deferredBindingsPerObject);
return true;
}
@@ -1741,13 +1735,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const
return *compiler->imports();
}
-QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *)
-{
- const int id = customParserBindings.count();
- customParserBindings.append(binding->value.compiledScriptIndex);
- return id;
-}
-
QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const
{
const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex);
@@ -2018,11 +2005,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
if (customParser && !customBindings.isEmpty()) {
customParser->clearErrors();
customParser->compiler = this;
- QQmlCompiledData::CustomParserData data;
- data.bindings = customParserBindings;
- data.compilationArtifact = customParser->compile(qmlUnit, customBindings);
+ customParser->imports = compiler->imports();
+ customParser->verifyBindings(qmlUnit, customBindings);
customParser->compiler = 0;
- customParserData->insert(objectIndex, data);
+ customParser->imports = (QQmlImports*)0;
+ customParserBindingsPerObject->insert(objectIndex, customParserBindings);
const QList<QQmlError> parserErrors = customParser->errors();
if (!parserErrors.isEmpty()) {
foreach (QQmlError error, parserErrors)
@@ -2168,7 +2155,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa
#endif // QT_NO_DATESTRING
case QVariant::Point: {
bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint();
+ QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok);
if (!ok) {
recordError(binding->valueLocation, tr("Invalid property assignment: point expected"));
return false;
@@ -2186,7 +2173,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa
break;
case QVariant::Size: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize();
+ QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok);
if (!ok) {
recordError(binding->valueLocation, tr("Invalid property assignment: size expected"));
return false;
@@ -2204,7 +2191,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa
break;
case QVariant::Rect: {
bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect();
+ QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok);
if (!ok) {
recordError(binding->valueLocation, tr("Invalid property assignment: rect expected"));
return false;
@@ -2259,7 +2246,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa
// generate single literal value assignment to a list property if required
if (property->propType == qMetaTypeId<QList<qreal> >()) {
if (binding->type != QV4::CompiledData::Binding::Type_Number) {
- recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected"));
+ recordError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected"));
return false;
}
break;
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index fb8ac94fcd..caf1f93923 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -84,7 +84,7 @@ public:
const QV4::CompiledData::QmlUnit *qmlUnit() const;
- QUrl url() const { return compiledData->url; }
+ QUrl url() const { return typeData->finalUrl(); }
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes();
@@ -96,11 +96,10 @@ public:
QVector<QByteArray> *vmeMetaObjects() const;
QHash<int, int> *objectIndexToIdForRoot();
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
- QHash<int, QQmlCompiledData::CustomParserData> *customParserData();
+ QHash<int, QBitArray> *customParserBindings();
QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
- void setCustomParserBindings(const QVector<int> &bindings);
void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
@@ -282,7 +281,6 @@ public:
// Re-implemented for QQmlCustomParser
virtual const QQmlImports &imports() const;
- virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser);
virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const;
private:
@@ -300,8 +298,7 @@ private:
const QHash<int, QQmlCustomParser*> &customParsers;
const QVector<QQmlPropertyCache *> &propertyCaches;
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
- QHash<int, QQmlCompiledData::CustomParserData> *customParserData;
- QVector<int> customParserBindings;
+ QHash<int, QBitArray> *customParserBindingsPerObject;
QHash<int, QBitArray> deferredBindingsPerObject;
bool _seenObjectWithId;
@@ -394,6 +391,7 @@ private:
virtual void visitClosure(QV4::IR::Closure *closure);
virtual void visitTemp(QV4::IR::Temp *) {}
+ virtual void visitArgLocal(QV4::IR::ArgLocal *) {}
virtual void visitMove(QV4::IR::Move *s) {
s->source->accept(this);
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index fdc4d5c9f2..3e8a0994ff 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -68,6 +68,12 @@ using namespace QV4;
using namespace QQmlJS;
using namespace AST;
+static inline void setLocation(IR::Stmt *s, const SourceLocation &loc)
+{
+ if (s && loc.isValid())
+ s->location = loc;
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
@@ -487,11 +493,9 @@ void Codegen::leaveEnvironment()
_env = _env->parent;
}
-void Codegen::enterLoop(Statement *node, IR::BasicBlock *startBlock, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock)
+void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock)
{
- if (startBlock)
- startBlock->markAsGroupStart();
- _loop = new Loop(node, startBlock, breakBlock, continueBlock, _loop);
+ _loop = new Loop(node, breakBlock, continueBlock, _loop);
_loop->labelledStatement = _labelledStatement; // consume the enclosing labelled statement
_loop->scopeAndFinally = _scopeAndFinally;
_labelledStatement = 0;
@@ -509,8 +513,8 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name)
if (hasError)
return 0;
- if (base->asTemp() /*|| base->asName()*/)
- return _block->MEMBER(base->asTemp(), name);
+ if (base->asTemp() || base->asArgLocal())
+ return _block->MEMBER(base, name);
else {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), base);
@@ -523,25 +527,26 @@ IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index)
if (hasError)
return 0;
- if (! base->asTemp()) {
+ if (! base->asTemp() || base->asArgLocal()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), base);
base = _block->TEMP(t);
}
- if (! index->asTemp()) {
+ if (! index->asTemp() || index->asArgLocal()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), index);
index = _block->TEMP(t);
}
- Q_ASSERT(base->asTemp() && index->asTemp());
+ Q_ASSERT(base->asTemp() || base->asArgLocal());
+ Q_ASSERT(index->asTemp() || index->asArgLocal());
return _block->SUBSCRIPT(base->asTemp(), index->asTemp());
}
IR::Expr *Codegen::argument(IR::Expr *expr)
{
- if (expr && ! expr->asTemp()) {
+ if (expr && !expr->asTemp() && !expr->asArgLocal()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), expr);
expr = _block->TEMP(t);
@@ -555,7 +560,7 @@ IR::Expr *Codegen::reference(IR::Expr *expr)
if (hasError)
return 0;
- if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) {
+ if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), expr);
expr = _block->TEMP(t);
@@ -563,7 +568,7 @@ IR::Expr *Codegen::reference(IR::Expr *expr)
return expr;
}
-IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr)
+IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr, const SourceLocation &loc)
{
if (hasError)
return 0;
@@ -591,16 +596,16 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr)
}
}
}
- if (! expr->asTemp()) {
+ if (!expr->asTemp() && !expr->asArgLocal()) {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), expr);
+ setLocation(move(_block->TEMP(t), expr), loc);
expr = _block->TEMP(t);
}
- Q_ASSERT(expr->asTemp());
- return _block->UNOP(op, expr->asTemp());
+ Q_ASSERT(expr->asTemp() || expr->asArgLocal());
+ return _block->UNOP(op, expr);
}
-IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right)
+IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AST::SourceLocation &loc)
{
if (hasError)
return 0;
@@ -655,20 +660,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right)
}
}
- if (!left->asTemp()) {
+ if (!left->asTemp() && !left->asArgLocal()) {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), left);
+ setLocation(move(_block->TEMP(t), left), loc);
left = _block->TEMP(t);
}
- if (!right->asTemp()) {
+ if (!right->asTemp() && !right->asArgLocal()) {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), right);
+ setLocation(move(_block->TEMP(t), right), loc);
right = _block->TEMP(t);
}
- Q_ASSERT(left->asTemp());
- Q_ASSERT(right->asTemp());
+ Q_ASSERT(left->asTemp() || left->asArgLocal());
+ Q_ASSERT(right->asTemp() || right->asArgLocal());
return _block->BINOP(op, left, right);
}
@@ -681,43 +686,42 @@ IR::Expr *Codegen::call(IR::Expr *base, IR::ExprList *args)
return _block->CALL(base, args);
}
-void Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op)
+IR::Stmt *Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op)
{
if (hasError)
- return;
+ return 0;
Q_ASSERT(target->isLValue());
if (op != IR::OpInvalid) {
- move(target, binop(op, target, source));
- return;
+ return move(target, binop(op, target, source));
}
- if (!source->asTemp() && !source->asConst() && !target->asTemp()) {
+ if (!source->asTemp() && !source->asConst() && !target->asTemp() && !source->asArgLocal() && !target->asArgLocal()) {
unsigned t = _block->newTemp();
_block->MOVE(_block->TEMP(t), source);
source = _block->TEMP(t);
}
- if (source->asConst() && !target->asTemp()) {
+ if (source->asConst() && !target->asTemp() && !target->asArgLocal()) {
unsigned t = _block->newTemp();
_block->MOVE(_block->TEMP(t), source);
source = _block->TEMP(t);
}
- _block->MOVE(target, source);
+ return _block->MOVE(target, source);
}
-void Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
+IR::Stmt *Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (hasError)
- return;
+ return 0;
if (! (cond->asTemp() || cond->asBinop())) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), cond);
cond = _block->TEMP(t);
}
- _block->CJUMP(cond, iftrue, iffalse);
+ return _block->CJUMP(cond, iftrue, iffalse);
}
void Codegen::accept(Node *node)
@@ -749,7 +753,7 @@ void Codegen::statement(ExpressionNode *ast)
if (r.format == ex) {
if (r->asCall()) {
_block->EXP(*r); // the nest nx representation for calls is EXP(CALL(c..))
- } else if (r->asTemp()) {
+ } else if (r->asTemp() || r->asArgLocal()) {
// there is nothing to do
} else {
unsigned t = _block->newTemp();
@@ -767,7 +771,7 @@ void Codegen::condition(ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBl
accept(ast);
qSwap(_expr, r);
if (r.format == ex) {
- cjump(*r, r.iftrue, r.iffalse);
+ setLocation(cjump(*r, r.iftrue, r.iffalse), ast->firstSourceLocation());
}
}
}
@@ -1065,7 +1069,7 @@ bool Codegen::visit(ArrayLiteral *ast)
current = arg;
IR::Expr *exp = *expr;
- if (exp->asTemp() || exp->asConst()) {
+ if (exp->asTemp() || expr->asArgLocal() || exp->asConst()) {
current->expr = exp;
} else {
unsigned value = _block->newTemp();
@@ -1126,18 +1130,18 @@ bool Codegen::visit(BinaryExpression *ast)
if (ast->op == QSOperator::And) {
if (_expr.accept(cx)) {
- IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler());
condition(ast->left, iftrue, _expr.iffalse);
_block = iftrue;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
const unsigned r = _block->newTemp();
move(_block->TEMP(r), *expression(ast->left));
- cjump(_block->TEMP(r), iftrue, endif);
+ setLocation(cjump(_block->TEMP(r), iftrue, endif), ast->operatorToken);
_block = iftrue;
move(_block->TEMP(r), *expression(ast->right));
_block->JUMP(endif);
@@ -1148,17 +1152,17 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
} else if (ast->op == QSOperator::Or) {
if (_expr.accept(cx)) {
- IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler());
condition(ast->left, _expr.iftrue, iffalse);
_block = iffalse;
condition(ast->right, _expr.iftrue, _expr.iffalse);
} else {
- IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
const unsigned r = _block->newTemp();
move(_block->TEMP(r), *expression(ast->left));
- cjump(_block->TEMP(r), endif, iffalse);
+ setLocation(cjump(_block->TEMP(r), endif, iffalse), ast->operatorToken);
_block = iffalse;
move(_block->TEMP(r), *expression(ast->right));
_block->JUMP(endif);
@@ -1236,23 +1240,23 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::Lt:
case QSOperator::StrictEqual:
case QSOperator::StrictNotEqual: {
- if (!left->asTemp() && !left->asConst()) {
+ if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), left);
+ setLocation(move(_block->TEMP(t), left), ast->operatorToken);
left = _block->TEMP(t);
}
IR::Expr* right = *expression(ast->right);
if (_expr.accept(cx)) {
- cjump(binop(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ setLocation(cjump(binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken);
} else {
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right);
+ IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken);
if (e->asConst() || e->asString())
_expr.code = e;
else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), e);
+ setLocation(move(_block->TEMP(t), e), ast->operatorToken);
_expr.code = _block->TEMP(t);
}
}
@@ -1270,20 +1274,20 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::RShift:
case QSOperator::Sub:
case QSOperator::URShift: {
- if (!left->asTemp() && !left->asConst()) {
+ if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), left);
+ setLocation(move(_block->TEMP(t), left), ast->operatorToken);
left = _block->TEMP(t);
}
IR::Expr* right = *expression(ast->right);
- IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right);
+ IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken);
if (e->asConst() || e->asString())
_expr.code = e;
else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), e);
+ setLocation(move(_block->TEMP(t), e), ast->operatorToken);
_expr.code = _block->TEMP(t);
}
break;
@@ -1317,9 +1321,9 @@ bool Codegen::visit(ConditionalExpression *ast)
if (hasError)
return true;
- IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
const unsigned t = _block->newTemp();
@@ -1347,8 +1351,8 @@ bool Codegen::visit(DeleteExpression *ast)
IR::Expr* expr = *expression(ast->expression);
// Temporaries cannot be deleted
- IR::Temp *t = expr->asTemp();
- if (t && t->index < static_cast<unsigned>(_env->members.size())) {
+ IR::ArgLocal *al = expr->asArgLocal();
+ if (al && al->index < static_cast<unsigned>(_env->members.size())) {
// Trying to delete a function argument might throw.
if (_function->isStrict) {
throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
@@ -1375,7 +1379,9 @@ bool Codegen::visit(DeleteExpression *ast)
_expr.code = _block->CONST(IR::BoolType, 1);
return false;
}
- if (expr->asTemp() && expr->asTemp()->index >= static_cast<unsigned>(_env->members.size())) {
+ if (expr->asTemp() ||
+ (expr->asArgLocal() &&
+ expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) {
_expr.code = _block->CONST(IR::BoolType, 1);
return false;
}
@@ -1435,10 +1441,10 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
int index = e->findMember(name);
Q_ASSERT (index < e->members.size());
if (index != -1) {
- IR::Temp *t = _block->LOCAL(index, scope);
+ IR::ArgLocal *al = _block->LOCAL(index, scope);
if (name == QStringLiteral("arguments") || name == QStringLiteral("eval"))
- t->isArgumentsOrEval = true;
- return t;
+ al->isArgumentsOrEval = true;
+ return al;
}
const int argIdx = f->indexOfArgument(&name);
if (argIdx != -1)
@@ -1497,7 +1503,7 @@ bool Codegen::visit(NewExpression *ast)
Result base = expression(ast->expression);
IR::Expr *expr = *base;
- if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
+ if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), expr);
expr = _block->TEMP(t);
@@ -1513,7 +1519,7 @@ bool Codegen::visit(NewMemberExpression *ast)
Result base = expression(ast->base);
IR::Expr *expr = *base;
- if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
+ if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), expr);
expr = _block->TEMP(t);
@@ -1540,7 +1546,7 @@ bool Codegen::visit(NotExpression *ast)
Result expr = expression(ast->expression);
const unsigned r = _block->newTemp();
- move(_block->TEMP(r), unop(IR::OpNot, *expr));
+ setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken);
_expr.code = _block->TEMP(r);
return false;
}
@@ -1734,11 +1740,11 @@ bool Codegen::visit(PostDecrementExpression *ast)
return false;
const unsigned oldValue = _block->newTemp();
- move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr));
+ setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->decrementToken)), ast->decrementToken);
const unsigned newValue = _block->newTemp();
- move(_block->TEMP(newValue), binop(IR::OpSub, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1)));
- move(*expr, _block->TEMP(newValue));
+ setLocation(move(_block->TEMP(newValue), binop(IR::OpSub, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->decrementToken)), ast->decrementToken);
+ setLocation(move(*expr, _block->TEMP(newValue)), ast->decrementToken);
if (!_expr.accept(nx))
_expr.code = _block->TEMP(oldValue);
@@ -1760,11 +1766,11 @@ bool Codegen::visit(PostIncrementExpression *ast)
return false;
const unsigned oldValue = _block->newTemp();
- move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr));
+ setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->incrementToken)), ast->incrementToken);
const unsigned newValue = _block->newTemp();
- move(_block->TEMP(newValue), binop(IR::OpAdd, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1)));
- move(*expr, _block->TEMP(newValue));
+ setLocation(move(_block->TEMP(newValue), binop(IR::OpAdd, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->incrementToken)), ast->incrementToken);
+ setLocation(move(*expr, _block->TEMP(newValue)), ast->incrementToken);
if (!_expr.accept(nx))
_expr.code = _block->TEMP(oldValue);
@@ -1785,13 +1791,13 @@ bool Codegen::visit(PreDecrementExpression *ast)
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken))
return false;
- IR::Expr *op = binop(IR::OpSub, *expr, _block->CONST(IR::NumberType, 1));
+ IR::Expr *op = binop(IR::OpSub, *expr, _block->CONST(IR::NumberType, 1), ast->decrementToken);
if (_expr.accept(nx)) {
- move(*expr, op);
+ setLocation(move(*expr, op), ast->decrementToken);
} else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), op);
- move(*expr, _block->TEMP(t));
+ setLocation(move(_block->TEMP(t), op), ast->decrementToken);
+ setLocation(move(*expr, _block->TEMP(t)), ast->decrementToken);
_expr.code = _block->TEMP(t);
}
return false;
@@ -1810,13 +1816,13 @@ bool Codegen::visit(PreIncrementExpression *ast)
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken))
return false;
- IR::Expr *op = binop(IR::OpAdd, unop(IR::OpUPlus, *expr), _block->CONST(IR::NumberType, 1));
+ IR::Expr *op = binop(IR::OpAdd, unop(IR::OpUPlus, *expr, ast->incrementToken), _block->CONST(IR::NumberType, 1), ast->incrementToken);
if (_expr.accept(nx)) {
- move(*expr, op);
+ setLocation(move(*expr, op), ast->incrementToken);
} else {
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), op);
- move(*expr, _block->TEMP(t));
+ setLocation(move(_block->TEMP(t), op), ast->incrementToken);
+ setLocation(move(*expr, _block->TEMP(t)), ast->incrementToken);
_expr.code = _block->TEMP(t);
}
return false;
@@ -1856,7 +1862,7 @@ bool Codegen::visit(TildeExpression *ast)
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), unop(IR::OpCompl, *expr));
+ setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken);
_expr.code = _block->TEMP(t);
return false;
}
@@ -1893,7 +1899,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), unop(IR::OpUMinus, *expr));
+ setLocation(move(_block->TEMP(t), unop(IR::OpUMinus, *expr, ast->minusToken)), ast->minusToken);
_expr.code = _block->TEMP(t);
return false;
}
@@ -1905,7 +1911,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
Result expr = expression(ast->expression);
const unsigned t = _block->newTemp();
- move(_block->TEMP(t), unop(IR::OpUPlus, *expr));
+ setLocation(move(_block->TEMP(t), unop(IR::OpUPlus, *expr, ast->plusToken)), ast->plusToken);
_expr.code = _block->TEMP(t);
return false;
}
@@ -1947,9 +1953,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::Function *function = _module->newFunction(name, _function);
int functionIndex = _module->functions.count() - 1;
- IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock(), 0);
- IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), 0, IR::Function::DontInsertBlock);
- function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode;
+ IR::BasicBlock *entryBlock = function->newBasicBlock(0);
+ IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock);
+ function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode
+ || _module->debugMode; // Conditional breakpoints are like eval in the function
function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->usesThis = _env->usesThis;
function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
@@ -2005,7 +2012,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
unsigned returnAddress = entryBlock->newTemp();
entryBlock->MOVE(entryBlock->TEMP(returnAddress), entryBlock->CONST(IR::UndefinedType, 0));
- exitBlock->RET(exitBlock->TEMP(returnAddress));
+ setLocation(exitBlock->RET(exitBlock->TEMP(returnAddress)), ast->lastSourceLocation());
qSwap(_function, function);
qSwap(_block, entryBlock);
@@ -2162,11 +2169,11 @@ bool Codegen::visit(DoWhileStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody, exceptionHandler());
- IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *loopbody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *loopcond = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *loopend = _function->newBasicBlock(exceptionHandler());
- enterLoop(ast, loopbody, loopend, loopcond);
+ enterLoop(ast, loopend, loopcond);
_block->JUMP(loopbody);
@@ -2212,9 +2219,9 @@ bool Codegen::visit(ForEachStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
- IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler());
int objectToIterateOn = _block->newTemp();
move(_block->TEMP(objectToIterateOn), *expression(ast->expression));
@@ -2224,7 +2231,7 @@ bool Codegen::visit(ForEachStatement *ast)
int iterator = _block->newTemp();
move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args));
- enterLoop(ast, foreachin, foreachend, foreachin);
+ enterLoop(ast, foreachend, foreachin);
_block->JUMP(foreachin);
_block = foreachbody;
@@ -2240,7 +2247,7 @@ bool Codegen::visit(ForEachStatement *ast)
move(_block->TEMP(temp), _block->CALL(_block->NAME(IR::Name::builtin_foreach_next_property_name, 0, 0), args));
int null = _block->newTemp();
move(_block->TEMP(null), _block->CONST(IR::NullType, 0));
- cjump(_block->BINOP(IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend);
+ setLocation(cjump(_block->BINOP(IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend), ast->forToken);
_block = foreachend;
leaveLoop();
@@ -2252,15 +2259,15 @@ bool Codegen::visit(ForStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
- IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
- IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forend = _function->newBasicBlock(exceptionHandler());
statement(ast->initialiser);
_block->JUMP(forcond);
- enterLoop(ast, forcond, forend, forstep);
+ enterLoop(ast, forend, forstep);
_block = forcond;
if (ast->condition)
@@ -2288,9 +2295,9 @@ bool Codegen::visit(IfStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock(), exceptionHandler()) : 0;
- IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(exceptionHandler()) : 0;
+ IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
condition(ast->expression, iftrue, ast->ko ? iffalse : endif);
@@ -2335,8 +2342,8 @@ bool Codegen::visit(LabelledStatement *ast)
AST::cast<AST::LocalForEachStatement *>(ast->statement)) {
statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop.
} else {
- IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- enterLoop(ast->statement, 0, breakBlock, /*continueBlock*/ 0);
+ IR::BasicBlock *breakBlock = _function->newBasicBlock(exceptionHandler());
+ enterLoop(ast->statement, breakBlock, /*continueBlock*/ 0);
statement(ast->statement);
_block->JUMP(breakBlock);
_block = breakBlock;
@@ -2351,9 +2358,9 @@ bool Codegen::visit(LocalForEachStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler());
- IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler());
variableDeclaration(ast->declaration);
@@ -2364,7 +2371,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args));
_block->JUMP(foreachin);
- enterLoop(ast, foreachin, foreachend, foreachin);
+ enterLoop(ast, foreachend, foreachin);
_block = foreachbody;
int temp = _block->newTemp();
@@ -2379,7 +2386,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
move(_block->TEMP(temp), _block->CALL(_block->NAME(IR::Name::builtin_foreach_next_property_name, 0, 0), args));
int null = _block->newTemp();
move(_block->TEMP(null), _block->CONST(IR::NullType, 0));
- cjump(_block->BINOP(IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend);
+ setLocation(cjump(_block->BINOP(IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend), ast->forToken);
_block = foreachend;
leaveLoop();
@@ -2391,15 +2398,15 @@ bool Codegen::visit(LocalForStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler());
- IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler());
- IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *forend = _function->newBasicBlock(exceptionHandler());
variableDeclarationList(ast->declarations);
_block->JUMP(forcond);
- enterLoop(ast, forcond, forend, forstep);
+ enterLoop(ast, forend, forstep);
_block = forcond;
if (ast->condition)
@@ -2446,22 +2453,22 @@ bool Codegen::visit(SwitchStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *switchend = _function->newBasicBlock(exceptionHandler());
if (ast->block) {
Result lhs = expression(ast->expression);
- IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *switchcond = _function->newBasicBlock(exceptionHandler());
_block->JUMP(switchcond);
IR::BasicBlock *previousBlock = 0;
QHash<Node *, IR::BasicBlock *> blockMap;
- enterLoop(ast, 0, switchend, 0);
+ enterLoop(ast, switchend, 0);
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block = _function->newBasicBlock(exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2474,7 +2481,7 @@ bool Codegen::visit(SwitchStatement *ast)
}
if (ast->block->defaultClause) {
- _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block = _function->newBasicBlock(exceptionHandler());
blockMap[ast->block->defaultClause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2489,7 +2496,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
- _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ _block = _function->newBasicBlock(exceptionHandler());
blockMap[clause] = _block;
if (previousBlock && !previousBlock->isTerminated())
@@ -2510,8 +2517,8 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
IR::BasicBlock *iftrue = blockMap[clause];
- IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
+ IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler());
+ setLocation(cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse), clause->caseToken);
_block = iffalse;
}
@@ -2519,13 +2526,13 @@ bool Codegen::visit(SwitchStatement *ast)
CaseClause *clause = it->clause;
Result rhs = expression(clause->expression);
IR::BasicBlock *iftrue = blockMap[clause];
- IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
+ IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler());
+ setLocation(cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse), clause->caseToken);
_block = iffalse;
}
- if (ast->block->defaultClause) {
- _block->JUMP(blockMap[ast->block->defaultClause]);
+ if (DefaultClause *defaultClause = ast->block->defaultClause) {
+ setLocation(_block->JUMP(blockMap[ast->block->defaultClause]), defaultClause->defaultToken);
}
}
@@ -2568,16 +2575,16 @@ bool Codegen::visit(TryStatement *ast)
IR::BasicBlock *finallyBody = 0;
IR::BasicBlock *catchBody = 0;
IR::BasicBlock *catchExceptionHandler = 0;
- IR::BasicBlock *end = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, IR::Function::DontInsertBlock);
+ IR::BasicBlock *end = _function->newBasicBlock(surroundingExceptionHandler, IR::Function::DontInsertBlock);
if (ast->finallyExpression)
- finallyBody = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, IR::Function::DontInsertBlock);
+ finallyBody = _function->newBasicBlock(surroundingExceptionHandler, IR::Function::DontInsertBlock);
if (ast->catchExpression) {
// exception handler for the catch body
- catchExceptionHandler = _function->newBasicBlock(groupStartBlock(), 0, IR::Function::DontInsertBlock);
+ catchExceptionHandler = _function->newBasicBlock(0, IR::Function::DontInsertBlock);
pushExceptionHandler(catchExceptionHandler);
- catchBody = _function->newBasicBlock(groupStartBlock(), catchExceptionHandler, IR::Function::DontInsertBlock);
+ catchBody = _function->newBasicBlock(catchExceptionHandler, IR::Function::DontInsertBlock);
popExceptionHandler();
pushExceptionHandler(catchBody);
} else {
@@ -2585,7 +2592,7 @@ bool Codegen::visit(TryStatement *ast)
pushExceptionHandler(finallyBody);
}
- IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *tryBody = _function->newBasicBlock(exceptionHandler());
_block->JUMP(tryBody);
ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression);
@@ -2690,11 +2697,11 @@ bool Codegen::visit(WhileStatement *ast)
if (hasError)
return true;
- IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
- IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond, exceptionHandler());
- IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *whilecond = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *whilebody = _function->newBasicBlock(exceptionHandler());
+ IR::BasicBlock *whileend = _function->newBasicBlock(exceptionHandler());
- enterLoop(ast, whilecond, whileend, whilecond);
+ enterLoop(ast, whileend, whilecond);
_block->JUMP(whilecond);
_block = whilecond;
@@ -2718,7 +2725,7 @@ bool Codegen::visit(WithStatement *ast)
_function->hasWith = true;
// need an exception handler for with to cleanup the with scope
- IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler());
withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
if (!exceptionHandler())
withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(IR::Name::builtin_rethrow, 0, 0), 0));
@@ -2727,7 +2734,7 @@ bool Codegen::visit(WithStatement *ast)
pushExceptionHandler(withExceptionHandler);
- IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *withBlock = _function->newBasicBlock(exceptionHandler());
_block->JUMP(withBlock);
_block = withBlock;
@@ -2748,7 +2755,7 @@ bool Codegen::visit(WithStatement *ast)
_block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
popExceptionHandler();
- IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock(), exceptionHandler());
+ IR::BasicBlock *next = _function->newBasicBlock(exceptionHandler());
_block->JUMP(next);
_block = next;
@@ -2798,8 +2805,8 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, cons
if (IR::Name *n = expr->asName()) {
if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments"))
return false;
- } else if (IR::Temp *t = expr->asTemp()) {
- if (!t->isArgumentsOrEval)
+ } else if (IR::ArgLocal *al = expr->asArgLocal()) {
+ if (!al->isArgumentsOrEval)
return false;
} else {
return false;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 0d52fb83fa..c4c2a74e4b 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -256,28 +256,20 @@ protected:
struct Loop {
AST::LabelledStatement *labelledStatement;
AST::Statement *node;
- QV4::IR::BasicBlock *groupStartBlock;
QV4::IR::BasicBlock *breakBlock;
QV4::IR::BasicBlock *continueBlock;
Loop *parent;
ScopeAndFinally *scopeAndFinally;
- Loop(AST::Statement *node, QV4::IR::BasicBlock *groupStartBlock, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock, Loop *parent)
- : labelledStatement(0), node(node), groupStartBlock(groupStartBlock), breakBlock(breakBlock), continueBlock(continueBlock), parent(parent) {}
+ Loop(AST::Statement *node, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock, Loop *parent)
+ : labelledStatement(0), node(node), breakBlock(breakBlock), continueBlock(continueBlock), parent(parent) {}
};
void enterEnvironment(AST::Node *node);
void leaveEnvironment();
- void enterLoop(AST::Statement *node, QV4::IR::BasicBlock *startBlock, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock);
+ void enterLoop(AST::Statement *node, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock);
void leaveLoop();
- QV4::IR::BasicBlock *groupStartBlock() const
- {
- for (Loop *it = _loop; it; it = it->parent)
- if (it->groupStartBlock)
- return it->groupStartBlock;
- return 0;
- }
QV4::IR::BasicBlock *exceptionHandler() const
{
if (_exceptionHandlers.isEmpty())
@@ -299,11 +291,11 @@ protected:
QV4::IR::Expr *subscript(QV4::IR::Expr *base, QV4::IR::Expr *index);
QV4::IR::Expr *argument(QV4::IR::Expr *expr);
QV4::IR::Expr *reference(QV4::IR::Expr *expr);
- QV4::IR::Expr *unop(QV4::IR::AluOp op, QV4::IR::Expr *expr);
- QV4::IR::Expr *binop(QV4::IR::AluOp op, QV4::IR::Expr *left, QV4::IR::Expr *right);
+ QV4::IR::Expr *unop(QV4::IR::AluOp op, QV4::IR::Expr *expr, const AST::SourceLocation &loc = AST::SourceLocation());
+ QV4::IR::Expr *binop(QV4::IR::AluOp op, QV4::IR::Expr *left, QV4::IR::Expr *right, const AST::SourceLocation &loc = AST::SourceLocation());
QV4::IR::Expr *call(QV4::IR::Expr *base, QV4::IR::ExprList *args);
- void move(QV4::IR::Expr *target, QV4::IR::Expr *source, QV4::IR::AluOp op = QV4::IR::OpInvalid);
- void cjump(QV4::IR::Expr *cond, QV4::IR::BasicBlock *iftrue, QV4::IR::BasicBlock *iffalse);
+ QV4::IR::Stmt *move(QV4::IR::Expr *target, QV4::IR::Expr *source, QV4::IR::AluOp op = QV4::IR::OpInvalid);
+ QV4::IR::Stmt *cjump(QV4::IR::Expr *cond, QV4::IR::BasicBlock *iftrue, QV4::IR::BasicBlock *iffalse);
// Returns index in _module->functions
int defineFunction(const QString &name, AST::Node *ast,
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index d70c82233f..f7b7d23a49 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE
F(StoreQObjectProperty, storeQObjectProperty) \
F(LoadQObjectProperty, loadQObjectProperty) \
F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \
+ F(LoadSingletonQObjectProperty, loadQObjectProperty) \
F(Push, push) \
F(CallValue, callValue) \
F(CallProperty, callProperty) \
@@ -305,7 +306,6 @@ union Instr
int propertyIndex;
Param base;
Param result;
- int attachedPropertiesId;
bool captureRequired;
};
struct instr_loadAttachedQObjectProperty {
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 9288008632..958dfc7fbb 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -168,22 +168,30 @@ inline bool isBoolType(IR::Expr *e)
*/
class AllocateStackSlots: protected ConvertTemps
{
- const QVector<IR::LifeTimeInterval> _intervals;
- QVector<const IR::LifeTimeInterval *> _unhandled;
- QVector<const IR::LifeTimeInterval *> _live;
+ IR::LifeTimeIntervals::Ptr _intervals;
+ QVector<IR::LifeTimeInterval *> _unhandled;
+ QVector<IR::LifeTimeInterval *> _live;
QBitArray _slotIsInUse;
IR::Function *_function;
+ int defPosition(IR::Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(IR::Stmt *s) const
+ {
+ return _intervals->positionForStatement(s);
+ }
+
public:
- AllocateStackSlots(const QVector<IR::LifeTimeInterval> &intervals)
+ AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
: _intervals(intervals)
- , _slotIsInUse(intervals.size(), false)
+ , _slotIsInUse(intervals->size(), false)
, _function(0)
{
_live.reserve(8);
- _unhandled.reserve(_intervals.size());
- for (int i = _intervals.size() - 1; i >= 0; --i)
- _unhandled.append(&_intervals.at(i));
+ _unhandled = _intervals->intervals();
}
void forFunction(IR::Function *function)
@@ -219,8 +227,6 @@ protected:
virtual void process(IR::Stmt *s)
{
- Q_ASSERT(s->id > 0);
-
// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
if (IR::Phi *phi = s->asPhi()) {
@@ -229,7 +235,7 @@ protected:
// purge ranges no longer alive:
for (int i = 0; i < _live.size(); ) {
const IR::LifeTimeInterval *lti = _live.at(i);
- if (lti->end() < s->id) {
+ if (lti->end() < usePosition(s)) {
// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
_live.remove(i);
Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
@@ -242,8 +248,8 @@ protected:
// active new ranges:
while (!_unhandled.isEmpty()) {
- const IR::LifeTimeInterval *lti = _unhandled.last();
- if (lti->start() > s->id)
+ IR::LifeTimeInterval *lti = _unhandled.last();
+ if (lti->start() > defPosition(s))
break; // we're done
Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
_stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
@@ -286,7 +292,7 @@ protected:
int i = _unhandled.size() - 1;
for (; i >= 0; --i) {
- const IR::LifeTimeInterval *lti = _unhandled[i];
+ IR::LifeTimeInterval *lti = _unhandled[i];
if (lti->temp() == t) {
_live.append(lti);
_unhandled.remove(i);
@@ -322,9 +328,8 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex
, _codeNext(0)
, _codeEnd(0)
, _currentStatement(0)
-{
- compilationUnit = new CompilationUnit;
-}
+ , compilationUnit(new CompilationUnit)
+{}
InstructionSelection::~InstructionSelection()
{
@@ -453,10 +458,10 @@ QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
int i = 0;
foreach (IR::Function *irFunction, irModule->functions)
compilationUnit->codeRefs[i++] = codeRefs[irFunction];
- return compilationUnit;
+ return compilationUnit.take();
}
-void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Instruction::CallValue call;
prepareCallArgs(args, call.argc);
@@ -467,7 +472,7 @@ void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Te
}
void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
if (useFastLookups) {
Instruction::CallPropertyLookup call;
@@ -490,7 +495,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
}
void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
// call the property on the loaded base
Instruction::CallElement call;
@@ -502,7 +507,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex
addInstruction(call);
}
-void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
{
// FIXME: do something more useful with this info
if (target->type & IR::NumberType && !(source->type & IR::NumberType))
@@ -513,14 +518,14 @@ void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target)
void InstructionSelection::constructActivationProperty(IR::Name *func,
IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *target)
{
if (useFastLookups && func->global) {
Instruction::ConstructGlobalLookup call;
call.index = registerGlobalGetterLookup(*func->id);
prepareCallArgs(args, call.argc);
call.callData = callDataStart();
- call.result = getResultParam(result);
+ call.result = getResultParam(target);
addInstruction(call);
return;
}
@@ -528,11 +533,11 @@ void InstructionSelection::constructActivationProperty(IR::Name *func,
create.name = registerString(*func->id);
prepareCallArgs(args, create.argc);
create.callData = callDataStart();
- create.result = getResultParam(result);
+ create.result = getResultParam(target);
addInstruction(create);
}
-void InstructionSelection::constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *target)
{
if (useFastLookups) {
Instruction::ConstructPropertyLookup call;
@@ -540,7 +545,7 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name
call.index = registerGetterLookup(name);
prepareCallArgs(args, call.argc);
call.callData = callDataStart();
- call.result = getResultParam(result);
+ call.result = getResultParam(target);
addInstruction(call);
return;
}
@@ -549,101 +554,101 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name
create.name = registerString(name);
prepareCallArgs(args, create.argc);
create.callData = callDataStart();
- create.result = getResultParam(result);
+ create.result = getResultParam(target);
addInstruction(create);
}
-void InstructionSelection::constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *target)
{
Instruction::CreateValue create;
create.func = getParam(value);
prepareCallArgs(args, create.argc);
create.callData = callDataStart();
- create.result = getResultParam(result);
+ create.result = getResultParam(target);
addInstruction(create);
}
-void InstructionSelection::loadThisObject(IR::Temp *temp)
+void InstructionSelection::loadThisObject(IR::Expr *e)
{
Instruction::LoadThis load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
addInstruction(load);
}
-void InstructionSelection::loadQmlIdArray(IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(IR::Expr *e)
{
Instruction::LoadQmlIdArray load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
addInstruction(load);
}
-void InstructionSelection::loadQmlImportedScripts(IR::Temp *temp)
+void InstructionSelection::loadQmlImportedScripts(IR::Expr *e)
{
Instruction::LoadQmlImportedScripts load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
addInstruction(load);
}
-void InstructionSelection::loadQmlContextObject(IR::Temp *temp)
+void InstructionSelection::loadQmlContextObject(IR::Expr *e)
{
Instruction::LoadQmlContextObject load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
addInstruction(load);
}
-void InstructionSelection::loadQmlScopeObject(IR::Temp *temp)
+void InstructionSelection::loadQmlScopeObject(IR::Expr *e)
{
Instruction::LoadQmlScopeObject load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
addInstruction(load);
}
-void InstructionSelection::loadQmlSingleton(const QString &name, IR::Temp *temp)
+void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *e)
{
Instruction::LoadQmlSingleton load;
- load.result = getResultParam(temp);
+ load.result = getResultParam(e);
load.name = registerString(name);
addInstruction(load);
}
-void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
+void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *e)
{
Q_ASSERT(sourceConst);
Instruction::MoveConst move;
move.source = convertToValue(sourceConst).asReturnedValue();
- move.result = getResultParam(targetTemp);
+ move.result = getResultParam(e);
addInstruction(move);
}
-void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
+void InstructionSelection::loadString(const QString &str, IR::Expr *target)
{
Instruction::LoadRuntimeString load;
load.stringId = registerString(str);
- load.result = getResultParam(targetTemp);
+ load.result = getResultParam(target);
addInstruction(load);
}
-void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
Instruction::LoadRegExp load;
load.regExpId = registerRegExp(sourceRegexp);
- load.result = getResultParam(targetTemp);
+ load.result = getResultParam(target);
addInstruction(load);
}
-void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Temp *temp)
+void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
{
if (useFastLookups && name->global) {
Instruction::GetGlobalLookup load;
load.index = registerGlobalGetterLookup(*name->id);
- load.result = getResultParam(temp);
+ load.result = getResultParam(target);
addInstruction(load);
return;
}
Instruction::LoadName load;
load.name = registerString(*name->id);
- load.result = getResultParam(temp);
+ load.result = getResultParam(target);
addInstruction(load);
}
@@ -655,7 +660,7 @@ void InstructionSelection::setActivationProperty(IR::Expr *source, const QString
addInstruction(store);
}
-void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
+void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
Instruction::LoadClosure load;
@@ -664,7 +669,7 @@ void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
addInstruction(load);
}
-void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Temp *target)
+void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
{
if (useFastLookups) {
Instruction::GetLookup load;
@@ -708,7 +713,7 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target
addInstruction(store);
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target)
+void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0) {
Instruction::LoadAttachedQObjectProperty load;
@@ -716,6 +721,13 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex,
load.result = getResultParam(target);
load.attachedPropertiesId = attachedPropertiesId;
addInstruction(load);
+ } else if (isSingletonProperty) {
+ Instruction::LoadSingletonQObjectProperty load;
+ load.base = getParam(base);
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.captureRequired = captureRequired;
+ addInstruction(load);
} else {
Instruction::LoadQObjectProperty load;
load.base = getParam(base);
@@ -726,7 +738,7 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex,
}
}
-void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target)
+void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
if (useFastLookups) {
Instruction::LoadElementLookup load;
@@ -763,92 +775,92 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase,
addInstruction(store);
}
-void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
{
Instruction::Move move;
- move.source = getParam(sourceTemp);
- move.result = getResultParam(targetTemp);
+ move.source = getParam(source);
+ move.result = getResultParam(target);
if (move.source != move.result)
addInstruction(move);
}
-void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
{
Instruction::SwapTemps swap;
- swap.left = getParam(sourceTemp);
- swap.right = getParam(targetTemp);
+ swap.left = getParam(source);
+ swap.right = getParam(target);
addInstruction(swap);
}
-void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
switch (oper) {
case IR::OpIfTrue:
Q_ASSERT(!"unreachable"); break;
case IR::OpNot: {
// ### enabling this fails in some cases, where apparently the value is not a bool at runtime
- if (0 && isBoolType(sourceTemp)) {
+ if (0 && isBoolType(source)) {
Instruction::UNotBool unot;
- unot.source = getParam(sourceTemp);
- unot.result = getResultParam(targetTemp);
+ unot.source = getParam(source);
+ unot.result = getResultParam(target);
addInstruction(unot);
return;
}
Instruction::UNot unot;
- unot.source = getParam(sourceTemp);
- unot.result = getResultParam(targetTemp);
+ unot.source = getParam(source);
+ unot.result = getResultParam(target);
addInstruction(unot);
return;
}
case IR::OpUMinus: {
Instruction::UMinus uminus;
- uminus.source = getParam(sourceTemp);
- uminus.result = getResultParam(targetTemp);
+ uminus.source = getParam(source);
+ uminus.result = getResultParam(target);
addInstruction(uminus);
return;
}
case IR::OpUPlus: {
- if (isNumberType(sourceTemp)) {
+ if (isNumberType(source)) {
// use a move
Instruction::Move move;
- move.source = getParam(sourceTemp);
- move.result = getResultParam(targetTemp);
+ move.source = getParam(source);
+ move.result = getResultParam(target);
if (move.source != move.result)
addInstruction(move);
return;
}
Instruction::UPlus uplus;
- uplus.source = getParam(sourceTemp);
- uplus.result = getResultParam(targetTemp);
+ uplus.source = getParam(source);
+ uplus.result = getResultParam(target);
addInstruction(uplus);
return;
}
case IR::OpCompl: {
// ### enabling this fails in some cases, where apparently the value is not a int at runtime
- if (0 && isIntegerType(sourceTemp)) {
+ if (0 && isIntegerType(source)) {
Instruction::UComplInt unot;
- unot.source = getParam(sourceTemp);
- unot.result = getResultParam(targetTemp);
+ unot.source = getParam(source);
+ unot.result = getResultParam(target);
addInstruction(unot);
return;
}
Instruction::UCompl ucompl;
- ucompl.source = getParam(sourceTemp);
- ucompl.result = getResultParam(targetTemp);
+ ucompl.source = getParam(source);
+ ucompl.result = getResultParam(target);
addInstruction(ucompl);
return;
}
case IR::OpIncrement: {
Instruction::Increment inc;
- inc.source = getParam(sourceTemp);
- inc.result = getResultParam(targetTemp);
+ inc.source = getParam(source);
+ inc.result = getResultParam(target);
addInstruction(inc);
return;
}
case IR::OpDecrement: {
Instruction::Decrement dec;
- dec.source = getParam(sourceTemp);
- dec.result = getResultParam(targetTemp);
+ dec.source = getParam(source);
+ dec.result = getResultParam(target);
addInstruction(dec);
return;
}
@@ -858,12 +870,12 @@ void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *
Q_ASSERT(!"unreachable");
}
-void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
binopHelper(oper, leftSource, rightSource, target);
}
-Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
if (oper == IR::OpAdd) {
Instruction::Add add;
@@ -1103,7 +1115,7 @@ void InstructionSelection::visitRet(IR::Ret *s)
addInstruction(ret);
}
-void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
if (useFastLookups && func->global) {
Instruction::CallGlobalLookup call;
@@ -1123,7 +1135,7 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args
}
void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
- IR::Temp *result)
+ IR::Expr *result)
{
Instruction::CallBuiltinTypeofMember call;
call.base = getParam(base);
@@ -1133,7 +1145,7 @@ void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString
}
void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
- IR::Temp *result)
+ IR::Expr *result)
{
Instruction::CallBuiltinTypeofSubscript call;
call.base = getParam(base);
@@ -1142,7 +1154,7 @@ void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *
addInstruction(call);
}
-void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
Instruction::CallBuiltinTypeofName call;
call.name = registerString(name);
@@ -1150,7 +1162,7 @@ void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp *
addInstruction(call);
}
-void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
Instruction::CallBuiltinTypeofValue call;
call.value = getParam(value);
@@ -1158,7 +1170,7 @@ void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *res
addInstruction(call);
}
-void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
Instruction::CallBuiltinDeleteMember call;
call.base = getParam(base);
@@ -1167,8 +1179,8 @@ void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString
addInstruction(call);
}
-void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index,
- IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
+ IR::Expr *result)
{
Instruction::CallBuiltinDeleteSubscript call;
call.base = getParam(base);
@@ -1177,7 +1189,7 @@ void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *
addInstruction(call);
}
-void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
Instruction::CallBuiltinDeleteName call;
call.name = registerString(name);
@@ -1185,7 +1197,7 @@ void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp *
addInstruction(call);
}
-void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
{
Instruction::MoveConst move;
move.source = QV4::Encode(false);
@@ -1217,7 +1229,7 @@ void InstructionSelection::callBuiltinReThrow()
}
}
-void InstructionSelection::callBuiltinUnwindException(IR::Temp *result)
+void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
{
Instruction::CallBuiltinUnwindException call;
call.result = getResultParam(result);
@@ -1232,7 +1244,7 @@ void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionNam
addInstruction(call);
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
{
Instruction::CallBuiltinForeachIteratorObject call;
call.arg = getParam(arg);
@@ -1240,7 +1252,7 @@ void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::T
addInstruction(call);
}
-void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
{
Instruction::CallBuiltinForeachNextPropertyName call;
call.arg = getParam(arg);
@@ -1248,7 +1260,7 @@ void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR:
addInstruction(call);
}
-void InstructionSelection::callBuiltinPushWithScope(IR::Temp *arg)
+void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
{
Instruction::CallBuiltinPushScope call;
call.arg = getParam(arg);
@@ -1269,7 +1281,7 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
addInstruction(call);
}
-void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args)
+void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
{
Instruction::CallBuiltinDefineArray call;
prepareCallArgs(args, call.argc, &call.args);
@@ -1277,7 +1289,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
addInstruction(call);
}
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
+void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
{
int argLocation = outgoingArgumentTempStart();
@@ -1397,7 +1409,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
addInstruction(call);
}
-void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result)
+void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
{
Instruction::CallBuiltinSetupArgumentsObject call;
call.result = getResultParam(result);
@@ -1475,16 +1487,22 @@ Param InstructionSelection::getParam(IR::Expr *e) {
return Param::createConstant(idx);
} else if (IR::Temp *t = e->asTemp()) {
switch (t->kind) {
- case IR::Temp::Formal:
- case IR::Temp::ScopedFormal: return Param::createArgument(t->index, t->scope);
- case IR::Temp::Local: return Param::createLocal(t->index);
- case IR::Temp::ScopedLocal: return Param::createScopedLocal(t->index, t->scope);
case IR::Temp::StackSlot:
return Param::createTemp(t->index);
default:
Q_UNREACHABLE();
return Param();
}
+ } else if (IR::ArgLocal *al = e->asArgLocal()) {
+ switch (al->kind) {
+ case IR::ArgLocal::Formal:
+ case IR::ArgLocal::ScopedFormal: return Param::createArgument(al->index, al->scope);
+ case IR::ArgLocal::Local: return Param::createLocal(al->index);
+ case IR::ArgLocal::ScopedLocal: return Param::createScopedLocal(al->index, al->scope);
+ default:
+ Q_UNREACHABLE();
+ return Param();
+ }
} else {
Q_UNIMPLEMENTED();
return Param();
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 0aa1972fb4..d64c604aba 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -80,60 +80,60 @@ protected:
virtual void visitCJump(IR::CJump *);
virtual void visitRet(IR::Ret *);
- virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result);
- virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result);
- virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result);
- virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result);
- virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result);
- virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result);
- virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result);
- virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result);
- virtual void callBuiltinDeleteValue(IR::Temp *result);
+ virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result);
+ virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result);
+ virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
+ virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result);
+ virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result);
+ virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result);
+ virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
+ virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result);
+ virtual void callBuiltinDeleteValue(IR::Expr *result);
virtual void callBuiltinThrow(IR::Expr *arg);
virtual void callBuiltinReThrow();
- virtual void callBuiltinUnwindException(IR::Temp *);
+ virtual void callBuiltinUnwindException(IR::Expr *);
virtual void callBuiltinPushCatchScope(const QString &exceptionName);
- virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result);
- virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
- virtual void callBuiltinPushWithScope(IR::Temp *arg);
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result);
+ virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result);
+ virtual void callBuiltinPushWithScope(IR::Expr *arg);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
- virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
- virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
- virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
+ virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args);
+ virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
+ virtual void callBuiltinSetupArgumentObject(IR::Expr *result);
virtual void callBuiltinConvertThisToObject();
- virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
- virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result);
- virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result);
- virtual void convertType(IR::Temp *source, IR::Temp *target);
- virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result);
- virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result);
- virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
- virtual void loadThisObject(IR::Temp *temp);
- virtual void loadQmlIdArray(IR::Temp *temp);
- virtual void loadQmlImportedScripts(IR::Temp *temp);
- virtual void loadQmlContextObject(IR::Temp *temp);
- virtual void loadQmlScopeObject(IR::Temp *temp);
- virtual void loadQmlSingleton(const QString &name, IR::Temp *temp);
- virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp);
- virtual void loadString(const QString &str, IR::Temp *targetTemp);
- virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
- virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp);
+ virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
+ virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
+ virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result);
+ virtual void convertType(IR::Expr *source, IR::Expr *target);
+ virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result);
+ virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
+ virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
+ virtual void loadThisObject(IR::Expr *e);
+ virtual void loadQmlIdArray(IR::Expr *e);
+ virtual void loadQmlImportedScripts(IR::Expr *e);
+ virtual void loadQmlContextObject(IR::Expr *e);
+ virtual void loadQmlScopeObject(IR::Expr *e);
+ virtual void loadQmlSingleton(const QString &name, IR::Expr *e);
+ virtual void loadConst(IR::Const *sourceConst, IR::Expr *e);
+ virtual void loadString(const QString &str, IR::Expr *target);
+ virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target);
+ virtual void getActivationProperty(const IR::Name *name, IR::Expr *target);
virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
- virtual void initClosure(IR::Closure *closure, IR::Temp *target);
- virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target);
+ virtual void initClosure(IR::Closure *closure, IR::Expr *target);
+ virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target);
- virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target);
+ virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
+ virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target);
virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex);
- virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+ virtual void copyValue(IR::Expr *source, IR::Expr *target);
+ virtual void swapValues(IR::Expr *source, IR::Expr *target);
+ virtual void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target);
+ virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
private:
- Param binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+ Param binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
struct Instruction {
#define MOTH_INSTR_DATA_TYPEDEF(I, FMT) typedef InstrData<Instr::I> I;
@@ -145,7 +145,7 @@ private:
Param getParam(IR::Expr *e);
- Param getResultParam(IR::Temp *result)
+ Param getResultParam(IR::Expr *result)
{
if (result)
return getParam(result);
@@ -184,7 +184,7 @@ private:
QSet<IR::Jump *> _removableJumps;
IR::Stmt *_currentStatement;
- CompilationUnit *compilationUnit;
+ QScopedPointer<CompilationUnit> compilationUnit;
QHash<IR::Function *, QByteArray> codeRefs;
};
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 429688090c..2acf97f8c2 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -93,54 +93,54 @@ QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool gener
void IRDecoder::visitMove(IR::Move *s)
{
if (IR::Name *n = s->target->asName()) {
- if (s->source->asTemp() || s->source->asConst()) {
+ if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
setActivationProperty(s->source, *n->id);
return;
}
- } else if (IR::Temp *t = s->target->asTemp()) {
+ } else if (s->target->asTemp() || s->target->asArgLocal()) {
if (IR::Name *n = s->source->asName()) {
if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
- loadThisObject(t);
+ loadThisObject(s->target);
else if (n->builtin == IR::Name::builtin_qml_id_array)
- loadQmlIdArray(t);
+ loadQmlIdArray(s->target);
else if (n->builtin == IR::Name::builtin_qml_context_object)
- loadQmlContextObject(t);
+ loadQmlContextObject(s->target);
else if (n->builtin == IR::Name::builtin_qml_scope_object)
- loadQmlScopeObject(t);
+ loadQmlScopeObject(s->target);
else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object)
- loadQmlImportedScripts(t);
+ loadQmlImportedScripts(s->target);
else if (n->qmlSingleton)
- loadQmlSingleton(*n->id, t);
+ loadQmlSingleton(*n->id, s->target);
else
- getActivationProperty(n, t);
+ getActivationProperty(n, s->target);
return;
} else if (IR::Const *c = s->source->asConst()) {
- loadConst(c, t);
+ loadConst(c, s->target);
return;
- } else if (IR::Temp *t2 = s->source->asTemp()) {
+ } else if (s->source->asTemp() || s->source->asArgLocal()) {
if (s->swap)
- swapValues(t2, t);
+ swapValues(s->source, s->target);
else
- copyValue(t2, t);
+ copyValue(s->source, s->target);
return;
} else if (IR::String *str = s->source->asString()) {
- loadString(*str->value, t);
+ loadString(*str->value, s->target);
return;
} else if (IR::RegExp *re = s->source->asRegExp()) {
- loadRegexp(re, t);
+ loadRegexp(re, s->target);
return;
} else if (IR::Closure *clos = s->source->asClosure()) {
- initClosure(clos, t);
+ initClosure(clos, s->target);
return;
} else if (IR::New *ctor = s->source->asNew()) {
if (Name *func = ctor->base->asName()) {
- constructActivationProperty(func, ctor->args, t);
+ constructActivationProperty(func, ctor->args, s->target);
return;
} else if (IR::Member *member = ctor->base->asMember()) {
- constructProperty(member->base->asTemp(), *member->name, ctor->args, t);
+ constructProperty(member->base, *member->name, ctor->args, s->target);
return;
- } else if (IR::Temp *value = ctor->base->asTemp()) {
- constructValue(value, ctor->args, t);
+ } else if (ctor->base->asTemp() || ctor->base->asArgLocal()) {
+ constructValue(ctor->base, ctor->args, s->target);
return;
}
} else if (IR::Member *m = s->source->asMember()) {
@@ -152,6 +152,7 @@ void IRDecoder::visitMove(IR::Move *s)
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
+ const bool isSingletonProperty = m->kind == IR::Member::MemberOfSingletonObject;
if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
if (m->kind == IR::Member::MemberOfQmlContextObject) {
@@ -162,46 +163,44 @@ void IRDecoder::visitMove(IR::Move *s)
captureRequired = false;
}
}
- getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t);
+ getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target);
#endif // V4_BOOTSTRAP
return;
- } else if (m->base->asTemp() || m->base->asConst()) {
- getProperty(m->base, *m->name, t);
+ } else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
+ getProperty(m->base, *m->name, s->target);
return;
}
} else if (IR::Subscript *ss = s->source->asSubscript()) {
- getElement(ss->base, ss->index, t);
+ getElement(ss->base, ss->index, s->target);
return;
} else if (IR::Unop *u = s->source->asUnop()) {
- if (IR::Temp *e = u->expr->asTemp()) {
- unop(u->op, e, t);
- return;
- }
+ unop(u->op, u->expr, s->target);
+ return;
} else if (IR::Binop *b = s->source->asBinop()) {
- binop(b->op, b->left, b->right, t);
+ binop(b->op, b->left, b->right, s->target);
return;
} else if (IR::Call *c = s->source->asCall()) {
if (c->base->asName()) {
- callBuiltin(c, t);
+ callBuiltin(c, s->target);
return;
} else if (Member *member = c->base->asMember()) {
- callProperty(member->base, *member->name, c->args, t);
+ callProperty(member->base, *member->name, c->args, s->target);
return;
} else if (Subscript *ss = c->base->asSubscript()) {
- callSubscript(ss->base, ss->index, c->args, t);
+ callSubscript(ss->base, ss->index, c->args, s->target);
return;
- } else if (IR::Temp *value = c->base->asTemp()) {
- callValue(value, c->args, t);
+ } else if (c->base->asTemp() || c->base->asArgLocal()) {
+ callValue(c->base, c->args, s->target);
return;
}
} else if (IR::Convert *c = s->source->asConvert()) {
- Q_ASSERT(c->expr->asTemp());
- convertType(c->expr->asTemp(), t);
+ Q_ASSERT(c->expr->asTemp() || c->expr->asArgLocal());
+ convertType(c->expr, s->target);
return;
}
} else if (IR::Member *m = s->target->asMember()) {
- if (m->base->asTemp() || m->base->asConst()) {
- if (s->source->asTemp() || s->source->asConst()) {
+ if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) {
+ if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
Q_ASSERT(m->kind != IR::Member::MemberOfEnum);
const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
if (m->property && attachedPropertiesId == 0) {
@@ -218,7 +217,7 @@ void IRDecoder::visitMove(IR::Move *s)
}
}
} else if (IR::Subscript *ss = s->target->asSubscript()) {
- if (s->source->asTemp() || s->source->asConst()) {
+ if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) {
setElement(s->source, ss->base, ss->index);
return;
}
@@ -226,7 +225,7 @@ void IRDecoder::visitMove(IR::Move *s)
// For anything else...:
Q_UNIMPLEMENTED();
- s->dump(qout, IR::Stmt::MIR);
+ IRPrinter(&qout).print(s);
qout << endl;
Q_ASSERT(!"TODO");
}
@@ -241,22 +240,22 @@ void IRDecoder::visitExp(IR::Exp *s)
// These are calls where the result is ignored.
if (c->base->asName()) {
callBuiltin(c, 0);
- } else if (Temp *value = c->base->asTemp()) {
- callValue(value, c->args, 0);
+ } else if (c->base->asTemp() || c->base->asArgLocal() || c->base->asConst()) {
+ callValue(c->base, c->args, 0);
} else if (Member *member = c->base->asMember()) {
- Q_ASSERT(member->base->asTemp());
- callProperty(member->base->asTemp(), *member->name, c->args, 0);
+ Q_ASSERT(member->base->asTemp() || member->base->asArgLocal());
+ callProperty(member->base, *member->name, c->args, 0);
} else if (Subscript *s = c->base->asSubscript()) {
callSubscript(s->base, s->index, c->args, 0);
} else {
- Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
}
} else {
- Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
}
}
-void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
+void IRDecoder::callBuiltin(IR::Call *call, Expr *result)
{
IR::Name *baseName = call->base->asName();
Q_ASSERT(baseName != 0);
@@ -276,7 +275,9 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
} else if (IR::Name *n = call->args->expr->asName()) {
callBuiltinTypeofName(*n->id, result);
return;
- } else if (call->args->expr->asTemp() || call->args->expr->asConst()){
+ } else if (call->args->expr->asTemp() ||
+ call->args->expr->asConst() ||
+ call->args->expr->asArgLocal()) {
callBuiltinTypeofValue(call->args->expr, result);
return;
}
@@ -284,15 +285,16 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
case IR::Name::builtin_delete: {
if (IR::Member *m = call->args->expr->asMember()) {
- callBuiltinDeleteMember(m->base->asTemp(), *m->name, result);
+ callBuiltinDeleteMember(m->base, *m->name, result);
return;
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
- callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index, result);
+ callBuiltinDeleteSubscript(ss->base, ss->index, result);
return;
} else if (IR::Name *n = call->args->expr->asName()) {
callBuiltinDeleteName(*n->id, result);
return;
- } else if (call->args->expr->asTemp()){
+ } else if (call->args->expr->asTemp() ||
+ call->args->expr->asArgLocal()) {
// TODO: should throw in strict mode
callBuiltinDeleteValue(result);
return;
@@ -301,7 +303,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
case IR::Name::builtin_throw: {
IR::Expr *arg = call->args->expr;
- Q_ASSERT(arg->asTemp() || arg->asConst());
+ Q_ASSERT(arg->asTemp() || arg->asConst() || arg->asArgLocal());
callBuiltinThrow(arg);
} return;
@@ -326,14 +328,15 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
} return;
case IR::Name::builtin_foreach_next_property_name: {
- IR::Temp *arg = call->args->expr->asTemp();
+ IR::Expr *arg = call->args->expr;
Q_ASSERT(arg != 0);
callBuiltinForeachNextPropertyname(arg, result);
} return;
case IR::Name::builtin_push_with_scope: {
- IR::Temp *arg = call->args->expr->asTemp();
- Q_ASSERT(arg != 0);
- callBuiltinPushWithScope(arg);
+ if (call->args->expr->asTemp() || call->args->expr->asArgLocal())
+ callBuiltinPushWithScope(call->args->expr);
+ else
+ Q_UNIMPLEMENTED();
} return;
case IR::Name::builtin_pop_scope:
@@ -402,7 +405,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result)
}
Q_UNIMPLEMENTED();
- call->dump(qout); qout << endl;
+ IRPrinter(&qout).print(call); qout << endl;
Q_ASSERT(!"TODO!");
Q_UNREACHABLE();
}
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 74e6ba8200..854fc5c444 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -112,60 +112,60 @@ public: // visitor methods for StmtVisitor:
virtual void visitExp(IR::Exp *s);
public: // to implement by subclasses:
- virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result) = 0;
- virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result) = 0;
- virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result) = 0;
- virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result) = 0;
- virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result) = 0;
- virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result) = 0;
- virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result) = 0;
- virtual void callBuiltinDeleteValue(IR::Temp *result) = 0;
+ virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) = 0;
+ virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) = 0;
+ virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result) = 0;
+ virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) = 0;
+ virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) = 0;
+ virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) = 0;
+ virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result) = 0;
+ virtual void callBuiltinDeleteValue(IR::Expr *result) = 0;
virtual void callBuiltinThrow(IR::Expr *arg) = 0;
virtual void callBuiltinReThrow() = 0;
- virtual void callBuiltinUnwindException(IR::Temp *) = 0;
+ virtual void callBuiltinUnwindException(IR::Expr *) = 0;
virtual void callBuiltinPushCatchScope(const QString &exceptionName) = 0;
- virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result) = 0;
- virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) = 0;
- virtual void callBuiltinPushWithScope(IR::Temp *arg) = 0;
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) = 0;
+ virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) = 0;
+ virtual void callBuiltinPushWithScope(IR::Expr *arg) = 0;
virtual void callBuiltinPopScope() = 0;
virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
- virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) = 0;
- virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) = 0;
- virtual void callBuiltinSetupArgumentObject(IR::Temp *result) = 0;
+ virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) = 0;
+ virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) = 0;
+ virtual void callBuiltinSetupArgumentObject(IR::Expr *result) = 0;
virtual void callBuiltinConvertThisToObject() = 0;
- virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void convertType(IR::Temp *source, IR::Temp *target) = 0;
- virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) = 0;
- virtual void loadThisObject(IR::Temp *temp) = 0;
- virtual void loadQmlIdArray(IR::Temp *temp) = 0;
- virtual void loadQmlImportedScripts(IR::Temp *temp) = 0;
- virtual void loadQmlContextObject(IR::Temp *temp) = 0;
- virtual void loadQmlScopeObject(IR::Temp *temp) = 0;
- virtual void loadQmlSingleton(const QString &name, IR::Temp *temp) = 0;
- virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) = 0;
- virtual void loadString(const QString &str, IR::Temp *targetTemp) = 0;
- virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) = 0;
- virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp) = 0;
+ virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void convertType(IR::Expr *source, IR::Expr *target) = 0;
+ virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0;
+ virtual void loadThisObject(IR::Expr *target) = 0;
+ virtual void loadQmlIdArray(IR::Expr *target) = 0;
+ virtual void loadQmlImportedScripts(IR::Expr *target) = 0;
+ virtual void loadQmlContextObject(IR::Expr *target) = 0;
+ virtual void loadQmlScopeObject(IR::Expr *target) = 0;
+ virtual void loadQmlSingleton(const QString &name, IR::Expr *target) = 0;
+ virtual void loadConst(IR::Const *sourceConst, IR::Expr *target) = 0;
+ virtual void loadString(const QString &str, IR::Expr *target) = 0;
+ virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) = 0;
+ virtual void getActivationProperty(const IR::Name *name, IR::Expr *target) = 0;
virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0;
- virtual void initClosure(IR::Closure *closure, IR::Temp *target) = 0;
- virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target) = 0;
- virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *targetTemp) = 0;
+ virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0;
+ virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0;
+ virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0;
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0;
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0;
- virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target) = 0;
+ virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) = 0;
virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) = 0;
- virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0;
- virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0;
- virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0;
- virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) = 0;
+ virtual void copyValue(IR::Expr *source, IR::Expr *target) = 0;
+ virtual void swapValues(IR::Expr *source, IR::Expr *target) = 0;
+ virtual void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) = 0;
+ virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) = 0;
protected:
- virtual void callBuiltin(IR::Call *c, IR::Temp *result);
+ virtual void callBuiltin(IR::Call *c, IR::Expr *result);
IR::Function *_function; // subclass needs to set
};
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 09b98a18d1..483e0eb8b4 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -153,6 +153,7 @@ protected:
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(IR::Name *) {}
virtual void visitTemp(IR::Temp *e) { renumber(e); }
+ virtual void visitArgLocal(IR::ArgLocal *) {}
virtual void visitClosure(IR::Closure *) {}
virtual void visitConvert(IR::Convert *e) { e->expr->accept(this); }
virtual void visitUnop(IR::Unop *e) { e->expr->accept(this); }
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index f81985c07d..4b26ff20b7 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -45,6 +45,8 @@
#ifndef V4_BOOTSTRAP
#include <private/qqmlpropertycache_p.h>
#endif
+
+#include <QtCore/QBuffer>
#include <QtCore/qtextstream.h>
#include <QtCore/qdebug.h>
#include <QtCore/qset.h>
@@ -231,6 +233,7 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
virtual void visitRegExp(RegExp *) {}
virtual void visitName(Name *) {}
virtual void visitTemp(Temp *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e)
@@ -275,104 +278,6 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
}
};
-static QString dumpStart(const Expr *e) {
- if (e->type == UnknownType)
-// return QStringLiteral("**UNKNOWN**");
- return QString();
-
- QString result = typeName(e->type);
-#ifndef V4_BOOTSTRAP
- const Temp *temp = const_cast<Expr*>(e)->asTemp();
- if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
- result += QLatin1Char('<');
- result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
- result += QLatin1Char('>');
- }
-#endif
- result += QLatin1Char('{');
- return result;
-}
-
-static const char *dumpEnd(const Expr *e) {
- if (e->type == UnknownType)
- return "";
- else
- return "}";
-}
-
-void Const::dump(QTextStream &out) const
-{
- if (type != UndefinedType && type != NullType)
- out << dumpStart(this);
- switch (type) {
- case QV4::IR::UndefinedType:
- out << "undefined";
- break;
- case QV4::IR::NullType:
- out << "null";
- break;
- case QV4::IR::BoolType:
- out << (value ? "true" : "false");
- break;
- case QV4::IR::MissingType:
- out << "missing";
- break;
- default:
- if (int(value) == 0 && int(value) == value) {
- if (isNegative(value))
- out << "-0";
- else
- out << "0";
- } else {
- out << QString::number(value, 'g', 16);
- }
- break;
- }
- if (type != UndefinedType && type != NullType)
- out << dumpEnd(this);
-}
-
-void String::dump(QTextStream &out) const
-{
- out << '"' << escape(*value) << '"';
-}
-
-QString String::escape(const QString &s)
-{
- QString r;
- for (int i = 0; i < s.length(); ++i) {
- const QChar ch = s.at(i);
- if (ch == QLatin1Char('\n'))
- r += QStringLiteral("\\n");
- else if (ch == QLatin1Char('\r'))
- r += QStringLiteral("\\r");
- else if (ch == QLatin1Char('\\'))
- r += QStringLiteral("\\\\");
- else if (ch == QLatin1Char('"'))
- r += QStringLiteral("\\\"");
- else if (ch == QLatin1Char('\''))
- r += QStringLiteral("\\'");
- else
- r += ch;
- }
- return r;
-}
-
-void RegExp::dump(QTextStream &out) const
-{
- char f[3];
- int i = 0;
- if (flags & RegExp_Global)
- f[i++] = 'g';
- if (flags & RegExp_IgnoreCase)
- f[i++] = 'i';
- if (flags & RegExp_Multiline)
- f[i++] = 'm';
- f[i] = 0;
-
- out << '/' << *value << '/' << f;
-}
-
void Name::initGlobal(const QString *id, quint32 line, quint32 column)
{
this->id = id;
@@ -453,185 +358,11 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_(###FIXME)";
};
-void Name::dump(QTextStream &out) const
-{
- if (id)
- out << *id;
- else
- out << builtin_to_string(builtin);
-}
-
-void Temp::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- switch (kind) {
- case Formal: out << '#' << index; break;
- case ScopedFormal: out << '#' << index
- << '@' << scope; break;
- case Local: out << '$' << index; break;
- case ScopedLocal: out << '$' << index
- << '@' << scope; break;
- case VirtualRegister: out << '%' << index; break;
- case PhysicalRegister: out << (type == DoubleType ? "fp" : "r")
- << index; break;
- case StackSlot: out << '&' << index; break;
- default: out << "INVALID";
- }
- out << dumpEnd(this);
-}
-
bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
{
if (t1.kind < t2.kind) return true;
if (t1.kind > t2.kind) return false;
- if (t1.index < t2.index) return true;
- if (t1.index > t2.index) return false;
- return t1.scope < t2.scope;
-}
-
-void Closure::dump(QTextStream &out) const
-{
- QString name = functionName ? *functionName : QString();
- if (name.isEmpty())
- name.sprintf("%x", value);
- out << "closure(" << name << ')';
-}
-
-void Convert::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- out << "convert(";
- expr->dump(out);
- out << ')' << dumpEnd(this);
-}
-
-void Unop::dump(QTextStream &out) const
-{
- out << dumpStart(this) << opname(op);
- expr->dump(out);
- out << dumpEnd(this);
-}
-
-void Binop::dump(QTextStream &out) const
-{
- out << dumpStart(this);
- left->dump(out);
- out << ' ' << opname(op) << ' ';
- right->dump(out);
- out << dumpEnd(this);
-}
-
-void Call::dump(QTextStream &out) const
-{
- base->dump(out);
- out << '(';
- for (ExprList *it = args; it; it = it->next) {
- if (it != args)
- out << ", ";
- it->expr->dump(out);
- }
- out << ')';
-}
-
-void New::dump(QTextStream &out) const
-{
- out << "new ";
- base->dump(out);
- out << '(';
- for (ExprList *it = args; it; it = it->next) {
- if (it != args)
- out << ", ";
- it->expr->dump(out);
- }
- out << ')';
-}
-
-void Subscript::dump(QTextStream &out) const
-{
- base->dump(out);
- out << '[';
- index->dump(out);
- out << ']';
-}
-
-void Member::dump(QTextStream &out) const
-{
- if (kind != MemberOfEnum && attachedPropertiesIdOrEnumValue != 0 && !base->asTemp())
- out << "[[attached property from " << attachedPropertiesIdOrEnumValue << "]]";
- else
- base->dump(out);
- out << '.' << *name;
-#ifndef V4_BOOTSTRAP
- if (property)
- out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
-#endif
-}
-
-void Exp::dump(QTextStream &out, Mode)
-{
- out << "(void) ";
- expr->dump(out);
- out << ';';
-}
-
-void Move::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
-
- target->dump(out);
- out << ' ';
- if (swap)
- out << "<=> ";
- else
- out << "= ";
-// if (source->type != target->type)
-// out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
- source->dump(out);
-// if (source->type != target->type)
-// out << ')';
- out << ';';
-}
-
-void Jump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "goto " << 'L' << target->index() << ';';
-}
-
-void CJump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "if (";
- cond->dump(out);
- if (mode == HIR)
- out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';';
- else
- out << ") goto " << 'L' << iftrue->index() << ";";
-}
-
-void Ret::dump(QTextStream &out, Mode)
-{
- out << "return";
- if (expr) {
- out << ' ';
- expr->dump(out);
- }
- out << ';';
-}
-
-void Phi::dump(QTextStream &out, Stmt::Mode mode)
-{
- Q_UNUSED(mode);
-
- targetTemp->dump(out);
- out << " = phi(";
- for (int i = 0, ei = d->incoming.size(); i < ei; ++i) {
- if (i > 0)
- out << ", ";
- if (d->incoming[i])
- d->incoming[i]->dump(out);
- }
- out << ");";
+ return t1.index < t2.index;
}
Function *Module::newFunction(const QString &name, Function *outer)
@@ -680,6 +411,7 @@ Function::Function(Module *module, Function *outer, const QString &name)
, line(-1)
, column(-1)
, _allBasicBlocks(0)
+ , _statementCount(0)
{
this->name = newString(name);
_basicBlocks.reserve(8);
@@ -704,9 +436,9 @@ const QString *Function::newString(const QString &text)
return &*strings.insert(text);
}
-BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
+BasicBlock *Function::newBasicBlock(BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
- BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
+ BasicBlock *block = new BasicBlock(this, catchBlock);
return mode == InsertBlock ? addBasicBlock(block) : block;
}
@@ -734,21 +466,6 @@ int Function::liveBasicBlocksCount() const
return count;
}
-void Function::dump(QTextStream &out, Stmt::Mode mode)
-{
- QString n = name ? *name : QString();
- if (n.isEmpty())
- n.sprintf("%p", this);
- out << "function " << n << "() {" << endl;
- foreach (const QString *formal, formals)
- out << "\treceive " << *formal << ';' << endl;
- foreach (const QString *local, locals)
- out << "\tlocal " << *local << ';' << endl;
- foreach (BasicBlock *bb, basicBlocks())
- bb->dump(out, mode);
- out << '}' << endl;
-}
-
void Function::removeSharedExpressions()
{
RemoveSharedExpressions removeSharedExpressions;
@@ -793,23 +510,23 @@ Temp *BasicBlock::TEMP(unsigned index)
{
Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
- e->init(Temp::VirtualRegister, index, 0);
+ e->init(Temp::VirtualRegister, index);
return e;
}
-Temp *BasicBlock::ARG(unsigned index, unsigned scope)
+ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope)
{
Q_ASSERT(!isRemoved());
- Temp *e = function->New<Temp>();
- e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
+ ArgLocal *e = function->New<ArgLocal>();
+ e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope);
return e;
}
-Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
+ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope)
{
Q_ASSERT(!isRemoved());
- Temp *e = function->New<Temp>();
- e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
+ ArgLocal *e = function->New<ArgLocal>();
+ e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope);
return e;
}
@@ -949,7 +666,7 @@ Stmt *BasicBlock::EXP(Expr *expr)
if (isTerminated())
return 0;
- Exp *s = function->New<Exp>();
+ Exp *s = function->NewStmt<Exp>();
s->init(expr);
appendStatement(s);
return s;
@@ -961,7 +678,7 @@ Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
if (isTerminated())
return 0;
- Move *s = function->New<Move>();
+ Move *s = function->NewStmt<Move>();
s->init(target, source);
appendStatement(s);
return s;
@@ -973,7 +690,7 @@ Stmt *BasicBlock::JUMP(BasicBlock *target)
if (isTerminated())
return 0;
- Jump *s = function->New<Jump>();
+ Jump *s = function->NewStmt<Jump>();
s->init(target);
appendStatement(s);
@@ -997,7 +714,7 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
return JUMP(iftrue);
}
- CJump *s = function->New<CJump>();
+ CJump *s = function->NewStmt<CJump>();
s->init(cond, iftrue, iffalse);
appendStatement(s);
@@ -1022,29 +739,12 @@ Stmt *BasicBlock::RET(Temp *expr)
if (isTerminated())
return 0;
- Ret *s = function->New<Ret>();
+ Ret *s = function->NewStmt<Ret>();
s->init(expr);
appendStatement(s);
return s;
}
-void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
-{
- out << 'L' << index() << ':';
- if (catchBlock)
- out << " (catchBlock L" << catchBlock->index() << ")";
- out << endl;
- foreach (Stmt *s, statements()) {
- out << '\t';
- s->dump(out, mode);
-
- if (s->location.isValid())
- out << " // line: " << s->location.startLine << " ; column: " << s->location.startColumn;
-
- out << endl;
- }
-}
-
void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
{
Q_ASSERT(!isRemoved());
@@ -1071,6 +771,14 @@ void BasicBlock::prependStatement(Stmt *stmt)
_statements.prepend(stmt);
}
+void BasicBlock::prependStatements(const QVector<Stmt *> &stmts)
+{
+ Q_ASSERT(!isRemoved());
+ QVector<Stmt *> newStmts = stmts;
+ newStmts += _statements;
+ _statements = newStmts;
+}
+
void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt)
{
int idx = _statements.indexOf(before);
@@ -1156,6 +864,11 @@ void CloneExpr::visitTemp(Temp *e)
cloned = cloneTemp(e, block->function);
}
+void CloneExpr::visitArgLocal(ArgLocal *e)
+{
+ cloned = cloneArgLocal(e, block->function);
+}
+
void CloneExpr::visitClosure(Closure *e)
{
cloned = block->CLOSURE(e->value);
@@ -1197,6 +910,401 @@ void CloneExpr::visitMember(Member *e)
cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue);
}
+IRPrinter::IRPrinter(QTextStream *out)
+ : out(out)
+ , printElse(true)
+{
+}
+
+IRPrinter::~IRPrinter()
+{
+}
+
+void IRPrinter::print(Stmt *s)
+{
+ s->accept(this);
+}
+
+void IRPrinter::print(const Expr &e)
+{
+ const_cast<Expr *>(&e)->accept(this);
+}
+
+void IRPrinter::print(Expr *e)
+{
+ e->accept(this);
+}
+
+void IRPrinter::print(Function *f)
+{
+ QString n = f->name ? *f->name : QString();
+ if (n.isEmpty())
+ n.sprintf("%p", f);
+ *out << "function " << n << '(';
+
+ for (int i = 0; i < f->formals.size(); ++i) {
+ if (i != 0)
+ *out << ", ";
+ *out << *f->formals.at(i);
+ }
+ *out << ')' << endl
+ << '{' << endl;
+
+ foreach (const QString *local, f->locals)
+ *out << " var " << *local << ';' << endl;
+
+ foreach (BasicBlock *bb, f->basicBlocks())
+ if (!bb->isRemoved())
+ print(bb);
+ *out << '}' << endl;
+}
+
+void IRPrinter::print(BasicBlock *bb)
+{
+ bool prevPrintElse = false;
+ std::swap(printElse, prevPrintElse);
+ printBlockStart(bb);
+
+ foreach (Stmt *s, bb->statements()) {
+ QByteArray str;
+ QBuffer buf(&str);
+ buf.open(QIODevice::WriteOnly);
+ QTextStream os(&buf);
+ QTextStream *prevOut = &os;
+ std::swap(out, prevOut);
+ addStmtNr(s);
+ s->accept(this);
+ if (s->location.isValid()) {
+ out->flush();
+ for (int i = 58 - str.length(); i > 0; --i)
+ *out << ' ';
+ *out << " // line: " << s->location.startLine << " column: " << s->location.startColumn;
+ }
+
+ out->flush();
+ std::swap(out, prevOut);
+
+ *out << " " << str;
+ *out << endl;
+
+ if (s->asCJump()) {
+ *out << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
+ }
+ }
+
+ std::swap(printElse, prevPrintElse);
+}
+
+void IRPrinter::visitExp(Exp *s)
+{
+ *out << "(void) ";
+ s->expr->accept(this);
+ *out << ';';
+}
+
+void IRPrinter::visitMove(Move *s)
+{
+ s->target->accept(this);
+ *out << ' ';
+ if (s->swap)
+ *out << "<=> ";
+ else
+ *out << "= ";
+ s->source->accept(this);
+ *out << ';';
+}
+
+void IRPrinter::visitJump(Jump *s)
+{
+ *out << "goto L" << s->target->index() << ';';
+}
+
+void IRPrinter::visitCJump(CJump *s)
+{
+ *out << "if (";
+ s->cond->accept(this);
+ *out << ") goto L" << s->iftrue->index() << ';';
+ if (printElse)
+ *out << " else goto L" << s->iffalse->index() << ';';
+}
+
+void IRPrinter::visitRet(Ret *s)
+{
+ *out << "return";
+ if (s->expr) {
+ *out << ' ';
+ s->expr->accept(this);
+ }
+ *out << ';';
+}
+
+void IRPrinter::visitPhi(Phi *s)
+{
+ s->targetTemp->accept(this);
+ *out << " = phi(";
+ for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) {
+ if (i > 0)
+ *out << ", ";
+ if (s->d->incoming[i])
+ s->d->incoming[i]->accept(this);
+ }
+ *out << ");";
+}
+
+void IRPrinter::visitConst(Const *e)
+{
+ if (e->type != UndefinedType && e->type != NullType)
+ *out << dumpStart(e);
+ switch (e->type) {
+ case QV4::IR::UndefinedType:
+ *out << "undefined";
+ break;
+ case QV4::IR::NullType:
+ *out << "null";
+ break;
+ case QV4::IR::BoolType:
+ *out << (e->value ? "true" : "false");
+ break;
+ case QV4::IR::MissingType:
+ *out << "missing";
+ break;
+ default:
+ if (int(e->value) == 0 && int(e->value) == e->value) {
+ if (isNegative(e->value))
+ *out << "-0";
+ else
+ *out << "0";
+ } else {
+ *out << QString::number(e->value, 'g', 16);
+ }
+ break;
+ }
+ if (e->type != UndefinedType && e->type != NullType)
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitString(String *e)
+{
+ *out << '"' << escape(*e->value) << '"';
+}
+
+void IRPrinter::visitRegExp(RegExp *e)
+{
+ char f[3];
+ int i = 0;
+ if (e->flags & RegExp::RegExp_Global)
+ f[i++] = 'g';
+ if (e->flags & RegExp::RegExp_IgnoreCase)
+ f[i++] = 'i';
+ if (e->flags & RegExp::RegExp_Multiline)
+ f[i++] = 'm';
+ f[i] = 0;
+
+ *out << '/' << *e->value << '/' << f;
+}
+
+void IRPrinter::visitName(Name *e)
+{
+ if (e->id)
+ *out << *e->id;
+ else
+ *out << builtin_to_string(e->builtin);
+}
+
+void IRPrinter::visitTemp(Temp *e)
+{
+ *out << dumpStart(e);
+ switch (e->kind) {
+ case Temp::VirtualRegister: *out << '%' << e->index; break;
+ case Temp::PhysicalRegister: *out << (e->type == DoubleType ? "fp" : "r")
+ << e->index; break;
+ case Temp::StackSlot: *out << '&' << e->index; break;
+ default: *out << "INVALID";
+ }
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitArgLocal(ArgLocal *e)
+{
+ *out << dumpStart(e);
+ switch (e->kind) {
+ case ArgLocal::Formal: *out << '#' << e->index; break;
+ case ArgLocal::ScopedFormal: *out << '#' << e->index
+ << '@' << e->scope; break;
+ case ArgLocal::Local: *out << '$' << e->index; break;
+ case ArgLocal::ScopedLocal: *out << '$' << e->index
+ << '@' << e->scope; break;
+ default: *out << "INVALID";
+ }
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitClosure(Closure *e)
+{
+ QString name = e->functionName ? *e->functionName : QString();
+ if (name.isEmpty())
+ name.sprintf("%x", e->value);
+ *out << "closure(" << name << ')';
+}
+
+void IRPrinter::visitConvert(Convert *e)
+{
+ *out << dumpStart(e);
+ *out << "convert(";
+ e->expr->accept(this);
+ *out << ')' << dumpEnd(e);
+}
+
+void IRPrinter::visitUnop(Unop *e)
+{
+ *out << dumpStart(e) << opname(e->op);
+ e->expr->accept(this);
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitBinop(Binop *e)
+{
+ *out << dumpStart(e);
+ e->left->accept(this);
+ *out << ' ' << opname(e->op) << ' ';
+ e->right->accept(this);
+ *out << dumpEnd(e);
+}
+
+void IRPrinter::visitCall(Call *e)
+{
+ e->base->accept(this);
+ *out << '(';
+ for (ExprList *it = e->args; it; it = it->next) {
+ if (it != e->args)
+ *out << ", ";
+ it->expr->accept(this);
+ }
+ *out << ')';
+}
+
+void IRPrinter::visitNew(New *e)
+{
+ *out << "new ";
+ e->base->accept(this);
+ *out << '(';
+ for (ExprList *it = e->args; it; it = it->next) {
+ if (it != e->args)
+ *out << ", ";
+ it->expr->accept(this);
+ }
+ *out << ')';
+}
+
+void IRPrinter::visitSubscript(Subscript *e)
+{
+ e->base->accept(this);
+ *out << '[';
+ e->index->accept(this);
+ *out << ']';
+}
+
+void IRPrinter::visitMember(Member *e)
+{
+ if (e->kind != Member::MemberOfEnum
+ && e->attachedPropertiesIdOrEnumValue != 0 && !e->base->asTemp())
+ *out << "[[attached property from " << e->attachedPropertiesIdOrEnumValue << "]]";
+ else
+ e->base->accept(this);
+ *out << '.' << *e->name;
+#ifndef V4_BOOTSTRAP
+ if (e->property)
+ *out << " (meta-property " << e->property->coreIndex
+ << " <" << QMetaType::typeName(e->property->propType)
+ << ">)";
+#endif
+}
+
+QString IRPrinter::escape(const QString &s)
+{
+ QString r;
+ for (int i = 0; i < s.length(); ++i) {
+ const QChar ch = s.at(i);
+ if (ch == QLatin1Char('\n'))
+ r += QStringLiteral("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QStringLiteral("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QStringLiteral("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QStringLiteral("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QStringLiteral("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+void IRPrinter::addStmtNr(Stmt *s)
+{
+ if (s->id() >= 0)
+ *out << s->id() << ": ";
+}
+
+QString IRPrinter::dumpStart(const Expr *e)
+{
+ if (e->type == UnknownType)
+ return QString();
+
+ QString result = typeName(e->type);
+#ifndef V4_BOOTSTRAP
+ const Temp *temp = const_cast<Expr*>(e)->asTemp();
+ if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
+ result += QLatin1Char('<');
+ result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
+ result += QLatin1Char('>');
+ }
+#endif
+ result += QLatin1Char('{');
+ return result;
+}
+
+const char *IRPrinter::dumpEnd(const Expr *e)
+{
+ if (e->type == UnknownType)
+ return "";
+ else
+ return "}";
+}
+
+void IRPrinter::printBlockStart(BasicBlock *bb)
+{
+ if (bb->isRemoved()) {
+ *out << "(block has been removed)";
+ return;
+ }
+
+ QByteArray str;
+ str.append('L');
+ str.append(QByteArray::number(bb->index()));
+ str.append(':');
+ if (bb->catchBlock) {
+ str.append(" (exception handler L");
+ str.append(QByteArray::number(bb->catchBlock->index()));
+ str.append(')');
+ }
+ for (int i = 66 - str.length(); i; --i)
+ str.append(' ');
+ *out << str;
+
+ *out << "// predecessor blocks:";
+ foreach (BasicBlock *in, bb->in)
+ *out << " L" << in->index();
+ if (bb->in.isEmpty())
+ *out << " (none)";
+ if (BasicBlock *container = bb->containingGroup())
+ *out << "; container block: L" << container->index();
+ if (bb->isGroupStart())
+ *out << "; group start";
+ *out << endl;
+}
+
} // end of namespace IR
} // end of namespace QV4
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 9eff90dd30..fcdcdf9038 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -108,6 +108,7 @@ struct String;
struct RegExp;
struct Name;
struct Temp;
+struct ArgLocal;
struct Closure;
struct Convert;
struct Unop;
@@ -210,6 +211,7 @@ struct ExprVisitor {
virtual void visitRegExp(RegExp *) = 0;
virtual void visitName(Name *) = 0;
virtual void visitTemp(Temp *) = 0;
+ virtual void visitArgLocal(ArgLocal *) = 0;
virtual void visitClosure(Closure *) = 0;
virtual void visitConvert(Convert *) = 0;
virtual void visitUnop(Unop *) = 0;
@@ -260,6 +262,7 @@ struct Q_AUTOTEST_EXPORT Expr {
virtual RegExp *asRegExp() { return 0; }
virtual Name *asName() { return 0; }
virtual Temp *asTemp() { return 0; }
+ virtual ArgLocal *asArgLocal() { return 0; }
virtual Closure *asClosure() { return 0; }
virtual Convert *asConvert() { return 0; }
virtual Unop *asUnop() { return 0; }
@@ -268,7 +271,6 @@ struct Q_AUTOTEST_EXPORT Expr {
virtual New *asNew() { return 0; }
virtual Subscript *asSubscript() { return 0; }
virtual Member *asMember() { return 0; }
- virtual void dump(QTextStream &out) const = 0;
};
struct ExprList {
@@ -295,8 +297,6 @@ struct Const: Expr {
virtual void accept(ExprVisitor *v) { v->visitConst(this); }
virtual Const *asConst() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct String: Expr {
@@ -309,9 +309,6 @@ struct String: Expr {
virtual void accept(ExprVisitor *v) { v->visitString(this); }
virtual String *asString() { return this; }
-
- virtual void dump(QTextStream &out) const;
- static QString escape(const QString &s);
};
struct RegExp: Expr {
@@ -333,8 +330,6 @@ struct RegExp: Expr {
virtual void accept(ExprVisitor *v) { v->visitRegExp(this); }
virtual RegExp *asRegExp() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Name: Expr {
@@ -376,60 +371,85 @@ struct Name: Expr {
virtual void accept(ExprVisitor *v) { v->visitName(this); }
virtual bool isLValue() { return true; }
virtual Name *asName() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Q_AUTOTEST_EXPORT Temp: Expr {
enum Kind {
- Formal = 0,
- ScopedFormal,
- Local,
- ScopedLocal,
+ Invalid = 0,
VirtualRegister,
PhysicalRegister,
StackSlot
};
- unsigned index;
- unsigned scope : 27; // how many scopes outside the current one?
- unsigned kind : 3;
- unsigned isArgumentsOrEval : 1;
- unsigned isReadOnly : 1;
+ unsigned index : 28;
+ unsigned kind : 3;
+ unsigned isReadOnly : 1;
// Used when temp is used as base in member expression
MemberExpressionResolver memberResolver;
- void init(unsigned kind, unsigned index, unsigned scope)
- {
- Q_ASSERT((kind == ScopedLocal && scope != 0) ||
- (kind == ScopedFormal && scope != 0) ||
- (scope == 0));
+ Temp()
+ : index((1 << 28) - 1)
+ , kind(Invalid)
+ , isReadOnly(0)
+ {}
+ void init(unsigned kind, unsigned index)
+ {
this->kind = kind;
this->index = index;
- this->scope = scope;
- this->isArgumentsOrEval = false;
this->isReadOnly = false;
}
+ bool isInvalid() const { return kind == Invalid; }
virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
virtual bool isLValue() { return !isReadOnly; }
virtual Temp *asTemp() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
-{ return t1.index == t2.index && t1.scope == t2.scope && t1.kind == t2.kind && t1.type == t2.type; }
+{ return t1.index == t2.index && t1.kind == t2.kind && t1.type == t2.type; }
inline bool operator!=(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
{ return !(t1 == t2); }
inline uint qHash(const Temp &t, uint seed = 0) Q_DECL_NOTHROW
-{ return t.index ^ (t.kind | (t.scope << 3)) ^ seed; }
+{ return t.index ^ t.kind ^ seed; }
bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW;
+struct Q_AUTOTEST_EXPORT ArgLocal: Expr {
+ enum Kind {
+ Formal = 0,
+ ScopedFormal,
+ Local,
+ ScopedLocal
+ };
+
+ unsigned index;
+ unsigned scope : 29; // how many scopes outside the current one?
+ unsigned kind : 2;
+ unsigned isArgumentsOrEval : 1;
+
+ void init(unsigned kind, unsigned index, unsigned scope)
+ {
+ Q_ASSERT((kind == ScopedLocal && scope != 0) ||
+ (kind == ScopedFormal && scope != 0) ||
+ (scope == 0));
+
+ this->kind = kind;
+ this->index = index;
+ this->scope = scope;
+ this->isArgumentsOrEval = false;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitArgLocal(this); }
+ virtual bool isLValue() { return true; }
+ virtual ArgLocal *asArgLocal() { return this; }
+
+ bool operator==(const ArgLocal &other) const
+ { return index == other.index && scope == other.scope && kind == other.kind; }
+};
+
struct Closure: Expr {
int value; // index in _module->functions
const QString *functionName;
@@ -442,8 +462,6 @@ struct Closure: Expr {
virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
virtual Closure *asClosure() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Convert: Expr {
@@ -457,8 +475,6 @@ struct Convert: Expr {
virtual void accept(ExprVisitor *v) { v->visitConvert(this); }
virtual Convert *asConvert() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Unop: Expr {
@@ -473,8 +489,6 @@ struct Unop: Expr {
virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
virtual Unop *asUnop() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Binop: Expr {
@@ -491,8 +505,6 @@ struct Binop: Expr {
virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
virtual Binop *asBinop() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Call: Expr {
@@ -513,8 +525,6 @@ struct Call: Expr {
virtual void accept(ExprVisitor *v) { v->visitCall(this); }
virtual Call *asCall() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct New: Expr {
@@ -535,8 +545,6 @@ struct New: Expr {
virtual void accept(ExprVisitor *v) { v->visitNew(this); }
virtual New *asNew() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Subscript: Expr {
@@ -552,8 +560,6 @@ struct Subscript: Expr {
virtual void accept(ExprVisitor *v) { v->visitSubscript(this); }
virtual bool isLValue() { return true; }
virtual Subscript *asSubscript() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Member: Expr {
@@ -562,14 +568,14 @@ struct Member: Expr {
UnspecifiedMember,
MemberOfEnum,
MemberOfQmlScopeObject,
- MemberOfQmlContextObject
+ MemberOfQmlContextObject,
+ MemberOfSingletonObject
};
Expr *base;
const QString *name;
QQmlPropertyData *property;
int attachedPropertiesIdOrEnumValue; // depending on kind
- uchar memberIsEnum : 1;
uchar freeOfSideEffects : 1;
// This is set for example for for QObject properties. All sorts of extra behavior
@@ -596,7 +602,6 @@ struct Member: Expr {
this->name = name;
this->property = property;
this->attachedPropertiesIdOrEnumValue = attachedPropertiesIdOrEnumValue;
- this->memberIsEnum = false;
this->freeOfSideEffects = false;
this->inhibitTypeConversionOnWrite = property != 0;
this->kind = kind;
@@ -605,25 +610,20 @@ struct Member: Expr {
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
virtual bool isLValue() { return true; }
virtual Member *asMember() { return this; }
-
- virtual void dump(QTextStream &out) const;
};
struct Stmt {
- enum Mode {
- HIR,
- MIR
- };
-
struct Data {
QVector<Expr *> incoming; // used by Phi nodes
};
+ enum { InvalidId = -1 };
+
Data *d;
- int id;
QQmlJS::AST::SourceLocation location;
- Stmt(): d(0), id(-1) {}
+ explicit Stmt(int id): d(0), _id(id) {}
+
virtual ~Stmt()
{
#ifdef Q_CC_MSVC
@@ -641,7 +641,8 @@ struct Stmt {
virtual CJump *asCJump() { return 0; }
virtual Ret *asRet() { return 0; }
virtual Phi *asPhi() { return 0; }
- virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+
+ int id() const { return _id; }
private: // For memory management in BasicBlock
friend struct BasicBlock;
@@ -649,11 +650,17 @@ private: // For memory management in BasicBlock
delete d;
d = 0;
}
+
+private:
+ friend struct Function;
+ int _id;
};
struct Exp: Stmt {
Expr *expr;
+ Exp(int id): Stmt(id) {}
+
void init(Expr *expr)
{
this->expr = expr;
@@ -662,7 +669,6 @@ struct Exp: Stmt {
virtual void accept(StmtVisitor *v) { v->visitExp(this); }
virtual Exp *asExp() { return this; }
- virtual void dump(QTextStream &out, Mode);
};
struct Move: Stmt {
@@ -670,6 +676,8 @@ struct Move: Stmt {
Expr *source;
bool swap;
+ Move(int id): Stmt(id) {}
+
void init(Expr *target, Expr *source)
{
this->target = target;
@@ -680,12 +688,13 @@ struct Move: Stmt {
virtual void accept(StmtVisitor *v) { v->visitMove(this); }
virtual Move *asMove() { return this; }
- virtual void dump(QTextStream &out, Mode mode = HIR);
};
struct Jump: Stmt {
BasicBlock *target;
+ Jump(int id): Stmt(id) {}
+
void init(BasicBlock *target)
{
this->target = target;
@@ -695,8 +704,6 @@ struct Jump: Stmt {
virtual void accept(StmtVisitor *v) { v->visitJump(this); }
virtual Jump *asJump() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
};
struct CJump: Stmt {
@@ -704,6 +711,8 @@ struct CJump: Stmt {
BasicBlock *iftrue;
BasicBlock *iffalse;
+ CJump(int id): Stmt(id) {}
+
void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
{
this->cond = cond;
@@ -715,13 +724,13 @@ struct CJump: Stmt {
virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
virtual CJump *asCJump() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
};
struct Ret: Stmt {
Expr *expr;
+ Ret(int id): Stmt(id) {}
+
void init(Expr *expr)
{
this->expr = expr;
@@ -731,17 +740,15 @@ struct Ret: Stmt {
virtual void accept(StmtVisitor *v) { v->visitRet(this); }
virtual Ret *asRet() { return this; }
-
- virtual void dump(QTextStream &out, Mode);
};
struct Phi: Stmt {
Temp *targetTemp;
+ Phi(int id): Stmt(id) {}
+
virtual void accept(StmtVisitor *v) { v->visitPhi(this); }
virtual Phi *asPhi() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
};
struct Q_QML_PRIVATE_EXPORT Module {
@@ -775,10 +782,10 @@ public:
QVector<BasicBlock *> out;
QQmlJS::AST::SourceLocation nextLocation;
- BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
+ BasicBlock(Function *function, BasicBlock *catcher)
: function(function)
, catchBlock(catcher)
- , _containingGroup(containingLoop)
+ , _containingGroup(0)
, _index(-1)
, _isExceptionHandler(false)
, _groupStart(false)
@@ -812,6 +819,7 @@ public:
void appendStatement(Stmt *statement);
void prependStatement(Stmt *stmt);
+ void prependStatements(const QVector<Stmt *> &stmts);
void insertStatementBefore(Stmt *before, Stmt *newStmt);
void insertStatementBefore(int index, Stmt *newStmt);
void insertStatementBeforeTerminator(Stmt *stmt);
@@ -841,8 +849,8 @@ public:
unsigned newTemp();
Temp *TEMP(unsigned kind);
- Temp *ARG(unsigned index, unsigned scope);
- Temp *LOCAL(unsigned index, unsigned scope);
+ ArgLocal *ARG(unsigned index, unsigned scope);
+ ArgLocal *LOCAL(unsigned index, unsigned scope);
Expr *CONST(Type type, double value);
Expr *STRING(const QString *value);
@@ -871,8 +879,6 @@ public:
Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
Stmt *RET(Temp *expr);
- void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
-
BasicBlock *containingGroup() const
{
Q_ASSERT(!isRemoved());
@@ -994,7 +1000,10 @@ struct Function {
PropertyDependencyMap contextObjectPropertyDependencies;
PropertyDependencyMap scopeObjectPropertyDependencies;
- template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+ template <typename T> T *New() { return new (pool->allocate(sizeof(T))) T(); }
+ template <typename T> T *NewStmt() {
+ return new (pool->allocate(sizeof(T))) T(getNewStatementId());
+ }
Function(Module *module, Function *outer, const QString &name);
~Function();
@@ -1004,7 +1013,7 @@ struct Function {
DontInsertBlock
};
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
+ BasicBlock *newBasicBlock(BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
const QString *newString(const QString &text);
void RECEIVE(const QString &name) { formals.append(newString(name)); }
@@ -1024,8 +1033,6 @@ struct Function {
int liveBasicBlocksCount() const;
- void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
-
void removeSharedExpressions();
int indexOfArgument(const QStringRef &string) const;
@@ -1036,9 +1043,13 @@ struct Function {
void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
void renumberBasicBlocks();
+ unsigned getNewStatementId() { return _statementCount++; }
+ unsigned statementCount() const { return _statementCount; }
+
private:
QVector<BasicBlock *> _basicBlocks;
QVector<BasicBlock *> *_allBasicBlocks;
+ unsigned _statementCount;
};
class CloneExpr: protected IR::ExprVisitor
@@ -1088,12 +1099,20 @@ public:
static Temp *cloneTemp(Temp *t, Function *f)
{
Temp *newTemp = f->New<Temp>();
- newTemp->init(t->kind, t->index, t->scope);
+ newTemp->init(t->kind, t->index);
newTemp->type = t->type;
newTemp->memberResolver = t->memberResolver;
return newTemp;
}
+ static ArgLocal *cloneArgLocal(ArgLocal *argLocal, Function *f)
+ {
+ ArgLocal *newArgLocal = f->New<ArgLocal>();
+ newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope);
+ newArgLocal->type = argLocal->type;
+ return newArgLocal;
+ }
+
protected:
IR::ExprList *clone(IR::ExprList *list);
@@ -1102,6 +1121,7 @@ protected:
virtual void visitRegExp(RegExp *);
virtual void visitName(Name *);
virtual void visitTemp(Temp *);
+ virtual void visitArgLocal(ArgLocal *);
virtual void visitClosure(Closure *);
virtual void visitConvert(Convert *);
virtual void visitUnop(Unop *);
@@ -1116,6 +1136,54 @@ private:
IR::Expr *cloned;
};
+class IRPrinter: public StmtVisitor, public ExprVisitor
+{
+public:
+ IRPrinter(QTextStream *out);
+ virtual ~IRPrinter();
+
+ void print(Stmt *s);
+ void print(Expr *e);
+ void print(const Expr &e);
+
+ virtual void print(Function *f);
+ virtual void print(BasicBlock *bb);
+
+ virtual void visitExp(Exp *s);
+ virtual void visitMove(Move *s);
+ virtual void visitJump(Jump *s);
+ virtual void visitCJump(CJump *s);
+ virtual void visitRet(Ret *s);
+ virtual void visitPhi(Phi *s);
+
+ virtual void visitConst(Const *e);
+ virtual void visitString(String *e);
+ virtual void visitRegExp(RegExp *e);
+ virtual void visitName(Name *e);
+ virtual void visitTemp(Temp *e);
+ virtual void visitArgLocal(ArgLocal *e);
+ virtual void visitClosure(Closure *e);
+ virtual void visitConvert(Convert *e);
+ virtual void visitUnop(Unop *e);
+ virtual void visitBinop(Binop *e);
+ virtual void visitCall(Call *e);
+ virtual void visitNew(New *e);
+ virtual void visitSubscript(Subscript *e);
+ virtual void visitMember(Member *e);
+
+ static QString escape(const QString &s);
+
+protected:
+ virtual void addStmtNr(Stmt *s);
+ QString dumpStart(const Expr *e);
+ const char *dumpEnd(const Expr *e);
+ void printBlockStart(BasicBlock *bb);
+
+protected:
+ QTextStream *out;
+ bool printElse;
+};
+
} // end of namespace IR
} // end of namespace QV4
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index d7dbfac50b..5e9401afc3 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -39,9 +39,10 @@
**
****************************************************************************/
-#ifndef QT_NO_DEBUG
-# define _LIBCPP_DEBUG2 0
-#endif // QT_NO_DEBUG
+// When building with debug code, the macro below will enable debug helpers when using libc++.
+// For example, the std::vector<T>::operator[] will use _LIBCPP_ASSERT to check if the index is
+// within the array bounds. Note that this only works reliably with OSX 10.9 or later.
+//#define _LIBCPP_DEBUG2 2
#include "qv4ssa_p.h"
#include "qv4isel_util_p.h"
@@ -50,7 +51,6 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QSet>
-#include <QtCore/QBuffer>
#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <qv4runtime_p.h>
@@ -69,102 +69,20 @@ using namespace IR;
namespace {
+#ifdef QT_NO_DEBUG
+enum { DoVerification = 0 };
+#else
+enum { DoVerification = 1 };
+#endif
+
Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
#define qout *qout()
void showMeTheCode(IR::Function *function)
{
static bool showCode = !qgetenv("QV4_SHOW_IR").isNull();
- if (showCode) {
- QVector<Stmt *> code;
- QHash<Stmt *, BasicBlock *> leader;
-
- foreach (BasicBlock *block, function->basicBlocks()) {
- if (block->isRemoved() || block->isEmpty())
- continue;
- leader.insert(block->statements().first(), block);
- foreach (Stmt *s, block->statements()) {
- code.append(s);
- }
- }
-
- QString name;
- if (function->name && !function->name->isEmpty())
- name = *function->name;
- else
- name.sprintf("%p", function);
-
- qout << "function " << name << "(";
- for (int i = 0; i < function->formals.size(); ++i) {
- if (i != 0)
- qout << ", ";
- qout << *function->formals.at(i);
- }
- qout << ")" << endl
- << "{" << endl;
-
- foreach (const QString *local, function->locals) {
- qout << " var " << *local << ';' << endl;
- }
-
- for (int i = 0; i < code.size(); ++i) {
- Stmt *s = code.at(i);
- Q_ASSERT(s);
-
- if (BasicBlock *bb = leader.value(s)) {
- qout << endl;
- QByteArray str;
- str.append('L');
- str.append(QByteArray::number(bb->index()));
- str.append(':');
- if (bb->catchBlock) {
- str.append(" (exception handler L");
- str.append(QByteArray::number(bb->catchBlock->index()));
- str.append(')');
- }
- for (int i = 66 - str.length(); i; --i)
- str.append(' ');
- qout << str;
- qout << "// predecessor blocks:";
- foreach (BasicBlock *in, bb->in)
- qout << " L" << in->index();
- if (bb->in.isEmpty())
- qout << "(none)";
- if (BasicBlock *container = bb->containingGroup())
- qout << "; container block: L" << container->index();
- if (bb->isGroupStart())
- qout << "; group start";
- qout << endl;
- }
- Stmt *n = (i + 1) < code.size() ? code.at(i + 1) : 0;
-
- QByteArray str;
- QBuffer buf(&str);
- buf.open(QIODevice::WriteOnly);
- QTextStream out(&buf);
- if (s->id > 0)
- out << s->id << ": ";
- s->dump(out, Stmt::MIR);
- if (s->location.isValid()) {
- out.flush();
- for (int i = 58 - str.length(); i > 0; --i)
- out << ' ';
- out << " // line: " << s->location.startLine << " column: " << s->location.startColumn;
- }
-
- out.flush();
-
- qout << " " << str;
- qout << endl;
-
- if (n && s->asCJump()) {
- qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
- }
- }
-
- qout << "}" << endl
- << endl;
- }
+ if (showCode)
+ IRPrinter(&qout).print(function);
}
class ProcessedBlocks
@@ -190,29 +108,6 @@ public:
}
};
-inline bool unescapableTemp(Temp *t, IR::Function *f)
-{
- switch (t->kind) {
- case Temp::Formal:
- case Temp::ScopedFormal:
- case Temp::ScopedLocal:
- return false;
- case Temp::Local:
- return !f->variablesCanEscape();
- default:
- return true;
- }
-}
-
-inline Temp *unescapableTemp(Expr *e, IR::Function *f)
-{
- Temp *t = e->asTemp();
- if (!t)
- return 0;
-
- return unescapableTemp(t, f) ? t : 0;
-}
-
class BasicBlockSet
{
typedef std::vector<int> Numbers;
@@ -223,8 +118,6 @@ class BasicBlockSet
IR::Function *function;
enum { MaxVectorCapacity = 8 };
- // Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector
-
public:
class const_iterator
{
@@ -237,7 +130,7 @@ public:
const_iterator(const BasicBlockSet &set, bool end)
: set(set)
{
- if (end) {
+ if (end || !set.function) {
if (set.blockNumbers)
numberIt = set.blockNumbers->end();
else
@@ -274,10 +167,11 @@ public:
public:
BasicBlock *operator*() const
{
+
if (set.blockNumbers) {
return set.function->basicBlock(*numberIt);
} else {
- Q_ASSERT(flagIt <= INT_MAX);
+ Q_ASSERT(flagIt <= static_cast<size_t>(set.function->basicBlockCount()));
return set.function->basicBlock(static_cast<int>(flagIt));
}
}
@@ -309,7 +203,12 @@ public:
friend class const_iterator;
public:
- BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {}
+ BasicBlockSet(IR::Function *f = 0): blockNumbers(0), blockFlags(0), function(0)
+ {
+ if (f)
+ init(f);
+ }
+
#ifdef Q_COMPILER_RVALUE_REFS
BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0)
{
@@ -317,8 +216,36 @@ public:
std::swap(blockFlags, other.blockFlags);
std::swap(function, other.function);
}
-
#endif // Q_COMPILER_RVALUE_REFS
+
+ BasicBlockSet(const BasicBlockSet &other)
+ : blockNumbers(0)
+ , blockFlags(0)
+ , function(other.function)
+ {
+ if (other.blockFlags)
+ blockFlags = new Flags(*other.blockFlags);
+ else if (other.blockNumbers)
+ blockNumbers = new Numbers(*other.blockNumbers);
+ }
+
+ BasicBlockSet &operator=(const BasicBlockSet &other)
+ {
+ if (blockFlags) {
+ delete blockFlags;
+ blockFlags = 0;
+ } else {
+ delete blockNumbers;
+ blockNumbers = 0;
+ }
+ function = other.function;
+ if (other.blockFlags)
+ blockFlags = new Flags(*other.blockFlags);
+ else if (other.blockNumbers)
+ blockNumbers = new Numbers(*other.blockNumbers);
+ return *this;
+ }
+
~BasicBlockSet() { delete blockNumbers; delete blockFlags; }
void init(IR::Function *f)
@@ -330,8 +257,15 @@ public:
blockNumbers->reserve(MaxVectorCapacity);
}
+ bool empty() const
+ {
+ return begin() == end();
+ }
+
void insert(BasicBlock *bb)
{
+ Q_ASSERT(function);
+
if (blockFlags) {
(*blockFlags)[bb->index()] = true;
return;
@@ -355,34 +289,77 @@ public:
}
}
+ void remove(BasicBlock *bb)
+ {
+ Q_ASSERT(function);
+
+ if (blockFlags) {
+ (*blockFlags)[bb->index()] = false;
+ return;
+ }
+
+ for (std::vector<int>::iterator i = blockNumbers->begin(), ei = blockNumbers->end(); i != ei; ++i) {
+ if (*i == bb->index()) {
+ blockNumbers->erase(i);
+ return;
+ }
+ }
+ }
+
const_iterator begin() const { return const_iterator(*this, false); }
const_iterator end() const { return const_iterator(*this, true); }
- QList<BasicBlock *> values() const
+ void collectValues(std::vector<BasicBlock *> &bbs) const
{
- QList<BasicBlock *> result;
+ Q_ASSERT(function);
for (const_iterator it = begin(), eit = end(); it != eit; ++it)
- result.append(*it);
+ bbs.push_back(*it);
+ }
- return result;
+ bool contains(BasicBlock *bb) const
+ {
+ Q_ASSERT(function);
+
+ if (blockFlags)
+ return (*blockFlags)[bb->index()];
+
+ for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end(); i != ei; ++i) {
+ if (*i == bb->index())
+ return true;
+ }
+
+ return false;
}
};
-class DominatorTree {
+class DominatorTree
+{
+ enum {
+ DebugDominatorFrontiers = 0,
+ DebugImmediateDominators = 0
+ };
+
typedef int BasicBlockIndex;
enum { InvalidBasicBlockIndex = -1 };
+ struct Data
+ {
+ int N;
+ std::vector<int> dfnum; // BasicBlock index -> dfnum
+ std::vector<int> vertex;
+ std::vector<BasicBlockIndex> parent; // BasicBlock index -> parent BasicBlock index
+ std::vector<BasicBlockIndex> ancestor; // BasicBlock index -> ancestor BasicBlock index
+ std::vector<BasicBlockIndex> best; // BasicBlock index -> best BasicBlock index
+ std::vector<BasicBlockIndex> semi; // BasicBlock index -> semi dominator BasicBlock index
+ std::vector<BasicBlockIndex> samedom; // BasicBlock index -> same dominator BasicBlock index
+
+ Data(): N(0) {}
+ };
+
IR::Function *function;
- int N;
- std::vector<int> dfnum; // BasicBlock index -> dfnum
- std::vector<int> vertex;
- std::vector<BasicBlockIndex> parent; // BasicBlock index -> parent BasicBlock index
- std::vector<BasicBlockIndex> ancestor; // BasicBlock index -> ancestor BasicBlock index
- std::vector<BasicBlockIndex> best; // BasicBlock index -> best BasicBlock index
- std::vector<BasicBlockIndex> semi; // BasicBlock index -> semi dominator BasicBlock index
+ QScopedPointer<Data> d;
std::vector<BasicBlockIndex> idom; // BasicBlock index -> immediate dominator BasicBlock index
- std::vector<BasicBlockIndex> samedom; // BasicBlock index -> same dominator BasicBlock index
std::vector<BasicBlockSet> DF; // BasicBlock index -> dominator frontier
struct DFSTodo {
@@ -401,17 +378,17 @@ class DominatorTree {
void DFS(BasicBlockIndex node) {
std::vector<DFSTodo> worklist;
- worklist.reserve(vertex.capacity() / 2);
+ worklist.reserve(d->vertex.capacity() / 2);
DFSTodo todo(node, InvalidBasicBlockIndex);
while (true) {
BasicBlockIndex n = todo.node;
- if (dfnum[n] == 0) {
- dfnum[n] = N;
- vertex[N] = n;
- parent[n] = todo.parent;
- ++N;
+ if (d->dfnum[n] == 0) {
+ d->dfnum[n] = d->N;
+ d->vertex[d->N] = n;
+ d->parent[n] = todo.parent;
+ ++d->N;
const QVector<BasicBlock *> &out = function->basicBlock(n)->out;
for (int i = out.size() - 1; i > 0; --i)
worklist.push_back(DFSTodo(out[i]->index(), n));
@@ -438,20 +415,20 @@ class DominatorTree {
BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v, std::vector<BasicBlockIndex> &worklist) {
worklist.clear();
- for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = ancestor[it])
+ for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = d->ancestor[it])
worklist.push_back(it);
if (worklist.size() < 2)
- return best[v];
+ return d->best[v];
BasicBlockIndex b = InvalidBasicBlockIndex;
BasicBlockIndex last = worklist.back();
Q_ASSERT(worklist.size() <= INT_MAX);
for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) {
BasicBlockIndex bbIt = worklist[it];
- ancestor[bbIt] = last;
- BasicBlockIndex &best_it = best[bbIt];
- if (b != InvalidBasicBlockIndex && dfnum[semi[b]] < dfnum[semi[best_it]])
+ d->ancestor[bbIt] = last;
+ BasicBlockIndex &best_it = d->best[bbIt];
+ if (b != InvalidBasicBlockIndex && d->dfnum[d->semi[b]] < d->dfnum[d->semi[best_it]])
best_it = b;
else
b = best_it;
@@ -460,57 +437,57 @@ class DominatorTree {
}
void link(BasicBlockIndex p, BasicBlockIndex n) {
- ancestor[n] = p;
- best[n] = n;
+ d->ancestor[n] = p;
+ d->best[n] = n;
}
void calculateIDoms() {
Q_ASSERT(function->basicBlock(0)->in.isEmpty());
const int bbCount = function->basicBlockCount();
- vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex);
- parent = std::vector<int>(bbCount, InvalidBasicBlockIndex);
- dfnum = std::vector<int>(bbCount, 0);
- semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
- ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ d->vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ d->parent = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ d->dfnum = std::vector<int>(bbCount, 0);
+ d->semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ d->ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
- samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
- best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ d->samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ d->best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket;
bucket.reserve(bbCount);
DFS(function->basicBlock(0)->index());
- Q_ASSERT(N == function->liveBasicBlocksCount());
+ Q_ASSERT(d->N == function->liveBasicBlocksCount());
std::vector<BasicBlockIndex> worklist;
- worklist.reserve(vertex.capacity() / 2);
+ worklist.reserve(d->vertex.capacity() / 2);
- for (int i = N - 1; i > 0; --i) {
- BasicBlockIndex n = vertex[i];
- BasicBlockIndex p = parent[n];
+ for (int i = d->N - 1; i > 0; --i) {
+ BasicBlockIndex n = d->vertex[i];
+ BasicBlockIndex p = d->parent[n];
BasicBlockIndex s = p;
foreach (BasicBlock *v, function->basicBlock(n)->in) {
BasicBlockIndex ss = InvalidBasicBlockIndex;
- if (dfnum[v->index()] <= dfnum[n])
+ if (d->dfnum[v->index()] <= d->dfnum[n])
ss = v->index();
else
- ss = semi[ancestorWithLowestSemi(v->index(), worklist)];
- if (dfnum[ss] < dfnum[s])
+ ss = d->semi[ancestorWithLowestSemi(v->index(), worklist)];
+ if (d->dfnum[ss] < d->dfnum[s])
s = ss;
}
- semi[n] = s;
+ d->semi[n] = s;
bucket[s].push_back(n);
link(p, n);
if (bucket.contains(p)) {
foreach (BasicBlockIndex v, bucket[p]) {
BasicBlockIndex y = ancestorWithLowestSemi(v, worklist);
- BasicBlockIndex semi_v = semi[v];
- if (semi[y] == semi_v)
+ BasicBlockIndex semi_v = d->semi[v];
+ if (d->semi[y] == semi_v)
idom[v] = semi_v;
else
- samedom[v] = y;
+ d->samedom[v] = y;
}
bucket.remove(p);
}
@@ -521,31 +498,19 @@ class DominatorTree {
qDebug("\tL%d: ancestor = %d, semi = %d, samedom = %d", i, ancestor[i], semi[i], samedom[i]);
#endif // SHOW_SSA
- for (int i = 1; i < N; ++i) {
- BasicBlockIndex n = vertex[i];
+ for (int i = 1; i < d->N; ++i) {
+ BasicBlockIndex n = d->vertex[i];
Q_ASSERT(n != InvalidBasicBlockIndex);
Q_ASSERT(!bucket.contains(n));
- Q_ASSERT(ancestor[n] != InvalidBasicBlockIndex
- && ((semi[n] != InvalidBasicBlockIndex
- && dfnum[ancestor[n]] <= dfnum[semi[n]]) || semi[n] == n));
- BasicBlockIndex sdn = samedom[n];
+ Q_ASSERT(d->ancestor[n] != InvalidBasicBlockIndex
+ && ((d->semi[n] != InvalidBasicBlockIndex
+ && d->dfnum[d->ancestor[n]] <= d->dfnum[d->semi[n]]) || d->semi[n] == n));
+ BasicBlockIndex sdn = d->samedom[n];
if (sdn != InvalidBasicBlockIndex)
idom[n] = idom[sdn];
}
-#if defined(SHOW_SSA)
- qout << "Immediate dominators:" << endl;
- foreach (BasicBlock *to, nodes) {
- qout << '\t';
- BasicBlockIndex from = idom.at(to->index);
- if (from != InvalidBasicBlockIndex)
- qout << from;
- else
- qout << "(none)";
- qout << " -> " << to->index << endl;
- }
- qout << "N = " << N << endl;
-#endif // SHOW_SSA
+ dumpImmediateDominators();
}
struct NodeProgress {
@@ -553,7 +518,18 @@ class DominatorTree {
std::vector<BasicBlockIndex> todo;
};
+public:
+ DominatorTree(IR::Function *function)
+ : function(function)
+ , d(new Data)
+ {
+ calculateIDoms();
+ d.reset();
+ }
+
void computeDF() {
+ DF.resize(function->basicBlockCount());
+
// compute children of each node in the dominator tree
std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children
children.resize(function->basicBlockCount());
@@ -569,10 +545,10 @@ class DominatorTree {
}
// Fill the worklist and initialize the node status for each basic-block
- QHash<BasicBlockIndex, NodeProgress> nodeStatus;
- nodeStatus.reserve(function->basicBlockCount());
+ std::vector<NodeProgress> nodeStatus;
+ nodeStatus.resize(function->basicBlockCount());
std::vector<BasicBlockIndex> worklist;
- worklist.reserve(function->basicBlockCount() * 2);
+ worklist.reserve(function->basicBlockCount());
foreach (BasicBlock *bb, function->basicBlocks()) {
if (bb->isRemoved())
continue;
@@ -624,19 +600,23 @@ class DominatorTree {
}
}
-#if defined(SHOW_SSA)
- qout << "Dominator Frontiers:" << endl;
- foreach (BasicBlock *n, nodes) {
- qout << "\tDF[" << n->index << "]: {";
- QList<BasicBlock *> SList = DF[n->index].values();
- for (int i = 0; i < SList.size(); ++i) {
- if (i > 0)
- qout << ", ";
- qout << SList[i]->index;
+ if (DebugDominatorFrontiers) {
+ qout << "Dominator Frontiers:" << endl;
+ foreach (BasicBlock *n, function->basicBlocks()) {
+ if (n->isRemoved())
+ continue;
+
+ qout << "\tDF[" << n->index() << "]: {";
+ const BasicBlockSet &SList = DF[n->index()];
+ for (BasicBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) {
+ if (i != SList.begin())
+ qout << ", ";
+ qout << (*i)->index();
+ }
+ qout << "}" << endl;
}
- qout << "}" << endl;
}
-#endif // SHOW_SSA
+
#if !defined(QT_NO_DEBUG) && defined(CAN_TAKE_LOSTS_OF_TIME)
foreach (BasicBlock *n, nodes) {
const BasicBlockSet &fBlocks = DF[n->index];
@@ -659,37 +639,40 @@ class DominatorTree {
#endif // !QT_NO_DEBUG
}
-public:
- DominatorTree(IR::Function *function)
- : function(function)
- , N(0)
- {
- DF.resize(function->basicBlockCount());
- calculateIDoms();
- computeDF();
- }
-
const BasicBlockSet &dominatorFrontier(BasicBlock *n) const {
return DF[n->index()];
}
BasicBlock *immediateDominator(BasicBlock *bb) const {
- return function->basicBlock(idom[bb->index()]);
+ const BasicBlockIndex idx = idom[bb->index()];
+ if (idx == -1)
+ return 0;
+ return function->basicBlock(idx);
}
void dumpImmediateDominators() const
{
- qDebug() << "Immediate dominators for" << idom.size() << "nodes:";
- for (size_t i = 0, ei = idom.size(); i != ei; ++i)
- if (idom[i] == InvalidBasicBlockIndex)
- qDebug("\tnone -> L%d", int(i));
- else
- qDebug("\tL%d -> L%d", idom[i], int(i));
+ if (DebugImmediateDominators) {
+ qout << "Immediate dominators:" << endl;
+ foreach (BasicBlock *to, function->basicBlocks()) {
+ if (to->isRemoved())
+ continue;
+
+ qout << '\t';
+ BasicBlockIndex from = idom.at(to->index());
+ if (from != InvalidBasicBlockIndex)
+ qout << from;
+ else
+ qout << "(none)";
+ qout << " -> " << to->index() << endl;
+ }
+ }
}
void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator)
{
Q_ASSERT(bb->index() >= 0);
+ Q_ASSERT(!newDominator || newDominator->index() >= 0);
if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) {
// This is a new block, probably introduced by edge splitting. So, we'll have to grow
@@ -697,13 +680,61 @@ public:
idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex);
}
- idom[bb->index()] = newDominator->index();
+ idom[bb->index()] = newDominator ? newDominator->index() : 0;
}
bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
return dominates(dominator->index(), dominated->index());
}
+ struct Cmp {
+ std::vector<int> *nodeDepths;
+ Cmp(std::vector<int> *nodeDepths)
+ : nodeDepths(nodeDepths)
+ { Q_ASSERT(nodeDepths); }
+ bool operator()(BasicBlock *one, BasicBlock *two) const
+ {
+ if (one->isRemoved())
+ return false;
+ if (two->isRemoved())
+ return true;
+ return nodeDepths->at(one->index()) > nodeDepths->at(two->index());
+ }
+ };
+
+ // Calculate a depth-first iteration order on the nodes of the dominator tree.
+ //
+ // The order of the nodes in the vector is not the same as one where a recursive depth-first
+ // iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth.
+ // So for the:
+ // 1 dominates 2
+ // 2 dominates 3
+ // 3 dominates 4
+ // 2 dominates 5
+ // the order will be:
+ // 4, 3, 5, 2, 1
+ // or:
+ // 4, 5, 3, 2, 1
+ // So the order of nodes on the same depth is undefined, but it will be after the nodes
+ // they dominate, and before the nodes that dominate them.
+ //
+ // The reason for this order is that a proper DFS pre-/post-order would require inverting
+ // the idom vector by either building a real tree datastructure or by searching the idoms
+ // for siblings and children. Both have a higher time complexity than sorting by depth.
+ QVector<BasicBlock *> calculateDFNodeIterOrder() const
+ {
+ std::vector<int> depths = calculateNodeDepths();
+ QVector<BasicBlock *> order = function->basicBlocks();
+ std::sort(order.begin(), order.end(), Cmp(&depths));
+ for (int i = 0; i < order.size(); ) {
+ if (order[i]->isRemoved())
+ order.remove(i);
+ else
+ ++i;
+ }
+ return order;
+ }
+
private:
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
@@ -719,28 +750,95 @@ private:
return false;
}
+
+ // Algorithm:
+ // - for each node:
+ // - get the depth of a node. If it's unknown (-1):
+ // - get the depth of the immediate dominator.
+ // - if that's unknown too, calculate it by calling calculateNodeDepth
+ // - set the current node's depth to that of immediate dominator + 1
+ std::vector<int> calculateNodeDepths() const
+ {
+ std::vector<int> nodeDepths(function->basicBlockCount(), -1);
+ nodeDepths[0] = 0;
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ int &bbDepth = nodeDepths[bb->index()];
+ if (bbDepth == -1) {
+ const int immDom = idom[bb->index()];
+ int immDomDepth = nodeDepths[immDom];
+ if (immDomDepth == -1)
+ immDomDepth = calculateNodeDepth(immDom, nodeDepths);
+ bbDepth = immDomDepth + 1;
+ }
+ }
+ return nodeDepths;
+ }
+
+ // Algorithm:
+ // - search for the first dominator of a node that has a known depth. As all nodes are
+ // reachable from the start node, and that node's depth is 0, this is finite.
+ // - while doing that search, put all unknown nodes in the worklist
+ // - pop all nodes from the worklist, and set their depth to the previous' (== dominating)
+ // node's depth + 1
+ // This way every node's depth is calculated once, and the complexity is O(n).
+ int calculateNodeDepth(int nodeIdx, std::vector<int> &nodeDepths) const
+ {
+ std::vector<int> worklist;
+ worklist.reserve(8);
+ int depth = -1;
+
+ do {
+ worklist.push_back(nodeIdx);
+ nodeIdx = idom[nodeIdx];
+ depth = nodeDepths[nodeIdx];
+ } while (depth == -1);
+
+ for (std::vector<int>::const_reverse_iterator it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it)
+ nodeDepths[*it] = ++depth;
+
+ return depth;
+ }
};
class VariableCollector: public StmtVisitor, ExprVisitor {
- typedef QHash<Temp, QSet<BasicBlock *> > DefSites;
- DefSites _defsites;
- QVector<QSet<Temp> > A_orig;
- QSet<Temp> nonLocals;
- QSet<Temp> killed;
+ std::vector<Temp> _allTemps;
+ std::vector<BasicBlockSet> _defsites;
+ std::vector<std::vector<int> > A_orig;
+ std::vector<bool> nonLocals;
+ std::vector<bool> killed;
BasicBlock *currentBB;
- IR::Function *function;
bool isCollectable(Temp *t) const
{
+ Q_UNUSED(t);
Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot);
- return unescapableTemp(t, function);
+ return true;
+ }
+
+ void addDefInCurrentBlock(Temp *t)
+ {
+ std::vector<int> &temps = A_orig[currentBB->index()];
+ if (std::find(temps.begin(), temps.end(), t->index) == temps.end())
+ temps.push_back(t->index);
+ }
+
+ void addTemp(Temp *t)
+ {
+ if (_allTemps[t->index].kind == Temp::Invalid)
+ _allTemps[t->index] = *t;
}
public:
VariableCollector(IR::Function *function)
- : function(function)
{
- _defsites.reserve(function->tempCount);
+ _allTemps.resize(function->tempCount);
+ _defsites.resize(function->tempCount);
+ for (int i = 0; i < function->tempCount; ++i)
+ _defsites[i].init(function);
+ nonLocals.resize(function->tempCount);
A_orig.resize(function->basicBlockCount());
for (int i = 0, ei = A_orig.size(); i != ei; ++i)
A_orig[i].reserve(8);
@@ -754,11 +852,9 @@ public:
continue;
currentBB = bb;
- killed.clear();
- killed.reserve(bb->statements().size() / 2);
- foreach (Stmt *s, bb->statements()) {
+ killed.assign(function->tempCount, false);
+ foreach (Stmt *s, bb->statements())
s->accept(this);
- }
}
#if defined(SHOW_SSA)
@@ -773,28 +869,36 @@ public:
#endif // SHOW_SSA
}
- QList<Temp> vars() const {
- return _defsites.keys();
- }
+ const std::vector<Temp> &allTemps() const
+ { return _allTemps; }
- QSet<BasicBlock *> defsite(const Temp &n) const {
- return _defsites[n];
+ void collectDefSites(const Temp &n, std::vector<BasicBlock *> &bbs) const {
+ Q_ASSERT(!n.isInvalid());
+ Q_ASSERT(n.index < _defsites.size());
+ _defsites[n.index].collectValues(bbs);
}
- QSet<Temp> inBlock(BasicBlock *n) const {
+ const std::vector<int> &inBlock(BasicBlock *n) const
+ {
return A_orig.at(n->index());
}
- bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
+ bool isNonLocal(const Temp &var) const
+ {
+ Q_ASSERT(!var.isInvalid());
+ Q_ASSERT(var.index < nonLocals.size());
+ return nonLocals[var.index];
+ }
protected:
- virtual void visitPhi(Phi *) {};
- virtual void visitConvert(Convert *e) { e->expr->accept(this); };
+ virtual void visitPhi(Phi *) {}
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
virtual void visitConst(Const *) {}
virtual void visitString(IR::String *) {}
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitUnop(Unop *e) { e->expr->accept(this); }
virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
@@ -821,6 +925,8 @@ protected:
s->source->accept(this);
if (Temp *t = s->target->asTemp()) {
+ addTemp(t);
+
if (isCollectable(t)) {
#if defined(SHOW_SSA)
qout << '\t';
@@ -828,18 +934,11 @@ protected:
qout << " -> L" << currentBB->index << endl;
#endif // SHOW_SSA
- DefSites::iterator defsitesIt = _defsites.find(*t);
- if (defsitesIt == _defsites.end()) {
- QSet<BasicBlock *> bbs;
- bbs.reserve(4);
- defsitesIt = _defsites.insert(*t, bbs);
- }
- defsitesIt->insert(currentBB);
-
- A_orig[currentBB->index()].insert(*t);
+ _defsites[t->index].insert(currentBB);
+ addDefInCurrentBlock(t);
// For semi-pruned SSA:
- killed.insert(*t);
+ killed[t->index] = true;
}
} else {
s->target->accept(this);
@@ -848,9 +947,243 @@ protected:
virtual void visitTemp(Temp *t)
{
+ addTemp(t);
+
if (isCollectable(t))
- if (!killed.contains(*t))
- nonLocals.insert(*t);
+ if (!killed[t->index])
+ nonLocals[t->index] = true;
+ }
+};
+
+struct UntypedTemp {
+ Temp temp;
+ UntypedTemp() {}
+ UntypedTemp(const Temp &t): temp(t) {}
+};
+inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
+{ return t1.temp.index == t2.temp.index && t1.temp.kind == t2.temp.kind; }
+inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
+{ return !(t1 == t2); }
+
+class DefUses
+{
+public:
+ struct DefUse {
+ DefUse()
+ : defStmt(0)
+ , blockOfStatement(0)
+ { uses.reserve(8); }
+ Temp temp;
+ Stmt *defStmt;
+ BasicBlock *blockOfStatement;
+ QVector<Stmt *> uses;
+
+ bool isValid() const
+ { return temp.kind != Temp::Invalid; }
+
+ void clear()
+ { defStmt = 0; blockOfStatement = 0; uses.clear(); }
+ };
+
+private:
+ std::vector<DefUse> _defUses;
+ class Temps: public QVector<Temp> {
+ public:
+ Temps() { reserve(4); }
+ };
+ std::vector<Temps> _usesPerStatement;
+
+ void ensure(Temp *newTemp)
+ {
+ if (_defUses.size() <= newTemp->index) {
+ _defUses.reserve(newTemp->index + _defUses.size() / 3 + 1);
+ _defUses.resize(newTemp->index + 1);
+ }
+ }
+
+ void ensure(Stmt *s)
+ {
+ Q_ASSERT(s->id() >= 0);
+ if (static_cast<unsigned>(s->id()) >= _usesPerStatement.size()) {
+ _usesPerStatement.reserve(s->id() + _usesPerStatement.size() / 3 + 1);
+ _usesPerStatement.resize(s->id() + 1);
+ }
+ }
+
+ void addUseForStatement(Stmt *s, const Temp &var)
+ {
+ ensure(s);
+ _usesPerStatement[s->id()].push_back(var);
+ }
+
+public:
+ DefUses(IR::Function *function)
+ {
+ _usesPerStatement.resize(function->statementCount());
+ _defUses.resize(function->tempCount);
+ }
+
+ void cleanup()
+ {
+ for (size_t i = 0, ei = _defUses.size(); i != ei; ++i) {
+ DefUse &defUse = _defUses[i];
+ if (defUse.isValid() && !defUse.defStmt)
+ defUse.clear();
+ }
+ }
+
+ unsigned statementCount() const
+ { return _usesPerStatement.size(); }
+
+ unsigned tempCount() const
+ { return _defUses.size(); }
+
+ const Temp &temp(int idx) const
+ { return _defUses[idx].temp; }
+
+ void addDef(Temp *newTemp, Stmt *defStmt, BasicBlock *defBlock)
+ {
+ ensure(newTemp);
+ DefUse &defUse = _defUses[newTemp->index];
+ Q_ASSERT(!defUse.isValid());
+ defUse.temp = *newTemp;
+ defUse.defStmt = defStmt;
+ defUse.blockOfStatement = defBlock;
+ }
+
+ QList<UntypedTemp> defsUntyped() const
+ {
+ QList<UntypedTemp> res;
+ foreach (const DefUse &du, _defUses)
+ if (du.isValid())
+ res.append(UntypedTemp(du.temp));
+ return res;
+ }
+
+ std::vector<const Temp *> defs() const {
+ std::vector<const Temp *> res;
+ res.reserve(_defUses.size());
+ for (unsigned i = 0, ei = _defUses.size(); i != ei; ++i) {
+ const DefUse &du = _defUses.at(i);
+ if (du.isValid())
+ res.push_back(&du.temp);
+ }
+ return res;
+ }
+
+ void removeDef(const Temp &variable) {
+ Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
+ _defUses[variable.index].clear();
+ }
+
+ void addUses(const Temp &variable, const QVector<Stmt *> &newUses)
+ {
+ Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
+ QVector<Stmt *> &uses = _defUses[variable.index].uses;
+ foreach (Stmt *stmt, newUses)
+ if (std::find(uses.begin(), uses.end(), stmt) == uses.end())
+ uses.push_back(stmt);
+ }
+
+ void addUse(const Temp &variable, Stmt *newUse)
+ {
+ if (_defUses.size() <= variable.index) {
+ _defUses.resize(variable.index + 1);
+ DefUse &du = _defUses[variable.index];
+ du.temp = variable;
+ du.uses.push_back(newUse);
+ addUseForStatement(newUse, variable);
+ return;
+ }
+
+ QVector<Stmt *> &uses = _defUses[variable.index].uses;
+ if (std::find(uses.begin(), uses.end(), newUse) == uses.end())
+ uses.push_back(newUse);
+ addUseForStatement(newUse, variable);
+ }
+
+ int useCount(const Temp &variable) const
+ {
+ Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
+ return _defUses[variable.index].uses.size();
+ }
+
+ Stmt *defStmt(const Temp &variable) const
+ {
+ Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
+ return _defUses[variable.index].defStmt;
+ }
+
+ BasicBlock *defStmtBlock(const Temp &variable) const
+ {
+ Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size());
+ return _defUses[variable.index].blockOfStatement;
+ }
+
+ void removeUse(Stmt *usingStmt, const Temp &var)
+ {
+ Q_ASSERT(static_cast<unsigned>(var.index) < _defUses.size());
+ QVector<Stmt *> &uses = _defUses[var.index].uses;
+ uses.erase(std::remove(uses.begin(), uses.end(), usingStmt), uses.end());
+ }
+
+ void registerNewStatement(Stmt *s)
+ {
+ ensure(s);
+ }
+
+ const QVector<Temp> &usedVars(Stmt *s) const
+ {
+ Q_ASSERT(s->id() >= 0);
+ Q_ASSERT(static_cast<unsigned>(s->id()) < _usesPerStatement.size());
+ return _usesPerStatement[s->id()];
+ }
+
+ const QVector<Stmt *> &uses(const Temp &var) const
+ {
+ return _defUses[var.index].uses;
+ }
+
+ QVector<Stmt*> removeDefUses(Stmt *s)
+ {
+ QVector<Stmt*> defStmts;
+ foreach (const Temp &usedVar, usedVars(s)) {
+ if (Stmt *ds = defStmt(usedVar))
+ defStmts += ds;
+ removeUse(s, usedVar);
+ }
+ if (Move *m = s->asMove()) {
+ if (Temp *t = m->target->asTemp())
+ removeDef(*t);
+ } else if (Phi *p = s->asPhi()) {
+ removeDef(*p->targetTemp);
+ }
+
+ return defStmts;
+ }
+
+ void dump() const
+ {
+ qout << "Defines and uses:" << endl;
+ foreach (const DefUse &du, _defUses) {
+ if (!du.isValid())
+ continue;
+ qout << '%' << du.temp.index;
+ qout << " -> defined in block " << du.blockOfStatement->index()
+ << ", statement: " << du.defStmt->id()
+ << endl;
+ qout << " uses:";
+ foreach (Stmt *s, du.uses)
+ qout << ' ' << s->id();
+ qout << endl;
+ }
+ qout << "Uses per statement:" << endl;
+ for (unsigned i = 0, ei = _usesPerStatement.size(); i != ei; ++i) {
+ qout << " " << i << ":";
+ foreach (const Temp &t, _usesPerStatement[i])
+ qout << ' ' << t.index;
+ qout << endl;
+ }
}
};
@@ -861,16 +1194,16 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
qout << " in block " << y->index << endl;
#endif
- Phi *phiNode = f->New<Phi>();
+ Phi *phiNode = f->NewStmt<Phi>();
phiNode->d = new Stmt::Data;
phiNode->targetTemp = f->New<Temp>();
- phiNode->targetTemp->init(a.kind, a.index, 0);
+ phiNode->targetTemp->init(a.kind, a.index);
y->prependStatement(phiNode);
phiNode->d->incoming.resize(y->in.size());
for (int i = 0, ei = y->in.size(); i < ei; ++i) {
Temp *t = f->New<Temp>();
- t->init(a.kind, a.index, 0);
+ t->init(a.kind, a.index);
phiNode->d->incoming[i] = t;
}
}
@@ -945,23 +1278,22 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
// mapping[t] = c
class VariableRenamer: public StmtVisitor, public ExprVisitor
{
+ Q_DISABLE_COPY(VariableRenamer)
+
IR::Function *function;
+ DefUses &defUses;
unsigned tempCount;
- typedef QHash<unsigned, int> Mapping; // maps from existing/old temp number to the new and unique temp number.
+ typedef std::vector<int> Mapping; // maps from existing/old temp number to the new and unique temp number.
enum { Absent = -1 };
- Mapping localMapping;
Mapping vregMapping;
ProcessedBlocks processed;
- bool isRenamable(Temp *t) const
- {
- Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot);
- return unescapableTemp(t, function);
- }
+ BasicBlock *currentBB;
+ Stmt *currentStmt;
struct TodoAction {
- enum { RestoreLocal, RestoreVReg, Rename } action;
+ enum { RestoreVReg, Rename } action;
union {
struct {
unsigned temp;
@@ -982,9 +1314,9 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor
TodoAction(const Temp &t, int prev)
{
- Q_ASSERT(t.kind == Temp::Local || t.kind == Temp::VirtualRegister);
+ Q_ASSERT(t.kind == Temp::VirtualRegister);
- action = t.kind == Temp::Local ? RestoreLocal : RestoreVReg;
+ action = RestoreVReg;
restoreData.temp = t.index;
restoreData.previous = prev;
}
@@ -1001,13 +1333,13 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor
QVector<TodoAction> todo;
public:
- VariableRenamer(IR::Function *f)
+ VariableRenamer(IR::Function *f, DefUses &defUses)
: function(f)
+ , defUses(defUses)
, tempCount(0)
, processed(f)
{
- localMapping.reserve(f->tempCount);
- vregMapping.reserve(f->tempCount);
+ vregMapping.assign(f->tempCount, Absent);
todo.reserve(f->basicBlockCount());
}
@@ -1023,9 +1355,6 @@ public:
case TodoAction::Rename:
rename(todoAction.renameData.basicBlock);
break;
- case TodoAction::RestoreLocal:
- restore(localMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
- break;
case TodoAction::RestoreVReg:
restore(vregMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
break;
@@ -1038,12 +1367,9 @@ public:
}
private:
- static inline void restore(Mapping &mapping, unsigned temp, int previous)
+ static inline void restore(Mapping &mapping, int temp, int previous)
{
- if (previous == Absent)
- mapping.remove(temp);
- else
- mapping[temp] = previous;
+ mapping[temp] = previous;
}
void rename(BasicBlock *bb)
@@ -1067,8 +1393,12 @@ private:
void renameStatementsAndPhis(BasicBlock *bb)
{
- foreach (Stmt *s, bb->statements())
+ currentBB = bb;
+
+ foreach (Stmt *s, bb->statements()) {
+ currentStmt = s;
s->accept(this);
+ }
foreach (BasicBlock *Y, bb->out) {
const int j = Y->in.indexOf(bb);
@@ -1080,6 +1410,7 @@ private:
// qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index;
t->index = newTmp;
t->kind = Temp::VirtualRegister;
+ defUses.addUse(*t, phi);
} else {
break;
}
@@ -1091,11 +1422,8 @@ private:
{
int nr = Absent;
switch (t.kind) {
- case Temp::Local:
- nr = localMapping.value(t.index, Absent);
- break;
case Temp::VirtualRegister:
- nr = vregMapping.value(t.index, Absent);
+ nr = vregMapping[t.index];
break;
default:
Q_UNREACHABLE();
@@ -1122,13 +1450,9 @@ private:
int oldIndex = Absent;
switch (t.kind) {
- case Temp::Local:
- oldIndex = localMapping.value(t.index, Absent);
- localMapping.insert(t.index, newIndex);
- break;
case Temp::VirtualRegister:
- oldIndex = vregMapping.value(t.index, Absent);
- vregMapping.insert(t.index, newIndex);
+ oldIndex = vregMapping[t.index];
+ vregMapping[t.index] = newIndex;
break;
default:
Q_UNREACHABLE();
@@ -1141,11 +1465,10 @@ private:
protected:
virtual void visitTemp(Temp *e) { // only called for uses, not defs
- if (isRenamable(e)) {
-// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
- e->index = currentNumber(*e);
- e->kind = Temp::VirtualRegister;
- }
+// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
+ e->index = currentNumber(*e);
+ e->kind = Temp::VirtualRegister;
+ defUses.addUse(*e, currentStmt);
}
virtual void visitMove(Move *s) {
@@ -1159,13 +1482,12 @@ protected:
s->target->accept(this);
}
- void renameTemp(Temp *t) {
- if (isRenamable(t)) {
- const int newIdx = nextFreeTemp(*t);
-// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
- t->kind = Temp::VirtualRegister;
- t->index = newIdx;
- }
+ void renameTemp(Temp *t) { // only called for defs, not uses
+ const int newIdx = nextFreeTemp(*t);
+// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
+ t->kind = Temp::VirtualRegister;
+ t->index = newIdx;
+ defUses.addDef(t, currentStmt, currentBB);
}
virtual void visitConvert(Convert *e) { e->expr->accept(this); }
@@ -1181,6 +1503,7 @@ protected:
virtual void visitString(IR::String *) {}
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitUnop(Unop *e) { e->expr->accept(this); }
virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
@@ -1206,7 +1529,9 @@ protected:
}
};
-void convertToSSA(IR::Function *function, const DominatorTree &df)
+// This function converts the IR to semi-pruned SSA form. For details about SSA and the algorightm,
+// see [Appel]. For the changes needed for semi-pruned SSA form, and for its advantages, see [Briggs].
+void convertToSSA(IR::Function *function, const DominatorTree &df, DefUses &defUses)
{
#if defined(SHOW_SSA)
qout << "Converting function ";
@@ -1221,376 +1546,214 @@ void convertToSSA(IR::Function *function, const DominatorTree &df)
VariableCollector variables(function);
// Prepare for phi node insertion:
- QVector<QSet<Temp> > A_phi;
+ std::vector<std::vector<bool> > A_phi;
A_phi.resize(function->basicBlockCount());
- for (int i = 0, ei = A_phi.size(); i != ei; ++i) {
- QSet<Temp> temps;
- temps.reserve(4);
- A_phi[i] = temps;
- }
+ for (int i = 0, ei = A_phi.size(); i != ei; ++i)
+ A_phi[i].assign(function->tempCount, false);
+
+ std::vector<BasicBlock *> W;
+ W.reserve(8);
// Place phi functions:
- foreach (Temp a, variables.vars()) {
+ foreach (const Temp &a, variables.allTemps()) {
+ if (a.isInvalid())
+ continue;
if (!variables.isNonLocal(a))
continue; // for semi-pruned SSA
- QList<BasicBlock *> W = QList<BasicBlock *>::fromSet(variables.defsite(a));
- while (!W.isEmpty()) {
- BasicBlock *n = W.first();
- W.removeFirst();
+ W.clear();
+ variables.collectDefSites(a, W);
+ while (!W.empty()) {
+ BasicBlock *n = W.back();
+ W.pop_back();
const BasicBlockSet &dominatorFrontierForN = df.dominatorFrontier(n);
for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end();
it != eit; ++it) {
BasicBlock *y = *it;
- if (!A_phi.at(y->index()).contains(a)) {
+ if (!A_phi.at(y->index()).at(a.index)) {
insertPhiNode(a, y, function);
- A_phi[y->index()].insert(a);
- if (!variables.inBlock(y).contains(a))
- W.append(y);
+ A_phi[y->index()].at(a.index) = true;
+ const std::vector<int> &varsInBlockY = variables.inBlock(y);
+ if (std::find(varsInBlockY.begin(), varsInBlockY.end(), a.index) == varsInBlockY.end())
+ W.push_back(y);
}
}
}
}
// Rename variables:
- VariableRenamer(function).run();
+ VariableRenamer(function, defUses).run();
}
-struct UntypedTemp {
- Temp temp;
- UntypedTemp() {}
- UntypedTemp(const Temp &t): temp(t) {}
-};
-inline uint qHash(const UntypedTemp &t, uint seed = 0) Q_DECL_NOTHROW
-{ return t.temp.index ^ (t.temp.kind | (t.temp.scope << 3)) ^ seed; }
-inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
-{ return t1.temp.index == t2.temp.index && t1.temp.scope == t2.temp.scope && t1.temp.kind == t2.temp.kind; }
-inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
-{ return !(t1 == t2); }
-
-class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
-public:
- struct DefUse {
- DefUse()
- : defStmt(0)
- , blockOfStatement(0)
- {}
- Stmt *defStmt;
- BasicBlock *blockOfStatement;
- QList<Stmt *> uses;
- };
-
-private:
- IR::Function *function;
- typedef QHash<UntypedTemp, DefUse> DefUses;
- DefUses _defUses;
- QHash<Stmt *, QList<Temp> > _usesPerStatement;
-
- BasicBlock *_block;
- Stmt *_stmt;
-
- bool isCollectible(Temp *t) const {
- Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot);
- return unescapableTemp(t, function);
- }
-
- void addUse(Temp *t) {
- Q_ASSERT(t);
- if (!isCollectible(t))
- return;
-
- _defUses[*t].uses.append(_stmt);
- _usesPerStatement[_stmt].append(*t);
- }
-
- void addDef(Temp *t) {
- if (!isCollectible(t))
- return;
-
- Q_ASSERT(!_defUses.contains(*t) || _defUses.value(*t).defStmt == 0 || _defUses.value(*t).defStmt == _stmt);
-
- DefUse &defUse = _defUses[*t];
- defUse.defStmt = _stmt;
- defUse.blockOfStatement = _block;
- }
-
-public:
- DefUsesCalculator(IR::Function *function)
- : function(function)
- {
- foreach (BasicBlock *bb, function->basicBlocks()) {
- if (bb->isRemoved())
- continue;
-
- _block = bb;
- foreach (Stmt *stmt, bb->statements()) {
- _stmt = stmt;
- stmt->accept(this);
- }
- }
-
- QMutableHashIterator<UntypedTemp, DefUse> it(_defUses);
- while (it.hasNext()) {
- it.next();
- if (!it.value().defStmt)
- it.remove();
- }
- }
-
- void addTemp(Temp *newTemp, Stmt *defStmt, BasicBlock *defBlock)
- {
- DefUse &defUse = _defUses[*newTemp];
- defUse.defStmt = defStmt;
- defUse.blockOfStatement = defBlock;
- }
-
- QList<UntypedTemp> defsUntyped() const { return _defUses.keys(); }
-
- QList<Temp> defs() const {
- QList<Temp> res;
- res.reserve(_defUses.size());
- foreach (const UntypedTemp &t, _defUses.keys())
- res.append(t.temp);
- return res;
- }
-
- void removeDef(const Temp &var) {
- _defUses.remove(var);
- }
-
- void addUses(const Temp &variable, const QList<Stmt *> &newUses)
- { _defUses[variable].uses.append(newUses); }
-
- void addUse(const Temp &variable, Stmt * newUse)
- { _defUses[variable].uses.append(newUse); }
-
- int useCount(const UntypedTemp &variable) const
- { return _defUses[variable].uses.size(); }
-
- Stmt *defStmt(const UntypedTemp &variable) const
- { return _defUses[variable].defStmt; }
-
- BasicBlock *defStmtBlock(const Temp &variable) const
- { return _defUses[variable].blockOfStatement; }
-
- void removeUse(Stmt *usingStmt, const Temp &var)
- { _defUses[var].uses.removeAll(usingStmt); }
-
- QList<Temp> usedVars(Stmt *s) const
- { return _usesPerStatement[s]; }
-
- const QList<Stmt *> &uses(const UntypedTemp &var) const
- {
- static const QList<Stmt *> noUses;
-
- DefUses::const_iterator it = _defUses.find(var);
- if (it == _defUses.end())
- return noUses;
- else
- return it->uses;
- }
-
- QVector<Stmt*> removeDefUses(Stmt *s)
- {
- QVector<Stmt*> defStmts;
- foreach (const Temp &usedVar, usedVars(s)) {
- if (Stmt *ds = defStmt(usedVar))
- defStmts += ds;
- removeUse(s, usedVar);
- }
- if (Move *m = s->asMove()) {
- if (Temp *t = m->target->asTemp())
- removeDef(*t);
- } else if (Phi *p = s->asPhi()) {
- removeDef(*p->targetTemp);
- }
-
- return defStmts;
- }
-
- void dump() const
- {
- foreach (const UntypedTemp &var, _defUses.keys()) {
- const DefUse &du = _defUses[var];
- var.temp.dump(qout);
- qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: ";
- du.defStmt->dump(qout);
- qout<<endl<<" uses:"<<endl;
- foreach (Stmt *s, du.uses) {
- qout<<" ";s->dump(qout);qout<<endl;
- }
- }
- }
-
-protected:
- virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *s) { s->cond->accept(this); }
- virtual void visitRet(Ret *s) { s->expr->accept(this); }
-
- virtual void visitPhi(Phi *s) {
- addDef(s->targetTemp);
- foreach (Expr *e, s->d->incoming)
- addUse(e->asTemp());
- }
-
- virtual void visitMove(Move *s) {
- if (Temp *t = s->target->asTemp())
- addDef(t);
- else
- s->target->accept(this);
-
- s->source->accept(this);
- }
-
- virtual void visitTemp(Temp *e) { addUse(e); }
+/// Calculate if a phi node result is used only by other phi nodes, and if those uses are
+/// in turn also used by other phi nodes.
+bool hasPhiOnlyUses(Phi *phi, const DefUses &defUses, QBitArray &collectedPhis)
+{
+ collectedPhis.setBit(phi->id());
- virtual void visitConst(Const *) {}
- virtual void visitString(IR::String *) {}
- virtual void visitRegExp(IR::RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitClosure(Closure *) {}
- virtual void visitConvert(Convert *e) { e->expr->accept(this); }
- virtual void visitUnop(Unop *e) { e->expr->accept(this); }
- virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
- virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
- virtual void visitMember(Member *e) { e->base->accept(this); }
- virtual void visitCall(Call *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
+ foreach (Stmt *use, defUses.uses(*phi->targetTemp)) {
+ Phi *dependentPhi = use->asPhi();
+ if (!dependentPhi)
+ return false; // there is a use by a non-phi node
- virtual void visitNew(New *e) {
- e->base->accept(this);
- for (ExprList *it = e->args; it; it = it->next)
- it->expr->accept(this);
- }
-};
+ if (collectedPhis.at(dependentPhi->id()))
+ continue; // we already found this node
-bool hasPhiOnlyUses(Phi *phi, const DefUsesCalculator &defUses, QSet<Phi *> &collectedPhis)
-{
- collectedPhis.insert(phi);
- foreach (Stmt *use, defUses.uses(*phi->targetTemp)) {
- if (Phi *dependentPhi = use->asPhi()) {
- if (!collectedPhis.contains(dependentPhi)) {
- if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis))
- return false;
- }
- } else {
+ if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis))
return false;
- }
}
+
return true;
}
-void cleanupPhis(DefUsesCalculator &defUses)
+void cleanupPhis(DefUses &defUses)
{
- QLinkedList<Phi *> phis;
- foreach (const Temp &def, defUses.defs())
- if (Phi *phi = defUses.defStmt(def)->asPhi())
- phis.append(phi);
-
- QSet<Phi *> toRemove;
- while (!phis.isEmpty()) {
- Phi *phi = phis.first();
- phis.removeFirst();
- if (toRemove.contains(phi))
+ QBitArray toRemove(defUses.statementCount());
+ QBitArray collectedPhis(defUses.statementCount());
+ std::vector<Phi *> allPhis;
+ allPhis.reserve(32);
+
+ foreach (const Temp *def, defUses.defs()) {
+ Stmt *defStmt = defUses.defStmt(*def);
+ if (!defStmt)
+ continue;
+
+ Phi *phi = defStmt->asPhi();
+ if (!phi)
continue;
- QSet<Phi *> collectedPhis;
+ allPhis.push_back(phi);
+ if (toRemove.at(phi->id()))
+ continue;
+
+ collectedPhis.fill(false);
if (hasPhiOnlyUses(phi, defUses, collectedPhis))
- toRemove.unite(collectedPhis);
+ toRemove |= collectedPhis;
}
- foreach (Phi *phi, toRemove) {
- Temp targetVar = *phi->targetTemp;
+ foreach (Phi *phi, allPhis) {
+ if (!toRemove.at(phi->id()))
+ continue;
+ const Temp &targetVar = *phi->targetTemp;
defUses.defStmtBlock(targetVar)->removeStatement(phi);
foreach (const Temp &usedVar, defUses.usedVars(phi))
defUses.removeUse(phi, usedVar);
defUses.removeDef(targetVar);
}
+
+ defUses.cleanup();
}
class StatementWorklist
{
- QVector<Stmt *> worklist;
- QBitArray inWorklist;
- QSet<Stmt *> removed;
- QHash<Stmt*,Stmt*> replaced;
+ IR::Function *theFunction;
+ std::vector<Stmt *> stmts;
+ std::vector<bool> worklist;
+ unsigned worklistSize;
+ std::vector<int> replaced;
+ std::vector<bool> removed;
Q_DISABLE_COPY(StatementWorklist)
public:
StatementWorklist(IR::Function *function)
+ : theFunction(function)
+ , stmts(function->statementCount(), 0)
+ , worklist(function->statementCount(), false)
+ , worklistSize(0)
+ , replaced(function->statementCount(), Stmt::InvalidId)
+ , removed(function->statementCount())
{
- QVector<Stmt *> w;
- int stmtCount = 0;
+ grow();
- // Put in all statements, and number them on the fly. The numbering is used to index the
- // bit array.
foreach (BasicBlock *bb, function->basicBlocks()) {
if (bb->isRemoved())
continue;
foreach (Stmt *s, bb->statements()) {
- s->id = stmtCount++;
- w.append(s);
+ if (!s)
+ continue;
+
+ stmts[s->id()] = s;
+ worklist[s->id()] = true;
+ ++worklistSize;
}
}
+ }
- // For QVector efficiency reasons, we process statements from the back. However, it is more
- // effective to process the statements in ascending order. So we need to invert the
- // order.
- worklist.reserve(w.size());
- for (int i = w.size() - 1; i >= 0; --i)
- worklist.append(w.at(i));
+ void reset()
+ {
+ foreach (Stmt *s, stmts) {
+ if (!s)
+ continue;
- inWorklist = QBitArray(stmtCount, true);
+ worklist[s->id()] = true;
+ ++worklistSize;
+ }
+
+ replaced.assign(replaced.size(), Stmt::InvalidId);
+ removed.assign(removed.size(), false);
}
- // This will clear the entry for the statement in the basic block. After processing all
- // statements, the cleanup method needs to be run to remove all null-pointers.
- void clear(Stmt *stmt)
+ void remove(Stmt *stmt)
{
- Q_ASSERT(!inWorklist.at(stmt->id));
- removed.insert(stmt);
+ replaced[stmt->id()] = Stmt::InvalidId;
+ removed[stmt->id()] = true;
+ std::vector<bool>::reference inWorklist = worklist[stmt->id()];
+ if (inWorklist) {
+ inWorklist = false;
+ Q_ASSERT(worklistSize > 0);
+ --worklistSize;
+ }
}
void replace(Stmt *oldStmt, Stmt *newStmt)
{
Q_ASSERT(oldStmt);
+ Q_ASSERT(replaced[oldStmt->id()] == Stmt::InvalidId);
+ Q_ASSERT(removed[oldStmt->id()] == false);
+
Q_ASSERT(newStmt);
- Q_ASSERT(!removed.contains(oldStmt));
+ registerNewStatement(newStmt);
+ Q_ASSERT(replaced[newStmt->id()] == Stmt::InvalidId);
+ Q_ASSERT(removed[newStmt->id()] == false);
- if (newStmt->id == -1)
- newStmt->id = oldStmt->id;
- QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt);
- if (it != replaced.end())
- oldStmt = it.key();
- replaced[oldStmt] = newStmt;
+ replaced[oldStmt->id()] = newStmt->id();
+ worklist[oldStmt->id()] = false;
}
- void cleanup(IR::Function *function)
+ void applyToFunction()
{
- foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (BasicBlock *bb, theFunction->basicBlocks()) {
if (bb->isRemoved())
continue;
for (int i = 0; i < bb->statementCount();) {
- Stmt *stmt = bb->statements()[i];
- QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt);
- if (it != replaced.end() && !removed.contains(it.value())) {
- bb->replaceStatement(i, it.value());
- } else if (removed.contains(stmt)) {
+ Stmt *stmt = bb->statements().at(i);
+
+ int id = stmt->id();
+ Q_ASSERT(id != Stmt::InvalidId);
+ Q_ASSERT(static_cast<unsigned>(stmt->id()) < stmts.size());
+
+ for (int replacementId = replaced[id]; replacementId != Stmt::InvalidId; replacementId = replaced[replacementId])
+ id = replacementId;
+ Q_ASSERT(id != Stmt::InvalidId);
+ Q_ASSERT(static_cast<unsigned>(stmt->id()) < stmts.size());
+
+ if (removed[id]) {
bb->removeStatement(i);
- continue;
- }
+ } else {
+ if (id != stmt->id())
+ bb->replaceStatement(i, stmts[id]);
- ++i;
+ ++i;
+ }
}
}
+
+ replaced.assign(replaced.size(), Stmt::InvalidId);
+ removed.assign(removed.size(), false);
}
StatementWorklist &operator+=(const QVector<Stmt *> &stmts)
@@ -1601,18 +1764,17 @@ public:
return *this;
}
-
StatementWorklist &operator+=(Stmt *s)
{
if (!s)
return *this;
- Q_ASSERT(s->id >= 0);
- Q_ASSERT(s->id < inWorklist.size());
+ Q_ASSERT(s->id() >= 0);
+ Q_ASSERT(static_cast<unsigned>(s->id()) < worklist.size());
- if (!inWorklist.at(s->id)) {
- worklist.append(s);
- inWorklist.setBit(s->id);
+ if (!worklist[s->id()]) {
+ worklist[s->id()] = true;
+ ++worklistSize;
}
return *this;
@@ -1620,12 +1782,14 @@ public:
StatementWorklist &operator-=(Stmt *s)
{
- Q_ASSERT(s->id >= 0);
- Q_ASSERT(s->id < inWorklist.size());
-
- if (inWorklist.at(s->id)) {
- worklist.remove(worklist.indexOf(s));
- inWorklist.clearBit(s->id);
+ Q_ASSERT(s->id() >= 0);
+ Q_ASSERT(static_cast<unsigned>(s->id()) < worklist.size());
+
+ std::vector<bool>::reference inWorklist = worklist[s->id()];
+ if (inWorklist) {
+ inWorklist = false;
+ Q_ASSERT(worklistSize > 0);
+ --worklistSize;
}
return *this;
@@ -1633,34 +1797,78 @@ public:
bool isEmpty() const
{
- return worklist.isEmpty();
+ return worklistSize == 0;
}
- Stmt *takeOne()
+ Stmt *takeNext(Stmt *last)
{
if (isEmpty())
return 0;
- Stmt *s = worklist.last();
- Q_ASSERT(s->id < inWorklist.size());
- worklist.removeLast();
- inWorklist.clearBit(s->id);
+ const int startAt = last ? last->id() + 1 : 0;
+ Q_ASSERT(startAt >= 0);
+ Q_ASSERT(static_cast<unsigned>(startAt) <= worklist.size());
+
+ Q_ASSERT(worklist.size() == stmts.size());
+
+ // Do not compare the result of find with the end iterator, because some libc++ versions
+ // have a bug where the result of the ++operator is past-the-end of the vector, but unequal
+ // to end().
+ size_t pos = std::find(worklist.begin() + startAt, worklist.end(), true) - worklist.begin();
+ if (pos >= worklist.size())
+ pos = std::find(worklist.begin(), worklist.begin() + startAt, true) - worklist.begin();
+
+ worklist[pos] = false;
+ Q_ASSERT(worklistSize > 0);
+ --worklistSize;
+ Stmt *s = stmts.at(pos);
+ Q_ASSERT(s);
return s;
}
+
+ IR::Function *function() const
+ {
+ return theFunction;
+ }
+
+ void registerNewStatement(Stmt *s)
+ {
+ Q_ASSERT(s->id() >= 0);
+ if (static_cast<unsigned>(s->id()) >= stmts.size()) {
+ if (static_cast<unsigned>(s->id()) >= stmts.capacity())
+ grow();
+
+ int newSize = s->id() + 1;
+ stmts.resize(newSize, 0);
+ worklist.resize(newSize, false);
+ replaced.resize(newSize, Stmt::InvalidId);
+ removed.resize(newSize, false);
+ }
+
+ stmts[s->id()] = s;
+ }
+
+private:
+ void grow()
+ {
+ size_t newCapacity = ((stmts.capacity() + 1) * 3) / 2;
+ stmts.reserve(newCapacity);
+ worklist.reserve(newCapacity);
+ replaced.reserve(newCapacity);
+ removed.reserve(newCapacity);
+ }
};
class EliminateDeadCode: public ExprVisitor {
- DefUsesCalculator &_defUses;
+ DefUses &_defUses;
StatementWorklist &_worklist;
- IR::Function *function;
bool _sideEffect;
QVector<Temp *> _collectedTemps;
public:
- EliminateDeadCode(DefUsesCalculator &defUses, StatementWorklist &worklist, IR::Function *function)
+ EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist)
: _defUses(defUses)
, _worklist(worklist)
- , function(function)
{
_collectedTemps.reserve(8);
}
@@ -1691,11 +1899,6 @@ private:
_collectedTemps.clear();
}
- bool isCollectable(Temp *t) const
- {
- return unescapableTemp(t, function);
- }
-
protected:
virtual void visitConst(Const *) {}
virtual void visitString(IR::String *) {}
@@ -1713,10 +1916,11 @@ protected:
virtual void visitTemp(Temp *e)
{
- if (isCollectable(e))
- _collectedTemps.append(e);
+ _collectedTemps.append(e);
}
+ virtual void visitArgLocal(ArgLocal *) {}
+
virtual void visitClosure(Closure *)
{
markAsSideEffect();
@@ -1814,12 +2018,12 @@ struct DiscoveredType {
class PropagateTempTypes: public StmtVisitor, ExprVisitor
{
- const DefUsesCalculator &defUses;
+ const DefUses &defUses;
UntypedTemp theTemp;
DiscoveredType newType;
public:
- PropagateTempTypes(const DefUsesCalculator &defUses)
+ PropagateTempTypes(const DefUses &defUses)
: defUses(defUses)
{}
@@ -1827,9 +2031,9 @@ public:
{
newType = type;
theTemp = temp;
- if (Stmt *defStmt = defUses.defStmt(temp))
+ if (Stmt *defStmt = defUses.defStmt(temp.temp))
defStmt->accept(this);
- foreach (Stmt *use, defUses.uses(temp))
+ foreach (Stmt *use, defUses.uses(temp.temp))
use->accept(this);
}
@@ -1844,6 +2048,7 @@ protected:
e->memberResolver = newType.memberResolver;
}
}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e) { e->expr->accept(this); }
virtual void visitUnop(Unop *e) { e->expr->accept(this); }
@@ -1884,71 +2089,81 @@ protected:
}
};
-class TypeInference: public StmtVisitor, public ExprVisitor {
+class TypeInference: public StmtVisitor, public ExprVisitor
+{
+ enum { DebugTypeInference = 0 };
+
QQmlEnginePrivate *qmlEngine;
- IR::Function *function;
- const DefUsesCalculator &_defUses;
- typedef QHash<Temp, DiscoveredType> TempTypes;
+ const DefUses &_defUses;
+ typedef std::vector<DiscoveredType> TempTypes;
TempTypes _tempTypes;
- QList<Stmt *> _worklist;
+ StatementWorklist *_worklist;
struct TypingResult {
DiscoveredType type;
bool fullyTyped;
- TypingResult(const DiscoveredType &type = DiscoveredType()) : type(type), fullyTyped(type.type != UnknownType) {}
- explicit TypingResult(MemberExpressionResolver memberResolver): type(memberResolver), fullyTyped(true) {}
+ TypingResult(const DiscoveredType &type = DiscoveredType())
+ : type(type)
+ , fullyTyped(type.type != UnknownType)
+ {}
+ explicit TypingResult(MemberExpressionResolver memberResolver)
+ : type(memberResolver)
+ , fullyTyped(true)
+ {}
};
TypingResult _ty;
public:
- TypeInference(QQmlEnginePrivate *qmlEngine, const DefUsesCalculator &defUses)
+ TypeInference(QQmlEnginePrivate *qmlEngine, const DefUses &defUses)
: qmlEngine(qmlEngine)
, _defUses(defUses)
+ , _tempTypes(_defUses.tempCount())
+ , _worklist(0)
, _ty(UnknownType)
{}
- void run(IR::Function *f) {
- function = f;
+ void run(StatementWorklist &w) {
+ _worklist = &w;
- // TODO: the worklist handling looks a bit inefficient... check if there is something better
- _worklist.clear();
- for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlock(i);
- if (bb->isRemoved())
+ Stmt *s = 0;
+ while ((s = _worklist->takeNext(s))) {
+ if (s->asJump())
continue;
- if (i == 0 || !bb->in.isEmpty())
- _worklist += bb->statements().toList();
- }
-
- while (!_worklist.isEmpty()) {
- QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList();
- _worklist.clear();
- while (!worklist.isEmpty()) {
- Stmt *s = worklist.first();
- worklist.removeFirst();
- if (s->asJump())
- continue;
-#if defined(SHOW_SSA)
- qout<<"Typing stmt ";s->dump(qout);qout<<endl;
-#endif
+ if (DebugTypeInference) {
+ qout<<"Typing stmt ";
+ IRPrinter(&qout).print(s);
+ qout<<endl;
+ }
- if (!run(s)) {
- _worklist += s;
-#if defined(SHOW_SSA)
+ if (!run(s)) {
+ *_worklist += s;
+ if (DebugTypeInference) {
qout<<"Pushing back stmt: ";
- s->dump(qout);qout<<endl;
- } else {
+ IRPrinter(&qout).print(s);
+ qout<<endl;
+ }
+ } else {
+ if (DebugTypeInference) {
qout<<"Finished: ";
- s->dump(qout);qout<<endl;
-#endif
+ IRPrinter(&qout).print(s);
+ qout<<endl;
}
}
}
PropagateTempTypes propagator(_defUses);
- for (QHash<Temp, DiscoveredType>::const_iterator i = _tempTypes.begin(), ei = _tempTypes.end(); i != ei; ++i)
- propagator.run(i.key(), i.value());
+ for (unsigned i = 0, ei = _tempTypes.size(); i != ei; ++i) {
+ const Temp &temp = _defUses.temp(i);
+ if (temp.kind == Temp::Invalid)
+ continue;
+ const DiscoveredType &tempType = _tempTypes[i];
+ if (tempType.type == UnknownType)
+ continue;
+ propagator.run(temp, tempType);
+ }
+
+ _worklist = 0;
}
private:
@@ -1971,35 +2186,26 @@ private:
return ty;
}
- bool isAlwaysVar(Temp *t) {
- if (unescapableTemp(t, function))
- return false;
- t->type = VarType;
- return true;
- }
-
void setType(Expr *e, DiscoveredType ty) {
if (Temp *t = e->asTemp()) {
-#if defined(SHOW_SSA)
- qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
-#endif
- if (isAlwaysVar(t))
- ty = DiscoveredType(VarType);
- TempTypes::iterator it = _tempTypes.find(*t);
- if (it == _tempTypes.end())
- it = _tempTypes.insert(*t, DiscoveredType());
- if (it.value() != ty) {
- it.value() = ty;
-
-#if defined(SHOW_SSA)
- foreach (Stmt *s, _defUses.uses(*t)) {
- qout << "Pushing back dependent stmt: ";
- s->dump(qout);
- qout << endl;
+ if (DebugTypeInference)
+ qout << "Setting type for temp " << t->index
+ << " to " << typeName(Type(ty.type)) << " (" << ty.type << ")"
+ << endl;
+
+ DiscoveredType &it = _tempTypes[t->index];
+ if (it != ty) {
+ it = ty;
+
+ if (DebugTypeInference) {
+ foreach (Stmt *s, _defUses.uses(*t)) {
+ qout << "Pushing back dependent stmt: ";
+ IRPrinter(&qout).print(s);
+ qout<<endl;
+ }
}
-#endif
- _worklist += _defUses.uses(*t);
+ *_worklist += _defUses.uses(*t);
}
} else {
e->type = (Type) ty.type;
@@ -2022,14 +2228,17 @@ protected:
virtual void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); }
virtual void visitName(Name *) { _ty = TypingResult(VarType); }
virtual void visitTemp(Temp *e) {
- if (isAlwaysVar(e))
- _ty = TypingResult(VarType);
- else if (e->memberResolver.isValid())
+ if (e->memberResolver.isValid())
_ty = TypingResult(e->memberResolver);
else
- _ty = TypingResult(_tempTypes.value(*e));
+ _ty = TypingResult(_tempTypes[e->index]);
setType(e, _ty.type);
}
+ virtual void visitArgLocal(ArgLocal *e) {
+ _ty = TypingResult(VarType);
+ setType(e, _ty.type);
+ }
+
virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); }
virtual void visitConvert(Convert *e) {
_ty = TypingResult(e->type);
@@ -2201,15 +2410,17 @@ protected:
class ReverseInference
{
- const DefUsesCalculator &_defUses;
+ const DefUses &_defUses;
public:
- ReverseInference(const DefUsesCalculator &defUses)
+ ReverseInference(const DefUses &defUses)
: _defUses(defUses)
{}
void run(IR::Function *f)
{
+ Q_UNUSED(f);
+
QVector<UntypedTemp> knownOk;
QList<UntypedTemp> candidates = _defUses.defsUntyped();
while (!candidates.isEmpty()) {
@@ -2222,7 +2433,7 @@ public:
if (!isUsedAsInt32(temp, knownOk))
continue;
- Stmt *s = _defUses.defStmt(temp);
+ Stmt *s = _defUses.defStmt(temp.temp);
Move *m = s->asMove();
if (!m)
continue;
@@ -2252,13 +2463,13 @@ public:
default:
continue;
}
- if (Temp *lt = unescapableTemp(b->left, f))
+ if (Temp *lt = b->left->asTemp())
candidates.append(*lt);
- if (Temp *rt = unescapableTemp(b->right, f))
+ if (Temp *rt = b->right->asTemp())
candidates.append(*rt);
} else if (Unop *u = m->source->asUnop()) {
if (u->op == OpCompl || u->op == OpUPlus) {
- if (Temp *t = unescapableTemp(u->expr, f))
+ if (Temp *t = u->expr->asTemp())
candidates.append(*t);
}
} else {
@@ -2271,7 +2482,7 @@ public:
PropagateTempTypes propagator(_defUses);
foreach (const UntypedTemp &t, knownOk) {
propagator.run(t, SInt32Type);
- if (Stmt *defStmt = _defUses.defStmt(t)) {
+ if (Stmt *defStmt = _defUses.defStmt(t.temp)) {
if (Move *m = defStmt->asMove()) {
if (Convert *c = m->source->asConvert()) {
c->type = SInt32Type;
@@ -2289,7 +2500,7 @@ public:
private:
bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
{
- const QList<Stmt *> &uses = _defUses.uses(t);
+ const QVector<Stmt *> &uses = _defUses.uses(t.temp);
if (uses.isEmpty())
return false;
@@ -2364,7 +2575,7 @@ void convertConst(Const *c, Type targetType)
}
class TypePropagation: public StmtVisitor, public ExprVisitor {
- DefUsesCalculator &_defUses;
+ DefUses &_defUses;
Type _ty;
IR::Function *_f;
@@ -2415,9 +2626,9 @@ class TypePropagation: public StmtVisitor, public ExprVisitor {
}
public:
- TypePropagation(DefUsesCalculator &defUses) : _defUses(defUses), _ty(UnknownType) {}
+ TypePropagation(DefUses &defUses) : _defUses(defUses), _ty(UnknownType) {}
- void run(IR::Function *f) {
+ void run(IR::Function *f, StatementWorklist &worklist) {
_f = f;
foreach (BasicBlock *bb, f->basicBlocks()) {
if (bb->isRemoved())
@@ -2438,13 +2649,35 @@ public:
*conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType);
} else if (Const *c = (*conversion.expr)->asConst()) {
convertConst(c, conversion.targetType);
+ } else if (ArgLocal *al = (*conversion.expr)->asArgLocal()) {
+ Temp *target = bb->TEMP(bb->newTemp());
+ target->type = conversion.targetType;
+ Expr *convert = bb->CONVERT(al, conversion.targetType);
+ Move *convCall = f->NewStmt<Move>();
+ worklist.registerNewStatement(convCall);
+ convCall->init(target, convert);
+ _defUses.addDef(target, convCall, bb);
+
+ Temp *source = bb->TEMP(target->index);
+ source->type = conversion.targetType;
+ _defUses.addUse(*source, conversion.stmt);
+
+ if (conversion.stmt->asPhi()) {
+ // Only temps can be used as arguments to phi nodes, so this is a sanity check...:
+ Q_UNREACHABLE();
+ } else {
+ bb->insertStatementBefore(conversion.stmt, convCall);
+ }
+
+ *conversion.expr = source;
} else if (Temp *t = (*conversion.expr)->asTemp()) {
Temp *target = bb->TEMP(bb->newTemp());
target->type = conversion.targetType;
Expr *convert = bb->CONVERT(t, conversion.targetType);
- Move *convCall = f->New<Move>();
+ Move *convCall = f->NewStmt<Move>();
+ worklist.registerNewStatement(convCall);
convCall->init(target, convert);
- _defUses.addTemp(target, convCall, bb);
+ _defUses.addDef(target, convCall, bb);
_defUses.addUse(*t, convCall);
Temp *source = bb->TEMP(target->index);
@@ -2469,9 +2702,10 @@ public:
// int32{%2} = int32{convert(double{%3})};
Temp *tmp = bb->TEMP(bb->newTemp());
tmp->type = u->type;
- Move *extraMove = f->New<Move>();
+ Move *extraMove = f->NewStmt<Move>();
+ worklist.registerNewStatement(extraMove);
extraMove->init(tmp, u);
- _defUses.addTemp(tmp, extraMove, bb);
+ _defUses.addDef(tmp, extraMove, bb);
if (Temp *unopOperand = u->expr->asTemp()) {
_defUses.addUse(*unopOperand, extraMove);
@@ -2480,7 +2714,7 @@ public:
bb->insertStatementBefore(conversion.stmt, extraMove);
- *conversion.expr = bb->CONVERT(tmp, conversion.targetType);
+ *conversion.expr = bb->CONVERT(CloneExpr::cloneTemp(tmp, f), conversion.targetType);
_defUses.addUse(*tmp, move);
} else {
Q_UNREACHABLE();
@@ -2504,6 +2738,7 @@ protected:
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {}
virtual void visitTemp(Temp *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e) { run(e->expr, e->type); }
virtual void visitUnop(Unop *e) { run(e->expr, e->type); }
@@ -2608,7 +2843,7 @@ protected:
}
};
-void splitCriticalEdges(IR::Function *f, DominatorTree &df)
+void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &worklist, DefUses &defUses)
{
foreach (BasicBlock *bb, f->basicBlocks()) {
if (bb->isRemoved())
@@ -2622,11 +2857,11 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df)
continue;
// We found a critical edge.
- BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
-
// create the basic block:
- BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock);
- Jump *s = f->New<Jump>();
+ BasicBlock *newBB = f->newBasicBlock(bb->catchBlock);
+ Jump *s = f->NewStmt<Jump>();
+ worklist.registerNewStatement(s);
+ defUses.registerNewStatement(s);
s->init(bb);
newBB->appendStatement(s);
@@ -2663,6 +2898,231 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df)
}
}
+// Detect all (sub-)loops in a function.
+//
+// Doing loop detection on the CFG is better than relying on the statement information in
+// order to mark loops. Although JavaScript only has natural loops, it can still be the case
+// that something is not a loop even though a loop-like-statement is in the source. For
+// example:
+// while (true) {
+// if (i > 0)
+// break;
+// else
+// break;
+// }
+//
+// Algorithm:
+// - do a DFS on the dominator tree, where for each node:
+// - collect all back-edges
+// - if there are back-edges, the node is a loop-header for a new loop, so:
+// - walk the CFG is reverse-direction, and for every node:
+// - if the node already belongs to a loop, we've found a nested loop:
+// - get the loop-header for the (outermost) nested loop
+// - add that loop-header to the current loop
+// - continue by walking all incoming edges that do not yet belong to the current loop
+// - if the node does not belong to a loop yet, add it to the current loop, and
+// go on with all incoming edges
+//
+// Loop-header detection by checking for back-edges is very straight forward: a back-edge is
+// an incoming edge where the other node is dominated by the current node. Meaning: all
+// execution paths that reach that other node have to go through the current node, that other
+// node ends with a (conditional) jump back to the loop header.
+//
+// The exact order of the DFS on the dominator tree is not important. The only property has to
+// be that a node is only visited when all the nodes it dominates have been visited before.
+// The reason for the DFS is that for nested loops, the inner loop's loop-header is dominated
+// by the outer loop's header. So, by visiting depth-first, sub-loops are identified before
+// their containing loops, which makes nested-loop identification free. An added benefit is
+// that the nodes for those sub-loops are only processed once.
+//
+// Note: independent loops that share the same header are merged together. For example, in
+// the code snippet below, there are 2 back-edges into the loop-header, but only one single
+// loop will be detected.
+// while (a) {
+// if (b)
+// continue;
+// else
+// continue;
+// }
+class LoopDetection
+{
+ enum { DebugLoopDetection = 0 };
+
+ Q_DISABLE_COPY(LoopDetection)
+
+public:
+ struct LoopInfo
+ {
+ BasicBlock *loopHeader;
+ QVector<BasicBlock *> loopBody;
+ QVector<LoopInfo *> nestedLoops;
+ LoopInfo *parentLoop;
+
+ LoopInfo(BasicBlock *loopHeader = 0)
+ : loopHeader(loopHeader)
+ , parentLoop(0)
+ {}
+
+ bool isValid() const
+ { return loopHeader != 0; }
+
+ void addNestedLoop(LoopInfo *nested)
+ {
+ Q_ASSERT(nested);
+ Q_ASSERT(!nestedLoops.contains(nested));
+ Q_ASSERT(nested->parentLoop == 0);
+ nested->parentLoop = this;
+ nestedLoops.append(nested);
+ }
+ };
+
+public:
+ LoopDetection(const DominatorTree &dt)
+ : dt(dt)
+ {}
+
+ ~LoopDetection()
+ {
+ qDeleteAll(loopInfos);
+ }
+
+ void run(IR::Function *function)
+ {
+ std::vector<BasicBlock *> backedges;
+ backedges.reserve(4);
+
+ foreach (BasicBlock *bb, dt.calculateDFNodeIterOrder()) {
+ Q_ASSERT(!bb->isRemoved());
+
+ backedges.clear();
+
+ foreach (BasicBlock *in, bb->in)
+ if (dt.dominates(bb, in))
+ backedges.push_back(in);
+
+ if (!backedges.empty()) {
+ subLoop(bb, backedges);
+ }
+ }
+
+ createLoopInfos(function);
+ dumpLoopInfo();
+ }
+
+ void dumpLoopInfo() const
+ {
+ if (!DebugLoopDetection)
+ return;
+
+ foreach (LoopInfo *info, loopInfos) {
+ qDebug() << "Loop header:" << info->loopHeader->index()
+ << "for loop" << quint64(info);
+ foreach (BasicBlock *bb, info->loopBody)
+ qDebug() << " " << bb->index();
+ foreach (LoopInfo *nested, info->nestedLoops)
+ qDebug() << " sub loop:" << quint64(nested);
+ qDebug() << " parent loop:" << quint64(info->parentLoop);
+ }
+ }
+
+ QVector<LoopInfo *> allLoops() const
+ { return loopInfos; }
+
+ // returns all loop headers for loops that have no nested loops.
+ QVector<LoopInfo *> innermostLoops() const
+ {
+ QVector<LoopInfo *> inner(loopInfos);
+
+ for (int i = 0; i < inner.size(); ) {
+ if (inner.at(i)->nestedLoops.isEmpty())
+ ++i;
+ else
+ inner.remove(i);
+ }
+
+ return inner;
+ }
+
+private:
+ void subLoop(BasicBlock *loopHead, const std::vector<BasicBlock *> &backedges)
+ {
+ loopHead->markAsGroupStart();
+
+ std::vector<BasicBlock *> worklist;
+ worklist.reserve(backedges.size() + 8);
+ worklist.insert(worklist.end(), backedges.begin(), backedges.end());
+ while (!worklist.empty()) {
+ BasicBlock *predIt = worklist.back();
+ worklist.pop_back();
+
+ BasicBlock *subloop = predIt->containingGroup();
+ if (subloop) {
+ // This is a discovered block. Find its outermost discovered loop.
+ while (BasicBlock *parentLoop = subloop->containingGroup())
+ subloop = parentLoop;
+
+ // If it is already discovered to be a subloop of this loop, continue.
+ if (subloop == loopHead)
+ continue;
+
+ // Yay, it's a subloop of this loop.
+ subloop->setContainingGroup(loopHead);
+ predIt = subloop;
+
+ // Add all predecessors of the subloop header to the worklist, as long as
+ // those predecessors are not in the current subloop. It might be the case
+ // that they are in other loops, which we will then add as a subloop to the
+ // current loop.
+ foreach (BasicBlock *predIn, predIt->in)
+ if (predIn->containingGroup() != subloop)
+ worklist.push_back(predIn);
+ } else {
+ if (predIt == loopHead)
+ continue;
+
+ // This is an undiscovered block. Map it to the current loop.
+ predIt->setContainingGroup(loopHead);
+
+ // Add all incoming edges to the worklist.
+ foreach (BasicBlock *bb, predIt->in)
+ worklist.push_back(bb);
+ }
+ }
+ }
+
+private:
+ const DominatorTree &dt;
+ QVector<LoopInfo *> loopInfos;
+
+ void createLoopInfos(IR::Function *function)
+ {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ if (BasicBlock *loopHeader = bb->containingGroup())
+ findLoop(loopHeader)->loopBody.append(bb);
+ }
+
+ foreach (LoopInfo *info, loopInfos) {
+ if (BasicBlock *containingLoopHeader = info->loopHeader->containingGroup())
+ findLoop(containingLoopHeader)->addNestedLoop(info);
+ }
+ }
+
+ LoopInfo *findLoop(BasicBlock *loopHeader)
+ {
+ foreach (LoopInfo *info, loopInfos) {
+ if (info->loopHeader == loopHeader)
+ return info;
+ }
+
+ LoopInfo *info = new LoopInfo;
+ info->loopHeader = loopHeader;
+ loopInfos.append(info);
+ return info;
+ }
+};
+
// High-level algorithm:
// 0. start with the first node (the start node) of a function
// 1. emit the node
@@ -2931,20 +3391,20 @@ static Expr *clone(Expr *e, IR::Function *function) {
class ExprReplacer: public StmtVisitor, public ExprVisitor
{
- DefUsesCalculator &_defUses;
+ DefUses &_defUses;
IR::Function* _function;
Temp *_toReplace;
Expr *_replacement;
public:
- ExprReplacer(DefUsesCalculator &defUses, IR::Function *function)
+ ExprReplacer(DefUses &defUses, IR::Function *function)
: _defUses(defUses)
, _function(function)
, _toReplace(0)
, _replacement(0)
{}
- void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0)
+ void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0)
{
Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
@@ -2953,7 +3413,7 @@ public:
qSwap(_toReplace, toReplace);
qSwap(_replacement, replacement);
- const QList<Stmt *> &uses = _defUses.uses(*_toReplace);
+ const QVector<Stmt *> &uses = _defUses.uses(*_toReplace);
if (newUses)
newUses->reserve(uses.size());
@@ -2964,7 +3424,7 @@ public:
// qout<<" -> ";use->dump(qout);qout<<"\n";
W += use;
if (newUses)
- newUses->append(use);
+ newUses->push_back(use);
}
qSwap(_replacement, replacement);
@@ -2977,6 +3437,7 @@ protected:
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {}
virtual void visitTemp(Temp *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e) { check(e->expr); }
virtual void visitUnop(Unop *e) { check(e->expr); }
@@ -3047,7 +3508,7 @@ namespace {
/// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them
/// anymore.
/// Important: this assumes that there are no critical edges in the control-flow graph!
-void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W,
+void purgeBB(BasicBlock *bb, IR::Function *func, DefUses &defUses, StatementWorklist &W,
DominatorTree &df)
{
// TODO: after the change above: if we keep on detaching the block from predecessors or
@@ -3085,8 +3546,10 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
if (!outStmt)
continue;
if (Phi *phi = outStmt->asPhi()) {
- if (Temp *t = phi->d->incoming[idx]->asTemp())
+ if (Temp *t = phi->d->incoming[idx]->asTemp()) {
defUses.removeUse(phi, *t);
+ W += defUses.defStmt(*t);
+ }
phi->d->incoming.remove(idx);
W += phi;
} else
@@ -3180,24 +3643,79 @@ bool tryOptimizingComparison(Expr *&expr)
return false;
}
+
+void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = QVector<LoopDetection::LoopInfo *>())
+{
+ static bool showCode = !qgetenv("QV4_SHOW_IR").isNull();
+ if (!showCode)
+ return;
+
+ struct Util {
+ static void genLoop(LoopDetection::LoopInfo *loop)
+ {
+ qout << " subgraph \"cluster" << quint64(loop) << "\" {\n";
+ qout << " L" << loop->loopHeader->index() << ";\n";
+ foreach (BasicBlock *bb, loop->loopBody)
+ qout << " L" << bb->index() << ";\n";
+ foreach (LoopDetection::LoopInfo *nested, loop->nestedLoops)
+ genLoop(nested);
+ qout << " }\n";
+ }
+ };
+
+ QString name;
+ if (f->name) name = *f->name;
+ else name = QString::fromLatin1("%1").arg((unsigned long long)f);
+ qout << "digraph \"" << name << "\" { ordering=out;\n";
+
+ foreach (LoopDetection::LoopInfo *l, loops) {
+ if (l->parentLoop == 0)
+ Util::genLoop(l);
+ }
+
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ int idx = bb->index();
+ qout << " L" << idx << " [label=\"L" << idx << "\"";
+ if (idx == 0 || bb->terminator()->asRet())
+ qout << ", shape=doublecircle";
+ else
+ qout << ", shape=circle";
+ qout << "];\n";
+ foreach (BasicBlock *out, bb->out)
+ qout << " L" << idx << " -> L" << out->index() << "\n";
+ }
+
+ qout << "}\n" << flush;
+}
+
} // anonymous namespace
-void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTree &df)
+void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df)
{
- StatementWorklist W(function);
+ IR::Function *function = W.function();
ExprReplacer replaceUses(defUses, function);
+ Stmt *s = 0;
while (!W.isEmpty()) {
- Stmt *s = W.takeOne();
- if (!s)
- continue;
+ s = W.takeNext(s);
+ Q_ASSERT(s);
if (Phi *phi = s->asPhi()) {
+ // dead code elimination:
+ if (defUses.useCount(*phi->targetTemp) == 0) {
+ W += defUses.removeDefUses(phi);
+ W.remove(s);
+ continue;
+ }
+
// constant propagation:
if (Const *c = isConstPhi(phi)) {
replaceUses(phi->targetTemp, c, W);
defUses.removeDef(*phi->targetTemp);
- W.clear(s);
+ W.remove(s);
continue;
}
@@ -3206,26 +3724,15 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
Temp *t = phi->targetTemp;
Expr *e = phi->d->incoming.first();
- QList<Stmt *> newT2Uses;
+ QVector<Stmt *> newT2Uses;
replaceUses(t, e, W, &newT2Uses);
if (Temp *t2 = e->asTemp()) {
defUses.removeUse(s, *t2);
defUses.addUses(*t2, newT2Uses);
+ W += defUses.defStmt(*t2);
}
defUses.removeDef(*t);
- W.clear(s);
- continue;
- }
-
- // dead code elimination:
- if (defUses.useCount(*phi->targetTemp) == 0) {
- foreach (Expr *in, phi->d->incoming) {
- if (Temp *t = in->asTemp())
- W += defUses.defStmt(*t);
- }
-
- defUses.removeDef(*phi->targetTemp);
- W.clear(s);
+ W.remove(s);
continue;
}
} else if (Move *m = s->asMove()) {
@@ -3244,12 +3751,12 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
}
}
- if (Temp *targetTemp = unescapableTemp(m->target, function)) {
+ if (Temp *targetTemp = m->target->asTemp()) {
// dead code elimination:
if (defUses.useCount(*targetTemp) == 0) {
- EliminateDeadCode(defUses, W, function).run(m->source, s);
+ EliminateDeadCode(defUses, W).run(m->source, s);
if (!m->source)
- W.clear(s);
+ W.remove(s);
continue;
}
@@ -3257,7 +3764,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
if (Const *sourceConst = m->source->asConst()) {
replaceUses(targetTemp, sourceConst, W);
defUses.removeDef(*targetTemp);
- W.clear(s);
+ W.remove(s);
continue;
}
if (Member *member = m->source->asMember()) {
@@ -3267,7 +3774,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
c->init(SInt32Type, enumValue);
replaceUses(targetTemp, c, W);
defUses.removeDef(*targetTemp);
- W.clear(s);
+ W.remove(s);
defUses.removeUse(s, *member->base->asTemp());
continue;
} else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) {
@@ -3282,13 +3789,13 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
}
// copy propagation:
- if (Temp *sourceTemp = unescapableTemp(m->source, function)) {
- QList<Stmt *> newT2Uses;
+ if (Temp *sourceTemp = m->source->asTemp()) {
+ QVector<Stmt *> newT2Uses;
replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
defUses.removeUse(s, *sourceTemp);
defUses.addUses(*sourceTemp, newT2Uses);
defUses.removeDef(*targetTemp);
- W.clear(s);
+ W.remove(s);
continue;
}
@@ -3451,7 +3958,8 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
if (Const *constantCondition = cjump->cond->asConst()) {
// Note: this assumes that there are no critical edges! Meaning, we can safely purge
// any basic blocks that are found to be unreachable.
- Jump *jump = function->New<Jump>();
+ Jump *jump = function->NewStmt<Jump>();
+ W.registerNewStatement(jump);
if (convertToValue(constantCondition).toBoolean()) {
jump->target = cjump->iftrue;
purgeBB(cjump->iffalse, function, defUses, W, df);
@@ -3473,21 +3981,27 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
}
}
- W.cleanup(function);
+ W.applyToFunction();
}
+//### TODO: use DefUses from the optimizer, because it already has all this information
class InputOutputCollector: protected StmtVisitor, protected ExprVisitor {
- IR::Function *function;
+ void setOutput(Temp *out)
+ {
+ Q_ASSERT(!output);
+ output = out;
+ }
public:
- QList<Temp> inputs;
- QList<Temp> outputs;
+ std::vector<Temp *> inputs;
+ Temp *output;
- InputOutputCollector(IR::Function *f): function(f) {}
+ InputOutputCollector()
+ { inputs.reserve(4); }
void collect(Stmt *s) {
- inputs.clear();
- outputs.clear();
+ inputs.resize(0);
+ output = 0;
s->accept(this);
}
@@ -3497,9 +4011,9 @@ protected:
virtual void visitRegExp(IR::RegExp *) {}
virtual void visitName(Name *) {}
virtual void visitTemp(Temp *e) {
- if (unescapableTemp(e, function))
- inputs.append(*e);
+ inputs.push_back(e);
}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitClosure(Closure *) {}
virtual void visitConvert(Convert *e) { e->expr->accept(this); }
virtual void visitUnop(Unop *e) { e->expr->accept(this); }
@@ -3520,10 +4034,7 @@ protected:
virtual void visitMove(Move *s) {
s->source->accept(this);
if (Temp *t = s->target->asTemp()) {
- if (unescapableTemp(t, function))
- outputs.append(*t);
- else
- s->target->accept(this);
+ setOutput(t);
} else {
s->target->accept(this);
}
@@ -3542,74 +4053,88 @@ protected:
* Linear Scan Register Allocation on SSA Form
* Christian Wimmer & Michael Franz, CGO'10, April 24-28, 2010
*
- * There is one slight difference w.r.t. the phi-nodes: in the artice, the phi nodes are attached
- * to the basic-blocks. Therefore, in the algorithm in the article, the ranges for input parameters
- * for phi nodes run from their definition upto the branch instruction into the block with the phi
- * node. In our representation, phi nodes are mostly treaded as normal instructions, so we have to
- * enlarge the range to cover the phi node itself.
+ * See LifeTimeIntervals::renumber for details on the numbering.
*/
class LifeRanges {
typedef QSet<Temp> LiveRegs;
- QVector<LiveRegs> _liveIn;
- QHash<Temp, LifeTimeInterval> _intervals;
- typedef QVector<LifeTimeInterval> LifeTimeIntervals;
- LifeTimeIntervals _sortedIntervals;
+ std::vector<LiveRegs> _liveIn;
+ std::vector<LifeTimeInterval *> _intervals;
+ LifeTimeIntervals::Ptr _sortedIntervals;
+
+ LifeTimeInterval &interval(const Temp *temp)
+ {
+ LifeTimeInterval *&lti = _intervals[temp->index];
+ if (Q_UNLIKELY(!lti)) {
+ lti = new LifeTimeInterval;
+ lti->setTemp(*temp);
+ }
+ return *lti;
+ }
+
+ int defPosition(IR::Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(IR::Stmt *s) const
+ {
+ return _sortedIntervals->positionForStatement(s);
+ }
+
+ int start(IR::BasicBlock *bb) const
+ {
+ return _sortedIntervals->startPosition(bb);
+ }
+
+ int end(IR::BasicBlock *bb) const
+ {
+ return _sortedIntervals->endPosition(bb);
+ }
public:
LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
+ : _intervals(function->tempCount)
{
+ _sortedIntervals = LifeTimeIntervals::create(function);
_liveIn.resize(function->basicBlockCount());
- int id = 0;
- foreach (BasicBlock *bb, function->basicBlocks()) {
- foreach (Stmt *s, bb->statements()) {
- if (s->asPhi())
- s->id = id + 1;
- else
- s->id = ++id;
- }
- }
-
for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
BasicBlock *bb = function->basicBlock(i);
- buildIntervals(bb, startEndLoops.value(bb, 0), function);
+ buildIntervals(bb, startEndLoops.value(bb, 0));
}
- _sortedIntervals.reserve(_intervals.size());
- for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) {
- LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value());
- lti->setTemp(i.key());
- }
- std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan);
_intervals.clear();
}
- QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; }
+ LifeTimeIntervals::Ptr intervals() const { return _sortedIntervals; }
void dump() const
{
qout << "Life ranges:" << endl;
qout << "Intervals:" << endl;
- foreach (const LifeTimeInterval &range, _sortedIntervals) {
- range.dump(qout);
+ foreach (const LifeTimeInterval *range, _sortedIntervals->intervals()) {
+ range->dump(qout);
qout << endl;
}
+ IRPrinter printer(&qout);
for (int i = 0, ei = _liveIn.size(); i != ei; ++i) {
qout << "L" << i <<" live-in: ";
QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
+ if (live.isEmpty())
+ qout << "(none)";
std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) {
if (i > 0) qout << ", ";
- live[i].dump(qout);
+ printer.print(&live[i]);
}
qout << endl;
}
}
private:
- void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd, IR::Function *function)
+ void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd)
{
LiveRegs live;
foreach (BasicBlock *successor, bb->out) {
@@ -3630,35 +4155,41 @@ private:
QVector<Stmt *> statements = bb->statements();
foreach (const Temp &opd, live)
- _intervals[opd].addRange(statements.first()->id, statements.last()->id);
+ interval(&opd).addRange(start(bb), end(bb));
- InputOutputCollector collector(function);
+ InputOutputCollector collector;
for (int i = statements.size() - 1; i >= 0; --i) {
- Stmt *s = statements[i];
+ Stmt *s = statements.at(i);
if (Phi *phi = s->asPhi()) {
LiveRegs::iterator it = live.find(*phi->targetTemp);
if (it == live.end()) {
// a phi node target that is only defined, but never used
- _intervals[*phi->targetTemp].setFrom(s);
+ interval(phi->targetTemp).setFrom(start(bb));
} else {
live.erase(it);
}
+ _sortedIntervals->add(&interval(phi->targetTemp));
continue;
}
collector.collect(s);
- foreach (const Temp &opd, collector.outputs) {
- _intervals[opd].setFrom(s);
- live.remove(opd);
+ //### TODO: use DefUses from the optimizer, because it already has all this information
+ if (Temp *opd = collector.output) {
+ LifeTimeInterval &lti = interval(opd);
+ lti.setFrom(defPosition(s));
+ live.remove(lti.temp());
+ _sortedIntervals->add(&lti);
}
- foreach (const Temp &opd, collector.inputs) {
- _intervals[opd].addRange(statements.first()->id, s->id);
- live.insert(opd);
+ //### TODO: use DefUses from the optimizer, because it already has all this information
+ for (unsigned i = 0, ei = collector.inputs.size(); i != ei; ++i) {
+ Temp *opd = collector.inputs[i];
+ interval(opd).addRange(start(bb), usePosition(s));
+ live.insert(*opd);
}
}
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
foreach (const Temp &opd, live)
- _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id);
+ interval(&opd).addRange(start(bb), usePosition(loopEnd->terminator()));
}
_liveIn[bb->index()] = live;
@@ -3675,17 +4206,280 @@ void removeUnreachleBlocks(IR::Function *function)
function->setScheduledBlocks(newSchedule);
function->renumberBasicBlocks();
}
+
+class ConvertArgLocals: protected StmtVisitor, protected ExprVisitor
+{
+public:
+ ConvertArgLocals(IR::Function *function)
+ : function(function)
+ , convertArgs(!function->usesArgumentsObject)
+ {
+ tempForFormal.resize(function->formals.size(), -1);
+ tempForLocal.resize(function->locals.size(), -1);
+ }
+
+ void toTemps()
+ {
+ if (function->variablesCanEscape())
+ return;
+
+ QVector<Stmt *> extraMoves;
+ if (convertArgs) {
+ const int formalCount = function->formals.size();
+ extraMoves.reserve(formalCount + function->basicBlock(0)->statementCount());
+ extraMoves.resize(formalCount);
+
+ for (int i = 0; i != formalCount; ++i) {
+ const int newTemp = function->tempCount++;
+ tempForFormal[i] = newTemp;
+
+ ArgLocal *source = function->New<ArgLocal>();
+ source->init(ArgLocal::Formal, i, 0);
+
+ Temp *target = function->New<Temp>();
+ target->init(Temp::VirtualRegister, newTemp);
+
+ Move *m = function->NewStmt<Move>();
+ m->init(target, source);
+ extraMoves[i] = m;
+ }
+ }
+
+ foreach (BasicBlock *bb, function->basicBlocks())
+ if (!bb->isRemoved())
+ foreach (Stmt *s, bb->statements())
+ s->accept(this);
+
+ if (convertArgs && function->formals.size() > 0)
+ function->basicBlock(0)->prependStatements(extraMoves);
+
+ function->locals.clear();
+ }
+
+protected:
+ virtual void visitConst(Const *) {}
+ virtual void visitString(IR::String *) {}
+ virtual void visitRegExp(IR::RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitArgLocal(ArgLocal *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { check(e->expr); }
+ virtual void visitUnop(Unop *e) { check(e->expr); }
+ virtual void visitBinop(Binop *e) { check(e->left); check(e->right); }
+ virtual void visitCall(Call *e) {
+ check(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ check(it->expr);
+ }
+ virtual void visitNew(New *e) {
+ check(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ check(it->expr);
+ }
+ virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); }
+ virtual void visitMember(Member *e) { check(e->base); }
+ virtual void visitExp(Exp *s) { check(s->expr); }
+ virtual void visitMove(Move *s) { check(s->target); check(s->source); }
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { check(s->cond); }
+ virtual void visitRet(Ret *s) { check(s->expr); }
+ virtual void visitPhi(Phi *) {
+ Q_UNREACHABLE();
+ }
+
+private:
+ void check(Expr *&e) {
+ if (ArgLocal *al = e->asArgLocal()) {
+ if (al->kind == ArgLocal::Local) {
+ Temp *t = function->New<Temp>();
+ t->init(Temp::VirtualRegister, fetchTempForLocal(al->index));
+ e = t;
+ } else if (convertArgs && al->kind == ArgLocal::Formal) {
+ Temp *t = function->New<Temp>();
+ t->init(Temp::VirtualRegister, fetchTempForFormal(al->index));
+ e = t;
+ }
+ } else {
+ e->accept(this);
+ }
+ }
+
+ int fetchTempForLocal(int local)
+ {
+ int &ref = tempForLocal[local];
+ if (ref == -1)
+ ref = function->tempCount++;
+ return ref;
+ }
+
+ int fetchTempForFormal(int formal)
+ {
+ return tempForFormal[formal];
+ }
+
+ IR::Function *function;
+ bool convertArgs;
+ std::vector<int> tempForFormal;
+ std::vector<int> tempForLocal;
+};
+
+static void verifyCFG(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved()) {
+ Q_ASSERT(bb->in.isEmpty());
+ Q_ASSERT(bb->out.isEmpty());
+ continue;
+ }
+
+ Q_ASSERT(function->basicBlock(bb->index()) == bb);
+
+ // Check the terminators:
+ if (Jump *jump = bb->terminator()->asJump()) {
+ Q_UNUSED(jump);
+ Q_ASSERT(jump->target);
+ Q_ASSERT(!jump->target->isRemoved());
+ Q_ASSERT(bb->out.size() == 1);
+ Q_ASSERT(bb->out.first() == jump->target);
+ } else if (CJump *cjump = bb->terminator()->asCJump()) {
+ Q_UNUSED(cjump);
+ Q_ASSERT(bb->out.size() == 2);
+ Q_ASSERT(cjump->iftrue);
+ Q_ASSERT(!cjump->iftrue->isRemoved());
+ Q_ASSERT(cjump->iftrue == bb->out[0]);
+ Q_ASSERT(cjump->iffalse);
+ Q_ASSERT(!cjump->iffalse->isRemoved());
+ Q_ASSERT(cjump->iffalse == bb->out[1]);
+ } else if (bb->terminator()->asRet()) {
+ Q_ASSERT(bb->out.size() == 0);
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ // Check the outgoing edges:
+ foreach (BasicBlock *out, bb->out) {
+ Q_UNUSED(out);
+ Q_ASSERT(!out->isRemoved());
+ Q_ASSERT(out->in.contains(bb));
+ }
+
+ // Check the incoming edges:
+ foreach (BasicBlock *in, bb->in) {
+ Q_UNUSED(in);
+ Q_ASSERT(!in->isRemoved());
+ Q_ASSERT(in->out.contains(bb));
+ }
+ }
+}
+
+static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ cfg2dot(function);
+ dt.dumpImmediateDominators();
+ DominatorTree referenceTree(function);
+
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ BasicBlock *idom = dt.immediateDominator(bb);
+ BasicBlock *referenceIdom = referenceTree.immediateDominator(bb);
+ Q_UNUSED(idom);
+ Q_UNUSED(referenceIdom);
+ Q_ASSERT(idom == referenceIdom);
+ }
+}
+
+static void verifyNoPointerSharing(IR::Function *function)
+{
+ if (!DoVerification)
+ return;
+
+ class : public StmtVisitor, public ExprVisitor {
+ public:
+ void operator()(IR::Function *f)
+ {
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ foreach (Stmt *s, bb->statements())
+ s->accept(this);
+ }
+ }
+
+ protected:
+ virtual void visitExp(Exp *s) { check(s); s->expr->accept(this); }
+ virtual void visitMove(Move *s) { check(s); s->target->accept(this); s->source->accept(this); }
+ virtual void visitJump(Jump *s) { check(s); }
+ virtual void visitCJump(CJump *s) { check(s); s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { check(s); s->expr->accept(this); }
+ virtual void visitPhi(Phi *s)
+ {
+ check(s);
+ s->targetTemp->accept(this);
+ foreach (Expr *e, s->d->incoming)
+ e->accept(this);
+ }
+
+ virtual void visitConst(Const *e) { check(e); }
+ virtual void visitString(IR::String *e) { check(e); }
+ virtual void visitRegExp(IR::RegExp *e) { check(e); }
+ virtual void visitName(Name *e) { check(e); }
+ virtual void visitTemp(Temp *e) { check(e); }
+ virtual void visitArgLocal(ArgLocal *e) { check(e); }
+ virtual void visitClosure(Closure *e) { check(e); }
+ virtual void visitConvert(Convert *e) { check(e); e->expr->accept(this); }
+ virtual void visitUnop(Unop *e) { check(e); e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { check(e); e->left->accept(this); e->right->accept(this); }
+ virtual void visitCall(Call *e) { check(e); e->base->accept(this); check(e->args); }
+ virtual void visitNew(New *e) { check(e); e->base->accept(this); check(e->args); }
+ virtual void visitSubscript(Subscript *e) { check(e); e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(Member *e) { check(e); e->base->accept(this); }
+
+ void check(ExprList *l)
+ {
+ for (ExprList *it = l; it; it = it->next)
+ check(it->expr);
+ }
+
+ private:
+ void check(Stmt *s)
+ {
+ Q_ASSERT(!stmts.contains(s));
+ stmts.insert(s);
+ }
+
+ void check(Expr *e)
+ {
+ Q_ASSERT(!exprs.contains(e));
+ exprs.insert(e);
+ }
+
+ QSet<Stmt *> stmts;
+ QSet<Expr *> exprs;
+ } V;
+ V(function);
+}
+
} // anonymous namespace
-void LifeTimeInterval::setFrom(Stmt *from) {
- Q_ASSERT(from && from->id > 0);
+void LifeTimeInterval::setFrom(int from) {
+ Q_ASSERT(from > 0);
if (_ranges.isEmpty()) { // this is the case where there is no use, only a define
- _ranges.push_front(Range(from->id, from->id));
- if (_end == Invalid)
- _end = from->id;
+ _ranges.push_front(Range(from, from));
+ if (_end == InvalidPosition)
+ _end = from;
} else {
- _ranges.first().start = from->id;
+ _ranges.first().start = from;
}
}
@@ -3705,7 +4499,7 @@ void LifeTimeInterval::addRange(int from, int to) {
p->start = qMin(p->start, from);
p->end = qMax(p->end, to);
while (_ranges.count() > 1) {
- Range *p1 = &_ranges[1];
+ Range *p1 = p + 1;
if (p->end + 1 < p1->start || p1->end + 1 < p->start)
break;
p1->start = qMin(p->start, p1->start);
@@ -3727,7 +4521,7 @@ void LifeTimeInterval::addRange(int from, int to) {
LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
{
- Q_ASSERT(atPosition < newStart || newStart == Invalid);
+ Q_ASSERT(atPosition < newStart || newStart == InvalidPosition);
if (_ranges.isEmpty() || atPosition < _ranges.first().start)
return LifeTimeInterval();
@@ -3756,7 +4550,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
if (newInterval._ranges.first().end == atPosition)
newInterval._ranges.removeFirst();
- if (newStart == Invalid) {
+ if (newStart == InvalidPosition) {
// the temp stays inactive for the rest of its lifetime
newInterval = LifeTimeInterval();
} else {
@@ -3793,7 +4587,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
}
void LifeTimeInterval::dump(QTextStream &out) const {
- _temp.dump(out);
+ IRPrinter(&out).print(const_cast<Temp *>(&_temp));
out << ": ends at " << _end << " with ranges ";
if (_ranges.isEmpty())
out << "(none)";
@@ -3801,23 +4595,87 @@ void LifeTimeInterval::dump(QTextStream &out) const {
if (i > 0) out << ", ";
out << _ranges[i].start << " - " << _ranges[i].end;
}
- if (_reg != Invalid)
+ if (_reg != InvalidRegister)
out << " (register " << _reg << ")";
}
-bool LifeTimeInterval::lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2) {
- if (r1._ranges.first().start == r2._ranges.first().start) {
- if (r1.isSplitFromInterval() == r2.isSplitFromInterval())
- return r1._ranges.last().end < r2._ranges.last().end;
+bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) {
+ if (r1->_ranges.first().start == r2->_ranges.first().start) {
+ if (r1->isSplitFromInterval() == r2->isSplitFromInterval())
+ return r1->_ranges.last().end < r2->_ranges.last().end;
else
- return r1.isSplitFromInterval();
+ return r1->isSplitFromInterval();
} else
- return r1._ranges.first().start < r2._ranges.first().start;
+ return r1->_ranges.first().start < r2->_ranges.first().start;
+}
+
+bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2)
+{
+ return r1->temp() < r2->temp();
}
-bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2)
+LifeTimeIntervals::LifeTimeIntervals(IR::Function *function)
+ : _basicBlockPosition(function->basicBlockCount())
+ , _positionForStatement(function->statementCount(), IR::Stmt::InvalidId)
+ , _lastPosition(0)
{
- return r1.temp() < r2.temp();
+ _intervals.reserve(function->tempCount + 32); // we reserve a bit more space for intervals, because the register allocator will add intervals with fixed ranges for each register.
+ renumber(function);
+}
+
+// Renumbering works as follows:
+// - phi statements are not numbered
+// - statement numbers start at 0 (zero) and increment get an even number (lastPosition + 2)
+// - basic blocks start at firstStatementNumber - 1, or rephrased: lastPosition + 1
+// - basic blocks end at the number of the last statement
+// And during life-time calculation the next rule is used:
+// - any temporary starts its life-time at definingStatementPosition + 1
+//
+// This numbering simulates half-open intervals. For example:
+// 0: %1 = 1
+// 2: %2 = 2
+// 4: %3 = %1 + %2
+// 6: print(%3)
+// Here the half-open life-time intervals would be:
+// %1: (0-4]
+// %2: (2-4]
+// %3: (4-6]
+// Instead, we use the even statement positions for uses of temporaries, and the odd positions for
+// their definitions:
+// %1: [1-4]
+// %2: [3-4]
+// %3: [5-6]
+// This has the nice advantage that placing %3 (for example) is really easy: the start will
+// never overlap with the end of the uses of the operands used in the defining statement.
+//
+// The reason to start a basic-block at firstStatementPosition - 1 is to have correct start
+// positions for target temporaries of phi-nodes. Those temporaries will now start before the
+// first statement. This also means that any moves that get generated when transforming out of SSA
+// form, will not interfere with (read: overlap) any defining statements in the preceding
+// basic-block.
+void LifeTimeIntervals::renumber(IR::Function *function)
+{
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ _basicBlockPosition[bb->index()].start = _lastPosition + 1;
+
+ foreach (Stmt *s, bb->statements()) {
+ if (s->asPhi())
+ continue;
+
+ _lastPosition += 2;
+ _positionForStatement[s->id()] = _lastPosition;
+ }
+
+ _basicBlockPosition[bb->index()].end = _lastPosition;
+ }
+}
+
+LifeTimeIntervals::~LifeTimeIntervals()
+{
+ qDeleteAll(_intervals);
}
Optimizer::Optimizer(IR::Function *function)
@@ -3845,22 +4703,31 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) {
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
+ ConvertArgLocals(function).toTemps();
+ showMeTheCode(function);
+
// Calculate the dominator tree:
DominatorTree df(function);
+ df.computeDF();
+
+ verifyCFG(function);
+ verifyImmediateDominators(df, function);
+
+ DefUses defUses(function);
// qout << "Converting to SSA..." << endl;
- convertToSSA(function, df);
+ convertToSSA(function, df, defUses);
// showMeTheCode(function);
-
-// qout << "Starting def/uses calculation..." << endl;
- DefUsesCalculator defUses(function);
+// defUses.dump();
// qout << "Cleaning up phi nodes..." << endl;
cleanupPhis(defUses);
// showMeTheCode(function);
+ StatementWorklist worklist(function);
+
// qout << "Running type inference..." << endl;
- TypeInference(qmlEngine, defUses).run(function);
+ TypeInference(qmlEngine, defUses).run(worklist);
// showMeTheCode(function);
// qout << "Doing reverse inference..." << endl;
@@ -3868,18 +4735,20 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// showMeTheCode(function);
// qout << "Doing type propagation..." << endl;
- TypePropagation(defUses).run(function);
+ TypePropagation(defUses).run(function, worklist);
// showMeTheCode(function);
+ verifyNoPointerSharing(function);
// Transform the CFG into edge-split SSA.
// qout << "Starting edge splitting..." << endl;
- splitCriticalEdges(function, df);
+ splitCriticalEdges(function, df, worklist, defUses);
// showMeTheCode(function);
static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
if (doOpt) {
// qout << "Running SSA optimization..." << endl;
- optimizeSSA(function, defUses, df);
+ worklist.reset();
+ optimizeSSA(worklist, defUses, df);
// showMeTheCode(function);
}
@@ -3894,6 +4763,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
cleanupBasicBlocks(function);
// showMeTheCode(function);
+ LoopDetection(df).run(function);
+ showMeTheCode(function);
+
// qout << "Doing block scheduling..." << endl;
// df.dumpImmediateDominators();
startEndLoops = BlockScheduler(function, df).go();
@@ -3960,7 +4832,7 @@ void Optimizer::convertOutOfSSA() {
}
}
-QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const
+LifeTimeIntervals::Ptr Optimizer::lifeTimeIntervals() const
{
Q_ASSERT(isInSSA());
@@ -4021,8 +4893,6 @@ static inline bool overlappingStorage(const Temp &t1, const Temp &t2)
// This is the same as the operator==, but for one detail: memory locations are not sensitive
// to types, and neither are general-purpose registers.
- if (t1.scope != t2.scope)
- return false;
if (t1.index != t2.index)
return false; // different position, where-ever that may (physically) be.
if (t1.kind != t2.kind)
@@ -4103,7 +4973,7 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio
int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
foreach (const Move &m, _moves) {
- IR::Move *move = function->New<IR::Move>();
+ IR::Move *move = function->NewStmt<IR::Move>();
move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
bb->insertStatementBefore(insertionPoint++, move);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 372fe5cdeb..8a2241641e 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -43,6 +43,7 @@
#define QV4SSA_P_H
#include "qv4jsir_p.h"
+#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QTextStream;
@@ -57,7 +58,7 @@ public:
int start;
int end;
- Range(int start = Invalid, int end = Invalid)
+ Range(int start = InvalidPosition, int end = InvalidPosition)
: start(start)
, end(end)
{}
@@ -75,22 +76,23 @@ private:
unsigned _isSplitFromInterval : 1;
public:
- enum { Invalid = -1 };
+ enum { InvalidPosition = -1 };
+ enum { InvalidRegister = -1 };
explicit LifeTimeInterval(int rangeCapacity = 2)
- : _end(Invalid)
- , _reg(Invalid)
+ : _end(InvalidPosition)
+ , _reg(InvalidRegister)
, _isFixedInterval(0)
, _isSplitFromInterval(0)
{ _ranges.reserve(rangeCapacity); }
- bool isValid() const { return _end != Invalid; }
+ bool isValid() const { return _end != InvalidRegister; }
void setTemp(const Temp &temp) { this->_temp = temp; }
Temp temp() const { return _temp; }
bool isFP() const { return _temp.type == IR::DoubleType; }
- void setFrom(Stmt *from);
+ void setFrom(int from);
void addRange(int from, int to);
const Ranges &ranges() const { return _ranges; }
@@ -98,15 +100,13 @@ public:
int end() const { return _end; }
bool covers(int position) const
{
- foreach (const Range &r, _ranges) {
- if (r.covers(position))
+ for (int i = 0, ei = _ranges.size(); i != ei; ++i) {
+ if (_ranges.at(i).covers(position))
return true;
}
return false;
}
- int firstPossibleUsePosition(bool isPhiTarget) const { return start() + (isSplitFromInterval() || isPhiTarget ? 0 : 1); }
-
int reg() const { return _reg; }
void setReg(int reg) { Q_ASSERT(!_isFixedInterval); _reg = reg; }
@@ -118,13 +118,13 @@ public:
void setSplitFromInterval(bool isSplitFromInterval) { _isSplitFromInterval = isSplitFromInterval; }
void dump(QTextStream &out) const;
- static bool lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2);
- static bool lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2);
+ static bool lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2);
+ static bool lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2);
void validate() const {
#if !defined(QT_NO_DEBUG)
// Validate the new range
- if (_end != Invalid) {
+ if (_end != InvalidPosition) {
Q_ASSERT(!_ranges.isEmpty());
foreach (const Range &range, _ranges) {
Q_ASSERT(range.start >= 0);
@@ -136,6 +136,78 @@ public:
}
};
+class LifeTimeIntervals
+{
+ Q_DISABLE_COPY(LifeTimeIntervals)
+
+ LifeTimeIntervals(IR::Function *function);
+ void renumber(IR::Function *function);
+
+public:
+ typedef QSharedPointer<LifeTimeIntervals> Ptr;
+ static Ptr create(IR::Function *function)
+ { return Ptr(new LifeTimeIntervals(function)); }
+
+ ~LifeTimeIntervals();
+
+ // takes ownership of the pointer
+ void add(LifeTimeInterval *interval)
+ { _intervals.append(interval); }
+
+ // After calling Optimizer::lifeTimeIntervals() the result will have all intervals in descending order of start position.
+ QVector<LifeTimeInterval *> intervals() const
+ { return _intervals; }
+
+ int size() const
+ { return _intervals.size(); }
+
+ int positionForStatement(Stmt *stmt) const
+ {
+ Q_ASSERT(stmt->id() >= 0);
+ if (static_cast<unsigned>(stmt->id()) < _positionForStatement.size())
+ return _positionForStatement[stmt->id()];
+
+ return Stmt::InvalidId;
+ }
+
+ int startPosition(BasicBlock *bb) const
+ {
+ Q_ASSERT(bb->index() >= 0);
+ Q_ASSERT(static_cast<unsigned>(bb->index()) < _basicBlockPosition.size());
+
+ return _basicBlockPosition.at(bb->index()).start;
+ }
+
+ int endPosition(BasicBlock *bb) const
+ {
+ Q_ASSERT(bb->index() >= 0);
+ Q_ASSERT(static_cast<unsigned>(bb->index()) < _basicBlockPosition.size());
+
+ return _basicBlockPosition.at(bb->index()).end;
+ }
+
+ int lastPosition() const
+ {
+ return _lastPosition;
+ }
+
+private:
+ struct BasicBlockPositions {
+ int start;
+ int end;
+
+ BasicBlockPositions()
+ : start(IR::Stmt::InvalidId)
+ , end(IR::Stmt::InvalidId)
+ {}
+ };
+
+ std::vector<BasicBlockPositions> _basicBlockPosition;
+ std::vector<int> _positionForStatement;
+ QVector<LifeTimeInterval *> _intervals;
+ int _lastPosition;
+};
+
class Q_QML_PRIVATE_EXPORT Optimizer
{
Q_DISABLE_COPY(Optimizer)
@@ -151,7 +223,7 @@ public:
QHash<BasicBlock *, BasicBlock *> loopStartEndBlocks() const { return startEndLoops; }
- QVector<LifeTimeInterval> lifeTimeIntervals() const;
+ LifeTimeIntervals::Ptr lifeTimeIntervals() const;
QSet<IR::Jump *> calculateOptionalJumps();
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h
index 9452260ce4..689a06a0d1 100644
--- a/src/qml/debugger/qqmlprofilerdefinitions_p.h
+++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h
@@ -67,6 +67,7 @@ struct QQmlProfilerDefinitions {
Complete, // end of transmission
PixmapCacheEvent,
SceneGraphFrame,
+ MemoryAllocation,
MaximumMessage
};
@@ -122,7 +123,7 @@ struct QQmlProfilerDefinitions {
SceneGraphPolishAndSync,
SceneGraphWindowsRenderShow,
SceneGraphWindowsAnimations,
- SceneGraphWindowsPolishFrame,
+ SceneGraphPolishFrame,
MaximumSceneGraphFrameType
};
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index 8e81d6e24e..1b30dd7f61 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -405,7 +405,7 @@ public:
void clearHandles(QV4::ExecutionEngine *engine)
{
- collector.reset(new VariableCollector(engine));
+ theCollector.reset(new VariableCollector(engine));
}
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
@@ -414,18 +414,18 @@ public:
QJsonObject frame;
frame[QLatin1String("index")] = frameNr;
frame[QLatin1String("debuggerFrame")] = false;
- frame[QLatin1String("func")] = collector->addFunctionRef(stackFrame.function);
- frame[QLatin1String("script")] = collector->addScriptRef(stackFrame.source);
+ frame[QLatin1String("func")] = theCollector->addFunctionRef(stackFrame.function);
+ frame[QLatin1String("script")] = theCollector->addScriptRef(stackFrame.source);
frame[QLatin1String("line")] = stackFrame.line - 1;
if (stackFrame.column >= 0)
frame[QLatin1String("column")] = stackFrame.column;
QJsonArray properties;
- collector->setDestination(&properties);
- if (debugger->collectThisInContext(collector.data(), frameNr)) {
+ theCollector->setDestination(&properties);
+ if (debugger->collectThisInContext(theCollector.data(), frameNr)) {
QJsonObject obj;
obj[QLatin1String("properties")] = properties;
- frame[QLatin1String("receiver")] = collector->addObjectRef(obj, false);
+ frame[QLatin1String("receiver")] = theCollector->addObjectRef(obj, false);
}
QJsonArray scopes;
@@ -473,7 +473,7 @@ public:
QJsonObject scope;
QJsonArray properties;
- collector->collectScope(&properties, debugger, frameNr, scopeNr);
+ theCollector->collectScope(&properties, debugger, frameNr, scopeNr);
QJsonObject anonymous;
anonymous[QLatin1String("properties")] = properties;
@@ -482,16 +482,21 @@ public:
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
scope[QLatin1String("index")] = scopeNr;
scope[QLatin1String("frameIndex")] = frameNr;
- scope[QLatin1String("object")] = collector->addObjectRef(anonymous, true);
+ scope[QLatin1String("object")] = theCollector->addObjectRef(anonymous, true);
return scope;
}
- QJsonValue lookup(int refId) const { return collector->lookup(refId); }
+ QJsonValue lookup(int refId) const { return theCollector->lookup(refId); }
QJsonArray buildRefs()
{
- return collector->retrieveRefsToInclude();
+ return theCollector->retrieveRefsToInclude();
+ }
+
+ VariableCollector *collector() const
+ {
+ return theCollector.data();
}
void selectFrame(int frameNr)
@@ -501,7 +506,7 @@ public:
{ return theSelectedFrame; }
private:
- QScopedPointer<VariableCollector> collector;
+ QScopedPointer<VariableCollector> theCollector;
int theSelectedFrame;
void addHandler(V8CommandHandler* handler);
@@ -959,6 +964,67 @@ public:
// response will be send by
}
};
+
+// Request:
+// {
+// "seq": 4,
+// "type": "request",
+// "command": "evaluate",
+// "arguments": {
+// "expression": "a",
+// "frame": 0
+// }
+// }
+//
+// Response:
+// {
+// "body": {
+// "handle": 3,
+// "type": "number",
+// "value": 1
+// },
+// "command": "evaluate",
+// "refs": [],
+// "request_seq": 4,
+// "running": false,
+// "seq": 5,
+// "success": true,
+// "type": "response"
+// }
+//
+// The "value" key in "body" is the result of evaluating the expression in the request.
+class V8EvaluateRequest: public V8CommandHandler
+{
+public:
+ V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {}
+
+ virtual void handleRequest()
+ {
+ //decypher the payload:
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString expression = arguments.value(QStringLiteral("expression")).toString();
+ const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
+
+ QV4::Debugging::Debugger *debugger = debugServicePrivate->debuggerAgent.firstDebugger();
+ Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused);
+
+ VariableCollector *collector = debugServicePrivate->collector();
+ QJsonArray dest;
+ collector->setDestination(&dest);
+ debugger->evaluateExpression(frame, expression, collector);
+
+ const int ref = dest.at(0).toObject().value(QStringLiteral("value")).toObject()
+ .value(QStringLiteral("ref")).toInt();
+
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(collector->lookup(ref).toObject());
+ addRefs();
+ }
+};
} // anonymous namespace
QV4DebugServicePrivate::QV4DebugServicePrivate()
@@ -978,8 +1044,7 @@ QV4DebugServicePrivate::QV4DebugServicePrivate()
addHandler(new V8DisconnectRequest);
addHandler(new V8SetExceptionBreakRequest);
addHandler(new V8ScriptsRequest);
-
- // TODO: evaluate
+ addHandler(new V8EvaluateRequest);
}
void QV4DebugServicePrivate::addHandler(V8CommandHandler* handler)
diff --git a/src/qml/debugger/qv4profileradapter.cpp b/src/qml/debugger/qv4profileradapter.cpp
index e7b82566d6..cdceb0e533 100644
--- a/src/qml/debugger/qv4profileradapter.cpp
+++ b/src/qml/debugger/qv4profileradapter.cpp
@@ -58,26 +58,47 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData()));
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
engine->profiler, SLOT(setTimer(QElapsedTimer)));
- connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>)),
- this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>)));
+ connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>,
+ QList<QV4::Profiling::MemoryAllocationProperties>)),
+ this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>,
+ QList<QV4::Profiling::MemoryAllocationProperties>)));
}
+qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages)
+{
+ QByteArray message;
+ while (!memory_data.empty() && memory_data.front().timestamp <= until) {
+ QQmlDebugStream d(&message, QIODevice::WriteOnly);
+ QV4::Profiling::MemoryAllocationProperties &props = memory_data.front();
+ d << props.timestamp << MemoryAllocation << props.type << props.size;
+ memory_data.pop_front();
+ messages.append(message);
+ }
+ return memory_data.empty() ? -1 : memory_data.front().timestamp;
+}
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
QByteArray message;
while (true) {
while (!stack.empty() && (data.empty() || stack.top() <= data.front().start)) {
- if (stack.top() > until)
- return stack.top();
+ if (stack.top() > until) {
+ qint64 memory_next = appendMemoryEvents(until, messages);
+ return memory_next == -1 ? stack.top() : qMin(stack.top(), memory_next);
+ }
+ appendMemoryEvents(stack.top(), messages);
QQmlDebugStream d(&message, QIODevice::WriteOnly);
d << stack.pop() << RangeEnd << Javascript;
messages.append(message);
}
while (!data.empty() && (stack.empty() || data.front().start < stack.top())) {
- if (data.front().start > until)
- return data.front().start;
const QV4::Profiling::FunctionCallProperties &props = data.front();
+ if (props.start > until) {
+ qint64 memory_next = appendMemoryEvents(until, messages);
+ return memory_next == -1 ? props.start : qMin(props.start, memory_next);
+ }
+ appendMemoryEvents(props.start, messages);
+
QQmlDebugStream d_start(&message, QIODevice::WriteOnly);
d_start << props.start << RangeStart << Javascript;
messages.push_back(message);
@@ -95,13 +116,15 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
data.pop_front();
}
if (stack.empty() && data.empty())
- return -1;
+ return appendMemoryEvents(until, messages);
}
}
-void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data)
+void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data,
+ const QList<QV4::Profiling::MemoryAllocationProperties> &new_memory_data)
{
data = new_data;
+ memory_data = new_memory_data;
stack.clear();
service->dataReady(this);
}
diff --git a/src/qml/debugger/qv4profileradapter_p.h b/src/qml/debugger/qv4profileradapter_p.h
index 922aedd828..29bdd606ef 100644
--- a/src/qml/debugger/qv4profileradapter_p.h
+++ b/src/qml/debugger/qv4profileradapter_p.h
@@ -71,11 +71,14 @@ public:
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
public slots:
- void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &);
+ void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &,
+ const QList<QV4::Profiling::MemoryAllocationProperties> &);
private:
QList<QV4::Profiling::FunctionCallProperties> data;
+ QList<QV4::Profiling::MemoryAllocationProperties> memory_data;
QStack<qint64> stack;
+ qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages);
};
QT_END_NAMESPACE
diff --git a/src/qml/doc/images/statemachine-button-history.png b/src/qml/doc/images/statemachine-button-history.png
new file mode 100644
index 0000000000..0462b3b99b
--- /dev/null
+++ b/src/qml/doc/images/statemachine-button-history.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-button-nested.png b/src/qml/doc/images/statemachine-button-nested.png
new file mode 100644
index 0000000000..762ac14df1
--- /dev/null
+++ b/src/qml/doc/images/statemachine-button-nested.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-button.png b/src/qml/doc/images/statemachine-button.png
new file mode 100644
index 0000000000..10102bdf2c
--- /dev/null
+++ b/src/qml/doc/images/statemachine-button.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-finished.png b/src/qml/doc/images/statemachine-finished.png
new file mode 100644
index 0000000000..0ac081d6ba
--- /dev/null
+++ b/src/qml/doc/images/statemachine-finished.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-nonparallel.png b/src/qml/doc/images/statemachine-nonparallel.png
new file mode 100644
index 0000000000..f9850a74a6
--- /dev/null
+++ b/src/qml/doc/images/statemachine-nonparallel.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-parallel.png b/src/qml/doc/images/statemachine-parallel.png
new file mode 100644
index 0000000000..a65c297f5b
--- /dev/null
+++ b/src/qml/doc/images/statemachine-parallel.png
Binary files differ
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index d691dbfd8a..6e07fd173b 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -28,7 +28,7 @@ qhp.QtQml.subprojects.examples.indexTitle = Qt Quick Examples and Tutorials
qhp.QtQml.subprojects.examples.selectors = fake:example
qhp.QtQml.subprojects.qmltypes.title = QML Types
qhp.QtQml.subprojects.qmltypes.indexTitle = Qt QML QML Types
-qhp.QtQml.subprojects.qmltypes.selectors = fake:qmlclass
+qhp.QtQml.subprojects.qmltypes.selectors = qmlclass
qhp.QtQml.subprojects.qmltypes.sortPages = true
@@ -40,7 +40,8 @@ headerdirs += .. \
../../imports/models
sourcedirs += .. \
- ../../imports/models
+ ../../imports/models \
+ ../../imports/statemachine
exampledirs += ../../../examples/qml \
../ \
diff --git a/src/qml/doc/snippets/qml/statemachine/Button.qml b/src/qml/doc/snippets/qml/statemachine/Button.qml
new file mode 100644
index 0000000000..2baad4cbfb
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/Button.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.1
+import QtQuick.Window 2.1
+
+Item {
+ id: container
+
+ property alias text: buttonLabel.text
+ property alias label: buttonLabel
+ signal clicked
+ property alias containsMouse: mouseArea.containsMouse
+ property alias pressed: mouseArea.pressed
+ implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
+ implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3)
+ height: implicitHeight
+ width: implicitWidth
+ property bool checkable: false
+ property bool checked: false
+
+ SystemPalette { id: palette }
+
+ Rectangle {
+ id: frame
+ anchors.fill: parent
+ color: palette.button
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: mouseArea.pressed ? Qt.darker(palette.button, 1.3) : palette.button }
+ GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) }
+ }
+ antialiasing: true
+ radius: height / 6
+ border.color: Qt.darker(palette.button, 1.5)
+ border.width: 1
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ onClicked: container.clicked()
+ hoverEnabled: true
+ }
+
+ Text {
+ id: buttonLabel
+ text: container.text
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+}
diff --git a/src/qml/doc/snippets/qml/statemachine/basicstate.qml b/src/qml/doc/snippets/qml/statemachine/basicstate.qml
new file mode 100644
index 0000000000..dd9d100e9d
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/basicstate.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ StateBase {
+ id: state
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/finalstate.qml b/src/qml/doc/snippets/qml/statemachine/finalstate.qml
new file mode 100644
index 0000000000..d03a4bce40
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/finalstate.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ StateBase {
+ id: state
+ TimeoutTransition {
+ targetState: finalState
+ timeout: 200
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ onFinished: console.log("state finished")
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/historystate.qml b/src/qml/doc/snippets/qml/statemachine/historystate.qml
new file mode 100644
index 0000000000..237cf57175
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/historystate.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Press me"
+ StateMachine {
+ id: stateMachine
+ initialState: parentState
+ running: true
+ StateBase {
+ id: parentState
+ initialState: child2
+ onEntered: console.log("parentState entered")
+ onExited: console.log("parentState exited")
+ StateBase {
+ id: child1
+ onEntered: console.log("child1 entered")
+ onExited: console.log("child1 exited")
+ }
+ StateBase {
+ id: child2
+ onEntered: console.log("child2 entered")
+ onExited: console.log("child2 exited")
+ }
+ HistoryState {
+ id: historyState
+ defaultState: child1
+ }
+ SignalTransition {
+ targetState: historyState
+
+ // Clicking the button will cause the state machine to enter the child state
+ // that parentState was in the last time parentState was exited, or the history state's default
+ // state if parentState has never been entered.
+ signal: button.clicked
+ }
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/signaltransition.qml b/src/qml/doc/snippets/qml/statemachine/signaltransition.qml
new file mode 100644
index 0000000000..7402ac089f
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/signaltransition.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ StateBase {
+ id: state
+ SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ guard: guardButton.checked
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ onFinished: Qt.quit()
+ }
+ Row {
+ spacing: 2
+ Button {
+ id: button
+ text: "Finish state"
+ }
+
+ Button {
+ id: guardButton
+ checkable: true
+ text: checked ? "Press to block the SignalTransition" : "Press to unblock the SignalTransition"
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml b/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml
new file mode 100644
index 0000000000..44608fed36
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ StateMachine {
+ StateBase {
+ SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml b/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml
new file mode 100644
index 0000000000..f5c6923cd1
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Finish state"
+ StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ StateBase {
+ id: state
+ SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ onFinished: Qt.quit()
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml
new file mode 100644
index 0000000000..10595a9398
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+//![0]
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : s13.active ? "s13" : "s3"
+ }
+ Button {
+ id: interruptButton
+ text: s1.active ? "Interrupt" : "Resume"
+ }
+ Button {
+ id: quitButton
+ // change the button label to the active state id
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ StateBase {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ StateBase {
+ id: s11
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+ StateBase {
+ id: s12
+ // create a transition from s2 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+ StateBase {
+ id: s13
+ // create a transition from s3 to s1 when the button is clicked
+ SignalTransition {
+ targetState: s1
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+
+ // create a transition from s1 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s3
+ signal: interruptButton.clicked
+ }
+ HistoryState {
+ id: s1h
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ StateBase {
+ id: s3
+ SignalTransition {
+ targetState: s1h
+ signal: interruptButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s3 entered")
+ onExited: console.log("s3 exited")
+ }
+ onFinished: Qt.quit()
+ }
+//![0]
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
new file mode 100644
index 0000000000..00f9cd3871
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : "s13"
+ }
+ Button {
+ id: quitButton
+ // change the button label to the active state id
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ StateBase {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ StateBase {
+ id: s11
+ // create a transition from s11 to s12 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+//![0]
+ StateBase {
+ id: s12
+ // create a transition from s12 to s13 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+
+ // ignore Quit button when we are in state 12
+ SignalTransition {
+ targetState: s12
+ signal: quitButton.clicked
+ }
+
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+//![0]
+
+ StateBase {
+ id: s13
+ // create a transition from s13 to s11 when the button is clicked
+ SignalTransition {
+ targetState: s11
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ onFinished: Qt.quit()
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml
new file mode 100644
index 0000000000..68bd57d85f
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+//![0]
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : "s13"
+ }
+ Button {
+ id: quitButton
+ // change the button label to the active state id
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ StateBase {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ StateBase {
+ id: s11
+ // create a transition from s11 to s12 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+ StateBase {
+ id: s12
+ // create a transition from s12 to s13 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+ StateBase {
+ id: s13
+ // create a transition from s13 to s11 when the button is clicked
+ SignalTransition {
+ targetState: s11
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ onFinished: Qt.quit()
+ }
+//![0]
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml
new file mode 100644
index 0000000000..f2817ead8b
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+//![0]
+ Button {
+ anchors.fill: parent
+ id: button
+
+ // change the button label to the active state id
+ text: s1.active ? "s1" : s2.active ? "s2" : "s3"
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ StateBase {
+ id: s1
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ }
+
+ StateBase {
+ id: s2
+ // create a transition from s2 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s3
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ StateBase {
+ id: s3
+ // create a transition from s3 to s1 when the button is clicked
+ SignalTransition {
+ targetState: s1
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s3 entered")
+ onExited: console.log("s3 exited")
+ }
+ }
+//![0]
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml b/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml
new file mode 100644
index 0000000000..b15c99cd22
--- /dev/null
+++ b/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [document]
+import QtQml.StateMachine 1.0
+import QtQuick 2.0
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Finish state"
+ enabled: !stateMachine.running
+ onClicked: stateMachine.running = true
+ StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ StateBase {
+ id: state
+ TimeoutTransition {
+ targetState: finalState
+ timeout: 1000
+ }
+ }
+ FinalState {
+ id: finalState
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index d3d3174193..e95784dc5c 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -157,6 +157,44 @@
*/
/*!
+ \fn int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
+ \relates QQmlEgine
+
+ This template function registers the C++ type and its extension
+ in the QML system with the name \a qmlName in the library imported
+ from \a uri having version number composed from \a versionMajor and
+ \a versionMinor.
+
+ While the type has a name and a type, it cannot be created, and the
+ given error \a message will result if creation is attempted.
+
+ This is useful where the type is only intended for providing attached
+ properties, enum values or an abstract base class with its extension.
+
+ Returns the QML type id.
+
+ #include <QtQml> to use this function.
+
+ \sa qmlRegisterUncreatableType()
+*/
+
+/*!
+ \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
+ \relates QQmlEgine
+
+ This template function registers the C++ type and its extension
+ in the QML system with the name \a qmlName in the library imported
+ from \a uri having version number composed from \a versionMajor and
+ \a versionMinor. Properties from the C++ type or its extension that
+ cannot be resolved directly by the QML system will be resolved using
+ the \a parser provided.
+
+ Returns the QML type id.
+
+ #include <QtQml> to use this function.
+*/
+
+/*!
\fn int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
\relates QQmlEngine
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index b9c008edf1..ae2cac7275 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -126,6 +126,11 @@ the QML code to interact with C++ code.
\li \l{Integrating QML and C++}
\endlist
+\section1 Additional Frameworks
+\list
+\li \l{The Declarative State Machine Framework}
+\endlist
+
\section1 Guides and Other Information
Further information for writing QML applications:
diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc
new file mode 100644
index 0000000000..5a37ef8026
--- /dev/null
+++ b/src/qml/doc/src/statemachine.qdoc
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \group qmlstatemachine
+ \page qmlstatemachine.html
+ \title The Declarative State Machine Framework
+ \brief An overview of the Declarative State Machine Framework for constructing and executing state graphs.
+
+ \ingroup frameworks-technologies
+
+ \tableofcontents
+
+ The Declarative State Machine Framework provides classes for creating and executing
+ state graphs in QML. The concepts and notation are based on those from Harel's
+ \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}
+ {Statecharts: A visual formalism for complex systems}, which
+ is also the basis of UML state diagrams. The semantics of state machine
+ execution are based on \l{State Chart XML: State Machine Notation for
+ Control Abstraction}{State Chart XML (SCXML)}.
+
+ Statecharts provide a graphical way of modeling how a system reacts to
+ stimuli. This is done by defining the possible \e states that the system can
+ be in, and how the system can move from one state to another (\e transitions
+ between states). A key characteristic of event-driven systems (such as Qt
+ applications) is that behavior often depends not only on the last or current
+ event, but also the events that preceded it. With statecharts, this
+ information is easy to express.
+
+ The Declarative State Machine Framework provides an API and execution model that can
+ be used to effectively embed the elements and semantics of statecharts in Qml
+ applications. The framework integrates tightly with Qt's meta-object system;
+ for example, transitions between states can be triggered by signals, and
+ states can be configured to set properties and invoke methods on QObjects.
+ Qt's event system is used to drive the state machines.
+
+ The state graph in the Declarative State Machine Framework is hierarchical. States
+ can be nested inside of other states, and the current configuration of the
+ state machine consists of the set of states which are currently active.
+ All the states in a valid configuration of the state machine will
+ have a common ancestor.
+
+ For user interfaces with multiple visual states, independent of the
+ application's logical state, consider using QML States and Transitions.
+
+ \section1 QML types in the Declarative State Machine Framework
+
+ These QML types are provided by QML for creating event-driven state machines.
+
+ \annotatedlist qmlstatemachine
+
+ \section1 A Simple State Machine
+
+ To demonstrate the core functionality of the State Machine API, let's look
+ at a small example: A state machine with three states, \c s1, \c s2 and \c
+ s3. The state machine is controlled by a single QPushButton; when the button
+ is clicked, the machine transitions to another state. Initially, the state
+ machine is in state \c s1. The statechart for this machine is as follows:
+
+ \image statemachine-button.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ The following snippet shows the code needed to create such a state machine.
+
+ \snippet qml/statemachine/statemachine-button.qml 0
+
+ The state machine executes asynchronously, i.e. it becomes part of your
+ application's event loop.
+
+ \section1 State Machines That Finish
+
+ The state machine defined in the previous section never finishes. In order
+ for a state machine to be able to finish, it needs to have a top-level \e
+ final state (FinalState object). When the state machine enters a top-level
+ final state, the machine will emit the \l{StateBase::finished}{finished}
+ signal and halt.
+
+ All you need to do to introduce a final state in the graph is create a
+ FinalState object and use it as the target of one or more transitions.
+
+ \section1 Sharing Transitions By Grouping States
+
+ Assume we wanted the user to be able to quit the application at any time by
+ clicking a Quit button. In order to achieve this, we need to create a final
+ state and make it the target of a transition associated with the Quit
+ button's clicked() signal. We could add a transition from each of \c s1, \c
+ s2 and \c s3; however, this seems redundant, and one would also have to
+ remember to add such a transition from every new state that is added in the
+ future.
+
+ We can achieve the same behavior (namely that clicking the Quit button quits
+ the state machine, regardless of which state the state machine is in) by
+ grouping states \c s1, \c s2 and \c s3. This is done by creating a new
+ top-level state and making the three original states children of the new
+ state. The following diagram shows the new state machine.
+
+ \image statemachine-button-nested.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ The three original states have been renamed \c s11, \c s12 and \c s13 to
+ reflect that they are now children of the new top-level state, \c s1. Child
+ states implicitly inherit the transitions of their parent state. This means
+ it is now sufficient to add a single transition from \c s1 to the final
+ state \c s2. New states added to \c s1 will also automatically inherit this
+ transition.
+
+ All that's needed to group states is to specify the proper parent when the
+ state is created. You also need to specify which of the child states is the
+ initial one (i.e. which child state the state machine should enter when the
+ parent state is the target of a transition).
+
+ \snippet qml/statemachine/statemachine-button-nested.qml 0
+
+ In this case we want the application to quit when the state machine is
+ finished, so the machine's finished() signal is connected to the
+ application's quit() slot.
+
+ A child state can override an inherited transition. For example, the
+ following code adds a transition that effectively causes the Quit button to
+ be ignored when the state machine is in state \c s12.
+
+ \snippet qml/statemachine/statemachine-button-nested-ignore-quit.qml 0
+
+ A transition can have any state as its target, i.e. the target state does
+ not have to be on the same level in the state hierarchy as the source state.
+
+ \section1 Using History States to Save and Restore the Current State
+
+ Imagine that we wanted to add an "interrupt" mechanism to the example
+ discussed in the previous section; the user should be able to click a button
+ to have the state machine perform some non-related task, after which the
+ state machine should resume whatever it was doing before (i.e. return to the
+ old state, which is one of \c s11, \c s12 and \c s13 in this case).
+
+ Such behavior can easily be modeled using \e{history states}. A history
+ state (HistoryState object) is a pseudo-state that represents the child
+ state that the parent state was in the last time the parent state was
+ exited.
+
+ A history state is created as a child of the state for which we wish to
+ record the current child state; when the state machine detects the presence
+ of such a state at runtime, it automatically records the current (real)
+ child state when the parent state is exited. A transition to the history
+ state is in fact a transition to the child state that the state machine had
+ previously saved; the state machine automatically "forwards" the transition
+ to the real child state.
+
+ The following diagram shows the state machine after the interrupt mechanism
+ has been added.
+
+ \image statemachine-button-history.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ The following code shows how it can be implemented; in this example we
+ simply display a message box when \c s3 is entered, then immediately return
+ to the previous child state of \c s1 via the history state.
+
+ \snippet qml/statemachine/statemachine-button-history.qml 0
+
+ \section1 Using Parallel States to Avoid a Combinatorial Explosion of States
+
+ Assume that you wanted to model a set of mutually exclusive properties of a
+ car in a single state machine. Let's say the properties we are interested in
+ are Clean vs Dirty, and Moving vs Not moving. It would take four mutually
+ exclusive states and eight transitions to be able to represent and freely
+ move between all possible combinations.
+
+ \image statemachine-nonparallel.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ If we added a third property (say, Red vs Blue), the total number of states
+ would double, to eight; and if we added a fourth property (say, Enclosed vs
+ Convertible), the total number of states would double again, to 16.
+
+ Using parallel states, the total number of states and transitions grows
+ linearly as we add more properties, instead of exponentially. Furthermore,
+ states can be added to or removed from the parallel state without affecting
+ any of their sibling states.
+
+ \image statemachine-parallel.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ To create a parallel state group, set childMode to QState.ParallelStates.
+
+ \qml
+ StateBase {
+ id: s1
+ childMode: QState.ParallelStates
+ StateBase {
+ id: s11
+ }
+ StateBase {
+ id: s12
+ }
+ }
+ \endqml
+
+ When a parallel state group is entered, all its child states will be
+ simultaneously entered. Transitions within the individual child states
+ operate normally. However, any of the child states may take a transition which exits the parent
+ state. When this happens, the parent state and all of its child states are exited.
+
+ The parallelism in the State Machine framework follows an interleaved semantics. All parallel
+ operations will be executed in a single, atomic step of the event processing, so no event can
+ interrupt the parallel operations. However, events will still be processed sequentially, since
+ the machine itself is single threaded. As an example: Consider the situation where there are two
+ transitions that exit the same parallel state group, and their conditions become true
+ simultaneously. In this case, the event that is processed last of the two will not have any
+ effect, since the first event will already have caused the machine to exit from the parallel
+ state.
+
+ \section1 Detecting that a Composite State has Finished
+
+ A child state can be final (a FinalState object); when a final child state
+ is entered, the parent state emits the StateBase::finished signal. The
+ following diagram shows a composite state \c s1 which does some processing
+ before entering a final state:
+
+ \image statemachine-finished.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ When \c s1 's final state is entered, \c s1 will automatically emit
+ \l{StateBase::finished}{finished}. We use a signal transition to cause this event to
+ trigger a state change:
+
+ \qml
+ StateBase {
+ id: s1
+ SignalTransition {
+ targetState: s2
+ signal: s1.finished
+ }
+ }
+ \endqml
+
+ Using final states in composite states is useful when you want to hide the
+ internal details of a composite state; i.e. the only thing the outside world
+ should be able to do is enter the state, and get a notification when the
+ state has completed its work. This is a very powerful abstraction and
+ encapsulation mechanism when building complex (deeply nested) state
+ machines. (In the above example, you could of course create a transition
+ directly from \c s1 's \c done state rather than relying on \c s1 's
+ finished() signal, but with the consequence that implementation details of
+ \c s1 are exposed and depended on).
+
+ For parallel state groups, the StateBase::finished signal is emitted when \e
+ all the child states have entered final states.
+
+ \section1 Targetless Transitions
+
+ A transition need not have a target state. A transition without a target can
+ be triggered the same way as any other transition; the difference is that
+ when a targetless transition is triggered, it doesn't cause any state
+ changes. This allows you to react to a signal or event when your machine is
+ in a certain state, without having to leave that state. Example:
+
+ \qml
+ Button {
+ id: button
+ text: "button"
+ StateMachine {
+ id: stateMachine
+ initialState: s1
+ running: true
+ StateBase {
+ id: s1
+ SignalTransition {
+ signal: button.clicked
+ onTriggered: console.log("button pressed")
+ }
+ }
+ }
+ }
+ \endqml
+
+ The "button pressed" message will be displayed each time the button is clicked, but the
+ state machine will remain in its current state (s1). If the target state
+ were explicitly set to s1, however, s1 would be exited and re-entered each
+ time (e.g. the QAbstractState::entered and QAbstractState::exited
+ signals would be emitted).
+*/
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index 151ff32df9..7ea4e951d5 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -6,9 +6,11 @@ INCLUDEPATH += $$OUT_PWD
HEADERS += \
$$PWD/qv4assembler_p.h \
$$PWD/qv4regalloc_p.h \
+ $$PWD/qv4targetplatform_p.h \
$$PWD/qv4isel_masm_p.h \
$$PWD/qv4binop_p.h \
$$PWD/qv4unop_p.h \
+ $$PWD/qv4registerinfo_p.h
SOURCES += \
$$PWD/qv4assembler.cpp \
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index cd44b537df..cb2279b336 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -91,58 +91,6 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu
return handle->chunk();
}
-
-
-/* Platform/Calling convention/Architecture specific section */
-
-#if CPU(X86_64)
-# if OS(LINUX) || OS(MAC_OS_X)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx,
- JSC::X86Registers::r12, // LocalsRegister
- JSC::X86Registers::r13,
- JSC::X86Registers::r14, // ContextRegister
- JSC::X86Registers::r15
-};
-# elif OS(WINDOWS)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx,
- JSC::X86Registers::esi,
- JSC::X86Registers::edi,
- JSC::X86Registers::r12, // LocalsRegister
- JSC::X86Registers::r13,
- JSC::X86Registers::r14, // ContextRegister
- JSC::X86Registers::r15
-};
-# endif
-#endif
-
-#if CPU(X86)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx, // temporary register
- JSC::X86Registers::esi, // ContextRegister
- JSC::X86Registers::edi // LocalsRegister
-};
-#endif
-
-#if CPU(ARM)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::ARMRegisters::r11,
- JSC::ARMRegisters::r10,
- JSC::ARMRegisters::r9,
- JSC::ARMRegisters::r8,
- JSC::ARMRegisters::r7,
- JSC::ARMRegisters::r6,
- JSC::ARMRegisters::r5,
- JSC::ARMRegisters::r4
-};
-#endif
-
-const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]);
-
-/* End of platform/calling convention/architecture specific section */
-
-
const Assembler::VoidType Assembler::Void;
Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
@@ -223,33 +171,47 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left
}
}
-Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, IR::Temp *t)
+Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
+{
+ IR::Temp *t = e->asTemp();
+ if (t)
+ return loadTempAddress(t);
+ else
+ return loadArgLocalAddress(tmp, e->asArgLocal());
+}
+
+Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
+{
+ if (t->kind == IR::Temp::StackSlot)
+ return stackSlotPointer(t);
+ else
+ Q_UNREACHABLE();
+}
+
+Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
{
int32_t offset = 0;
- int scope = t->scope;
+ int scope = al->scope;
RegisterID context = ContextRegister;
if (scope) {
- loadPtr(Address(ContextRegister, qOffsetOf(ExecutionContext, outer)), baseReg);
+ loadPtr(Address(ContextRegister, qOffsetOf(ExecutionContext::Data, outer)), baseReg);
--scope;
context = baseReg;
while (scope) {
- loadPtr(Address(context, qOffsetOf(ExecutionContext, outer)), context);
+ loadPtr(Address(context, qOffsetOf(ExecutionContext::Data, outer)), context);
--scope;
}
}
- switch (t->kind) {
- case IR::Temp::Formal:
- case IR::Temp::ScopedFormal: {
- loadPtr(Address(context, qOffsetOf(ExecutionContext, callData)), baseReg);
- offset = sizeof(CallData) + (t->index - 1) * sizeof(Value);
+ switch (al->kind) {
+ case IR::ArgLocal::Formal:
+ case IR::ArgLocal::ScopedFormal: {
+ loadPtr(Address(context, qOffsetOf(ExecutionContext::Data, callData)), baseReg);
+ offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
} break;
- case IR::Temp::Local:
- case IR::Temp::ScopedLocal: {
- loadPtr(Address(context, qOffsetOf(CallContext, locals)), baseReg);
- offset = t->index * sizeof(Value);
- } break;
- case IR::Temp::StackSlot: {
- return stackSlotPointer(t);
+ case IR::ArgLocal::Local:
+ case IR::ArgLocal::ScopedLocal: {
+ loadPtr(Address(context, qOffsetOf(CallContext::Data, locals)), baseReg);
+ offset = al->index * sizeof(Value);
} break;
default:
Q_UNREACHABLE();
@@ -259,7 +221,7 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, IR::Temp *t)
Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
{
- loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
+ loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
const int id = _isel->registerString(string);
return Pointer(reg, id * sizeof(QV4::StringValue));
@@ -267,21 +229,21 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
void Assembler::loadStringRef(RegisterID reg, const QString &string)
{
- loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), reg);
+ loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), reg);
loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg);
const int id = _isel->registerString(string);
- addPtr(TrustedImmPtr(id * sizeof(QV4::StringValue)), reg);
+ loadPtr(Address(reg, id * sizeof(QV4::StringValue)), reg);
}
-void Assembler::storeValue(QV4::Primitive value, IR::Temp* destination)
+void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination)
{
- Address addr = loadTempAddress(ScratchRegister, destination);
+ Address addr = loadAddress(ScratchRegister, destination);
storeValue(value, addr);
}
void Assembler::enterStandardStackFrame()
{
- platformEnterStandardStackFrame();
+ platformEnterStandardStackFrame(this);
// ### FIXME: Handle through calleeSavedRegisters mechanism
// or eliminate StackFrameRegister altogether.
@@ -292,16 +254,18 @@ void Assembler::enterStandardStackFrame()
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- for (int i = 0; i < calleeSavedRegisterCount; ++i)
- storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
+ const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
+ for (int i = 0; i < calleeSavedRegisterCount(); ++i)
+ storePtr(calleeSavedRegisters[i].reg<RegisterID>(), Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
}
void Assembler::leaveStandardStackFrame()
{
// restore the callee saved registers
- for (int i = calleeSavedRegisterCount - 1; i >= 0; --i)
- loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]);
+ const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
+ for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i)
+ loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg<RegisterID>());
int frameSize = _stackLayout.calculateStackFrameSize();
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
@@ -314,7 +278,7 @@ void Assembler::leaveStandardStackFrame()
#endif
pop(StackFrameRegister);
- platformLeaveStandardStackFrame();
+ platformLeaveStandardStackFrame(this);
}
@@ -347,13 +311,12 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
break;
}
- IR::Temp *sourceTemp = src->asTemp();
- Q_ASSERT(sourceTemp);
+ Q_ASSERT(src->asTemp() || src->asArgLocal());
// It's not a number type, so it cannot be in a register.
- Q_ASSERT(sourceTemp->kind != IR::Temp::PhysicalRegister || sourceTemp->type == IR::BoolType);
+ Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType);
- Assembler::Pointer tagAddr = loadTempAddress(Assembler::ScratchRegister, sourceTemp);
+ Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src);
tagAddr.offset += 4;
load32(tagAddr, Assembler::ScratchRegister);
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 6fde517e1f..5e1f162f39 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -47,6 +47,7 @@
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
#include "private/qv4lookup_p.h"
+#include "qv4targetplatform_p.h"
#include <QtCore/QHash>
#include <QtCore/QStack>
@@ -123,158 +124,12 @@ struct ExceptionCheck<void (*)(QV4::NoThrowContext *, A, B, C)> {
enum { NeedsCheck = 0 };
};
-class Assembler : public JSC::MacroAssembler
+class Assembler : public JSC::MacroAssembler, public TargetPlatform
{
public:
Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
int maxArgCountForBuiltins);
-#if CPU(X86)
-
-#undef VALUE_FITS_IN_REGISTER
-#undef ARGUMENTS_IN_REGISTERS
-
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-
- static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const RegisterID ContextRegister = JSC::X86Registers::esi;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static const int RegisterSize = 4;
-
- static const int RegisterArgumentCount = 0;
- static RegisterID registerForArgument(int)
- {
- Q_ASSERT(false);
- // Not reached.
- return JSC::X86Registers::eax;
- }
-
- // Return address is pushed onto stack by the CPU.
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
- static const int StackShadowSpace = 0;
- inline void platformEnterStandardStackFrame() {}
- inline void platformLeaveStandardStackFrame() {}
-#elif CPU(X86_64)
-
-#define VALUE_FITS_IN_REGISTER
-#define ARGUMENTS_IN_REGISTERS
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-
- static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const RegisterID ContextRegister = JSC::X86Registers::r14;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static const int RegisterSize = 8;
-
-#if OS(WINDOWS)
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::X86Registers::ecx,
- JSC::X86Registers::edx,
- JSC::X86Registers::r8,
- JSC::X86Registers::r9
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
- static const int StackShadowSpace = 32;
-#else // Unix
- static const int RegisterArgumentCount = 6;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::X86Registers::edi,
- JSC::X86Registers::esi,
- JSC::X86Registers::edx,
- JSC::X86Registers::ecx,
- JSC::X86Registers::r8,
- JSC::X86Registers::r9
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
- static const int StackShadowSpace = 0;
-#endif
-
- // Return address is pushed onto stack by the CPU.
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
- inline void platformEnterStandardStackFrame() {}
- inline void platformLeaveStandardStackFrame() {}
-#elif CPU(ARM)
-
-#undef VALUE_FITS_IN_REGISTER
-#define ARGUMENTS_IN_REGISTERS
-#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
-
- static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp; // r13
- static const RegisterID StackFrameRegister = JSC::ARMRegisters::fp; // r11
- static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
- static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
- static const RegisterID ContextRegister = JSC::ARMRegisters::r5;
- static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
-
- static const int RegisterSize = 4;
-
- static const RegisterID RegisterArgument1 = JSC::ARMRegisters::r0;
- static const RegisterID RegisterArgument2 = JSC::ARMRegisters::r1;
- static const RegisterID RegisterArgument3 = JSC::ARMRegisters::r2;
- static const RegisterID RegisterArgument4 = JSC::ARMRegisters::r3;
-
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index);
- };
-
- // Registers saved in platformEnterStandardStackFrame below.
- static const int StackSpaceAllocatedUponFunctionEntry = 5 * RegisterSize;
- static const int StackShadowSpace = 0;
- inline void platformEnterStandardStackFrame()
- {
- // Move the register arguments onto the stack as if they were
- // pushed by the caller, just like on ia32. This gives us consistent
- // access to the parameters if we need to.
- push(JSC::ARMRegisters::r3);
- push(JSC::ARMRegisters::r2);
- push(JSC::ARMRegisters::r1);
- push(JSC::ARMRegisters::r0);
- push(JSC::ARMRegisters::lr);
- }
- inline void platformLeaveStandardStackFrame()
- {
- pop(JSC::ARMRegisters::lr);
- addPtr(TrustedImm32(4 * RegisterSize), StackPointerRegister);
- }
-#else
-#error The JIT needs to be ported to this platform.
-#endif
- static const int calleeSavedRegisterCount;
-
-#if CPU(X86) || CPU(X86_64)
- static const int StackAlignment = 16;
-#elif CPU(ARM)
- // Per AAPCS
- static const int StackAlignment = 8;
-#else
-#error Stack alignment unknown for this platform.
-#endif
-
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
// to onto the stack when calling functions.
@@ -318,7 +173,7 @@ public:
{
public:
StackLayout(IR::Function *function, int maxArgCountForBuiltins)
- : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1)
+ : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1)
, maxOutgoingArgumentCount(function->maxNumberOfArguments)
, localCount(function->tempCount)
, savedRegCount(maxArgCountForBuiltins)
@@ -351,7 +206,7 @@ public:
+ RegisterSize; // saved StackFrameRegister
// space for the callee saved registers
- int frameSize = RegisterSize * calleeSavedRegisterCount;
+ int frameSize = RegisterSize * calleeSavedRegisterCount();
frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers
Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX);
@@ -460,8 +315,10 @@ public:
QString string;
};
struct Reference {
- Reference(IR::Temp *value) : value(value) {}
- IR::Temp *value;
+ Reference(IR::Expr *value) : value(value) {
+ Q_ASSERT(value->asTemp() || value->asArgLocal());
+ }
+ IR::Expr *value;
};
struct ReentryBlock {
@@ -504,13 +361,14 @@ public:
Jump genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest);
Assembler::Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Pointer loadTempAddress(RegisterID baseReg, IR::Temp *t);
+ Pointer loadAddress(RegisterID tmp, IR::Expr *t);
+ Pointer loadTempAddress(IR::Temp *t);
+ Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al);
Pointer loadStringAddress(RegisterID reg, const QString &string);
void loadStringRef(RegisterID reg, const QString &string);
Pointer stackSlotPointer(IR::Temp *t) const
{
Q_ASSERT(t->kind == IR::Temp::StackSlot);
- Q_ASSERT(t->scope == 0);
return Pointer(_stackLayout.stackSlotPointer(t->index));
}
@@ -585,7 +443,7 @@ public:
void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
{
Q_ASSERT(temp.value);
- Pointer addr = loadTempAddress(dest, temp.value);
+ Pointer addr = loadAddress(dest, temp.value);
loadArgumentInRegister(addr, dest, argumentNumber);
}
@@ -603,12 +461,25 @@ public:
{
Q_UNUSED(argumentNumber);
- if (!temp) {
+ if (temp) {
+ Pointer addr = loadTempAddress(temp);
+ load64(addr, dest);
+ } else {
QV4::Value undefined = QV4::Primitive::undefinedValue();
move(TrustedImm64(undefined.val), dest);
- } else {
- Pointer addr = loadTempAddress(dest, temp);
+ }
+ }
+
+ void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (al) {
+ Pointer addr = loadArgLocalAddress(dest, al);
load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ move(TrustedImm64(undefined.val), dest);
}
}
@@ -627,10 +498,12 @@ public:
if (!expr) {
QV4::Value undefined = QV4::Primitive::undefinedValue();
move(TrustedImm64(undefined.val), dest);
- } else if (expr->asTemp()){
- loadArgumentInRegister(expr->asTemp(), dest, argumentNumber);
- } else if (expr->asConst()) {
- loadArgumentInRegister(expr->asConst(), dest, argumentNumber);
+ } else if (IR::Temp *t = expr->asTemp()){
+ loadArgumentInRegister(t, dest, argumentNumber);
+ } else if (IR::ArgLocal *al = expr->asArgLocal()) {
+ loadArgumentInRegister(al, dest, argumentNumber);
+ } else if (IR::Const *c = expr->asConst()) {
+ loadArgumentInRegister(c, dest, argumentNumber);
} else {
Q_ASSERT(!"unimplemented expression type in loadArgument");
}
@@ -704,20 +577,26 @@ public:
}
#endif
- void storeReturnValue(IR::Temp *temp)
+ void storeReturnValue(IR::Expr *target)
{
- if (!temp)
+ if (!target)
return;
- 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);
- } else {
- Pointer addr = loadTempAddress(ScratchRegister, temp);
+ 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);
}
}
@@ -775,7 +654,7 @@ public:
{
Q_ASSERT (temp.value);
- Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
+ Pointer ptr = loadAddress(ScratchRegister, temp.value);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
@@ -807,30 +686,32 @@ public:
poke(TrustedImmPtr(name), StackSlot);
}
- void loadDouble(IR::Temp* temp, FPRegisterID dest)
+ void loadDouble(IR::Expr *source, FPRegisterID dest)
{
- if (temp->kind == IR::Temp::PhysicalRegister) {
- moveDouble((FPRegisterID) temp->index, dest);
+ IR::Temp *sourceTemp = source->asTemp();
+ if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
+ moveDouble((FPRegisterID) sourceTemp->index, dest);
return;
}
- Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ Pointer ptr = loadAddress(ScratchRegister, source);
loadDouble(ptr, dest);
}
- void storeDouble(FPRegisterID source, IR::Temp* temp)
+ void storeDouble(FPRegisterID source, IR::Expr* target)
{
- if (temp->kind == IR::Temp::PhysicalRegister) {
- moveDouble(source, (FPRegisterID) temp->index);
+ IR::Temp *targetTemp = target->asTemp();
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
+ moveDouble(source, (FPRegisterID) targetTemp->index);
return;
}
#if QT_POINTER_SIZE == 8
moveDoubleTo64(source, ReturnValueRegister);
move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
xor64(ScratchRegister, ReturnValueRegister);
- Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ Pointer ptr = loadAddress(ScratchRegister, target);
store64(ReturnValueRegister, ptr);
#else
- Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ Pointer ptr = loadAddress(ScratchRegister, target);
storeDouble(source, ptr);
#endif
}
@@ -862,11 +743,11 @@ public:
void copyValue(Result result, IR::Expr* source);
// The scratch register is used to calculate the temp address for the source.
- void memcopyValue(Pointer target, IR::Temp *sourceTemp, RegisterID scratchRegister)
+ void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister)
{
- Q_ASSERT(sourceTemp->kind != IR::Temp::PhysicalRegister);
+ Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- JSC::MacroAssembler::loadDouble(loadTempAddress(scratchRegister, sourceTemp), FPGpr0);
+ JSC::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
JSC::MacroAssembler::storeDouble(FPGpr0, target);
}
@@ -888,13 +769,13 @@ public:
#endif
}
- void storeValue(QV4::Primitive value, IR::Temp* temp);
+ void storeValue(QV4::Primitive value, IR::Expr* temp);
void enterStandardStackFrame();
void leaveStandardStackFrame();
void checkException() {
- loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext, engine)), ScratchRegister);
+ loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, engine)), ScratchRegister);
load32(Address(ScratchRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
@@ -988,10 +869,8 @@ public:
prepareRelativeCall(function, this);
loadArgumentOnStackOrRegister<0>(arg1);
-#if (OS(LINUX) && CPU(X86) && (defined(__PIC__) || defined(__PIE__))) || \
- (OS(WINDOWS) && CPU(X86))
- load32(Address(StackFrameRegister, -int(sizeof(void*))),
- JSC::X86Registers::ebx); // restore the GOT ptr
+#ifdef RESTORE_EBX_ON_CALL
+ load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
#endif
callAbsolute(functionName, function);
@@ -1050,13 +929,11 @@ public:
return Pointer(addr);
}
- IR::Temp *t = e->asTemp();
- Q_ASSERT(t);
- if (t->kind != IR::Temp::PhysicalRegister)
- return loadTempAddress(tmpReg, t);
-
+ if (IR::Temp *t = e->asTemp())
+ if (t->kind == IR::Temp::PhysicalRegister)
+ return Pointer(_stackLayout.savedRegPointer(offset));
- return Pointer(_stackLayout.savedRegPointer(offset));
+ return loadAddress(tmpReg, e);
}
void storeBool(RegisterID reg, Pointer addr)
@@ -1071,24 +948,31 @@ public:
move(src, dest);
}
- void storeBool(RegisterID reg, IR::Temp *target)
+ void storeBool(RegisterID reg, IR::Expr *target)
{
- if (target->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) target->index);
- } else {
- Pointer addr = loadTempAddress(ScratchRegister, target);
- storeBool(reg, addr);
+ if (IR::Temp *targetTemp = target->asTemp()) {
+ if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) targetTemp->index);
+ return;
+ }
}
+
+ Pointer addr = loadAddress(ScratchRegister, target);
+ storeBool(reg, addr);
}
- void storeBool(bool value, IR::Temp *target) {
+ void storeBool(bool value, IR::Expr *target) {
TrustedImm32 trustedValue(value ? 1 : 0);
- if (target->kind == IR::Temp::PhysicalRegister) {
- move(trustedValue, (RegisterID) target->index);
- } else {
- move(trustedValue, ScratchRegister);
- storeBool(ScratchRegister, target);
+
+ if (IR::Temp *targetTemp = target->asTemp()) {
+ if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ move(trustedValue, (RegisterID) targetTemp->index);
+ return;
+ }
}
+
+ move(trustedValue, ScratchRegister);
+ storeBool(ScratchRegister, target);
}
void storeInt32(RegisterID src, RegisterID dest)
@@ -1103,12 +987,17 @@ public:
store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag), addr);
}
- void storeInt32(RegisterID reg, IR::Temp *target)
+ void storeInt32(RegisterID reg, IR::Expr *target)
{
- if (target->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) target->index);
- } else {
- Pointer addr = loadTempAddress(ScratchRegister, 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);
}
}
@@ -1130,12 +1019,13 @@ public:
done.link(this);
}
- void storeUInt32(RegisterID reg, IR::Temp *target)
+ void storeUInt32(RegisterID reg, IR::Expr *target)
{
- if (target->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) target->index);
+ IR::Temp *targetTemp = target->asTemp();
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) targetTemp->index);
} else {
- Pointer addr = loadTempAddress(ScratchRegister, target);
+ Pointer addr = loadAddress(ScratchRegister, target);
storeUInt32(reg, addr);
}
}
@@ -1157,12 +1047,11 @@ public:
return target;
}
- IR::Temp *t = e->asTemp();
- Q_ASSERT(t);
- if (t->kind == IR::Temp::PhysicalRegister)
- return (FPRegisterID) t->index;
+ if (IR::Temp *t = e->asTemp())
+ if (t->kind == IR::Temp::PhysicalRegister)
+ return (FPRegisterID) t->index;
- loadDouble(t, target);
+ loadDouble(e, target);
return target;
}
@@ -1178,12 +1067,11 @@ public:
return scratchReg;
}
- IR::Temp *t = e->asTemp();
- Q_ASSERT(t);
- if (t->kind == IR::Temp::PhysicalRegister)
- return (RegisterID) t->index;
+ if (IR::Temp *t = e->asTemp())
+ if (t->kind == IR::Temp::PhysicalRegister)
+ return (RegisterID) t->index;
- return toInt32Register(loadTempAddress(scratchReg, t), scratchReg);
+ return toInt32Register(loadAddress(scratchReg, e), scratchReg);
}
RegisterID toInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1199,12 +1087,11 @@ public:
return scratchReg;
}
- IR::Temp *t = e->asTemp();
- Q_ASSERT(t);
- if (t->kind == IR::Temp::PhysicalRegister)
- return (RegisterID) t->index;
+ if (IR::Temp *t = e->asTemp())
+ if (t->kind == IR::Temp::PhysicalRegister)
+ return (RegisterID) t->index;
- return toUInt32Register(loadTempAddress(scratchReg, t), scratchReg);
+ return toUInt32Register(loadAddress(scratchReg, e), scratchReg);
}
RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1291,17 +1178,15 @@ void Assembler::copyValue(Result result, IR::Expr* source)
storeUInt32(reg, result);
} else if (source->type == IR::DoubleType) {
storeDouble(toDoubleRegister(source), result);
- } else if (IR::Temp *temp = source->asTemp()) {
+ } else if (source->asTemp() || source->asArgLocal()) {
#ifdef VALUE_FITS_IN_REGISTER
- Q_UNUSED(temp);
-
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
+ // Use ReturnValueRegister as "scratch" register because loadArgument
+ // and storeArgument are functions that may need a scratch register themselves.
+ loadArgumentInRegister(source, ReturnValueRegister, 0);
+ storeReturnValue(result);
#else
- loadDouble(temp, FPGpr0);
- storeDouble(FPGpr0, result);
+ loadDouble(source, FPGpr0);
+ storeDouble(FPGpr0, result);
#endif
} else if (IR::Const *c = source->asConst()) {
QV4::Primitive v = convertToValue(c);
@@ -1316,7 +1201,7 @@ void Assembler::copyValue(Result result, IR::Expr* source)
template <typename T> inline void prepareRelativeCall(const T &, Assembler *){}
template <> inline void prepareRelativeCall(const RelativeCall &relativeCall, Assembler *as)
{
- as->loadPtr(Assembler::Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lookups)),
+ as->loadPtr(Assembler::Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, lookups)),
relativeCall.addr.base);
}
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index 344bbf56e0..a19072f52e 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -112,7 +112,7 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
-void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
+void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
if (op != IR::OpMod
&& lhs->type == IR::DoubleType && rhs->type == IR::DoubleType
@@ -156,14 +156,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
}
-void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
+void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
Q_ASSERT(lhs->asConst() == 0 || rhs->asConst() == 0);
Q_ASSERT(isPregOrConst(lhs));
Q_ASSERT(isPregOrConst(rhs));
+ IR::Temp *targetTemp = target->asTemp();
Assembler::FPRegisterID targetReg;
- if (target->kind == IR::Temp::PhysicalRegister)
- targetReg = (Assembler::FPRegisterID) target->index;
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::FPRegisterID) targetTemp->index;
else
targetReg = Assembler::FPGpr0;
@@ -232,31 +233,33 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target)
} return;
}
- if (target->kind != IR::Temp::PhysicalRegister)
+ if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
as->storeDouble(Assembler::FPGpr0, target);
}
-bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Q_ASSERT(leftSource->type == IR::SInt32Type);
+ IR::Temp *targetTemp = target->asTemp();
Assembler::RegisterID targetReg = Assembler::ReturnValueRegister;
- if (target->kind == IR::Temp::PhysicalRegister) {
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
// We try to load leftSource into the target's register, but we can't do that if
// the target register is the same as rightSource.
IR::Temp *rhs = rightSource->asTemp();
- if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != target->index)
- targetReg = (Assembler::RegisterID) target->index;
+ if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index)
+ targetReg = (Assembler::RegisterID) targetTemp->index;
}
switch (op) {
case IR::OpBitAnd: {
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister
- && target->kind == IR::Temp::PhysicalRegister
- && target->index == rightSource->asTemp()->index) {
+ && targetTemp
+ && targetTemp->kind == IR::Temp::PhysicalRegister
+ && targetTemp->index == rightSource->asTemp()->index) {
as->and32(as->toInt32Register(leftSource, Assembler::ScratchRegister),
- (Assembler::RegisterID) target->index);
+ (Assembler::RegisterID) targetTemp->index);
return true;
}
@@ -268,10 +271,11 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
case IR::OpBitOr: {
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister
- && target->kind == IR::Temp::PhysicalRegister
- && target->index == rightSource->asTemp()->index) {
+ && targetTemp
+ && targetTemp->kind == IR::Temp::PhysicalRegister
+ && targetTemp->index == rightSource->asTemp()->index) {
as->or32(as->toInt32Register(leftSource, Assembler::ScratchRegister),
- (Assembler::RegisterID) target->index);
+ (Assembler::RegisterID) targetTemp->index);
return true;
}
@@ -283,10 +287,11 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
case IR::OpBitXor: {
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister
- && target->kind == IR::Temp::PhysicalRegister
- && target->index == rightSource->asTemp()->index) {
+ && targetTemp
+ && targetTemp->kind == IR::Temp::PhysicalRegister
+ && targetTemp->index == rightSource->asTemp()->index) {
as->xor32(as->toInt32Register(leftSource, Assembler::ScratchRegister),
- (Assembler::RegisterID) target->index);
+ (Assembler::RegisterID) targetTemp->index);
return true;
}
@@ -370,9 +375,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister
- && target->kind == IR::Temp::PhysicalRegister
- && target->index == rightSource->asTemp()->index) {
- Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index;
+ && targetTemp
+ && targetTemp->kind == IR::Temp::PhysicalRegister
+ && targetTemp->index == rightSource->asTemp()->index) {
+ Assembler::RegisterID targetReg = (Assembler::RegisterID) targetTemp->index;
as->move(targetReg, Assembler::ScratchRegister);
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
as->sub32(Assembler::ScratchRegister, targetReg);
@@ -407,7 +413,7 @@ static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, u
return Assembler::FPRegisterID(hint);
}
-Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Assembler::Jump done;
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index a6292e6fb5..8c7fa4337a 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -58,10 +58,10 @@ struct Binop {
, op(operation)
{}
- void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target);
- void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target);
- bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
- Assembler::Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+ void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
+ void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
+ bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
+ Assembler::Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
typedef Assembler::Jump (Binop::*MemRegOp)(Assembler::Address, Assembler::RegisterID);
typedef Assembler::Jump (Binop::*ImmRegOp)(Assembler::TrustedImm32, Assembler::RegisterID);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 17e2730669..8449ff6c0c 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -203,9 +203,9 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex
: EvalInstructionSelection(execAllocator, module, jsGenerator)
, _block(0)
, _as(0)
+ , compilationUnit(new CompilationUnit)
, qmlEngine(qmlEngine)
{
- compilationUnit = new CompilationUnit;
compilationUnit->codeRefs.resize(module->functions.size());
}
@@ -214,90 +214,6 @@ InstructionSelection::~InstructionSelection()
delete _as;
}
-#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX))
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
-# if CPU(X86) && OS(LINUX) // x86 with linux
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::edx
- << JSC::X86Registers::ebx;
-# else // x86_64 with linux or with macos
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::ebx
- << JSC::X86Registers::edi
- << JSC::X86Registers::esi
- << JSC::X86Registers::edx
- << JSC::X86Registers::r9
- << JSC::X86Registers::r8
- << JSC::X86Registers::r13
- << JSC::X86Registers::r15;
-# endif
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
-// linux/x86_64, linux/x86, and macos/x86_64:
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::X86Registers::xmm2
- << JSC::X86Registers::xmm3
- << JSC::X86Registers::xmm4
- << JSC::X86Registers::xmm5
- << JSC::X86Registers::xmm6
- << JSC::X86Registers::xmm7;
- return fpRegisters;
-}
-
-#elif CPU(ARM) && OS(LINUX)
- // Note: this is not generic for all ARM platforms. Specifically, r9 is platform dependent
- // (e.g. iOS reserves it). See the ARM GNU Linux abi for details.
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::ARMRegisters::r1
- << JSC::ARMRegisters::r2
- << JSC::ARMRegisters::r3
- << JSC::ARMRegisters::r4
- << JSC::ARMRegisters::r8
- << JSC::ARMRegisters::r9;
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::ARMRegisters::d2
- << JSC::ARMRegisters::d3
- << JSC::ARMRegisters::d4
- << JSC::ARMRegisters::d5
- << JSC::ARMRegisters::d6;
- return fpRegisters;
-}
-#elif CPU(X86) && OS(WINDOWS)
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::edx
- << JSC::X86Registers::ebx;
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::X86Registers::xmm2
- << JSC::X86Registers::xmm3
- << JSC::X86Registers::xmm4
- << JSC::X86Registers::xmm5
- << JSC::X86Registers::xmm6
- << JSC::X86Registers::xmm7;
- return fpRegisters;
-}
-#endif
-
void InstructionSelection::run(int functionIndex)
{
IR::Function *function = irModule->functions[functionIndex];
@@ -307,19 +223,16 @@ void InstructionSelection::run(int functionIndex)
IR::Optimizer opt(_function);
opt.run(qmlEngine);
-#ifdef REGALLOC_IS_SUPPORTED
static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty();
- if (opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator(getIntRegisters(), getFpRegisters()).run(_function, opt);
- } else
-#endif // REGALLOC_IS_SUPPORTED
- {
+ if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
+ RegisterAllocator(Assembler::getRegisterInfo()).run(_function, opt);
+ } else {
if (opt.isInSSA())
// No register allocator available for this platform, or env. var was set, so:
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
+ IR::Optimizer::showMeTheCode(_function);
}
- IR::Optimizer::showMeTheCode(_function);
QSet<IR::Jump *> removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
@@ -335,7 +248,7 @@ void InstructionSelection::run(int functionIndex)
#endif
const int locals = _as->stackLayout().calculateJSStackFrameSize();
- _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
_as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister);
_as->addPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
@@ -351,7 +264,7 @@ void InstructionSelection::run(int functionIndex)
foreach (IR::Stmt *s, _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
- Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
+ Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
_as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
@@ -385,10 +298,10 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
{
- return compilationUnit;
+ return compilationUnit.take();
}
-void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, 0);
@@ -407,52 +320,52 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args
}
void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
- IR::Temp *result)
+ IR::Expr *result)
{
generateFunctionCall(result, Runtime::typeofMember, Assembler::ContextRegister,
Assembler::PointerToValue(base), Assembler::PointerToString(name));
}
void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
- IR::Temp *result)
+ IR::Expr *result)
{
generateFunctionCall(result, Runtime::typeofElement,
Assembler::ContextRegister,
Assembler::PointerToValue(base), Assembler::PointerToValue(index));
}
-void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
generateFunctionCall(result, Runtime::typeofName, Assembler::ContextRegister,
Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result)
+void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
generateFunctionCall(result, Runtime::typeofValue, Assembler::ContextRegister,
Assembler::PointerToValue(value));
}
-void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
generateFunctionCall(result, Runtime::deleteMember, Assembler::ContextRegister,
Assembler::Reference(base), Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index,
- IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
+ IR::Expr *result)
{
generateFunctionCall(result, Runtime::deleteElement, Assembler::ContextRegister,
Assembler::Reference(base), Assembler::PointerToValue(index));
}
-void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
generateFunctionCall(result, Runtime::deleteName, Assembler::ContextRegister,
Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result)
+void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
{
_as->storeValue(Primitive::fromBoolean(false), result);
}
@@ -468,7 +381,7 @@ void InstructionSelection::callBuiltinReThrow()
_as->jumpToExceptionHandler();
}
-void InstructionSelection::callBuiltinUnwindException(IR::Temp *result)
+void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
{
generateFunctionCall(result, Runtime::unwindException, Assembler::ContextRegister);
@@ -476,11 +389,10 @@ void InstructionSelection::callBuiltinUnwindException(IR::Temp *result)
void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
{
- Assembler::Pointer s = _as->loadStringAddress(Assembler::ScratchRegister, exceptionName);
- generateFunctionCall(Assembler::ContextRegister, Runtime::pushCatchScope, Assembler::ContextRegister, s);
+ generateFunctionCall(Assembler::ContextRegister, Runtime::pushCatchScope, Assembler::ContextRegister, Assembler::PointerToString(exceptionName));
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
@@ -488,7 +400,7 @@ void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::T
generateFunctionCall(result, Runtime::foreachIterator, Assembler::ContextRegister, Assembler::PointerToValue(arg));
}
-void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result)
+void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
@@ -496,7 +408,7 @@ void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR:
generateFunctionCall(result, Runtime::foreachNextPropertyName, Assembler::Reference(arg));
}
-void InstructionSelection::callBuiltinPushWithScope(IR::Temp *arg)
+void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
{
Q_ASSERT(arg);
@@ -514,7 +426,7 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &
Assembler::TrustedImm32(deletable), Assembler::PointerToString(name));
}
-void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args)
+void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
{
Q_ASSERT(result);
@@ -523,7 +435,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList
baseAddressForCallArguments(), Assembler::TrustedImm32(length));
}
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
+void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
{
Q_ASSERT(result);
@@ -604,7 +516,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int
Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
}
-void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result)
+void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
{
generateFunctionCall(result, Runtime::setupArgumentsObject, Assembler::ContextRegister);
}
@@ -614,19 +526,24 @@ void InstructionSelection::callBuiltinConvertThisToObject()
generateFunctionCall(Assembler::Void, Runtime::convertThisToObject, Assembler::ContextRegister);
}
-void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value);
prepareCallData(args, 0);
- generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister,
- Assembler::Reference(value),
- baseAddressForCallData());
+ if (value->asConst())
+ generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister,
+ Assembler::PointerToValue(value),
+ baseAddressForCallData());
+ else
+ generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister,
+ Assembler::Reference(value),
+ baseAddressForCallData());
}
-void InstructionSelection::loadThisObject(IR::Temp *temp)
+void InstructionSelection::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, callData)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister);
#if defined(VALUE_FITS_IN_REGISTER)
_as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)),
Assembler::ReturnValueRegister);
@@ -636,60 +553,63 @@ void InstructionSelection::loadThisObject(IR::Temp *temp)
#endif
}
-void InstructionSelection::loadQmlIdArray(IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(IR::Expr *temp)
{
generateFunctionCall(temp, Runtime::getQmlIdArray, Assembler::ContextRegister);
}
-void InstructionSelection::loadQmlImportedScripts(IR::Temp *temp)
+void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp)
{
generateFunctionCall(temp, Runtime::getQmlImportedScripts, Assembler::ContextRegister);
}
-void InstructionSelection::loadQmlContextObject(IR::Temp *temp)
+void InstructionSelection::loadQmlContextObject(IR::Expr *temp)
{
generateFunctionCall(temp, Runtime::getQmlContextObject, Assembler::ContextRegister);
}
-void InstructionSelection::loadQmlScopeObject(IR::Temp *temp)
+void InstructionSelection::loadQmlScopeObject(IR::Expr *temp)
{
generateFunctionCall(temp, Runtime::getQmlScopeObject, Assembler::ContextRegister);
}
-void InstructionSelection::loadQmlSingleton(const QString &name, IR::Temp *temp)
+void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp)
{
generateFunctionCall(temp, Runtime::getQmlSingleton, Assembler::ContextRegister, Assembler::PointerToString(name));
}
-void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
-{
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp->type == IR::DoubleType) {
- Q_ASSERT(sourceConst->type == IR::DoubleType);
- _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::SInt32Type) {
- Q_ASSERT(sourceConst->type == IR::SInt32Type);
- _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::UInt32Type) {
- Q_ASSERT(sourceConst->type == IR::UInt32Type);
- _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::BoolType) {
- Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32),
- (Assembler::RegisterID) targetTemp->index);
- } else {
- Q_UNREACHABLE();
+void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
+{
+ if (IR::Temp *targetTemp = target->asTemp()) {
+ if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ if (targetTemp->type == IR::DoubleType) {
+ Q_ASSERT(sourceConst->type == IR::DoubleType);
+ _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
+ } else if (targetTemp->type == IR::SInt32Type) {
+ Q_ASSERT(sourceConst->type == IR::SInt32Type);
+ _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ } else if (targetTemp->type == IR::UInt32Type) {
+ Q_ASSERT(sourceConst->type == IR::UInt32Type);
+ _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ } else if (targetTemp->type == IR::BoolType) {
+ Q_ASSERT(sourceConst->type == IR::BoolType);
+ _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32),
+ (Assembler::RegisterID) targetTemp->index);
+ } else {
+ Q_UNREACHABLE();
+ }
+ return;
}
- } else {
- _as->storeValue(convertToValue(sourceConst), targetTemp);
}
+
+ _as->storeValue(convertToValue(sourceConst), target);
}
-void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
+void InstructionSelection::loadString(const QString &str, IR::Expr *target)
{
Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str);
_as->loadPtr(srcAddr, Assembler::ReturnValueRegister);
- Pointer destAddr = _as->loadTempAddress(Assembler::ScratchRegister, targetTemp);
+ Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target);
#if QT_POINTER_SIZE == 8
_as->store64(Assembler::ReturnValueRegister, destAddr);
#else
@@ -699,20 +619,20 @@ void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp)
#endif
}
-void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
int id = registerRegExp(sourceRegexp);
- generateFunctionCall(targetTemp, Runtime::regexpLiteral, Assembler::ContextRegister, Assembler::TrustedImm32(id));
+ generateFunctionCall(target, Runtime::regexpLiteral, Assembler::ContextRegister, Assembler::TrustedImm32(id));
}
-void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Temp *temp)
+void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
{
if (useFastLookups && name->global) {
uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(temp, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::Void);
return;
}
- generateFunctionCall(temp, Runtime::getActivationProperty, Assembler::ContextRegister, Assembler::PointerToString(*name->id));
+ generateFunctionCall(target, Runtime::getActivationProperty, Assembler::ContextRegister, Assembler::PointerToString(*name->id));
}
void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
@@ -722,13 +642,13 @@ void InstructionSelection::setActivationProperty(IR::Expr *source, const QString
Assembler::ContextRegister, Assembler::PointerToString(targetName), Assembler::PointerToValue(source));
}
-void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target)
+void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
generateFunctionCall(target, Runtime::closure, Assembler::ContextRegister, Assembler::TrustedImm32(id));
}
-void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Temp *target)
+void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
@@ -739,10 +659,13 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::
}
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target)
+void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0)
generateFunctionCall(target, Runtime::getQmlAttachedProperty, Assembler::ContextRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ else if (isSingleton)
+ generateFunctionCall(target, Runtime::getQmlSingletonQObjectProperty, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ Assembler::TrustedImm32(captureRequired));
else
generateFunctionCall(target, Runtime::getQmlQObjectProperty, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
Assembler::TrustedImm32(captureRequired));
@@ -769,7 +692,7 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target
Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
}
-void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target)
+void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
if (useFastLookups) {
uint lookup = registerIndexedGetterLookup();
@@ -797,13 +720,20 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR
Assembler::PointerToValue(source));
}
-void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
{
- if (*sourceTemp == *targetTemp)
+ IR::Temp *sourceTemp = source->asTemp();
+ IR::Temp *targetTemp = target->asTemp();
+
+ if (sourceTemp && targetTemp && *sourceTemp == *targetTemp)
return;
+ if (IR::ArgLocal *sal = source->asArgLocal())
+ if (IR::ArgLocal *tal = target->asArgLocal())
+ if (*sal == *tal)
+ return;
- if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
if (sourceTemp->type == IR::DoubleType)
_as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
(Assembler::FPRegisterID) targetTemp->index);
@@ -814,16 +744,16 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
} else {
switch (sourceTemp->type) {
case IR::DoubleType:
- _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, targetTemp);
+ _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target);
break;
case IR::SInt32Type:
- _as->storeInt32((Assembler::RegisterID) sourceTemp->index, targetTemp);
+ _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target);
break;
case IR::UInt32Type:
- _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, targetTemp);
+ _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target);
break;
case IR::BoolType:
- _as->storeBool((Assembler::RegisterID) sourceTemp->index, targetTemp);
+ _as->storeBool((Assembler::RegisterID) sourceTemp->index, target);
break;
default:
Q_ASSERT(!"Unreachable");
@@ -831,23 +761,23 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
}
return;
}
- } else if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ } else if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
switch (targetTemp->type) {
case IR::DoubleType:
- Q_ASSERT(sourceTemp->type == IR::DoubleType);
- _as->toDoubleRegister(sourceTemp, (Assembler::FPRegisterID) targetTemp->index);
+ Q_ASSERT(source->type == IR::DoubleType);
+ _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index);
return;
case IR::BoolType:
- Q_ASSERT(sourceTemp->type == IR::BoolType);
- _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ Q_ASSERT(source->type == IR::BoolType);
+ _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
return;
case IR::SInt32Type:
- Q_ASSERT(sourceTemp->type == IR::SInt32Type);
- _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ Q_ASSERT(source->type == IR::SInt32Type);
+ _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
return;
case IR::UInt32Type:
- Q_ASSERT(sourceTemp->type == IR::UInt32Type);
- _as->toUInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index);
+ Q_ASSERT(source->type == IR::UInt32Type);
+ _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index);
return;
default:
Q_ASSERT(!"Unreachable");
@@ -856,14 +786,16 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
}
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadTempAddress(Assembler::ReturnValueRegister, targetTemp), sourceTemp,
- Assembler::ScratchRegister);
+ _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister);
}
-void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
{
- if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ IR::Temp *sourceTemp = source->asTemp();
+ IR::Temp *targetTemp = target->asTemp();
+
+ if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
Q_ASSERT(sourceTemp->type == targetTemp->type);
if (sourceTemp->type == IR::DoubleType) {
@@ -877,11 +809,11 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp
}
return;
}
- } else if (sourceTemp->kind == IR::Temp::StackSlot) {
- if (targetTemp->kind == IR::Temp::StackSlot) {
+ } else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Assembler::Pointer sAddr = _as->stackSlotPointer(sourceTemp);
- Assembler::Pointer tAddr = _as->stackSlotPointer(targetTemp);
+ Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target);
// use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
_as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0);
_as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1);
@@ -891,25 +823,28 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp
}
}
- IR::Temp *stackTemp = sourceTemp->kind == IR::Temp::StackSlot ? sourceTemp : targetTemp;
- IR::Temp *registerTemp = sourceTemp->kind == IR::Temp::PhysicalRegister ? sourceTemp
- : targetTemp;
- Assembler::Pointer addr = _as->stackSlotPointer(stackTemp);
- if (registerTemp->type == IR::DoubleType) {
+ IR::Expr *memExpr = !sourceTemp || sourceTemp->kind == IR::Temp::StackSlot ? source : target;
+ IR::Temp *regTemp = sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister ? sourceTemp
+ : targetTemp;
+ Q_ASSERT(memExpr);
+ Q_ASSERT(regTemp);
+
+ Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr);
+ if (regTemp->type == IR::DoubleType) {
_as->loadDouble(addr, Assembler::FPGpr0);
- _as->storeDouble((Assembler::FPRegisterID) registerTemp->index, addr);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) registerTemp->index);
- } else if (registerTemp->type == IR::UInt32Type) {
+ _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr);
+ _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index);
+ } else if (regTemp->type == IR::UInt32Type) {
_as->toUInt32Register(addr, Assembler::ScratchRegister);
- _as->storeUInt32((Assembler::RegisterID) registerTemp->index, addr);
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) registerTemp->index);
+ _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr);
+ _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
} else {
_as->load32(addr, Assembler::ScratchRegister);
- _as->store32((Assembler::RegisterID) registerTemp->index, addr);
- if (registerTemp->type != stackTemp->type) {
+ _as->store32((Assembler::RegisterID) regTemp->index, addr);
+ if (regTemp->type != memExpr->type) {
addr.offset += 4;
quint32 tag;
- switch (registerTemp->type) {
+ switch (regTemp->type) {
case IR::BoolType:
tag = QV4::Value::_Boolean_Type;
break;
@@ -922,7 +857,7 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp
}
_as->store32(Assembler::TrustedImm32(tag), addr);
}
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) registerTemp->index);
+ _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
}
}
@@ -931,21 +866,21 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp
#define setOpContext(op, opName, operation) \
do { opContext = operation; opName = isel_stringIfy(operation); } while (0)
-void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp)
+void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
QV4::JIT::Unop unop(_as, oper);
- unop.generate(sourceTemp, targetTemp);
+ unop.generate(source, target);
}
-void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target)
+void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
QV4::JIT::Binop binop(_as, oper);
binop.generate(leftSource, rightSource, target);
}
void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
Q_ASSERT(base != 0);
@@ -965,7 +900,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
}
void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
Q_ASSERT(base != 0);
@@ -975,7 +910,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex
baseAddressForCallData());
}
-void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
{
switch (target->type) {
case IR::DoubleType:
@@ -996,7 +931,7 @@ void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target)
}
}
-void InstructionSelection::convertTypeSlowPath(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(target->type != IR::BoolType);
@@ -1006,7 +941,7 @@ void InstructionSelection::convertTypeSlowPath(IR::Temp *source, IR::Temp *targe
copyValue(source, target);
}
-void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::SInt32Type:
@@ -1018,13 +953,13 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadTempAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
+ _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
_as->storeDouble(Assembler::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, Assembler::ScratchRegister);
@@ -1051,17 +986,18 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe
// it is a double:
isDbl.link(_as);
- Assembler::Pointer addr2 = _as->loadTempAddress(Assembler::ScratchRegister, source);
- if (target->kind == IR::Temp::StackSlot) {
+ Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
#if QT_POINTER_SIZE == 8
_as->load64(addr2, Assembler::ScratchRegister);
- _as->store64(Assembler::ScratchRegister, _as->stackSlotPointer(target));
+ _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target));
#else
_as->loadDouble(addr2, Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
+ _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
#endif
} else {
- _as->loadDouble(addr2, (Assembler::FPRegisterID) target->index);
+ _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index);
}
noDoubleDone.link(_as);
@@ -1073,8 +1009,9 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe
}
}
-void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
{
+ IR::Temp *sourceTemp = source->asTemp();
switch (source->type) {
case IR::SInt32Type:
case IR::UInt32Type:
@@ -1085,8 +1022,8 @@ void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target)
// allocator was not used, then that means that we can use any register for to
// load the double into.
Assembler::FPRegisterID reg;
- if (source->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::FPRegisterID) source->index;
+ if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister)
+ reg = (Assembler::FPRegisterID) sourceTemp->index;
else
reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1);
Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0);
@@ -1116,13 +1053,13 @@ void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target)
}
}
-void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
#if QT_POINTER_SIZE == 8
- Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
_as->load64(addr, Assembler::ScratchRegister);
_as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
@@ -1142,12 +1079,13 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe
// not an int:
fallback.link(_as);
generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
- _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->loadAddress(Assembler::ScratchRegister, source));
isInt.link(_as);
success.link(_as);
- if (target->kind == IR::Temp::StackSlot) {
- Assembler::Pointer targetAddr = _as->stackSlotPointer(target);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
_as->store32(Assembler::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
_as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr);
@@ -1156,7 +1094,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe
}
#else
// load the tag:
- Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
Assembler::Pointer tagAddr = addr;
tagAddr.offset += 4;
_as->load32(tagAddr, Assembler::ReturnValueRegister);
@@ -1164,21 +1102,22 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe
// check if it's an int32:
Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
Assembler::TrustedImm32(Value::_Integer_Type));
- if (target->kind == IR::Temp::StackSlot) {
- _as->load32(addr, Assembler::ScratchRegister);
- Assembler::Pointer targetAddr = _as->stackSlotPointer(target);
- _as->store32(Assembler::ScratchRegister, targetAddr);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ _as->load32(addr, Assembler::ReturnValueRegister);
+ Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
+ _as->store32(Assembler::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
_as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr);
} else {
- _as->load32(addr, (Assembler::RegisterID) target->index);
+ _as->load32(addr, (Assembler::RegisterID) targetTemp->index);
}
Assembler::Jump intDone = _as->jump();
// not an int:
fallback.link(_as);
generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
- _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
intDone.link(_as);
@@ -1209,32 +1148,32 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe
case IR::StringType:
default:
generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt,
- _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
break;
} // switch (source->type)
}
-void InstructionSelection::convertTypeToUInt32(IR::Temp *source, IR::Temp *target)
+void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, Assembler::ScratchRegister);
// check if it's an int32:
Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
Assembler::TrustedImm32(Value::_Integer_Type));
- Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source);
+ Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
_as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target);
Assembler::Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toUInt,
- _as->loadTempAddress(Assembler::ScratchRegister, source));
+ _as->loadAddress(Assembler::ScratchRegister, source));
_as->storeInt32(Assembler::ReturnValueRegister, target);
intDone.link(_as);
@@ -1268,7 +1207,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Temp *source, IR::Temp *targe
} // switch (source->type)
}
-void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(func != 0);
prepareCallData(args, 0);
@@ -1288,7 +1227,7 @@ void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprL
}
-void InstructionSelection::constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (useFastLookups) {
@@ -1305,7 +1244,7 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name
baseAddressForCallData());
}
-void InstructionSelection::constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value != 0);
@@ -1324,16 +1263,17 @@ void InstructionSelection::visitJump(IR::Jump *s)
void InstructionSelection::visitCJump(IR::CJump *s)
{
- if (IR::Temp *t = s->cond->asTemp()) {
+ IR::Temp *t = s->cond->asTemp();
+ if (t || s->cond->asArgLocal()) {
Assembler::RegisterID reg;
- if (t->kind == IR::Temp::PhysicalRegister) {
+ if (t && t->kind == IR::Temp::PhysicalRegister) {
Q_ASSERT(t->type == IR::BoolType);
reg = (Assembler::RegisterID) t->index;
- } else if (t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
+ } else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
reg = Assembler::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += qOffsetOf(QV4::Value, tag);
Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type));
@@ -1345,7 +1285,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
booleanConversion.link(_as);
reg = Assembler::ReturnValueRegister;
- generateFunctionCall(reg, Runtime::toBoolean, Assembler::Reference(t));
+ generateFunctionCall(reg, Runtime::toBoolean, Assembler::Reference(s->cond));
testBoolean.link(_as);
}
@@ -1455,7 +1395,7 @@ void InstructionSelection::visitRet(IR::Ret *s)
Q_UNREACHABLE();
}
} else {
- Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t);
_as->load32(addr, lowReg);
addr.offset += 4;
_as->load32(addr, highReg);
@@ -1523,7 +1463,7 @@ void InstructionSelection::visitRet(IR::Ret *s)
const int locals = _as->stackLayout().calculateJSStackFrameSize();
_as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
- _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
_as->leaveStandardStackFrame();
@@ -1692,10 +1632,7 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I
return true;
}
- IR::Temp *t = varSrc->asTemp();
- Q_ASSERT(t);
-
- Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
tagAddr.offset += 4;
const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
_as->load32(tagAddr, tagReg);
@@ -1738,11 +1675,7 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
return true;
}
- IR::Temp *otherTemp = otherSrc->asTemp();
- Q_ASSERT(otherTemp); // constants cannot have "var" type
- Q_ASSERT(otherTemp->kind != IR::Temp::PhysicalRegister);
-
- Assembler::Pointer otherAddr = _as->loadTempAddress(Assembler::ReturnValueRegister, otherTemp);
+ Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
@@ -1790,10 +1723,7 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
return true;
}
- IR::Temp *t = varSrc->asTemp();
- Q_ASSERT(t);
-
- Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
tagAddr.offset += 4;
const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
_as->load32(tagAddr, tagReg);
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index d589223d7e..9ed8be844b 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -76,54 +76,54 @@ public:
protected:
virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
- virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result);
- virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result);
- virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result);
- virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result);
- virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result);
- virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result);
- virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result);
- virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result);
- virtual void callBuiltinDeleteValue(IR::Temp *result);
+ virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result);
+ virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result);
+ virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
+ virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result);
+ virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result);
+ virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result);
+ virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
+ virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result);
+ virtual void callBuiltinDeleteValue(IR::Expr *result);
virtual void callBuiltinThrow(IR::Expr *arg);
virtual void callBuiltinReThrow();
- virtual void callBuiltinUnwindException(IR::Temp *);
+ virtual void callBuiltinUnwindException(IR::Expr *);
virtual void callBuiltinPushCatchScope(const QString &exceptionName);
- virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result);
- virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
- virtual void callBuiltinPushWithScope(IR::Temp *arg);
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result);
+ virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result);
+ virtual void callBuiltinPushWithScope(IR::Expr *arg);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
- virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args);
- virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
- virtual void callBuiltinSetupArgumentObject(IR::Temp *result);
+ virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args);
+ virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
+ virtual void callBuiltinSetupArgumentObject(IR::Expr *result);
virtual void callBuiltinConvertThisToObject();
- virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
- virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result);
- virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result);
- virtual void convertType(IR::Temp *source, IR::Temp *target);
- virtual void loadThisObject(IR::Temp *temp);
- virtual void loadQmlIdArray(IR::Temp *temp);
- virtual void loadQmlImportedScripts(IR::Temp *temp);
- virtual void loadQmlContextObject(IR::Temp *temp);
- virtual void loadQmlScopeObject(IR::Temp *temp);
- virtual void loadQmlSingleton(const QString &name, IR::Temp *temp);
- virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp);
- virtual void loadString(const QString &str, IR::Temp *targetTemp);
- virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
- virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp);
+ virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
+ virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
+ virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result);
+ virtual void convertType(IR::Expr *source, IR::Expr *target);
+ virtual void loadThisObject(IR::Expr *temp);
+ virtual void loadQmlIdArray(IR::Expr *target);
+ virtual void loadQmlImportedScripts(IR::Expr *target);
+ virtual void loadQmlContextObject(IR::Expr *target);
+ virtual void loadQmlScopeObject(IR::Expr *target);
+ virtual void loadQmlSingleton(const QString &name, IR::Expr *target);
+ virtual void loadConst(IR::Const *sourceConst, IR::Expr *target);
+ virtual void loadString(const QString &str, IR::Expr *target);
+ virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target);
+ virtual void getActivationProperty(const IR::Name *name, IR::Expr *target);
virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
- virtual void initClosure(IR::Closure *closure, IR::Temp *target);
- virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target);
+ virtual void initClosure(IR::Closure *closure, IR::Expr *target);
+ virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
+ virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target);
- virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target);
+ virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target);
virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex);
- virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
- virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+ virtual void copyValue(IR::Expr *source, IR::Expr *target);
+ virtual void swapValues(IR::Expr *source, IR::Expr *target);
+ virtual void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target);
+ virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
typedef Assembler::Address Address;
typedef Assembler::Pointer Pointer;
@@ -148,9 +148,9 @@ protected:
return _as->stackLayout().callDataAddress();
}
- virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result);
- virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result);
- virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
+ virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result);
+ virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr*result);
+ virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
virtual void visitJump(IR::Jump *);
virtual void visitCJump(IR::CJump *);
@@ -167,44 +167,51 @@ protected:
void visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
private:
- void convertTypeSlowPath(IR::Temp *source, IR::Temp *target);
- void convertTypeToDouble(IR::Temp *source, IR::Temp *target);
- void convertTypeToBool(IR::Temp *source, IR::Temp *target);
- void convertTypeToSInt32(IR::Temp *source, IR::Temp *target);
- void convertTypeToUInt32(IR::Temp *source, IR::Temp *target);
+ void convertTypeSlowPath(IR::Expr *source, IR::Expr *target);
+ void convertTypeToDouble(IR::Expr *source, IR::Expr *target);
+ void convertTypeToBool(IR::Expr *source, IR::Expr *target);
+ void convertTypeToSInt32(IR::Expr *source, IR::Expr *target);
+ void convertTypeToUInt32(IR::Expr *source, IR::Expr *target);
- void convertIntToDouble(IR::Temp *source, IR::Temp *target)
+ void convertIntToDouble(IR::Expr *source, IR::Expr *target)
{
- if (target->kind == IR::Temp::PhysicalRegister) {
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- (Assembler::FPRegisterID) target->index);
- } else {
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
+ if (IR::Temp *targetTemp = target->asTemp()) {
+ if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
+ (Assembler::FPRegisterID) targetTemp->index);
+ return;
+ }
}
+
+ _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
+ Assembler::FPGpr0);
+ _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ScratchRegister, target));
}
- void convertUIntToDouble(IR::Temp *source, IR::Temp *target)
+ void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
{
Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
- if (target->kind == IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) target->index, tmpReg);
- } else {
- _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
- Assembler::FPGpr0, tmpReg);
- _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target));
+ if (IR::Temp *targetTemp = target->asTemp()) {
+ if (targetTemp->kind == IR::Temp::PhysicalRegister) {
+ _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg);
+ return;
+ }
}
+
+ _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
+ Assembler::FPGpr0, tmpReg);
+ _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target));
}
- void convertIntToBool(IR::Temp *source, IR::Temp *target)
+ void convertIntToBool(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID reg = target->kind == IR::Temp::PhysicalRegister
- ? (Assembler::RegisterID) target->index
- : Assembler::ScratchRegister;
+ Assembler::RegisterID reg = Assembler::ScratchRegister;
+ if (IR::Temp *targetTemp = target->asTemp())
+ if (targetTemp->kind == IR::Temp::PhysicalRegister)
+ reg = (Assembler::RegisterID) targetTemp->index;
_as->move(_as->toInt32Register(source, reg), reg);
_as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
_as->storeBool(reg, target);
@@ -247,7 +254,7 @@ private:
QSet<IR::Jump *> _removableJumps;
Assembler* _as;
- CompilationUnit *compilationUnit;
+ QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
};
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index b5765cd589..8ba3320c58 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -44,9 +44,9 @@
#include <algorithm>
-//#define DEBUG_REGALLOC
-
namespace {
+enum { DebugRegAlloc = 0 };
+
struct Use {
enum RegisterFlag { MustHaveRegister = 0, CouldHaveRegister = 1 };
unsigned flag : 1;
@@ -68,45 +68,135 @@ using namespace QV4::IR;
namespace QV4 {
namespace JIT {
+namespace {
+class IRPrinterWithPositions: public IRPrinter
+{
+ LifeTimeIntervals::Ptr intervals;
+ const int positionSize;
+
+public:
+ IRPrinterWithPositions(QTextStream *out, const LifeTimeIntervals::Ptr &intervals)
+ : IRPrinter(out)
+ , intervals(intervals)
+ , positionSize(QString::number(intervals->lastPosition()).size())
+ {}
+
+protected:
+ void addStmtNr(Stmt *s)
+ {
+ QString posStr;
+ int pos = intervals->positionForStatement(s);
+ if (pos != Stmt::InvalidId)
+ posStr = QString::number(pos);
+ *out << posStr.rightJustified(positionSize);
+ if (pos == Stmt::InvalidId)
+ *out << " ";
+ else
+ *out << ": ";
+ }
+};
+
+class IRPrinterWithRegisters: public IRPrinterWithPositions
+{
+ const RegisterInformation &_registerInformation;
+ QHash<int, const RegisterInfo *> _infoForRegularRegister;
+ QHash<int, const RegisterInfo *> _infoForFPRegister;
+
+public:
+ IRPrinterWithRegisters(QTextStream *out, const LifeTimeIntervals::Ptr &intervals,
+ const RegisterInformation &registerInformation)
+ : IRPrinterWithPositions(out, intervals)
+ , _registerInformation(registerInformation)
+ {
+ for (int i = 0, ei = _registerInformation.size(); i != ei; ++i)
+ if (_registerInformation.at(i).isRegularRegister())
+ _infoForRegularRegister.insert(_registerInformation.at(i).reg<int>(),
+ &_registerInformation.at(i));
+ else
+ _infoForFPRegister.insert(_registerInformation.at(i).reg<int>(),
+ &_registerInformation.at(i));
+ }
+
+protected:
+ void visitTemp(Temp *e)
+ {
+ switch (e->kind) {
+ case Temp::PhysicalRegister: {
+ const RegisterInfo *ri = e->type == DoubleType ? _infoForFPRegister.value(e->index, 0)
+ : _infoForRegularRegister.value(e->index, 0);
+ if (ri) {
+ *out << dumpStart(e);
+ *out << ri->prettyName();
+ *out << dumpEnd(e);
+ break;
+ }
+ }
+ default:
+ IRPrinterWithPositions::visitTemp(e);
+ }
+ }
+};
+}
+
class RegAllocInfo: public IRDecoder
{
struct Def {
- unsigned defStmt : 30;
+ unsigned valid : 1;
unsigned canHaveReg : 1;
unsigned isPhiTarget : 1;
- Def(): defStmt(0), canHaveReg(0), isPhiTarget(0) {}
- Def(int defStmt, bool canHaveReg, bool isPhiTarget)
- : defStmt(defStmt), canHaveReg(canHaveReg), isPhiTarget(isPhiTarget)
+ Def(): valid(0), canHaveReg(0), isPhiTarget(0) {}
+ Def(bool canHaveReg, bool isPhiTarget)
+ : valid(1), canHaveReg(canHaveReg), isPhiTarget(isPhiTarget)
{
- Q_ASSERT(defStmt > 0);
- Q_ASSERT(defStmt < (1 << 30));
}
- bool isValid() const { return defStmt != 0; } // 0 is invalid, as stmt numbers start at 1.
+ bool isValid() const { return valid != 0; }
};
+ IR::LifeTimeIntervals::Ptr _lifeTimeIntervals;
+ BasicBlock *_currentBB;
Stmt *_currentStmt;
- QHash<Temp, Def> _defs;
- QHash<Temp, QList<Use> > _uses;
- QList<int> _calls;
- QHash<Temp, QList<Temp> > _hints;
+ std::vector<Def> _defs;
+ std::vector<std::vector<Use> > _uses;
+ std::vector<int> _calls;
+ std::vector<QList<Temp> > _hints;
+
+ int defPosition(Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(Stmt *s) const
+ {
+ return _lifeTimeIntervals->positionForStatement(s);
+ }
public:
- RegAllocInfo(): _currentStmt(0) {}
+ RegAllocInfo(): _currentBB(0), _currentStmt(0) {}
- void collect(IR::Function *function)
+ void collect(IR::Function *function, const IR::LifeTimeIntervals::Ptr &lifeTimeIntervals)
{
+ _lifeTimeIntervals = lifeTimeIntervals;
+ _defs.resize(function->tempCount);
+ _uses.resize(function->tempCount);
+ _calls.reserve(function->statementCount() / 3);
+ _hints.resize(function->tempCount);
+
foreach (BasicBlock *bb, function->basicBlocks()) {
+ _currentBB = bb;
foreach (Stmt *s, bb->statements()) {
- Q_ASSERT(s->id > 0);
_currentStmt = s;
s->accept(this);
}
}
}
- QList<Use> uses(const Temp &t) const { return _uses[t]; }
+ const std::vector<Use> &uses(const Temp &t) const
+ {
+ return _uses[t.index];
+ }
+
bool useMustHaveReg(const Temp &t, int position) {
foreach (const Use &use, uses(t))
if (use.pos == position)
@@ -121,45 +211,52 @@ public:
return false;
}
- int def(const Temp &t) const {
- Q_ASSERT(_defs[t].isValid());
- return _defs[t].defStmt;
- }
bool canHaveRegister(const Temp &t) const {
- Q_ASSERT(_defs[t].isValid());
- return _defs[t].canHaveReg;
+ Q_ASSERT(_defs[t.index].isValid());
+ return _defs[t.index].canHaveReg;
}
bool isPhiTarget(const Temp &t) const {
- Q_ASSERT(_defs[t].isValid());
- return _defs[t].isPhiTarget;
+ Q_ASSERT(_defs[t.index].isValid());
+ return _defs[t.index].isPhiTarget;
}
- const QList<int> &calls() const { return _calls; }
- QList<Temp> hints(const Temp &t) const { return _hints[t]; }
+ const std::vector<int> &calls() const { return _calls; }
+ const QList<Temp> &hints(const Temp &t) const { return _hints[t.index]; }
void addHint(const Temp &t, int physicalRegister)
+ { addHint(t, Temp::PhysicalRegister, physicalRegister); }
+
+ void addHint(const Temp &t, Temp::Kind kind, int hintedIndex)
{
+ QList<Temp> &hints = _hints[t.index];
+ foreach (const Temp &hint, hints)
+ if (hint.index == hintedIndex)
+ return;
+
Temp hint;
- hint.init(Temp::PhysicalRegister, physicalRegister, 0);
- _hints[t].append(hint);
+ hint.init(kind, hintedIndex);
+ hints.append(hint);
}
-#ifdef DEBUG_REGALLOC
void dump() const
{
+ if (!DebugRegAlloc)
+ return;
+
QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions printer(&qout, _lifeTimeIntervals);
qout << "RegAllocInfo:" << endl << "Defs/uses:" << endl;
- QList<Temp> temps = _defs.keys();
- std::sort(temps.begin(), temps.end());
- foreach (const Temp &t, temps) {
- t.dump(qout);
- qout << " def at " << _defs[t].defStmt << " ("
+ for (unsigned t = 0; t < _defs.size(); ++t) {
+ const std::vector<Use> &uses = _uses[t];
+ if (uses.empty())
+ continue;
+ qout << "%" << t <<": "
+ << " ("
<< (_defs[t].canHaveReg ? "can" : "can NOT")
<< " have a register, and "
- << (isPhiTarget(t) ? "is" : "is NOT")
+ << (_defs[t].isPhiTarget ? "is" : "is NOT")
<< " defined by a phi node), uses at: ";
- const QList<Use> &uses = _uses[t];
- for (int i = 0; i < uses.size(); ++i) {
+ for (unsigned i = 0; i < uses.size(); ++i) {
if (i > 0) qout << ", ";
qout << uses[i].pos;
if (uses[i].mustHaveRegister()) qout << "(R)"; else qout << "(S)";
@@ -168,66 +265,62 @@ public:
}
qout << "Calls at: ";
- for (int i = 0; i < _calls.size(); ++i) {
+ for (unsigned i = 0; i < _calls.size(); ++i) {
if (i > 0) qout << ", ";
qout << _calls[i];
}
qout << endl;
qout << "Hints:" << endl;
- QList<Temp> hinted = _hints.keys();
- if (hinted.isEmpty())
- qout << "\t(none)" << endl;
- std::sort(hinted.begin(), hinted.end());
- foreach (const Temp &t, hinted) {
- qout << "\t";
- t.dump(qout);
- qout << ": ";
+ for (unsigned t = 0; t < _hints.size(); ++t) {
+ if (_uses[t].empty())
+ continue;
+ qout << "\t%" << t << ": ";
QList<Temp> hints = _hints[t];
for (int i = 0; i < hints.size(); ++i) {
if (i > 0) qout << ", ";
- hints[i].dump(qout);
+ printer.print(hints[i]);
}
qout << endl;
}
}
-#endif // DEBUG_REGALLOC
protected: // IRDecoder
- virtual void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Temp *) {}
- virtual void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Temp *) {}
- virtual void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Temp *) {}
- virtual void callBuiltinTypeofName(const QString &, IR::Temp *) {}
- virtual void callBuiltinTypeofValue(IR::Expr *, IR::Temp *) {}
- virtual void callBuiltinDeleteMember(IR::Temp *, const QString &, IR::Temp *) {}
- virtual void callBuiltinDeleteSubscript(IR::Temp *, IR::Expr *, IR::Temp *) {}
- virtual void callBuiltinDeleteName(const QString &, IR::Temp *) {}
- virtual void callBuiltinDeleteValue(IR::Temp *) {}
+ virtual void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Expr *) {}
+ virtual void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Expr *) {}
+ virtual void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {}
+ virtual void callBuiltinTypeofName(const QString &, IR::Expr *) {}
+ virtual void callBuiltinTypeofValue(IR::Expr *, IR::Expr *) {}
+ virtual void callBuiltinDeleteMember(IR::Expr *, const QString &, IR::Expr *) {}
+ virtual void callBuiltinDeleteSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {}
+ virtual void callBuiltinDeleteName(const QString &, IR::Expr *) {}
+ virtual void callBuiltinDeleteValue(IR::Expr *) {}
virtual void callBuiltinThrow(IR::Expr *) {}
virtual void callBuiltinReThrow() {}
- virtual void callBuiltinUnwindException(IR::Temp *) {}
+ virtual void callBuiltinUnwindException(IR::Expr *) {}
virtual void callBuiltinPushCatchScope(const QString &) {};
- virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Temp *) {}
+ virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Expr *) {}
virtual void callBuiltinForeachNextProperty(IR::Temp *, IR::Temp *) {}
- virtual void callBuiltinForeachNextPropertyname(IR::Temp *, IR::Temp *) {}
- virtual void callBuiltinPushWithScope(IR::Temp *) {}
+ virtual void callBuiltinForeachNextPropertyname(IR::Expr *, IR::Expr *) {}
+ virtual void callBuiltinPushWithScope(IR::Expr *) {}
virtual void callBuiltinPopScope() {}
virtual void callBuiltinDeclareVar(bool , const QString &) {}
- virtual void callBuiltinDefineArray(IR::Temp *, IR::ExprList *) {}
- virtual void callBuiltinDefineObjectLiteral(IR::Temp *, int, IR::ExprList *, IR::ExprList *, bool) {}
- virtual void callBuiltinSetupArgumentObject(IR::Temp *) {}
+ virtual void callBuiltinDefineArray(IR::Expr *, IR::ExprList *) {}
+ virtual void callBuiltinDefineObjectLiteral(IR::Expr *, int, IR::ExprList *, IR::ExprList *, bool) {}
+ virtual void callBuiltinSetupArgumentObject(IR::Expr *) {}
virtual void callBuiltinConvertThisToObject() {}
- virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+ virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
addDef(result);
- addUses(value, Use::CouldHaveRegister);
+ if (IR::Temp *tempValue = value->asTemp())
+ addUses(tempValue, Use::CouldHaveRegister);
addUses(args, Use::CouldHaveRegister);
addCall();
}
virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
Q_UNUSED(name)
@@ -238,7 +331,7 @@ protected: // IRDecoder
}
virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Temp *result)
+ IR::Expr *result)
{
addDef(result);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -247,7 +340,7 @@ protected: // IRDecoder
addCall();
}
- virtual void convertType(IR::Temp *source, IR::Temp *target)
+ virtual void convertType(IR::Expr *source, IR::Expr *target)
{
addDef(target);
@@ -310,22 +403,24 @@ protected: // IRDecoder
break;
}
- addUses(source, sourceReg);
+ Temp *sourceTemp = source->asTemp();
+ if (sourceTemp)
+ addUses(sourceTemp, sourceReg);
if (needsCall)
addCall();
- else
- addHint(target, source);
+ else if (target->asTemp())
+ addHint(target->asTemp(), sourceTemp);
}
- virtual void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Temp *result)
+ virtual void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Expr *result)
{
addDef(result);
addUses(args, Use::CouldHaveRegister);
addCall();
}
- virtual void constructProperty(IR::Temp *base, const QString &, IR::ExprList *args, IR::Temp *result)
+ virtual void constructProperty(IR::Expr *base, const QString &, IR::ExprList *args, IR::Expr *result)
{
addDef(result);
addUses(base, Use::CouldHaveRegister);
@@ -333,7 +428,7 @@ protected: // IRDecoder
addCall();
}
- virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result)
+ virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
addDef(result);
addUses(value, Use::CouldHaveRegister);
@@ -341,30 +436,30 @@ protected: // IRDecoder
addCall();
}
- virtual void loadThisObject(IR::Temp *temp)
+ virtual void loadThisObject(IR::Expr *temp)
{
addDef(temp);
}
- virtual void loadQmlIdArray(IR::Temp *temp)
+ virtual void loadQmlIdArray(IR::Expr *temp)
{
addDef(temp);
addCall();
}
- virtual void loadQmlImportedScripts(IR::Temp *temp)
+ virtual void loadQmlImportedScripts(IR::Expr *temp)
{
addDef(temp);
addCall();
}
- virtual void loadQmlContextObject(Temp *temp)
+ virtual void loadQmlContextObject(Expr *temp)
{
addDef(temp);
addCall();
}
- virtual void loadQmlScopeObject(Temp *temp)
+ virtual void loadQmlScopeObject(Expr *temp)
{
Q_UNUSED(temp);
@@ -372,7 +467,7 @@ protected: // IRDecoder
addCall();
}
- virtual void loadQmlSingleton(const QString &/*name*/, Temp *temp)
+ virtual void loadQmlSingleton(const QString &/*name*/, Expr *temp)
{
Q_UNUSED(temp);
@@ -380,21 +475,21 @@ protected: // IRDecoder
addCall();
}
- virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp)
+ virtual void loadConst(IR::Const *sourceConst, Expr *targetTemp)
{
Q_UNUSED(sourceConst);
addDef(targetTemp);
}
- virtual void loadString(const QString &str, IR::Temp *targetTemp)
+ virtual void loadString(const QString &str, Expr *targetTemp)
{
Q_UNUSED(str);
addDef(targetTemp);
}
- virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp)
+ virtual void loadRegexp(IR::RegExp *sourceRegexp, Expr *targetTemp)
{
Q_UNUSED(sourceRegexp);
@@ -402,7 +497,7 @@ protected: // IRDecoder
addCall();
}
- virtual void getActivationProperty(const IR::Name *, IR::Temp *temp)
+ virtual void getActivationProperty(const IR::Name *, Expr *temp)
{
addDef(temp);
addCall();
@@ -414,7 +509,7 @@ protected: // IRDecoder
addCall();
}
- virtual void initClosure(IR::Closure *closure, IR::Temp *target)
+ virtual void initClosure(IR::Closure *closure, Expr *target)
{
Q_UNUSED(closure);
@@ -422,7 +517,7 @@ protected: // IRDecoder
addCall();
}
- virtual void getProperty(IR::Expr *base, const QString &, IR::Temp *target)
+ virtual void getProperty(IR::Expr *base, const QString &, Expr *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -443,14 +538,14 @@ protected: // IRDecoder
addCall();
}
- virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, int /*attachedPropertiesId*/, IR::Temp *target)
+ virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
addCall();
}
- virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target)
+ virtual void getElement(IR::Expr *base, IR::Expr *index, Expr *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -466,25 +561,30 @@ protected: // IRDecoder
addCall();
}
- virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp)
+ virtual void copyValue(Expr *source, Expr *target)
{
- addDef(targetTemp);
+ addDef(target);
+ Temp *sourceTemp = source->asTemp();
+ if (!sourceTemp)
+ return;
addUses(sourceTemp, Use::CouldHaveRegister);
- addHint(targetTemp, sourceTemp);
+ Temp *targetTemp = target->asTemp();
+ if (targetTemp)
+ addHint(targetTemp, sourceTemp);
}
- virtual void swapValues(IR::Temp *, IR::Temp *)
+ virtual void swapValues(Expr *, Expr *)
{
// Inserted by the register allocator, so it cannot occur here.
Q_UNREACHABLE();
}
- virtual void unop(AluOp oper, Temp *sourceTemp, Temp *targetTemp)
+ virtual void unop(AluOp oper, Expr *source, Expr *target)
{
- addDef(targetTemp);
+ addDef(target);
bool needsCall = true;
- if (oper == OpNot && sourceTemp->type == IR::BoolType && targetTemp->type == IR::BoolType)
+ if (oper == OpNot && source->type == IR::BoolType && target->type == IR::BoolType)
needsCall = false;
#if 0 // TODO: change masm to generate code
@@ -504,15 +604,18 @@ protected: // IRDecoder
}
#endif
+ IR::Temp *sourceTemp = source->asTemp();
if (needsCall) {
- addUses(sourceTemp, Use::CouldHaveRegister);
+ if (sourceTemp)
+ addUses(sourceTemp, Use::CouldHaveRegister);
addCall();
} else {
- addUses(sourceTemp, Use::MustHaveRegister);
+ if (sourceTemp)
+ addUses(sourceTemp, Use::MustHaveRegister);
}
}
- virtual void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Temp *target)
+ virtual void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Expr *target)
{
bool needsCall = true;
@@ -590,25 +693,31 @@ protected: // IRDecoder
if (Temp *t = e->asTemp()) {
addUses(t, Use::CouldHaveRegister);
addHint(s->targetTemp, t);
+ addHint(t, s->targetTemp);
}
}
}
protected:
- virtual void callBuiltin(IR::Call *c, IR::Temp *result)
+ virtual void callBuiltin(IR::Call *c, IR::Expr *result)
{
addDef(result);
- addUses(c->base->asTemp(), Use::CouldHaveRegister);
+ addUses(c->base, Use::CouldHaveRegister);
addUses(c->args, Use::CouldHaveRegister);
addCall();
}
private:
- void addDef(Temp *t, bool isPhiTarget = false)
+ void addDef(Expr *e, bool isPhiTarget = false)
{
+ if (!e)
+ return;
+ Temp *t = e->asTemp();
+ if (!t)
+ return;
if (!t || t->kind != Temp::VirtualRegister)
return;
- Q_ASSERT(!_defs.contains(*t));
+ Q_ASSERT(!_defs[t->index].isValid());
bool canHaveReg = true;
switch (t->type) {
case QObjectType:
@@ -622,25 +731,40 @@ private:
break;
}
- _defs[*t] = Def(_currentStmt->id, canHaveReg, isPhiTarget);
+ _defs[t->index] = Def(canHaveReg, isPhiTarget);
}
- void addUses(Temp *t, Use::RegisterFlag flag)
+ void addUses(Expr *e, Use::RegisterFlag flag)
{
- Q_ASSERT(_currentStmt->id > 0);
+ int usePos = usePosition(_currentStmt);
+ if (usePos == Stmt::InvalidId)
+ usePos = _lifeTimeIntervals->startPosition(_currentBB);
+ Q_ASSERT(usePos > 0);
+ if (!e)
+ return;
+ Temp *t = e->asTemp();
+ if (!t)
+ return;
if (t && t->kind == Temp::VirtualRegister)
- _uses[*t].append(Use(_currentStmt->id, flag));
+ _uses[t->index].push_back(Use(usePosition(_currentStmt), flag));
}
void addUses(ExprList *l, Use::RegisterFlag flag)
{
for (ExprList *it = l; it; it = it->next)
- addUses(it->expr->asTemp(), flag);
+ addUses(it->expr, flag);
}
void addCall()
{
- _calls.append(_currentStmt->id);
+ _calls.push_back(usePosition(_currentStmt));
+ }
+
+ void addHint(Expr *hinted, Temp *hint1, Temp *hint2 = 0)
+ {
+ if (hinted)
+ if (Temp *hintedTemp = hinted->asTemp())
+ addHint(hintedTemp, hint1, hint2);
}
void addHint(Temp *hinted, Temp *hint1, Temp *hint2 = 0)
@@ -648,9 +772,9 @@ private:
if (!hinted || hinted->kind != Temp::VirtualRegister)
return;
if (hint1 && hint1->kind == Temp::VirtualRegister && hinted->type == hint1->type)
- _hints[*hinted].append(*hint1);
+ addHint(*hinted, Temp::VirtualRegister, hint1->index);
if (hint2 && hint2->kind == Temp::VirtualRegister && hinted->type == hint2->type)
- _hints[*hinted].append(*hint2);
+ addHint(*hinted, Temp::VirtualRegister, hint2->index);
}
};
@@ -666,16 +790,15 @@ using namespace QT_PREPEND_NAMESPACE(QV4);
namespace {
class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
- const QVector<LifeTimeInterval> &_intervals;
- QVector<const LifeTimeInterval *> _unprocessed;
+ Q_DISABLE_COPY(ResolutionPhase)
+
+ LifeTimeIntervals::Ptr _intervals;
+ QVector<LifeTimeInterval *> _unprocessed;
IR::Function *_function;
-#if !defined(QT_NO_DEBUG)
- RegAllocInfo *_info;
-#endif
- const QHash<IR::Temp, int> &_assignedSpillSlots;
+ const std::vector<int> &_assignedSpillSlots;
QHash<IR::Temp, const LifeTimeInterval *> _intervalForTemp;
- const QVector<int> &_intRegs;
- const QVector<int> &_fpRegs;
+ const QVector<const RegisterInfo *> &_intRegs;
+ const QVector<const RegisterInfo *> &_fpRegs;
Stmt *_currentStmt;
QVector<Move *> _loads;
@@ -685,54 +808,64 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor {
QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd;
public:
- ResolutionPhase(const QVector<LifeTimeInterval> &intervals, IR::Function *function, RegAllocInfo *info,
- const QHash<IR::Temp, int> &assignedSpillSlots,
- const QVector<int> &intRegs, const QVector<int> &fpRegs)
+ ResolutionPhase(const QVector<LifeTimeInterval *> &unprocessed,
+ const LifeTimeIntervals::Ptr &intervals,
+ IR::Function *function,
+ const std::vector<int> &assignedSpillSlots,
+ const QVector<const RegisterInfo *> &intRegs,
+ const QVector<const RegisterInfo *> &fpRegs)
: _intervals(intervals)
, _function(function)
-#if !defined(QT_NO_DEBUG)
- , _info(info)
-#endif
, _assignedSpillSlots(assignedSpillSlots)
, _intRegs(intRegs)
, _fpRegs(fpRegs)
{
-#if defined(QT_NO_DEBUG)
- Q_UNUSED(info)
-#endif
-
- _unprocessed.resize(_intervals.size());
- for (int i = 0, ei = _intervals.size(); i != ei; ++i)
- _unprocessed[i] = &_intervals[i];
-
+ _unprocessed = unprocessed;
_liveAtStart.reserve(function->basicBlockCount());
_liveAtEnd.reserve(function->basicBlockCount());
}
void run() {
renumber();
- Optimizer::showMeTheCode(_function);
+ if (DebugRegAlloc) {
+ QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions(&qout, _intervals).print(_function);
+ }
resolve();
}
private:
+ int defPosition(Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(Stmt *s) const
+ {
+ return _intervals->positionForStatement(s);
+ }
+
void renumber()
{
foreach (BasicBlock *bb, _function->basicBlocks()) {
+ _currentStmt = 0;
+
QVector<Stmt *> statements = bb->statements();
QVector<Stmt *> newStatements;
newStatements.reserve(bb->statements().size() + 7);
- bool seenFirstNonPhiStmt = false;
+ cleanOldIntervals(_intervals->startPosition(bb));
+ addNewIntervals(_intervals->startPosition(bb));
+ _liveAtStart[bb] = _intervalForTemp.values();
+
for (int i = 0, ei = statements.size(); i != ei; ++i) {
- _currentStmt = statements[i];
+ _currentStmt = statements.at(i);
_loads.clear();
_stores.clear();
- addNewIntervals();
- if (!seenFirstNonPhiStmt && !_currentStmt->asPhi()) {
- seenFirstNonPhiStmt = true;
- _liveAtStart[bb] = _intervalForTemp.values();
- }
+ if (_currentStmt->asTerminator())
+ addNewIntervals(usePosition(_currentStmt));
+ else
+ addNewIntervals(defPosition(_currentStmt));
_currentStmt->accept(this);
foreach (Move *load, _loads)
newStatements.append(load);
@@ -744,90 +877,71 @@ private:
newStatements.append(store);
}
- cleanOldIntervals();
+ cleanOldIntervals(_intervals->endPosition(bb));
_liveAtEnd[bb] = _intervalForTemp.values();
-#ifdef DEBUG_REGALLOC
- QTextStream os(stdout, QIODevice::WriteOnly);
- os << "Intervals live at the start of L" << bb->index << ":" << endl;
- if (_liveAtStart[bb].isEmpty())
- os << "\t(none)" << endl;
- foreach (const LifeTimeInterval *i, _liveAtStart[bb]) {
- os << "\t";
- i->dump(os);
- os << endl;
- }
- os << "Intervals live at the end of L" << bb->index << ":" << endl;
- if (_liveAtEnd[bb].isEmpty())
- os << "\t(none)" << endl;
- foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) {
- os << "\t";
- i->dump(os);
- os << endl;
+ if (DebugRegAlloc) {
+ QTextStream os(stdout, QIODevice::WriteOnly);
+ os << "Intervals live at the start of L" << bb->index() << ":" << endl;
+ if (_liveAtStart[bb].isEmpty())
+ os << "\t(none)" << endl;
+ foreach (const LifeTimeInterval *i, _liveAtStart[bb]) {
+ os << "\t";
+ i->dump(os);
+ os << endl;
+ }
+ os << "Intervals live at the end of L" << bb->index() << ":" << endl;
+ if (_liveAtEnd[bb].isEmpty())
+ os << "\t(none)" << endl;
+ foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) {
+ os << "\t";
+ i->dump(os);
+ os << endl;
+ }
}
-#endif
bb->setStatements(newStatements);
}
}
- void activate(const LifeTimeInterval *i)
+ void maybeGenerateSpill(Temp *t)
{
- Q_ASSERT(!i->isFixedInterval());
- _intervalForTemp[i->temp()] = i;
+ const LifeTimeInterval *i = _intervalForTemp[*t];
+ if (i->reg() == LifeTimeInterval::InvalidRegister)
+ return;
- if (i->reg() != LifeTimeInterval::Invalid) {
- // check if we need to generate spill/unspill instructions
- if (i->start() == _currentStmt->id) {
- if (i->isSplitFromInterval()) {
- int pReg = platformRegister(*i);
- _loads.append(generateUnspill(i->temp(), pReg));
- } else {
- int pReg = platformRegister(*i);
- int spillSlot = _assignedSpillSlots.value(i->temp(), -1);
- if (spillSlot != -1)
- _stores.append(generateSpill(spillSlot, i->temp().type, pReg));
- }
- }
- }
+ const RegisterInfo *pReg = platformRegister(*i);
+ Q_ASSERT(pReg);
+ int spillSlot = _assignedSpillSlots[i->temp().index];
+ if (spillSlot != RegisterAllocator::InvalidSpillSlot)
+ _stores.append(generateSpill(spillSlot, i->temp().type, pReg->reg<int>()));
}
- void addNewIntervals()
+ void addNewIntervals(int position)
{
- if (Phi *phi = _currentStmt->asPhi()) {
- // for phi nodes, only activate the range belonging to that node
- for (int it = 0, eit = _unprocessed.size(); it != eit; ++it) {
- const LifeTimeInterval *i = _unprocessed.at(it);
- if (i->start() > _currentStmt->id)
- break;
- if (i->temp() == *phi->targetTemp) {
- activate(i);
- _unprocessed.remove(it);
- break;
- }
- }
+ if (position == Stmt::InvalidId)
return;
- }
while (!_unprocessed.isEmpty()) {
const LifeTimeInterval *i = _unprocessed.first();
- if (i->start() > _currentStmt->id)
+ if (i->start() > position)
break;
- activate(i);
+ Q_ASSERT(!i->isFixedInterval());
+ _intervalForTemp[i->temp()] = i;
+// qDebug() << "-- Activating interval for temp" << i->temp().index;
_unprocessed.removeFirst();
}
}
- void cleanOldIntervals()
+ void cleanOldIntervals(int position)
{
- const int id = _currentStmt->id;
QMutableHashIterator<Temp, const LifeTimeInterval *> it(_intervalForTemp);
while (it.hasNext()) {
const LifeTimeInterval *i = it.next().value();
- if (i->end() < id || i->isFixedInterval())
+ if (i->end() < position || i->isFixedInterval())
it.remove();
}
}
@@ -840,77 +954,75 @@ private:
}
}
- void resolveEdge(BasicBlock *predecessor, BasicBlock *successor)
+ Phi *findDefPhi(const Temp &t, BasicBlock *bb) const
{
-#ifdef DEBUG_REGALLOC
- Optimizer::showMeTheCode(_function);
- qDebug() << "Resolving edge" << predecessor->index << "->" << successor->index;
-#endif // DEBUG_REGALLOC
+ foreach (Stmt *s, bb->statements()) {
+ Phi *phi = s->asPhi();
+ if (!phi)
+ return 0;
- MoveMapping mapping;
+ if (*phi->targetTemp == t)
+ return phi;
+ }
- const int predecessorEnd = predecessor->terminator()->id; // the terminator is always last and always has an id set...
- Q_ASSERT(predecessorEnd > 0); // ... but we verify it anyway for good measure.
+ Q_UNREACHABLE();
+ }
- int successorStart = -1;
- foreach (Stmt *s, successor->statements()) {
- if (s && s->id > 0) {
- successorStart = s->id;
- break;
- }
+ void resolveEdge(BasicBlock *predecessor, BasicBlock *successor)
+ {
+ if (DebugRegAlloc) {
+ qDebug() << "Resolving edge" << predecessor->index() << "->" << successor->index();
+ QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions printer(&qout, _intervals);
+ printer.print(predecessor);
+ printer.print(successor);
+ qout.flush();
}
+ MoveMapping mapping;
+
+ const int predecessorEnd = _intervals->endPosition(predecessor);
+ Q_ASSERT(predecessorEnd > 0);
+
+ int successorStart = _intervals->startPosition(successor);
Q_ASSERT(successorStart > 0);
foreach (const LifeTimeInterval *it, _liveAtStart[successor]) {
- if (it->end() < successorStart)
- continue;
-
bool isPhiTarget = false;
Expr *moveFrom = 0;
if (it->start() == successorStart) {
- foreach (Stmt *s, successor->statements()) {
- if (!s || s->id < 1)
- continue;
- if (Phi *phi = s->asPhi()) {
- if (*phi->targetTemp == it->temp()) {
- isPhiTarget = true;
- Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)];
- if (opd->asConst()) {
- moveFrom = opd;
- } else {
- Temp *t = opd->asTemp();
- Q_ASSERT(t);
-
- foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) {
- if (it2->temp() == *t
- && it2->reg() != LifeTimeInterval::Invalid
- && it2->covers(predecessorEnd)) {
- moveFrom = createTemp(Temp::PhysicalRegister,
- platformRegister(*it2), t->type);
- break;
- }
- }
- if (!moveFrom)
- moveFrom = createTemp(Temp::StackSlot,
- _assignedSpillSlots.value(*t, -1),
- t->type);
+ if (Phi *phi = findDefPhi(it->temp(), successor)) {
+ isPhiTarget = true;
+ Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)];
+ if (opd->asConst()) {
+ moveFrom = opd;
+ } else {
+ Temp *t = opd->asTemp();
+ Q_ASSERT(t);
+
+ foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) {
+ if (it2->temp() == *t
+ && it2->reg() != LifeTimeInterval::InvalidRegister
+ && it2->covers(predecessorEnd)) {
+ moveFrom = createPhysicalRegister(it2, t->type);
+ break;
}
}
- } else {
- break;
+ if (!moveFrom)
+ moveFrom = createTemp(Temp::StackSlot,
+ _assignedSpillSlots[t->index],
+ t->type);
}
}
} else {
foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) {
if (predIt->temp() == it->temp()) {
- if (predIt->reg() != LifeTimeInterval::Invalid
+ if (predIt->reg() != LifeTimeInterval::InvalidRegister
&& predIt->covers(predecessorEnd)) {
- moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(*predIt),
- predIt->temp().type);
+ moveFrom = createPhysicalRegister(predIt, predIt->temp().type);
} else {
- int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1);
+ int spillSlot = _assignedSpillSlots[predIt->temp().index];
if (spillSlot != -1)
moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type);
}
@@ -919,14 +1031,14 @@ private:
}
}
if (!moveFrom) {
-#if !defined(QT_NO_DEBUG)
+#if !defined(QT_NO_DEBUG) && 0
bool lifeTimeHole = false;
if (it->ranges().first().start <= successorStart && it->ranges().last().end >= successorStart)
lifeTimeHole = !it->covers(successorStart);
Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
- const int successorEnd = successor->terminator()->id;
+ const int successorEnd = successor->terminator()->id();
const int idx = successor->in.indexOf(predecessor);
foreach (const Use &use, _info->uses(it->temp())) {
if (use.pos == static_cast<unsigned>(successorStart)) {
@@ -956,15 +1068,15 @@ private:
}
Temp *moveTo;
- if (it->reg() == LifeTimeInterval::Invalid || !it->covers(successorStart)) {
+ if (it->reg() == LifeTimeInterval::InvalidRegister || !it->covers(successorStart)) {
if (!isPhiTarget) // if it->temp() is a phi target, skip it.
continue;
- const int spillSlot = _assignedSpillSlots.value(it->temp(), -1);
- if (spillSlot == -1)
+ const int spillSlot = _assignedSpillSlots[it->temp().index];
+ if (spillSlot == RegisterAllocator::InvalidSpillSlot)
continue; // it has a life-time hole here.
moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type);
} else {
- moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type);
+ moveTo = createPhysicalRegister(it, it->temp().type);
}
// add move to mapping
@@ -972,37 +1084,52 @@ private:
}
mapping.order();
-#ifdef DEBUG_REGALLOC
- mapping.dump();
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ mapping.dump();
bool insertIntoPredecessor = successor->in.size() > 1;
mapping.insertMoves(insertIntoPredecessor ? predecessor : successor, _function,
insertIntoPredecessor);
+
+ if (DebugRegAlloc) {
+ qDebug() << ".. done, result:";
+ QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions printer(&qout, _intervals);
+ printer.print(predecessor);
+ printer.print(successor);
+ qout.flush();
+ }
}
Temp *createTemp(Temp::Kind kind, int index, Type type) const
{
Q_ASSERT(index >= 0);
Temp *t = _function->New<Temp>();
- t->init(kind, index, 0);
+ t->init(kind, index);
t->type = type;
return t;
}
- int platformRegister(const LifeTimeInterval &i) const
+ Temp *createPhysicalRegister(const LifeTimeInterval *i, Type type) const
+ {
+ const RegisterInfo *ri = platformRegister(*i);
+ Q_ASSERT(ri);
+ return createTemp(Temp::PhysicalRegister, ri->reg<int>(), type);
+ }
+
+ const RegisterInfo *platformRegister(const LifeTimeInterval &i) const
{
if (i.isFP())
- return _fpRegs.value(i.reg(), -1);
+ return _fpRegs.value(i.reg(), 0);
else
- return _intRegs.value(i.reg(), -1);
+ return _intRegs.value(i.reg(), 0);
}
Move *generateSpill(int spillSlot, Type type, int pReg) const
{
Q_ASSERT(spillSlot >= 0);
- Move *store = _function->New<Move>();
+ Move *store = _function->NewStmt<Move>();
store->init(createTemp(Temp::StackSlot, spillSlot, type),
createTemp(Temp::PhysicalRegister, pReg, type));
return store;
@@ -1011,9 +1138,9 @@ private:
Move *generateUnspill(const Temp &t, int pReg) const
{
Q_ASSERT(pReg >= 0);
- int spillSlot = _assignedSpillSlots.value(t, -1);
+ int spillSlot = _assignedSpillSlots[t.index];
Q_ASSERT(spillSlot != -1);
- Move *load = _function->New<Move>();
+ Move *load = _function->NewStmt<Move>();
load->init(createTemp(Temp::PhysicalRegister, pReg, t.type),
createTemp(Temp::StackSlot, spillSlot, t.type));
return load;
@@ -1027,18 +1154,30 @@ protected:
const LifeTimeInterval *i = _intervalForTemp[*t];
Q_ASSERT(i->isValid());
- if (i->reg() != LifeTimeInterval::Invalid && i->covers(_currentStmt->id)) {
- int pReg = platformRegister(*i);
+
+ if (_currentStmt != 0 && i->start() == usePosition(_currentStmt)) {
+ Q_ASSERT(i->isSplitFromInterval());
+ const RegisterInfo *pReg = platformRegister(*i);
+ Q_ASSERT(pReg);
+ _loads.append(generateUnspill(i->temp(), pReg->reg<int>()));
+ }
+
+ if (i->reg() != LifeTimeInterval::InvalidRegister &&
+ (i->covers(defPosition(_currentStmt)) ||
+ i->covers(usePosition(_currentStmt)))) {
+ const RegisterInfo *pReg = platformRegister(*i);
+ Q_ASSERT(pReg);
t->kind = Temp::PhysicalRegister;
- t->index = pReg;
+ t->index = pReg->reg<unsigned>();
} else {
- int stackSlot = _assignedSpillSlots.value(*t, -1);
+ int stackSlot = _assignedSpillSlots[t->index];
Q_ASSERT(stackSlot >= 0);
t->kind = Temp::StackSlot;
t->index = stackSlot;
}
}
+ virtual void visitArgLocal(ArgLocal *) {}
virtual void visitConst(Const *) {}
virtual void visitString(IR::String *) {}
virtual void visitRegExp(IR::RegExp *) {}
@@ -1063,21 +1202,41 @@ protected:
}
virtual void visitExp(Exp *s) { s->expr->accept(this); }
- virtual void visitMove(Move *s) { s->source->accept(this); s->target->accept(this); }
+
+ virtual void visitMove(Move *s)
+ {
+ if (Temp *t = s->target->asTemp())
+ maybeGenerateSpill(t);
+
+ s->source->accept(this);
+ s->target->accept(this);
+ }
+
virtual void visitJump(Jump *) {}
virtual void visitCJump(CJump *s) { s->cond->accept(this); }
virtual void visitRet(Ret *s) { s->expr->accept(this); }
- virtual void visitPhi(Phi *) {}
+ virtual void visitPhi(Phi *s)
+ {
+ maybeGenerateSpill(s->targetTemp);
+ }
};
} // anonymous namespace
-RegisterAllocator::RegisterAllocator(const QVector<int> &normalRegisters, const QVector<int> &fpRegisters)
- : _normalRegisters(normalRegisters)
- , _fpRegisters(fpRegisters)
+RegisterAllocator::RegisterAllocator(const QV4::JIT::RegisterInformation &registerInformation)
+ : _registerInformation(registerInformation)
{
- Q_ASSERT(normalRegisters.size() >= 2);
- Q_ASSERT(fpRegisters.size() >= 2);
- _active.reserve((normalRegisters.size() + fpRegisters.size()) * 2);
+ for (int i = 0, ei = registerInformation.size(); i != ei; ++i) {
+ const RegisterInfo &regInfo = registerInformation.at(i);
+ if (regInfo.useForRegAlloc()) {
+ if (regInfo.isRegularRegister())
+ _normalRegisters.append(&regInfo);
+ else
+ _fpRegisters.append(&regInfo);
+ }
+ }
+ Q_ASSERT(_normalRegisters.size() >= 2);
+ Q_ASSERT(_fpRegisters.size() >= 2);
+ _active.reserve((_normalRegisters.size() + _fpRegisters.size()) * 2);
_inactive.reserve(_active.size());
}
@@ -1087,54 +1246,58 @@ RegisterAllocator::~RegisterAllocator()
void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
{
- _lastAssignedRegister.reserve(function->tempCount);
- _assignedSpillSlots.reserve(function->tempCount);
+ _lastAssignedRegister.assign(function->tempCount, LifeTimeInterval::InvalidRegister);
+ _assignedSpillSlots.assign(function->tempCount, InvalidSpillSlot);
_activeSpillSlots.resize(function->tempCount);
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
+
+ _lifeTimeIntervals = opt.lifeTimeIntervals();
- _unhandled = opt.lifeTimeIntervals();
+ _unhandled = _lifeTimeIntervals->intervals();
_handled.reserve(_unhandled.size());
_info.reset(new RegAllocInfo);
- _info->collect(function);
+ _info->collect(function, _lifeTimeIntervals);
-#ifdef DEBUG_REGALLOC
- {
+ if (DebugRegAlloc) {
QTextStream qout(stdout, QIODevice::WriteOnly);
qout << "Ranges:" << endl;
- QVector<LifeTimeInterval> intervals = _unhandled;
- std::sort(intervals.begin(), intervals.end(), LifeTimeInterval::lessThanForTemp);
- foreach (const LifeTimeInterval &r, intervals) {
- r.dump(qout);
+ QVector<LifeTimeInterval *> intervals = _unhandled;
+ std::reverse(intervals.begin(), intervals.end());
+ foreach (const LifeTimeInterval *r, intervals) {
+ r->dump(qout);
qout << endl;
}
+ _info->dump();
}
- _info->dump();
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc) {
+ qDebug() << "*** Before register allocation:";
+ QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions(&qout, _lifeTimeIntervals).print(function);
+ }
prepareRanges();
- Optimizer::showMeTheCode(function);
-
linearScan();
-#ifdef DEBUG_REGALLOC
- dump();
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ dump(function);
std::sort(_handled.begin(), _handled.end(), LifeTimeInterval::lessThan);
- ResolutionPhase(_handled, function, _info.data(), _assignedSpillSlots, _normalRegisters, _fpRegisters).run();
+ ResolutionPhase(_handled, _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run();
- function->tempCount = QSet<int>::fromList(_assignedSpillSlots.values()).size();
+ function->tempCount = *std::max_element(_assignedSpillSlots.begin(), _assignedSpillSlots.end()) + 1;
- Optimizer::showMeTheCode(function);
+ if (DebugRegAlloc)
+ qDebug() << "*** Finished regalloc , result:";
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** Finished regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
-#endif // DEBUG_REGALLOC
+ static bool showCode = !qgetenv("QV4_SHOW_IR").isNull();
+ if (showCode) {
+ QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithRegisters(&qout, _lifeTimeIntervals, _registerInformation).print(function);
+ }
}
static inline LifeTimeInterval createFixedInterval(int rangeCount)
@@ -1143,26 +1306,30 @@ static inline LifeTimeInterval createFixedInterval(int rangeCount)
i.setReg(0);
Temp t;
- t.init(Temp::PhysicalRegister, 0, 0);
+ t.init(Temp::PhysicalRegister, 0);
t.type = IR::SInt32Type;
i.setTemp(t);
return i;
}
-static inline LifeTimeInterval cloneFixedInterval(int reg, bool isFP, LifeTimeInterval lti)
+LifeTimeInterval *RegisterAllocator::cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original)
{
- lti.setReg(reg);
- lti.setFixedInterval(true);
+ LifeTimeInterval *lti = new LifeTimeInterval(original);
+ _lifeTimeIntervals->add(lti);
+ lti->setReg(reg);
+ lti->setFixedInterval(true);
Temp t;
- t.init(Temp::PhysicalRegister, reg, 0);
+ t.init(Temp::PhysicalRegister, reg);
t.type = isFP ? IR::DoubleType : IR::SInt32Type;
- lti.setTemp(t);
+ lti->setTemp(t);
return lti;
}
+// Creates the intervals with fixed ranges. See [Wimmer2]. Note that this only applies to callee-
+// saved registers.
void RegisterAllocator::prepareRanges()
{
LifeTimeInterval ltiWithCalls = createFixedInterval(_info->calls().size());
@@ -1172,37 +1339,41 @@ void RegisterAllocator::prepareRanges()
const int regCount = _normalRegisters.size();
_fixedRegisterRanges.reserve(regCount);
for (int reg = 0; reg < regCount; ++reg) {
- LifeTimeInterval lti = cloneFixedInterval(reg, false, ltiWithCalls);
- _fixedRegisterRanges.append(lti);
- if (lti.isValid())
- _active.append(lti);
+ if (_normalRegisters.at(reg)->isCallerSaved()) {
+ LifeTimeInterval *lti = cloneFixedInterval(reg, false, ltiWithCalls);
+ _fixedRegisterRanges.append(lti);
+ if (lti->isValid())
+ _active.append(lti);
+ }
}
const int fpRegCount = _fpRegisters.size();
_fixedFPRegisterRanges.reserve(fpRegCount);
for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) {
- LifeTimeInterval lti = cloneFixedInterval(fpReg, true, ltiWithCalls);
- _fixedFPRegisterRanges.append(lti);
- if (lti.isValid())
- _active.append(lti);
+ if (_fpRegisters.at(fpReg)->isCallerSaved()) {
+ LifeTimeInterval *lti = cloneFixedInterval(fpReg, true, ltiWithCalls);
+ _fixedFPRegisterRanges.append(lti);
+ if (lti->isValid())
+ _active.append(lti);
+ }
}
}
void RegisterAllocator::linearScan()
{
while (!_unhandled.isEmpty()) {
- LifeTimeInterval current = _unhandled.first();
- _unhandled.removeFirst();
- int position = current.start();
+ LifeTimeInterval *current = _unhandled.back();
+ _unhandled.pop_back();
+ const int position = current->start();
// check for intervals in active that are handled or inactive
for (int i = 0; i < _active.size(); ) {
- const LifeTimeInterval &it = _active.at(i);
- if (it.end() < position) {
- if (!it.isFixedInterval())
+ LifeTimeInterval *it = _active.at(i);
+ if (it->end() < position) {
+ if (!it->isFixedInterval())
_handled += it;
_active.remove(i);
- } else if (!it.covers(position)) {
+ } else if (!it->covers(position)) {
_inactive += it;
_active.remove(i);
} else {
@@ -1212,13 +1383,13 @@ void RegisterAllocator::linearScan()
// check for intervals in inactive that are handled or active
for (int i = 0; i < _inactive.size(); ) {
- const LifeTimeInterval &it = _inactive.at(i);
- if (it.end() < position) {
- if (!it.isFixedInterval())
+ LifeTimeInterval *it = _inactive.at(i);
+ if (it->end() < position) {
+ if (!it->isFixedInterval())
_handled += it;
_inactive.remove(i);
- } else if (it.covers(position)) {
- if (it.reg() != LifeTimeInterval::Invalid) {
+ } else if (it->covers(position)) {
+ if (it->reg() != LifeTimeInterval::InvalidRegister) {
_active += it;
_inactive.remove(i);
} else {
@@ -1231,34 +1402,33 @@ void RegisterAllocator::linearScan()
}
}
- Q_ASSERT(!current.isFixedInterval());
+ Q_ASSERT(!current->isFixedInterval());
#ifdef DEBUG_REGALLOC
qDebug() << "** Position" << position;
#endif // DEBUG_REGALLOC
- if (_info->canHaveRegister(current.temp())) {
- tryAllocateFreeReg(current, position);
- if (current.reg() == LifeTimeInterval::Invalid)
- allocateBlockedReg(current, position);
- if (current.reg() != LifeTimeInterval::Invalid)
+ if (_info->canHaveRegister(current->temp())) {
+ tryAllocateFreeReg(*current);
+ if (current->reg() == LifeTimeInterval::InvalidRegister)
+ allocateBlockedReg(*current);
+ if (current->reg() != LifeTimeInterval::InvalidRegister)
_active += current;
} else {
- assignSpillSlot(current.temp(), current.start(), current.end());
+ assignSpillSlot(current->temp(), current->start(), current->end());
_inactive += current;
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current.temp()]
- << "for %" << current.temp().index << "as it cannot be loaded in a register";
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current->temp().index]
+ << "for %" << current->temp().index << "as it cannot be loaded in a register";
}
}
- foreach (const LifeTimeInterval &r, _active)
- if (!r.isFixedInterval())
+ foreach (LifeTimeInterval *r, _active)
+ if (!r->isFixedInterval())
_handled.append(r);
_active.clear();
- foreach (const LifeTimeInterval &r, _inactive)
- if (!r.isFixedInterval())
+ foreach (LifeTimeInterval *r, _inactive)
+ if (!r->isFixedInterval())
_handled.append(r);
_inactive.clear();
}
@@ -1284,45 +1454,75 @@ static inline int intersectionPosition(const LifeTimeInterval::Range &one, const
static inline bool isFP(const Temp &t)
{ return t.type == DoubleType; }
-void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval &current, const int position)
+static inline bool candidateIsBetterFit(int bestSizeSoFar, int idealSize, int candidateSize)
{
- Q_ASSERT(!current.isFixedInterval());
- Q_ASSERT(current.reg() == LifeTimeInterval::Invalid);
+ // If the candidateSize is larger than the current we take it only if the current size does not
+ // yet fit for the whole interval.
+ if (bestSizeSoFar < candidateSize && bestSizeSoFar < idealSize)
+ return true;
- const bool needsFPReg = isFP(current.temp());
- QVector<int> freeUntilPos(needsFPReg ? _fpRegisters.size() : _normalRegisters.size(), INT_MAX);
- Q_ASSERT(freeUntilPos.size() > 0);
+ // If the candidateSize is smaller we only take it if it still fits the whole interval.
+ if (bestSizeSoFar > candidateSize && candidateSize >= idealSize)
+ return true;
- const bool isPhiTarget = _info->isPhiTarget(current.temp());
- foreach (const LifeTimeInterval &it, _active) {
- if (it.isFP() == needsFPReg) {
- if (!isPhiTarget && it.isFixedInterval() && !current.isSplitFromInterval()) {
- const int idx = indexOfRangeCoveringPosition(it.ranges(), position);
- if (it.ranges().at(idx).end == current.start()) {
- if (it.ranges().size() > idx + 1)
- freeUntilPos[it.reg()] = it.ranges().at(idx + 1).start;
- continue;
- }
- }
+ // Other wise: no luck.
+ return false;
+}
- if (isPhiTarget || it.end() >= current.firstPossibleUsePosition(isPhiTarget))
- freeUntilPos[it.reg()] = 0; // mark register as unavailable
+// Out of all available registers (with their next-uses), choose the one that fits the requested
+// duration best. This can return a register that is not free for the whole interval, but that's
+// fine: we just have to split the current interval.
+static void longestAvailableReg(int *nextUses, int nextUseCount, int &reg, int &freeUntilPos_reg, int lastUse)
+{
+ reg = LifeTimeInterval::InvalidRegister;
+ freeUntilPos_reg = 0;
+
+ for (int candidate = 0, candidateEnd = nextUseCount; candidate != candidateEnd; ++candidate) {
+ int fp = nextUses[candidate];
+ if (candidateIsBetterFit(freeUntilPos_reg, lastUse, fp)) {
+ reg = candidate;
+ freeUntilPos_reg = fp;
}
}
+}
- foreach (const LifeTimeInterval &it, _inactive) {
- if (current.isSplitFromInterval() || it.isFixedInterval()) {
- if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) {
- const int intersectionPos = nextIntersection(current, it, position);
- if (!isPhiTarget && it.isFixedInterval() && current.end() == intersectionPos)
- freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos + 1);
- else if (intersectionPos != -1)
- freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos);
- }
+#define CALLOC_ON_STACK(ty, ptr, sz, val) \
+ Q_ASSERT(sz > 0); \
+ ty *ptr = reinterpret_cast<ty *>(alloca(sizeof(ty) * (sz))); \
+ for (ty *it = ptr, *eit = ptr + (sz); it != eit; ++it) \
+ *it = val;
+
+// Try to allocate a register that's currently free.
+void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval &current)
+{
+ Q_ASSERT(!current.isFixedInterval());
+ Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister);
+
+ const bool needsFPReg = isFP(current.temp());
+ const int freeUntilPosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size();
+ CALLOC_ON_STACK(int, freeUntilPos, freeUntilPosCount, INT_MAX);
+
+ for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) {
+ const LifeTimeInterval *it = *i;
+ if (it->isFP() == needsFPReg)
+ freeUntilPos[it->reg()] = 0; // mark register as unavailable
+ }
+
+ for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) {
+ const LifeTimeInterval *it = *i;
+ if (it->isFP() != needsFPReg)
+ continue; // different register type, so not applicable.
+ if (it->reg() == LifeTimeInterval::InvalidRegister)
+ continue; // this range does not block a register from being used, as it has no register assigned
+
+ if (current.isSplitFromInterval() || it->isFixedInterval()) {
+ const int intersectionPos = nextIntersection(current, *it);
+ if (intersectionPos != -1)
+ freeUntilPos[it->reg()] = qMin(freeUntilPos[it->reg()], intersectionPos);
}
}
- int reg = LifeTimeInterval::Invalid;
+ int reg = LifeTimeInterval::InvalidRegister;
int freeUntilPos_reg = 0;
foreach (const Temp &hint, _info->hints(current.temp())) {
@@ -1330,173 +1530,165 @@ void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval &current, const int
if (hint.kind == Temp::PhysicalRegister)
candidate = hint.index;
else
- candidate = _lastAssignedRegister.value(hint, LifeTimeInterval::Invalid);
+ candidate = _lastAssignedRegister[hint.index];
const int end = current.end();
- if (candidate != LifeTimeInterval::Invalid) {
- if (current.isFP() == (hint.type == DoubleType)) {
- int fp = freeUntilPos[candidate];
- if ((freeUntilPos_reg < end && fp > freeUntilPos_reg)
- || (freeUntilPos_reg >= end && fp >= end && freeUntilPos_reg > fp)) {
- reg = candidate;
- freeUntilPos_reg = fp;
- }
- }
+ if (candidate == LifeTimeInterval::InvalidRegister)
+ continue; // the candidate has no register assigned, so it cannot be (re-)used
+ if (current.isFP() != isFP(hint))
+ continue; // different register type, so not applicable.
+
+ const int fp = freeUntilPos[candidate];
+ if (candidateIsBetterFit(freeUntilPos_reg, end, fp)) {
+ reg = candidate;
+ freeUntilPos_reg = fp;
}
}
- if (reg == LifeTimeInterval::Invalid)
- longestAvailableReg(freeUntilPos, reg, freeUntilPos_reg, current.end());
+ // None of the hinted registers could fit the interval, so try all registers next.
+ if (reg == LifeTimeInterval::InvalidRegister)
+ longestAvailableReg(freeUntilPos, freeUntilPosCount, reg, freeUntilPos_reg, current.end());
if (freeUntilPos_reg == 0) {
// no register available without spilling
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** no register available for %" << current.temp().index;
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ qDebug() << "*** no register available for %" << current.temp().index;
return;
} else if (current.end() < freeUntilPos_reg) {
// register available for the whole interval
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** allocating register" << reg << "for the whole interval of %" << current.temp().index;
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc)
+ qDebug() << "*** allocating register" << reg << "for the whole interval of %" << current.temp().index;
current.setReg(reg);
- _lastAssignedRegister.insert(current.temp(), reg);
+ _lastAssignedRegister[current.temp().index] = reg;
} else {
// register available for the first part of the interval
+
+ // TODO: this is slightly inefficient in the following case:
+ // %1 = something
+ // some_call(%1)
+ // %2 = %1 + 1
+ // Now %1 will get a register assigned, and will be spilled to the stack immediately. It
+ // would be better to check if there are actually uses in the range before the split.
+
current.setReg(reg);
- _lastAssignedRegister.insert(current.temp(), reg);
-#ifdef DEBUG_REGALLOC
- qDebug() << "*** allocating register" << reg << "for the first part of interval of %" << current.temp().index;
-#endif // DEBUG_REGALLOC
+ _lastAssignedRegister[current.temp().index] = reg;
+ if (DebugRegAlloc)
+ qDebug() << "*** allocating register" << reg << "for the first part of interval of %" << current.temp().index;
split(current, freeUntilPos_reg, true);
}
}
-void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int position)
+// This gets called when all registers are currently in use.
+void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current)
{
Q_ASSERT(!current.isFixedInterval());
- Q_ASSERT(current.reg() == LifeTimeInterval::Invalid);
+ Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister);
+ const int position = current.start();
const bool isPhiTarget = _info->isPhiTarget(current.temp());
if (isPhiTarget && !current.isSplitFromInterval()) {
+ // Special case: storing to a phi-node's target will result in a single move. So, if we
+ // would spill another interval to the stack (that's 1 store), and then do the move for the
+ // phi target (at least 1 move or a load), that would result in 2 instructions. Instead, we
+ // force the phi-node's target to go to the stack immediately, which is always a single
+ // store.
split(current, position + 1, true);
- _inactive.append(current);
+ _inactive.append(&current);
return;
}
const bool needsFPReg = isFP(current.temp());
- QVector<int> nextUsePos(needsFPReg ? _fpRegisters.size() : _normalRegisters.size(), INT_MAX);
- QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePos.size(), 0);
- Q_ASSERT(nextUsePos.size() > 0);
-
- const bool definedAtCurrentPosition = !current.isSplitFromInterval() && current.start() == position;
-
- for (int i = 0, ei = _active.size(); i != ei; ++i) {
- LifeTimeInterval &it = _active[i];
- if (it.isFP() == needsFPReg) {
- int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget));
- if (nu == position && !definedAtCurrentPosition) {
- nextUsePos[it.reg()] = 0;
- } else if (nu != -1 && nu < nextUsePos[it.reg()]) {
- nextUsePos[it.reg()] = nu;
- nextUseRangeForReg[it.reg()] = &it;
- } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) {
- // in a loop, the range can be active, but only used before the current position (e.g. in a loop header or phi node)
- nextUseRangeForReg[it.reg()] = &it;
- }
+ const int nextUsePosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size();
+ CALLOC_ON_STACK(int, nextUsePos, nextUsePosCount, INT_MAX);
+ QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePosCount, 0);
+
+ for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) {
+ LifeTimeInterval &it = **i;
+ if (it.isFP() != needsFPReg)
+ continue; // different register type, so not applicable.
+
+ const int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.start());
+ if (nu == position) {
+ nextUsePos[it.reg()] = 0;
+ } else if (nu != -1 && nu < nextUsePos[it.reg()]) {
+ nextUsePos[it.reg()] = nu;
+ nextUseRangeForReg[it.reg()] = &it;
+ } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) {
+ // in a loop, the range can be active, but the result might only be used before the
+ // current position (e.g. the induction variable being used in the phi node in the loop
+ // header). So, we can use this register, but we need to remember to split the interval
+ // in order to have the edge-resolving generate a load at the edge going back to the
+ // loop header.
+ nextUseRangeForReg[it.reg()] = &it;
}
}
- for (int i = 0, ei = _inactive.size(); i != ei; ++i) {
- LifeTimeInterval &it = _inactive[i];
+ for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) {
+ LifeTimeInterval &it = **i;
+ if (it.isFP() != needsFPReg)
+ continue; // different register type, so not applicable.
+ if (it.reg() == LifeTimeInterval::InvalidRegister)
+ continue; // this range does not block a register from being used, as it has no register assigned
+
if (current.isSplitFromInterval() || it.isFixedInterval()) {
- if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) {
- if (nextIntersection(current, it, position) != -1) {
- int nu = nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget));
- if (nu != -1 && nu < nextUsePos[it.reg()]) {
- nextUsePos[it.reg()] = nu;
- nextUseRangeForReg[it.reg()] = &it;
- }
+ if (nextIntersection(current, it) != -1) {
+ const int nu = nextUse(it.temp(), current.start());
+ if (nu != -1 && nu < nextUsePos[it.reg()]) {
+ nextUsePos[it.reg()] = nu;
+ nextUseRangeForReg[it.reg()] = &it;
}
}
}
}
int reg, nextUsePos_reg;
- longestAvailableReg(nextUsePos, reg, nextUsePos_reg, current.end());
+ longestAvailableReg(nextUsePos, nextUsePosCount, reg, nextUsePos_reg, current.end());
- if (current.start() > nextUsePos_reg) {
- // all other intervals are used before current, so it is best to spill current itself
-#ifdef DEBUG_REGALLOC
- QTextStream out(stderr, QIODevice::WriteOnly);
- out << "*** splitting current for range ";current.dump(out);out<<endl;
-#endif // DEBUG_REGALLOC
- Q_ASSERT(!_info->useMustHaveReg(current.temp(), position));
- split(current, position + 1, true);
- _inactive.append(current);
- } else {
- // spill intervals that currently block reg
-#ifdef DEBUG_REGALLOC
- QTextStream out(stderr, QIODevice::WriteOnly);
- out << "*** spilling intervals that block reg "<<reg<<" for interval ";current.dump(out);out<<endl;
-#endif // DEBUG_REGALLOC
- current.setReg(reg);
- _lastAssignedRegister.insert(current.temp(), reg);
- LifeTimeInterval *nextUse = nextUseRangeForReg[reg];
- Q_ASSERT(nextUse);
- Q_ASSERT(!nextUse->isFixedInterval());
-
- if (_info->isUsedAt(nextUse->temp(), position)) {
- Q_ASSERT(!_info->isUsedAt(current.temp(), position));
- // the register is used (as an incoming parameter) at the current position, so split
- // the interval immediately after the (use at the) current position
- split(*nextUse, position + 1);
- } else {
- // the register was used before the current position
- split(*nextUse, position);
- }
+ Q_ASSERT(current.start() <= nextUsePos_reg);
- splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
-
- // make sure that current does not intersect with the fixed interval for reg
- const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg)
- : _fixedRegisterRanges.at(reg);
- int ni = nextIntersection(current, fixedRegRange, position);
- if (ni != -1) {
-#ifdef DEBUG_REGALLOC
- out << "***-- current range intersects with a fixed reg use at "<<ni<<", so splitting it."<<endl;
-#endif // DEBUG_REGALLOC
- split(current, ni, true);
- }
- }
-}
-
-void RegisterAllocator::longestAvailableReg(const QVector<int> &nextUses, int &reg,
- int &freeUntilPos_reg, int lastUse) const
-{
- reg = LifeTimeInterval::Invalid;
- freeUntilPos_reg = 0;
-
- for (int candidate = 0, candidateEnd = nextUses.size(); candidate != candidateEnd; ++candidate) {
- int fp = nextUses[candidate];
- if ((freeUntilPos_reg < lastUse && fp > freeUntilPos_reg)
- || (freeUntilPos_reg >= lastUse && fp >= lastUse && freeUntilPos_reg > fp)) {
- reg = candidate;
- freeUntilPos_reg = fp;
+ // spill interval that currently block reg
+ if (DebugRegAlloc) {
+ QTextStream out(stderr, QIODevice::WriteOnly);
+ out << "*** spilling intervals that block reg " <<reg<< " for interval ";
+ current.dump(out);
+ out << endl;
+ }
+ current.setReg(reg);
+ _lastAssignedRegister[current.temp().index] = reg;
+ LifeTimeInterval *nextUse = nextUseRangeForReg[reg];
+ Q_ASSERT(nextUse);
+ Q_ASSERT(!nextUse->isFixedInterval());
+
+ split(*nextUse, position);
+
+ // We might have chosen a register that is used by a range that has a hole in its life time.
+ // If that's the case, check if the current interval completely fits in the hole. Or rephrased:
+ // check if the current interval will use the register after that hole ends (so that range, and
+ // if so, split that interval so that it gets a new register assigned when it needs one.
+ splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
+
+ // make sure that current does not intersect with the fixed interval for reg
+ const LifeTimeInterval &fixedRegRange = needsFPReg ? *_fixedFPRegisterRanges.at(reg)
+ : *_fixedRegisterRanges.at(reg);
+ int ni = nextIntersection(current, fixedRegRange);
+ if (ni != -1) {
+ if (DebugRegAlloc) {
+ QTextStream out(stderr, QIODevice::WriteOnly);
+ out << "***-- current range intersects with a fixed reg use at " << ni << ", so splitting it." << endl;
}
+ // current does overlap with a fixed interval, so split current before that intersection.
+ split(current, ni, true);
}
}
int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
- const LifeTimeInterval &another, const int position) const
+ const LifeTimeInterval &another) const
{
- LifeTimeInterval::Ranges currentRanges = current.ranges();
- int currentIt = indexOfRangeCoveringPosition(currentRanges, position);
- if (currentIt == -1)
- return -1;
+ const LifeTimeInterval::Ranges &currentRanges = current.ranges();
+ int currentIt = 0;
- LifeTimeInterval::Ranges anotherRanges = another.ranges();
- const int anotherItStart = indexOfRangeCoveringPosition(anotherRanges, position);
+ const LifeTimeInterval::Ranges &anotherRanges = another.ranges();
+ const int anotherItStart = indexOfRangeCoveringPosition(anotherRanges, current.start());
if (anotherItStart == -1)
return -1;
@@ -1515,11 +1707,12 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
return -1;
}
+/// Find the first use after the start position for the given temp.
int RegisterAllocator::nextUse(const Temp &t, int startPosition) const
{
- QList<Use> usePositions = _info->uses(t);
- for (int i = 0, ei = usePositions.size(); i != ei; ++i) {
- int usePos = usePositions[i].pos;
+ const std::vector<Use> &usePositions = _info->uses(t);
+ for (int i = 0, ei = usePositions.size(); i != ei; ++i) { //### FIXME: use an iterator
+ const int usePos = usePositions.at(i).pos;
if (usePos >= startPosition)
return usePos;
}
@@ -1527,16 +1720,16 @@ int RegisterAllocator::nextUse(const Temp &t, int startPosition) const
return -1;
}
-static inline void insertSorted(QVector<LifeTimeInterval> &intervals, const LifeTimeInterval &newInterval)
+static inline void insertReverseSorted(QVector<LifeTimeInterval *> &intervals, LifeTimeInterval *newInterval)
{
- newInterval.validate();
- for (int i = 0, ei = intervals.size(); i != ei; ++i) {
- if (LifeTimeInterval::lessThan(newInterval, intervals.at(i))) {
- intervals.insert(i, newInterval);
+ newInterval->validate();
+ for (int i = intervals.size(); i > 0;) {
+ if (LifeTimeInterval::lessThan(newInterval, intervals.at(--i))) {
+ intervals.insert(i + 1, newInterval);
return;
}
}
- intervals.append(newInterval);
+ intervals.insert(0, newInterval);
}
void RegisterAllocator::split(LifeTimeInterval &current, int beforePosition,
@@ -1544,28 +1737,21 @@ void RegisterAllocator::split(LifeTimeInterval &current, int beforePosition,
{ // TODO: check if we can always skip the optional register uses
Q_ASSERT(!current.isFixedInterval());
-#ifdef DEBUG_REGALLOC
- QTextStream out(stderr, QIODevice::WriteOnly);
- out << "***** split request for range ";current.dump(out);out<<" before position "<<beforePosition<<" and skipOptionalRegisterUses = "<<skipOptionalRegisterUses<<endl;
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc) {
+ QTextStream out(stderr, QIODevice::WriteOnly);
+ out << "***** split request for range ";current.dump(out);out<<" before position "<<beforePosition<<" and skipOptionalRegisterUses = "<<skipOptionalRegisterUses<<endl;
+ }
assignSpillSlot(current.temp(), current.start(), current.end());
- const int defPosition = _info->def(current.temp());
- if (beforePosition < defPosition) {
-#ifdef DEBUG_REGALLOC
- out << "***** split before position is before or at definition, so not splitting."<<endl;
-#endif // DEBUG_REGALLOC
- return;
- }
+ const int firstPosition = current.start();
+ Q_ASSERT(beforePosition > firstPosition && "split before start");
- int lastUse = -1;
- if (defPosition < beforePosition)
- lastUse = defPosition;
+ int lastUse = firstPosition;
int nextUse = -1;
- QList<Use> usePositions = _info->uses(current.temp());
+ const std::vector<Use> &usePositions = _info->uses(current.temp());
for (int i = 0, ei = usePositions.size(); i != ei; ++i) {
- const Use &usePosition = usePositions[i];
+ const Use &usePosition = usePositions.at(i);
const int usePos = usePosition.pos;
if (lastUse < usePos && usePos < beforePosition) {
lastUse = usePos;
@@ -1576,31 +1762,30 @@ void RegisterAllocator::split(LifeTimeInterval &current, int beforePosition,
}
}
}
- if (lastUse == -1)
- lastUse = beforePosition - 1;
-
+ Q_ASSERT(lastUse != -1);
Q_ASSERT(lastUse < beforePosition);
-#ifdef DEBUG_REGALLOC
- out << "***** last use = "<<lastUse<<", nextUse = " << nextUse<<endl;
-#endif // DEBUG_REGALLOC
LifeTimeInterval newInterval = current.split(lastUse, nextUse);
-#ifdef DEBUG_REGALLOC
- out << "***** new interval: "; newInterval.dump(out); out << endl;
- out << "***** preceding interval: "; current.dump(out); out << endl;
-#endif // DEBUG_REGALLOC
+ if (DebugRegAlloc) {
+ QTextStream out(stderr, QIODevice::WriteOnly);
+ out << "***** last use = "<<lastUse<<", nextUse = " << nextUse<<endl;
+ out << "***** new interval: "; newInterval.dump(out); out << endl;
+ out << "***** preceding interval: "; current.dump(out); out << endl;
+ }
if (newInterval.isValid()) {
- if (current.reg() != LifeTimeInterval::Invalid)
+ if (current.reg() != LifeTimeInterval::InvalidRegister)
_info->addHint(current.temp(), current.reg());
- newInterval.setReg(LifeTimeInterval::Invalid);
- insertSorted(_unhandled, newInterval);
+ newInterval.setReg(LifeTimeInterval::InvalidRegister);
+ LifeTimeInterval *newIntervalPtr = new LifeTimeInterval(newInterval);
+ _lifeTimeIntervals->add(newIntervalPtr);
+ insertReverseSorted(_unhandled, newIntervalPtr);
}
}
void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position)
{
for (int i = 0, ei = _inactive.size(); i != ei; ++i) {
- LifeTimeInterval &interval = _inactive[i];
+ LifeTimeInterval &interval = *_inactive[i];
if (interval.isFixedInterval())
continue;
if (isFPReg == interval.isFP() && interval.reg() == reg) {
@@ -1618,13 +1803,13 @@ void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg,
void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos)
{
- if (_assignedSpillSlots.contains(t))
+ if (_assignedSpillSlots[t.index] != InvalidSpillSlot)
return;
for (int i = 0, ei = _activeSpillSlots.size(); i != ei; ++i) {
if (_activeSpillSlots.at(i) < startPos) {
_activeSpillSlots[i] = endPos;
- _assignedSpillSlots.insert(t, i);
+ _assignedSpillSlots[t.index] = i;
return;
}
}
@@ -1632,32 +1817,33 @@ void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos)
Q_UNREACHABLE();
}
-void RegisterAllocator::dump() const
+void RegisterAllocator::dump(IR::Function *function) const
{
-#ifdef DEBUG_REGALLOC
QTextStream qout(stdout, QIODevice::WriteOnly);
+ IRPrinterWithPositions printer(&qout, _lifeTimeIntervals);
- {
- qout << "Ranges:" << endl;
- QVector<LifeTimeInterval> handled = _handled;
- std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp);
- foreach (const LifeTimeInterval &r, handled) {
- r.dump(qout);
- qout << endl;
- }
+ qout << "Ranges:" << endl;
+ QVector<LifeTimeInterval *> handled = _handled;
+ std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp);
+ foreach (const LifeTimeInterval *r, handled) {
+ r->dump(qout);
+ qout << endl;
}
- {
- qout << "Spill slots:" << endl;
- QList<Temp> temps = _assignedSpillSlots.keys();
- if (temps.isEmpty())
- qout << "\t(none)" << endl;
- std::sort(temps.begin(), temps.end());
- foreach (const Temp &t, temps) {
- qout << "\t";
- t.dump(qout);
- qout << " -> " << _assignedSpillSlots[t] << endl;
- }
- }
-#endif // DEBUG_REGALLOC
+ qout << "Spill slots:" << endl;
+ for (unsigned i = 0; i < _assignedSpillSlots.size(); ++i)
+ if (_assignedSpillSlots[i] != InvalidSpillSlot)
+ qout << "\t%" << i << " -> " << _assignedSpillSlots[i] << endl;
+
+ printer.print(function);
}
+
+// References:
+// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
+// CGO’10, ACM Press, 2010
+// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
+// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
+// Execution Environments, pages 132–141. ACM Press, 2005.
+// [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan
+// Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming
+// Language Design and Implementation, pages 142–151, June 1998.
diff --git a/src/qml/jit/qv4regalloc_p.h b/src/qml/jit/qv4regalloc_p.h
index 030fb4bf50..34ae19dfec 100644
--- a/src/qml/jit/qv4regalloc_p.h
+++ b/src/qml/jit/qv4regalloc_p.h
@@ -44,6 +44,7 @@
#include "qv4global_p.h"
#include "qv4isel_p.h"
#include "qv4ssa_p.h"
+#include "qv4registerinfo_p.h"
#include <config.h>
@@ -54,46 +55,68 @@ namespace JIT {
class RegAllocInfo;
+// This class implements a linear-scan register allocator, with a couple of tweaks:
+// - Second-chance allocation is used when an interval becomes active after a spill, which results
+// in fewer differences between edges, and hence fewer moves before jumps.
+// - Use positions are flagged with either "must have" register or "could have" register. This is
+// used to decide whether a register is really needed when a temporary is used after a spill
+// occurred.
+// - Fixed intervals are used to denotate IR positions where certain registers are needed in order
+// to implement the operation, and cannot be used by a temporary on that position. An example is
+// caller saved registers, where the call will use/clobber those registers.
+// - Hints are used to indicate which registers could be used to generate more compact code. An
+// example is an addition, where one (or both) operands' life-time ends at that instruction. In
+// this case, re-using an operand register for the result will result in an in-place add.
+// - SSA form properties are used:
+// - to simplify life-times (two temporaries will never interfere as long as their intervals
+// are not split), resulting in a slightly faster algorithm;
+// - when a temporary needs to be spilled, it is done directly after calculating it, so that
+// 1 store is generated even if multiple spills/splits happen.
+// - phi-node elimination (SSA form deconstruction) is done when resolving differences between
+// CFG edges
class RegisterAllocator
{
typedef IR::LifeTimeInterval LifeTimeInterval;
- QVector<int> _normalRegisters;
- QVector<int> _fpRegisters;
+ const RegisterInformation &_registerInformation;
+ QVector<const RegisterInfo *> _normalRegisters;
+ QVector<const RegisterInfo *> _fpRegisters;
QScopedPointer<RegAllocInfo> _info;
- QVector<LifeTimeInterval> _fixedRegisterRanges, _fixedFPRegisterRanges;
+ QVector<LifeTimeInterval *> _fixedRegisterRanges, _fixedFPRegisterRanges;
- QVector<LifeTimeInterval> _unhandled, _active, _inactive, _handled;
+ IR::LifeTimeIntervals::Ptr _lifeTimeIntervals;
+ typedef QVector<LifeTimeInterval *> Intervals;
+ Intervals _unhandled, _active, _inactive, _handled;
- QHash<IR::Temp, int> _lastAssignedRegister;
- QHash<IR::Temp, int> _assignedSpillSlots;
+ std::vector<int> _lastAssignedRegister;
+ std::vector<int> _assignedSpillSlots;
QVector<int> _activeSpillSlots;
Q_DISABLE_COPY(RegisterAllocator)
public:
- RegisterAllocator(const QVector<int> &normalRegisters, const QVector<int> &fpRegisters);
+ enum { InvalidSpillSlot = -1 };
+
+ RegisterAllocator(const RegisterInformation &registerInformation);
~RegisterAllocator();
void run(IR::Function *function, const IR::Optimizer &opt);
private:
+ LifeTimeInterval *cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original);
void prepareRanges();
void linearScan();
- void tryAllocateFreeReg(LifeTimeInterval &current, const int position);
- void allocateBlockedReg(LifeTimeInterval &current, const int position);
- void longestAvailableReg(const QVector<int> &nextUses, int &reg, int &nextUsePos_reg,
- int lastUse) const;
- int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another,
- const int position) const;
+ void tryAllocateFreeReg(LifeTimeInterval &current);
+ void allocateBlockedReg(LifeTimeInterval &current);
+ int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another) const;
int nextUse(const IR::Temp &t, int startPosition) const;
void split(LifeTimeInterval &current, int beforePosition, bool skipOptionalRegisterUses =false);
void splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position);
void assignSpillSlot(const IR::Temp &t, int startPos, int endPos);
void resolve(IR::Function *function, const IR::Optimizer &opt);
- void dump() const;
+ void dump(IR::Function *function) const;
};
} // end of namespace JIT
diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h
new file mode 100644
index 0000000000..b8701d72f4
--- /dev/null
+++ b/src/qml/jit/qv4registerinfo_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4REGISTERINFO_P_H
+#define QV4REGISTERINFO_P_H
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace JIT {
+
+class RegisterInfo
+{
+public:
+ enum { InvalidRegister = -1 };
+ enum SavedBy { CallerSaved, CalleeSaved };
+ enum RegisterType { RegularRegister, FloatingPointRegister };
+ enum Usage { Predefined, RegAlloc };
+
+public:
+ RegisterInfo()
+ : _reg(InvalidRegister)
+ , _type(RegularRegister)
+ , _savedBy(CallerSaved)
+ , _usage(Predefined)
+ {}
+
+ RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage)
+ : _reg(reg)
+ , _prettyName(prettyName)
+ , _type(type)
+ , _savedBy(savedBy)
+ , _usage(usage)
+ {}
+
+ bool isValid() const { return _reg != InvalidRegister; }
+ template <typename T> T reg() const { return static_cast<T>(_reg); }
+ QString prettyName() const { return _prettyName; }
+ bool isCallerSaved() const { return _savedBy == CallerSaved; }
+ bool isCalleeSaved() const { return _savedBy == CalleeSaved; }
+ bool isFloatingPoint() const { return _type == FloatingPointRegister; }
+ bool isRegularRegister() const { return _type == RegularRegister; }
+ bool useForRegAlloc() const { return _usage == RegAlloc; }
+
+private:
+ int _reg;
+ QString _prettyName;
+ RegisterType _type;
+ SavedBy _savedBy;
+ Usage _usage;
+};
+typedef QVector<RegisterInfo> RegisterInformation;
+
+} // JIT namespace
+} // QV4 namespace
+
+QT_END_NAMESPACE
+
+#endif // QV4REGISTERINFO_P_H
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
new file mode 100644
index 0000000000..4b384d2fe9
--- /dev/null
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4TARGETPLATFORM_P_H
+#define QV4TARGETPLATFORM_P_H
+
+#include <config.h>
+
+#if ENABLE(ASSEMBLER)
+
+#include "qv4registerinfo_p.h"
+#include <assembler/MacroAssembler.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace JIT {
+
+// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
+//
+// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
+// - Linux/x86 and win32, which are the same, except that linux non-PIC/PIE code does not need to
+// restore ebx (which holds the GOT ptr) before a call
+// - All (supported) ARM platforms, where the only variety is the platform specific usage of r9,
+// and the frame-pointer in Thumb/Thumb2 v.s. ARM mode.
+//
+// Specific handling of ebx when it holds the GOT:
+// In this case we can use it, but it needs to be restored when doing a call. So, the handling is as
+// follows: it is marked as caller saved, meaning the value in it won't survive a call. When
+// calculating the list of callee saved registers in getCalleeSavedRegisters (which is used to
+// generate push/pop instructions in the prelude/postlude), we add ebx too. Then when synthesizing
+// a call, we add a load it right before emitting the call instruction.
+//
+// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h!
+class TargetPlatform
+{
+public:
+#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD))
+ enum { RegAllocIsSupported = 1 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::esi;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::esi, QStringLiteral("esi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ }
+
+# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
+# undef VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 4;
+
+# undef ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 0;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+
+#if OS(WINDOWS) || OS(QNX) || \
+ ((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
+
+#define RESTORE_EBX_ON_CALL
+ static JSC::MacroAssembler::Address ebxAddressOnStack()
+ {
+ static int ebxIdx = -1;
+ if (ebxIdx == -1) {
+ int calleeSaves = 0;
+ foreach (const RegisterInfo &info, getRegisterInfo()) {
+ if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
+ ebxIdx = calleeSaves;
+ break;
+ } else if (info.isCalleeSaved()) {
+ ++calleeSaves;
+ }
+ }
+ Q_ASSERT(ebxIdx >= 0);
+ ebxIdx += 1;
+ }
+ return JSC::MacroAssembler::Address(StackFrameRegister, ebxIdx * -int(sizeof(void*)));
+ }
+#endif
+
+#endif // Windows on x86
+
+#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD))
+ enum { RegAllocIsSupported = 1 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ }
+
+#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
+#define VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 8;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 6;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::edi,
+ JSC::X86Registers::esi,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+#endif // Linux/MacOS on x86_64
+
+#if CPU(X86_64) && OS(WINDOWS)
+ // Register allocation is not (yet) supported on win64, because the ABI related stack handling
+ // is not completely implemented. Specifically, the saving of xmm registers, and the saving of
+ // incoming function parameters to the shadow space is missing.
+ enum { RegAllocIsSupported = 0 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ ;
+ }
+
+#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
+#define VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 8;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 4;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 32;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+#endif // Windows on x86_64
+
+#if CPU(ARM)
+ enum { RegAllocIsSupported = 1 };
+
+ // The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
+ // - The GNU/Linux ABI defines it as an additional callee-saved variable register (v6).
+ // - iOS (for which we cannot JIT, but still...) defines it as having a special use, so we do
+ // not touch it, nor use it.
+ // - Any other platform has not been verified, so we conservatively assume we cannot use it.
+#if OS(LINUX)
+#define CAN_USE_R9
+#endif
+
+ // 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)
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r7;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11;
+#else // Thumbs down
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r11;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+#endif
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r6;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::ARMRegisters::r5;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r3, QStringLiteral("r3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << 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)
+ << 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)
+#ifdef CAN_USE_R9
+ << 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)
+ << 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)
+ << RI(JSC::ARMRegisters::d3, QStringLiteral("d3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d4, QStringLiteral("d4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d5, QStringLiteral("d5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d6, QStringLiteral("d6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ // TODO: someone should check what's up with d8-d15: are they alway available, and are they caller or callee saved?
+ }
+
+#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
+#undef VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 4;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 4;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::ARMRegisters::r0,
+ JSC::ARMRegisters::r1,
+ JSC::ARMRegisters::r2,
+ JSC::ARMRegisters::r3
+ };
+
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 8; // Per AAPCS
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::ARMRegisters::lr); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); }
+#endif // Linux on ARM (32 bit)
+
+public: // utility functions
+ static RegisterInformation getRegisterInfo()
+ {
+ static const RegisterInformation info = getPlatformRegisterInfo();
+
+ return info;
+ }
+
+ static RegisterInformation &getCalleeSavedRegisters()
+ {
+ static RegisterInformation regs;
+ if (regs.isEmpty()) {
+ foreach (const RegisterInfo &info, getRegisterInfo()) {
+#if defined(RESTORE_EBX_ON_CALL)
+ if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
+ regs.append(info);
+ continue;
+ }
+#endif // RESTORE_EBX_ON_CALL
+ if (info.isCalleeSaved())
+ regs.append(info);
+ }
+ }
+
+ return regs;
+ }
+
+ static int calleeSavedRegisterCount()
+ {
+ return getCalleeSavedRegisters().size();
+ }
+};
+
+} // JIT namespace
+} // QV4 namespace
+
+QT_END_NAMESPACE
+
+#endif // ENABLE(ASSEMBLER)
+
+#endif // QV4TARGETPLATFORM_P_H
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 40f86f91b5..d92b5797cd 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -51,7 +51,7 @@ using namespace JIT;
#define setOp(operation) \
do { call = operation; name = stringIfy(operation); } while (0)
-void Unop::generate(IR::Temp *source, IR::Temp *target)
+void Unop::generate(IR::Expr *source, IR::Expr *target)
{
Runtime::UnaryOperation call = 0;
const char *name = 0;
@@ -77,16 +77,17 @@ void Unop::generate(IR::Temp *source, IR::Temp *target)
}
}
-void Unop::generateUMinus(IR::Temp *source, IR::Temp *target)
+void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
{
+ IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
Assembler::RegisterID tReg = Assembler::ScratchRegister;
- if (target->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) target->index;
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
+ tReg = (Assembler::RegisterID) targetTemp->index;
Assembler::RegisterID sReg = as->toInt32Register(source, tReg);
as->move(sReg, tReg);
as->neg32(tReg);
- if (target->kind != IR::Temp::PhysicalRegister)
+ if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
as->storeInt32(tReg, target);
return;
}
@@ -94,24 +95,25 @@ void Unop::generateUMinus(IR::Temp *source, IR::Temp *target)
as->generateFunctionCallImp(target, "Runtime::uMinus", Runtime::uMinus, Assembler::PointerToValue(source));
}
-void Unop::generateNot(IR::Temp *source, IR::Temp *target)
+void Unop::generateNot(IR::Expr *source, IR::Expr *target)
{
+ IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::BoolType) {
Assembler::RegisterID tReg = Assembler::ScratchRegister;
- if (target->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) target->index;
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
+ tReg = (Assembler::RegisterID) targetTemp->index;
as->xor32(Assembler::TrustedImm32(0x1), as->toInt32Register(source, tReg), tReg);
- if (target->kind != IR::Temp::PhysicalRegister)
+ if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
as->storeBool(tReg, target);
return;
} else if (source->type == IR::SInt32Type) {
Assembler::RegisterID tReg = Assembler::ScratchRegister;
- if (target->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) target->index;
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
+ tReg = (Assembler::RegisterID) targetTemp->index;
as->compare32(Assembler::Equal,
as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
tReg);
- if (target->kind != IR::Temp::PhysicalRegister)
+ if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
as->storeBool(tReg, target);
return;
} else if (source->type == IR::DoubleType) {
@@ -122,14 +124,15 @@ void Unop::generateNot(IR::Temp *source, IR::Temp *target)
as->generateFunctionCallImp(target, "Runtime::uNot", Runtime::uNot, Assembler::PointerToValue(source));
}
-void Unop::generateCompl(IR::Temp *source, IR::Temp *target)
+void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
{
+ IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
Assembler::RegisterID tReg = Assembler::ScratchRegister;
- if (target->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) target->index;
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
+ tReg = (Assembler::RegisterID) targetTemp->index;
as->xor32(Assembler::TrustedImm32(0xffffffff), as->toInt32Register(source, tReg), tReg);
- if (target->kind != IR::Temp::PhysicalRegister)
+ if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
as->storeInt32(tReg, target);
return;
}
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
index a8c62182ad..07fb6e5ad6 100644
--- a/src/qml/jit/qv4unop_p.h
+++ b/src/qml/jit/qv4unop_p.h
@@ -59,11 +59,11 @@ struct Unop {
, op(operation)
{}
- void generate(IR::Temp *source, IR::Temp *target);
+ void generate(IR::Expr *source, IR::Expr *target);
- void generateUMinus(IR::Temp *source, IR::Temp *target);
- void generateNot(IR::Temp *source, IR::Temp *target);
- void generateCompl(IR::Temp *source, IR::Temp *target);
+ void generateUMinus(IR::Expr *source, IR::Expr *target);
+ void generateNot(IR::Expr *source, IR::Expr *target);
+ void generateCompl(IR::Expr *source, IR::Expr *target);
Assembler *as;
IR::AluOp op;
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 9cb727dd63..929361bf72 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -50,6 +50,7 @@
#include "private/qv4globalobject_p.h"
#include "private/qv4script_p.h"
#include "private/qv4runtime_p.h"
+#include <private/qqmlbuiltinfunctions_p.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qmetaobject.h>
@@ -232,6 +233,45 @@ void QJSEngine::collectGarbage()
}
/*!
+ \since 5.4
+
+ Installs translator functions on the given \a object, or on the Global
+ Object if no object is specified.
+
+ The relation between script translator functions and C++ translator
+ functions is described in the following table:
+
+ \table
+ \header \li Script Function \li Corresponding C++ Function
+ \row \li qsTr() \li QObject::tr()
+ \row \li QT_TR_NOOP() \li QT_TR_NOOP()
+ \row \li qsTranslate() \li QCoreApplication::translate()
+ \row \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP()
+ \row \li qsTrId() \li qtTrId()
+ \row \li QT_TRID_NOOP() \li QT_TRID_NOOP()
+ \endtable
+
+ \sa {Internationalization with Qt}
+*/
+void QJSEngine::installTranslatorFunctions(const QJSValue &object)
+{
+ QV4::ExecutionEngine *v4 = d->m_v4Engine;
+ QV4::Scope scope(v4);
+ QJSValuePrivate *vp = QJSValuePrivate::get(object);
+ QV4::ScopedObject obj(scope, vp->getValue(v4));
+ if (!obj)
+ obj = v4->globalObject;
+#ifndef QT_NO_TRANSLATION
+ obj->defineDefaultProperty(QStringLiteral("qsTranslate"), QV4::GlobalExtensions::method_qsTranslate);
+ obj->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), QV4::GlobalExtensions::method_qsTranslateNoOp);
+ obj->defineDefaultProperty(QStringLiteral("qsTr"), QV4::GlobalExtensions::method_qsTr);
+ obj->defineDefaultProperty(QStringLiteral("QT_TR_NOOP"), QV4::GlobalExtensions::method_qsTrNoOp);
+ obj->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId);
+ obj->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp);
+#endif
+}
+
+/*!
Evaluates \a program, using \a lineNumber as the base line number,
and returns the result of the evaluation.
@@ -269,7 +309,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
QV4::ScopedValue result(scope);
QV4::Script script(ctx, program, fileName, lineNumber);
- script.strictMode = ctx->strictMode;
+ script.strictMode = ctx->d()->strictMode;
script.inheritContext = true;
script.parse();
if (!scope.engine->hasException)
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 0a575f84e9..9d810a85d1 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -89,6 +89,8 @@ public:
void collectGarbage();
+ void installTranslatorFunctions(const QJSValue &object = QJSValue());
+
QV8Engine *handle() const { return d; }
private:
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index b17ac17752..ec45ce9374 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -385,7 +385,7 @@ double QJSValue::toNumber() const
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
double dbl = d->value.toNumber();
- if (ctx && ctx->engine->hasException) {
+ if (ctx && ctx->d()->engine->hasException) {
ctx->catchException();
return 0;
}
@@ -411,7 +411,7 @@ bool QJSValue::toBool() const
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
bool b = d->value.toBoolean();
- if (ctx && ctx->engine->hasException) {
+ if (ctx && ctx->d()->engine->hasException) {
ctx->catchException();
return false;
}
@@ -437,7 +437,7 @@ qint32 QJSValue::toInt() const
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
qint32 i = d->value.toInt32();
- if (ctx && ctx->engine->hasException) {
+ if (ctx && ctx->d()->engine->hasException) {
ctx->catchException();
return 0;
}
@@ -463,7 +463,7 @@ quint32 QJSValue::toUInt() const
QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
quint32 u = d->value.toUInt32();
- if (ctx && ctx->engine->hasException) {
+ if (ctx && ctx->d()->engine->hasException) {
ctx->catchException();
return 0;
}
@@ -682,7 +682,7 @@ QJSValue QJSValue::prototype() const
Scoped<Object> p(scope, o->prototype());
if (!p)
return QJSValue(NullValue);
- return new QJSValuePrivate(o->internalClass->engine, p);
+ return new QJSValuePrivate(o->internalClass()->engine, p);
}
/*!
@@ -861,7 +861,7 @@ QJSValue QJSValue::property(const QString& name) const
s->makeIdentifier();
QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
- result = o->get(s);
+ result = o->get(s.getPointer());
if (scope.hasException())
result = ctx->catchException();
@@ -893,7 +893,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
- result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
+ result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax.getPointer()) : o->getIndexed(arrayIndex);
if (scope.hasException())
result = ctx->catchException();
return new QJSValuePrivate(engine, result);
@@ -936,7 +936,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
QV4::ExecutionContext *ctx = engine->currentContext();
s->makeIdentifier();
QV4::ScopedValue v(scope, value.d->getValue(engine));
- o->put(s, v);
+ o->put(s.getPointer(), v);
if (scope.hasException())
ctx->catchException();
}
@@ -969,7 +969,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
if (arrayIndex != UINT_MAX)
o->putIndexed(arrayIndex, v);
else
- o->put(engine->id_uintMax, v);
+ o->put(engine->id_uintMax.getPointer(), v);
if (scope.hasException())
ctx->catchException();
}
@@ -1004,7 +1004,7 @@ bool QJSValue::deleteProperty(const QString &name)
return false;
ScopedString s(scope, engine->newString(name));
- bool b = o->deleteProperty(s);
+ bool b = o->deleteProperty(s.getPointer());
if (scope.hasException())
ctx->catchException();
return b;
@@ -1028,7 +1028,7 @@ bool QJSValue::hasProperty(const QString &name) const
return false;
ScopedString s(scope, engine->newIdentifier(name));
- return o->hasProperty(s);
+ return o->hasProperty(s.getPointer());
}
/*!
@@ -1049,7 +1049,7 @@ bool QJSValue::hasOwnProperty(const QString &name) const
return false;
ScopedString s(scope, engine->newIdentifier(name));
- return o->hasOwnProperty(s);
+ return o->hasOwnProperty(s.getPointer());
}
/*!
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 6dcfafaa27..449fb8235a 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -108,8 +108,10 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object)
return;
QV4::Scope scope(v4);
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
- it->it.flags = QV4::ObjectIterator::NoFlags;
- it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ it->d()->it.flags = QV4::ObjectIterator::NoFlags;
+ QV4::String *nm = 0;
+ it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ d_ptr->nextName = nm;
}
/*!
@@ -155,7 +157,9 @@ bool QJSValueIterator::next()
return false;
QV4::Scope scope(v4);
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
- it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ QV4::String *nm = 0;
+ it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ d_ptr->nextName = nm;
return !!d_ptr->currentName || d_ptr->currentIndex != UINT_MAX;
}
@@ -229,8 +233,10 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
QV4::ScopedObject o(scope, jsp->value);
d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue();
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
- it->it.flags = QV4::ObjectIterator::NoFlags;
- it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ it->d()->it.flags = QV4::ObjectIterator::NoFlags;
+ QV4::String *nm = 0;
+ it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
+ d_ptr->nextName = nm;
return *this;
}
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 72010d3fa8..c27aaa90d8 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -105,13 +105,6 @@ SOURCES += \
$$PWD/qv4string.cpp \
$$PWD/qv4value.cpp
-# Use SSE2 floating point math on 32 bit instead of the default
-# 387 to make test results pass on 32 and on 64 bit builds.
-linux-g++*:isEqual(QT_ARCH,i386) {
- QMAKE_CFLAGS += -march=pentium4 -msse2 -mfpmath=sse
- QMAKE_CXXFLAGS += -march=pentium4 -msse2 -mfpmath=sse
-}
-
valgrind {
DEFINES += V4_USE_VALGRIND
}
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 987b228209..71563b7b0d 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -46,63 +46,58 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
-ArgumentsObject::ArgumentsObject(CallContext *context)
- : Object(context->strictMode ? context->engine->strictArgumentsObjectClass : context->engine->argumentsObjectClass)
+ArgumentsObject::Data::Data(CallContext *context)
+ : Object::Data(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass)
, context(context)
, fullyCreated(false)
{
- ExecutionEngine *v4 = context->engine;
+ Q_ASSERT(internalClass->vtable == staticVTable());
+
+ ExecutionEngine *v4 = context->d()->engine;
Scope scope(v4);
- ScopedObject protectThis(scope, this);
+ Scoped<ArgumentsObject> args(scope, this);
- setArrayType(ArrayData::Complex);
+ args->setArrayType(ArrayData::Complex);
- if (context->strictMode) {
- Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
- Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
- propertyAt(CalleePropertyIndex)->value = v4->thrower;
- propertyAt(CalleePropertyIndex)->set = v4->thrower;
- propertyAt(CallerPropertyIndex)->value = v4->thrower;
- propertyAt(CallerPropertyIndex)->set = v4->thrower;
+ 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->propertyAt(CalleePropertyIndex)->value = v4->thrower;
+ args->propertyAt(CalleePropertyIndex)->set = v4->thrower;
+ args->propertyAt(CallerPropertyIndex)->value = v4->thrower;
+ args->propertyAt(CallerPropertyIndex)->set = v4->thrower;
- arrayReserve(context->callData->argc);
- arrayPut(0, context->callData->args, context->callData->argc);
- fullyCreated = true;
+ args->arrayReserve(context->d()->callData->argc);
+ args->arrayPut(0, context->d()->callData->args, context->d()->callData->argc);
+ args->d()->fullyCreated = true;
} else {
- hasAccessorProperty = 1;
- Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
- memberData[CalleePropertyIndex] = context->function->asReturnedValue();
+ args->setHasAccessorProperty();
+ Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee));
+ args->memberData()[CalleePropertyIndex] = context->d()->function->asReturnedValue();
}
- Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
- memberData[LengthPropertyIndex] = Primitive::fromInt32(context->realArgumentCount);
-
- Q_ASSERT(internalClass->vtable == staticVTable());
-}
-
-void ArgumentsObject::destroy(Managed *that)
-{
- static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
+ Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length));
+ args->memberData()[LengthPropertyIndex] = Primitive::fromInt32(context->d()->realArgumentCount);
}
void ArgumentsObject::fullyCreate()
{
- if (fullyCreated)
+ if (fullyCreated())
return;
- uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount);
- uint argCount = qMin(context->realArgumentCount, context->callData->argc);
+ uint numAccessors = qMin((int)context()->d()->function->formalParameterCount(), context()->d()->realArgumentCount);
+ uint argCount = qMin(context()->d()->realArgumentCount, context()->d()->callData->argc);
ArrayData::realloc(this, ArrayData::Sparse, 0, argCount, true);
- context->engine->requireArgumentsAccessors(numAccessors);
- mappedArguments.ensureIndex(engine(), numAccessors);
+ context()->d()->engine->requireArgumentsAccessors(numAccessors);
+ mappedArguments().ensureIndex(engine(), numAccessors);
for (uint i = 0; i < (uint)numAccessors; ++i) {
- mappedArguments[i] = context->callData->args[i];
- arraySet(i, context->engine->argumentsAccessors[i], Attr_Accessor);
+ mappedArguments()[i] = context()->d()->callData->args[i];
+ arraySet(i, context()->d()->engine->argumentsAccessors[i], Attr_Accessor);
}
- arrayPut(numAccessors, context->callData->args + numAccessors, argCount - numAccessors);
+ arrayPut(numAccessors, context()->d()->callData->args + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
setArrayAttributes(i, Attr_Data);
- fullyCreated = true;
+ d()->fullyCreated = true;
}
bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
@@ -110,26 +105,26 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
fullyCreate();
Scope scope(ctx);
- Property *pd = arrayData->getProperty(index);
+ Property *pd = arrayData()->getProperty(index);
Property map;
PropertyAttributes mapAttrs;
bool isMapped = false;
- uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount);
+ uint numAccessors = qMin((int)context()->d()->function->formalParameterCount(), context()->d()->realArgumentCount);
if (pd && index < (uint)numAccessors)
- isMapped = arrayData->attributes(index).isAccessor() && pd->getter() == context->engine->argumentsAccessors[index].getter();
+ isMapped = arrayData()->attributes(index).isAccessor() && pd->getter() == context()->d()->engine->argumentsAccessors[index].getter();
if (isMapped) {
- mapAttrs = arrayData->attributes(index);
+ mapAttrs = arrayData()->attributes(index);
map.copy(*pd, mapAttrs);
setArrayAttributes(index, Attr_Data);
- pd = arrayData->getProperty(index);
- pd->value = mappedArguments[index];
+ pd = arrayData()->getProperty(index);
+ pd->value = mappedArguments()[index];
}
- bool strict = ctx->strictMode;
- ctx->strictMode = false;
+ bool strict = ctx->d()->strictMode;
+ ctx->d()->strictMode = false;
bool result = Object::defineOwnProperty2(ctx, index, desc, attrs);
- ctx->strictMode = strict;
+ ctx->d()->strictMode = strict;
if (isMapped && attrs.isData()) {
ScopedCallData callData(scope, 1);
@@ -139,12 +134,12 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
- pd = arrayData->getProperty(index);
+ pd = arrayData()->getProperty(index);
pd->copy(map, mapAttrs);
}
}
- if (ctx->strictMode && !result)
+ if (ctx->d()->strictMode && !result)
return ctx->throwTypeError();
return result;
}
@@ -152,13 +147,13 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
- if (args->fullyCreated)
+ if (args->fullyCreated())
return Object::getIndexed(m, index, hasProperty);
- if (index < static_cast<uint>(args->context->callData->argc)) {
+ if (index < static_cast<uint>(args->context()->d()->callData->argc)) {
if (hasProperty)
*hasProperty = true;
- return args->context->callData->args[index].asReturnedValue();
+ return args->context()->d()->callData->args[index].asReturnedValue();
}
if (hasProperty)
*hasProperty = false;
@@ -168,21 +163,21 @@ ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasPrope
void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
- if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc))
+ if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->d()->callData->argc))
args->fullyCreate();
- if (args->fullyCreated) {
+ if (args->fullyCreated()) {
Object::putIndexed(m, index, value);
return;
}
- args->context->callData->args[index] = value;
+ args->context()->d()->callData->args[index] = value;
}
bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
- if (!args->fullyCreated)
+ if (!args->fullyCreated())
args->fullyCreate();
return Object::deleteIndexedProperty(m, index);
}
@@ -190,11 +185,11 @@ bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
{
const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
- if (args->fullyCreated)
+ if (args->fullyCreated())
return Object::queryIndexed(m, index);
- uint numAccessors = qMin((int)args->context->function->formalParameterCount(), args->context->realArgumentCount);
- uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc);
+ uint numAccessors = qMin((int)args->context()->d()->function->formalParameterCount(), args->context()->d()->realArgumentCount);
+ uint argCount = qMin(args->context()->d()->realArgumentCount, args->context()->d()->callData->argc);
if (index >= argCount)
return PropertyAttributes();
if (index >= numAccessors)
@@ -213,8 +208,8 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
if (!o)
return v4->currentContext()->throwTypeError();
- Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc));
- return o->context->argument(g->index);
+ Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->d()->callData->argc));
+ return o->context()->argument(g->index());
}
DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
@@ -228,17 +223,17 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
if (!o)
return v4->currentContext()->throwTypeError();
- Q_ASSERT(s->index < static_cast<unsigned>(o->context->callData->argc));
- o->context->callData->args[s->index] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
+ Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->d()->callData->argc));
+ o->context()->d()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
return Encode::undefined();
}
void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e)
{
ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
- if (o->context)
- o->context->mark(e);
- o->mappedArguments.mark(e);
+ if (o->context())
+ o->context()->mark(e);
+ o->mappedArguments().mark(e);
Object::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 80c2a70501..59ab9f020e 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -50,43 +50,58 @@ namespace QV4 {
struct ArgumentsGetterFunction: FunctionObject
{
- V4_OBJECT
- uint index;
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, uint index)
+ : FunctionObject::Data(scope)
+ , index(index)
+ {
+ setVTable(staticVTable());
+ }
+ uint index;
+ };
+ V4_OBJECT(FunctionObject)
- ArgumentsGetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) {
- setVTable(staticVTable());
- }
+ uint index() const { return d()->index; }
static ReturnedValue call(Managed *that, CallData *d);
};
struct ArgumentsSetterFunction: FunctionObject
{
- V4_OBJECT
- uint index;
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, uint index)
+ : FunctionObject::Data(scope)
+ , index(index)
+ {
+ setVTable(staticVTable());
+ }
+ uint index;
+ };
+ V4_OBJECT(FunctionObject)
- ArgumentsSetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) {
- setVTable(staticVTable());
- }
+ uint index() const { return d()->index; }
static ReturnedValue call(Managed *that, CallData *callData);
};
struct ArgumentsObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(CallContext *context);
+ CallContext *context;
+ bool fullyCreated;
+ Members mappedArguments;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(ArgumentsObject)
- CallContext *context;
- bool fullyCreated;
- Members mappedArguments;
- ArgumentsObject(CallContext *context);
- ~ArgumentsObject() {}
+
+ CallContext *context() const { return d()->context; }
+ bool fullyCreated() const { return d()->fullyCreated; }
+ Members &mappedArguments() { return d()->mappedArguments; }
static bool isNonStrictArgumentsObject(Managed *m) {
- return m->internalClass->vtable->type == Type_ArgumentsObject &&
- !static_cast<ArgumentsObject *>(m)->context->strictMode;
+ return m->internalClass()->vtable->type == Type_ArgumentsObject &&
+ !static_cast<ArgumentsObject *>(m)->context()->d()->strictMode;
}
enum {
@@ -100,7 +115,6 @@ struct ArgumentsObject: Object {
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static void markObjects(Managed *that, ExecutionEngine *e);
- static void destroy(Managed *);
void fullyCreate();
};
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index ed2122fb89..f56c31b177 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -45,9 +45,25 @@
using namespace QV4;
+const QV4::ManagedVTable QV4::ArrayData::static_vtbl = {
+ 0,
+ QV4::ArrayData::IsExecutionContext,
+ QV4::ArrayData::IsString,
+ QV4::ArrayData::IsObject,
+ QV4::ArrayData::IsFunctionObject,
+ QV4::ArrayData::IsErrorObject,
+ QV4::ArrayData::IsArrayData,
+ 0,
+ QV4::ArrayData::MyType,
+ "ArrayData",
+ Q_VTABLE_FUNCTION(QV4::ArrayData, destroy),
+ 0,
+ isEqualTo
+};
+
const ArrayVTable SimpleArrayData::static_vtbl =
{
- DEFINE_MANAGED_VTABLE_INT(SimpleArrayData),
+ DEFINE_MANAGED_VTABLE_INT(SimpleArrayData, 0),
SimpleArrayData::Simple,
SimpleArrayData::reallocate,
SimpleArrayData::get,
@@ -64,7 +80,7 @@ const ArrayVTable SimpleArrayData::static_vtbl =
const ArrayVTable SparseArrayData::static_vtbl =
{
- DEFINE_MANAGED_VTABLE_INT(SparseArrayData),
+ DEFINE_MANAGED_VTABLE_INT(SparseArrayData, 0),
ArrayData::Sparse,
SparseArrayData::reallocate,
SparseArrayData::get,
@@ -82,7 +98,7 @@ const ArrayVTable SparseArrayData::static_vtbl =
void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes)
{
- ArrayData *d = o->arrayData;
+ ArrayData *d = o->arrayData();
uint oldAlloc = 0;
uint toCopy = 0;
@@ -90,19 +106,19 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
alloc = 8;
if (d) {
- bool hasAttrs = d->attrs;
+ bool hasAttrs = d->attrs();
enforceAttributes |= hasAttrs;
- if (!offset && alloc <= d->alloc && newType == d->type && hasAttrs == enforceAttributes)
+ if (!offset && alloc <= d->alloc() && newType == d->type() && hasAttrs == enforceAttributes)
return;
- oldAlloc = d->alloc;
- if (d->type < Sparse) {
- offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset);
- toCopy = static_cast<SimpleArrayData *>(d)->len;
+ oldAlloc = d->alloc();
+ if (d->type() < Sparse) {
+ offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset());
+ toCopy = static_cast<SimpleArrayData *>(d)->len();
} else {
Q_ASSERT(!offset);
- toCopy = d->alloc;
+ toCopy = d->alloc();
newType = Sparse;
}
}
@@ -115,69 +131,69 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
size += alloc*sizeof(PropertyAttributes);
if (newType < Sparse) {
- size += sizeof(SimpleArrayData);
+ size += sizeof(SimpleArrayData::Data);
SimpleArrayData *newData = static_cast<SimpleArrayData *>(o->engine()->memoryManager->allocManaged(size));
- new (newData) SimpleArrayData(o->engine());
- newData->alloc = alloc - offset;
- newData->type = newType;
- newData->data = reinterpret_cast<Value *>(newData + 1) + offset;
- newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) + offset : 0;
- newData->offset = offset;
- newData->len = d ? static_cast<SimpleArrayData *>(d)->len : 0;
- o->arrayData = newData;
+ new (newData->d()) SimpleArrayData::Data(o->engine());
+ newData->setAlloc(alloc - offset);
+ newData->setType(newType);
+ newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1) + offset);
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) + offset : 0);
+ newData->offset() = offset;
+ newData->len() = d ? static_cast<SimpleArrayData *>(d)->len() : 0;
+ o->setArrayData(newData);
} else {
- size += sizeof(SparseArrayData);
+ size += sizeof(SparseArrayData::Data);
SparseArrayData *newData = static_cast<SparseArrayData *>(o->engine()->memoryManager->allocManaged(size));
- new (newData) SparseArrayData(o->engine());
- newData->alloc = alloc;
- newData->type = newType;
- newData->data = reinterpret_cast<Value *>(newData + 1);
- newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) : 0;
- o->arrayData = newData;
+ new (newData->d()) SparseArrayData::Data(o->engine());
+ newData->setAlloc(alloc);
+ newData->setType(newType);
+ newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1));
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) : 0);
+ o->setArrayData(newData);
}
if (d) {
- memcpy(o->arrayData->data, d->data, sizeof(Value)*toCopy);
+ memcpy(o->arrayData()->arrayData(), d->arrayData(), sizeof(Value)*toCopy);
if (enforceAttributes) {
- if (d->attrs)
- memcpy(o->arrayData->attrs, d->attrs, sizeof(PropertyAttributes)*toCopy);
+ if (d->attrs())
+ memcpy(o->arrayData()->attrs(), d->attrs(), sizeof(PropertyAttributes)*toCopy);
else
for (uint i = 0; i < toCopy; ++i)
- o->arrayData->attrs[i] = Attr_Data;
+ o->arrayData()->attrs()[i] = Attr_Data;
}
}
if (newType != Sparse)
return;
- SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData);
- if (d && d->type == Sparse) {
+ SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData());
+ if (d && d->type() == Sparse) {
SparseArrayData *old = static_cast<SparseArrayData *>(d);
- newData->sparse = old->sparse;
- old->sparse = 0;
- newData->freeList = old->freeList;
+ newData->setSparse(old->sparse());
+ old->setSparse(0);
+ newData->freeList() = old->freeList();
} else {
- newData->sparse = new SparseArray;
- uint *lastFree = &newData->freeList;
+ newData->setSparse(new SparseArray);
+ uint *lastFree = &newData->freeList();
for (uint i = 0; i < toCopy; ++i) {
- if (!newData->data[i].isEmpty()) {
- SparseArrayNode *n = newData->sparse->insert(i);
+ if (!newData->arrayData()[i].isEmpty()) {
+ SparseArrayNode *n = newData->sparse()->insert(i);
n->value = i;
} else {
*lastFree = i;
- newData->data[i].tag = Value::Empty_Type;
- lastFree = &newData->data[i].uint_32;
+ newData->arrayData()[i].tag = Value::Empty_Type;
+ lastFree = &newData->arrayData()[i].uint_32;
}
}
}
- uint *lastFree = &newData->freeList;
- for (uint i = toCopy; i < newData->alloc; ++i) {
+ uint *lastFree = &newData->freeList();
+ for (uint i = toCopy; i < newData->alloc(); ++i) {
*lastFree = i;
- newData->data[i].tag = Value::Empty_Type;
- lastFree = &newData->data[i].uint_32;
+ newData->arrayData()[i].tag = Value::Empty_Type;
+ lastFree = &newData->arrayData()[i].uint_32;
}
- *lastFree = newData->alloc;
+ *lastFree = newData->alloc();
// ### Could explicitly free the old data
}
@@ -185,248 +201,244 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e
void SimpleArrayData::getHeadRoom(Object *o)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
Q_ASSERT(dd);
- Q_ASSERT(!dd->offset);
- uint offset = qMax(dd->len >> 2, (uint)16);
+ Q_ASSERT(!dd->offset());
+ uint offset = qMax(dd->len() >> 2, (uint)16);
realloc(o, Simple, offset, 0, false);
}
ArrayData *SimpleArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
realloc(o, Simple, 0, n, enforceAttributes);
- return o->arrayData;
+ return o->arrayData();
}
void ArrayData::ensureAttributes(Object *o)
{
- if (o->arrayData && o->arrayData->attrs)
+ if (o->arrayData() && o->arrayData()->attrs())
return;
ArrayData::realloc(o, Simple, 0, 0, true);
}
-void SimpleArrayData::destroy(Managed *)
-{
-}
-
void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e)
{
SimpleArrayData *dd = static_cast<SimpleArrayData *>(d);
- uint l = dd->len;
+ uint l = dd->len();
for (uint i = 0; i < l; ++i)
- dd->data[i].mark(e);
+ dd->arrayData()[i].mark(e);
}
ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index)
{
const SimpleArrayData *dd = static_cast<const SimpleArrayData *>(d);
- if (index >= dd->len)
+ if (index >= dd->len())
return Primitive::emptyValue().asReturnedValue();
- return dd->data[index].asReturnedValue();
+ return dd->arrayData()[index].asReturnedValue();
}
bool SimpleArrayData::put(Object *o, uint index, ValueRef value)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ Q_ASSERT(index >= dd->len() || !dd->attrs() || !dd->attrs()[index].isAccessor());
// ### honour attributes
- dd->data[index] = value;
- if (index >= dd->len) {
- if (dd->attrs)
- dd->attrs[index] = Attr_Data;
- dd->len = index + 1;
+ dd->arrayData()[index] = value;
+ if (index >= dd->len()) {
+ if (dd->attrs())
+ dd->attrs()[index] = Attr_Data;
+ dd->len() = index + 1;
}
return true;
}
bool SimpleArrayData::del(Object *o, uint index)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- if (index >= dd->len)
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ if (index >= dd->len())
return true;
- if (!dd->attrs || dd->attrs[index].isConfigurable()) {
- dd->data[index] = Primitive::emptyValue();
- if (dd->attrs)
- dd->attrs[index] = Attr_Data;
+ if (!dd->attrs() || dd->attrs()[index].isConfigurable()) {
+ dd->arrayData()[index] = Primitive::emptyValue();
+ if (dd->attrs())
+ dd->attrs()[index] = Attr_Data;
return true;
}
- if (dd->data[index].isEmpty())
+ if (dd->arrayData()[index].isEmpty())
return true;
return false;
}
void SimpleArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs)
{
- o->arrayData->attrs[index] = attrs;
+ o->arrayData()->attrs()[index] = attrs;
}
PropertyAttributes SimpleArrayData::attribute(const ArrayData *d, uint index)
{
- return d->attrs[index];
+ return d->attrs()[index];
}
void SimpleArrayData::push_front(Object *o, Value *values, uint n)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- Q_ASSERT(!dd->attrs);
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ Q_ASSERT(!dd->attrs());
for (int i = n - 1; i >= 0; --i) {
- if (!dd->offset) {
+ if (!dd->offset()) {
getHeadRoom(o);
- dd = static_cast<SimpleArrayData *>(o->arrayData);
+ dd = static_cast<SimpleArrayData *>(o->arrayData());
}
- --dd->offset;
- --dd->data;
- ++dd->len;
- ++dd->alloc;
- *dd->data = values[i].asReturnedValue();
+ --dd->offset();
+ --dd->arrayData();
+ ++dd->len();
+ ++dd->alloc();
+ *dd->arrayData() = values[i].asReturnedValue();
}
}
ReturnedValue SimpleArrayData::pop_front(Object *o)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- Q_ASSERT(!dd->attrs);
- if (!dd->len)
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ Q_ASSERT(!dd->attrs());
+ if (!dd->len())
return Encode::undefined();
- ReturnedValue v = dd->data[0].isEmpty() ? Encode::undefined() : dd->data[0].asReturnedValue();
- ++dd->offset;
- ++dd->data;
- --dd->len;
- --dd->alloc;
+ ReturnedValue v = dd->arrayData()[0].isEmpty() ? Encode::undefined() : dd->arrayData()[0].asReturnedValue();
+ ++dd->offset();
+ ++dd->arrayData();
+ --dd->len();
+ --dd->alloc();
return v;
}
uint SimpleArrayData::truncate(Object *o, uint newLen)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- if (dd->len < newLen)
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ if (dd->len() < newLen)
return newLen;
- if (dd->attrs) {
- Value *it = dd->data + dd->len;
- const Value *begin = dd->data + newLen;
+ if (dd->attrs()) {
+ Value *it = dd->arrayData() + dd->len();
+ const Value *begin = dd->arrayData() + newLen;
while (--it >= begin) {
- if (!it->isEmpty() && !dd->attrs[it - dd->data].isConfigurable()) {
- newLen = it - dd->data + 1;
+ if (!it->isEmpty() && !dd->attrs()[it - dd->arrayData()].isConfigurable()) {
+ newLen = it - dd->arrayData() + 1;
break;
}
*it = Primitive::emptyValue();
}
}
- dd->len = newLen;
+ dd->len() = newLen;
return newLen;
}
uint SimpleArrayData::length(const ArrayData *d)
{
- return static_cast<const SimpleArrayData *>(d)->len;
+ return static_cast<const SimpleArrayData *>(d)->len();
}
bool SimpleArrayData::putArray(Object *o, uint index, Value *values, uint n)
{
- SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData);
- if (index + n > dd->alloc) {
+ SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData());
+ if (index + n > dd->alloc()) {
reallocate(o, index + n + 1, false);
- dd = static_cast<SimpleArrayData *>(o->arrayData);
+ dd = static_cast<SimpleArrayData *>(o->arrayData());
}
- for (uint i = dd->len; i < index; ++i)
- dd->data[i] = Primitive::emptyValue();
+ for (uint i = dd->len(); i < index; ++i)
+ dd->arrayData()[i] = Primitive::emptyValue();
for (uint i = 0; i < n; ++i)
- dd->data[index + i] = values[i];
- dd->len = qMax(dd->len, index + n);
+ dd->arrayData()[index + i] = values[i];
+ dd->len() = qMax(dd->len(), index + n);
return true;
}
void SparseArrayData::free(ArrayData *d, uint idx)
{
- Q_ASSERT(d && d->type == ArrayData::Sparse);
+ Q_ASSERT(d && d->type() == ArrayData::Sparse);
SparseArrayData *dd = static_cast<SparseArrayData *>(d);
- Value *v = dd->data + idx;
- if (dd->attrs && dd->attrs[idx].isAccessor()) {
+ Value *v = dd->arrayData() + idx;
+ if (dd->attrs() && dd->attrs()[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
v[1].tag = Value::Empty_Type;
- v[1].uint_32 = dd->freeList;
+ v[1].uint_32 = dd->freeList();
v[0].tag = Value::Empty_Type;
v[0].uint_32 = idx + 1;
} else {
v->tag = Value::Empty_Type;
- v->uint_32 = dd->freeList;
+ v->uint_32 = dd->freeList();
}
- dd->freeList = idx;
- if (dd->attrs)
- dd->attrs[idx].clear();
+ dd->freeList() = idx;
+ if (dd->attrs())
+ dd->attrs()[idx].clear();
}
void SparseArrayData::destroy(Managed *d)
{
SparseArrayData *dd = static_cast<SparseArrayData *>(d);
- delete dd->sparse;
+ delete dd->sparse();
}
void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e)
{
SparseArrayData *dd = static_cast<SparseArrayData *>(d);
- uint l = dd->alloc;
+ uint l = dd->alloc();
for (uint i = 0; i < l; ++i)
- dd->data[i].mark(e);
+ dd->arrayData()[i].mark(e);
}
ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
realloc(o, Sparse, 0, n, enforceAttributes);
- return o->arrayData;
+ return o->arrayData();
}
// double slots are required for accessor properties
uint SparseArrayData::allocate(Object *o, bool doubleSlot)
{
- Q_ASSERT(o->arrayData->type == ArrayData::Sparse);
- SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData);
+ Q_ASSERT(o->arrayData()->type() == ArrayData::Sparse);
+ SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData());
if (doubleSlot) {
- uint *last = &dd->freeList;
+ uint *last = &dd->freeList();
while (1) {
- if (*last + 1 >= dd->alloc) {
- reallocate(o, o->arrayData->alloc + 2, true);
- dd = static_cast<SparseArrayData *>(o->arrayData);
- last = &dd->freeList;
+ if (*last + 1 >= dd->alloc()) {
+ reallocate(o, o->arrayData()->alloc() + 2, true);
+ dd = static_cast<SparseArrayData *>(o->arrayData());
+ last = &dd->freeList();
}
- if (dd->data[*last].uint_32 == (*last + 1)) {
+ if (dd->arrayData()[*last].uint_32 == (*last + 1)) {
// found two slots in a row
uint idx = *last;
- *last = dd->data[*last + 1].uint_32;
- o->arrayData->attrs[idx] = Attr_Accessor;
+ *last = dd->arrayData()[*last + 1].uint_32;
+ o->arrayData()->attrs()[idx] = Attr_Accessor;
return idx;
}
- last = &dd->data[*last].uint_32;
+ last = &dd->arrayData()[*last].uint_32;
}
} else {
- if (dd->alloc == dd->freeList) {
- reallocate(o, o->arrayData->alloc + 2, false);
- dd = static_cast<SparseArrayData *>(o->arrayData);
+ if (dd->alloc() == dd->freeList()) {
+ reallocate(o, o->arrayData()->alloc() + 2, false);
+ dd = static_cast<SparseArrayData *>(o->arrayData());
}
- uint idx = dd->freeList;
- dd->freeList = dd->data[idx].uint_32;
- if (dd->attrs)
- dd->attrs[idx] = Attr_Data;
+ uint idx = dd->freeList();
+ dd->freeList() = dd->arrayData()[idx].uint_32;
+ if (dd->attrs())
+ dd->attrs()[idx] = Attr_Data;
return idx;
}
}
ReturnedValue SparseArrayData::get(const ArrayData *d, uint index)
{
- SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->findNode(index);
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse()->findNode(index);
if (!n)
return Primitive::emptyValue().asReturnedValue();
- return d->data[n->value].asReturnedValue();
+ return d->arrayData()[n->value].asReturnedValue();
}
bool SparseArrayData::put(Object *o, uint index, ValueRef value)
@@ -434,93 +446,93 @@ bool SparseArrayData::put(Object *o, uint index, ValueRef value)
if (value->isEmpty())
return true;
- SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
- Q_ASSERT(n->value == UINT_MAX || !o->arrayData->attrs || !o->arrayData->attrs[n->value].isAccessor());
+ SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index);
+ Q_ASSERT(n->value == UINT_MAX || !o->arrayData()->attrs() || !o->arrayData()->attrs()[n->value].isAccessor());
if (n->value == UINT_MAX)
n->value = allocate(o);
- o->arrayData->data[n->value] = value;
- if (o->arrayData->attrs)
- o->arrayData->attrs[n->value] = Attr_Data;
+ o->arrayData()->arrayData()[n->value] = value;
+ if (o->arrayData()->attrs())
+ o->arrayData()->attrs()[n->value] = Attr_Data;
return true;
}
bool SparseArrayData::del(Object *o, uint index)
{
- SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData);
- SparseArrayNode *n = dd->sparse->findNode(index);
+ SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayNode *n = dd->sparse()->findNode(index);
if (!n)
return true;
uint pidx = n->value;
- Q_ASSERT(!dd->data[pidx].isEmpty());
+ Q_ASSERT(!dd->arrayData()[pidx].isEmpty());
bool isAccessor = false;
- if (dd->attrs) {
- if (!dd->attrs[pidx].isConfigurable())
+ if (dd->attrs()) {
+ if (!dd->attrs()[pidx].isConfigurable())
return false;
- isAccessor = dd->attrs[pidx].isAccessor();
- dd->attrs[pidx] = Attr_Data;
+ isAccessor = dd->attrs()[pidx].isAccessor();
+ dd->attrs()[pidx] = Attr_Data;
}
if (isAccessor) {
// free up both indices
- dd->data[pidx + 1].tag = Value::Undefined_Type;
- dd->data[pidx + 1].uint_32 = static_cast<SparseArrayData *>(dd)->freeList;
- dd->data[pidx].tag = Value::Undefined_Type;
- dd->data[pidx].uint_32 = pidx + 1;
+ dd->arrayData()[pidx + 1].tag = Value::Undefined_Type;
+ dd->arrayData()[pidx + 1].uint_32 = static_cast<SparseArrayData *>(dd)->freeList();
+ dd->arrayData()[pidx].tag = Value::Undefined_Type;
+ dd->arrayData()[pidx].uint_32 = pidx + 1;
} else {
- dd->data[pidx].tag = Value::Undefined_Type;
- dd->data[pidx].uint_32 = static_cast<SparseArrayData *>(dd)->freeList;
+ dd->arrayData()[pidx].tag = Value::Undefined_Type;
+ dd->arrayData()[pidx].uint_32 = static_cast<SparseArrayData *>(dd)->freeList();
}
- dd->freeList = pidx;
- dd->sparse->erase(n);
+ dd->freeList() = pidx;
+ dd->sparse()->erase(n);
return true;
}
void SparseArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs)
{
- SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData);
- SparseArrayNode *n = d->sparse->insert(index);
+ SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayNode *n = d->sparse()->insert(index);
if (n->value == UINT_MAX) {
n->value = allocate(o, attrs.isAccessor());
- d = static_cast<SparseArrayData *>(o->arrayData);
+ d = static_cast<SparseArrayData *>(o->arrayData());
}
- else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) {
+ else if (attrs.isAccessor() != d->attrs()[n->value].isAccessor()) {
// need to convert the slot
free(d, n->value);
n->value = allocate(o, attrs.isAccessor());
}
- o->arrayData->attrs[n->value] = attrs;
+ o->arrayData()->attrs()[n->value] = attrs;
}
PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index)
{
- SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->insert(index);
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse()->insert(index);
if (!n)
return PropertyAttributes();
- return d->attrs[n->value];
+ return d->attrs()[n->value];
}
void SparseArrayData::push_front(Object *o, Value *values, uint n)
{
- Q_ASSERT(!o->arrayData->attrs);
+ Q_ASSERT(!o->arrayData()->attrs());
for (int i = n - 1; i >= 0; --i) {
uint idx = allocate(o);
- o->arrayData->data[idx] = values[i];
- static_cast<SparseArrayData *>(o->arrayData)->sparse->push_front(idx);
+ o->arrayData()->arrayData()[idx] = values[i];
+ static_cast<SparseArrayData *>(o->arrayData())->sparse()->push_front(idx);
}
}
ReturnedValue SparseArrayData::pop_front(Object *o)
{
- Q_ASSERT(!o->arrayData->attrs);
- uint idx = static_cast<SparseArrayData *>(o->arrayData)->sparse->pop_front();
+ Q_ASSERT(!o->arrayData()->attrs());
+ uint idx = static_cast<SparseArrayData *>(o->arrayData())->sparse()->pop_front();
ReturnedValue v;
if (idx != UINT_MAX) {
- v = o->arrayData->data[idx].asReturnedValue();
- free(o->arrayData, idx);
+ v = o->arrayData()->arrayData()[idx].asReturnedValue();
+ free(o->arrayData(), idx);
} else {
v = Encode::undefined();
}
@@ -529,13 +541,13 @@ ReturnedValue SparseArrayData::pop_front(Object *o)
uint SparseArrayData::truncate(Object *o, uint newLen)
{
- SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData);
- SparseArrayNode *begin = d->sparse->lowerBound(newLen);
- if (begin != d->sparse->end()) {
- SparseArrayNode *it = d->sparse->end()->previousNode();
+ SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData());
+ SparseArrayNode *begin = d->sparse()->lowerBound(newLen);
+ if (begin != d->sparse()->end()) {
+ SparseArrayNode *it = d->sparse()->end()->previousNode();
while (1) {
- if (d->attrs) {
- if (!d->attrs[it->value].isConfigurable()) {
+ if (d->attrs()) {
+ if (!d->attrs()[it->value].isConfigurable()) {
newLen = it->key() + 1;
break;
}
@@ -543,7 +555,7 @@ uint SparseArrayData::truncate(Object *o, uint newLen)
free(d, it->value);
bool brk = (it == begin);
SparseArrayNode *prev = it->previousNode();
- static_cast<SparseArrayData *>(d)->sparse->erase(it);
+ static_cast<SparseArrayData *>(d)->sparse()->erase(it);
if (brk)
break;
it = prev;
@@ -555,9 +567,9 @@ uint SparseArrayData::truncate(Object *o, uint newLen)
uint SparseArrayData::length(const ArrayData *d)
{
const SparseArrayData *dd = static_cast<const SparseArrayData *>(d);
- if (!dd->sparse)
+ if (!dd->sparse())
return 0;
- SparseArrayNode *n = dd->sparse->end();
+ SparseArrayNode *n = dd->sparse()->end();
n = n->previousNode();
return n ? n->key() + 1 : 0;
}
@@ -572,12 +584,12 @@ bool SparseArrayData::putArray(Object *o, uint index, Value *values, uint n)
uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
{
- Q_ASSERT(!obj->arrayData->hasAttributes());
+ Q_ASSERT(!obj->arrayData()->hasAttributes());
if (!n)
return obj->getLength();
- const ArrayData *other = otherObj->arrayData;
+ const ArrayData *other = otherObj->arrayData();
if (other->isSparse())
obj->initSparseArray();
@@ -587,21 +599,21 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
uint oldSize = obj->getLength();
if (other->isSparse()) {
- if (otherObj->hasAccessorProperty && other->hasAttributes()) {
+ if (otherObj->hasAccessorProperty() && other->hasAttributes()) {
Scope scope(obj->engine());
ScopedValue v(scope);
- for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
- it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode()) {
- v = otherObj->getValue(reinterpret_cast<Property *>(other->data + it->value), other->attrs[it->value]);
+ for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse()->begin();
+ it != static_cast<const SparseArrayData *>(other)->sparse()->end(); it = it->nextNode()) {
+ v = otherObj->getValue(reinterpret_cast<Property *>(other->arrayData() + it->value), other->attrs()[it->value]);
obj->arraySet(oldSize + it->key(), v);
}
} else {
- for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin();
- it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode())
- obj->arraySet(oldSize + it->key(), ValueRef(other->data[it->value]));
+ for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse()->begin();
+ it != static_cast<const SparseArrayData *>(other)->sparse()->end(); it = it->nextNode())
+ obj->arraySet(oldSize + it->key(), ValueRef(other->arrayData()[it->value]));
}
} else {
- obj->arrayPut(oldSize, other->data, n);
+ obj->arrayPut(oldSize, other->arrayData(), n);
}
return oldSize + n;
@@ -609,42 +621,42 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n)
Property *ArrayData::insert(Object *o, uint index, bool isAccessor)
{
- if (!isAccessor && o->arrayData->type != ArrayData::Sparse) {
- SimpleArrayData *d = static_cast<SimpleArrayData *>(o->arrayData);
- if (index < 0x1000 || index < d->len + (d->len >> 2)) {
- if (index >= o->arrayData->alloc) {
+ if (!isAccessor && o->arrayData()->type() != ArrayData::Sparse) {
+ SimpleArrayData *d = static_cast<SimpleArrayData *>(o->arrayData());
+ if (index < 0x1000 || index < d->len() + (d->len() >> 2)) {
+ if (index >= o->arrayData()->alloc()) {
o->arrayReserve(index + 1);
- d = static_cast<SimpleArrayData *>(o->arrayData);
+ d = static_cast<SimpleArrayData *>(o->arrayData());
}
- if (index >= d->len) {
+ if (index >= d->len()) {
// 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->len(); i < index; ++i)
+ d->arrayData()[i] = Primitive::emptyValue();
+ d->len() = index + 1;
}
- return reinterpret_cast<Property *>(o->arrayData->data + index);
+ return reinterpret_cast<Property *>(o->arrayData()->arrayData() + index);
}
}
o->initSparseArray();
- SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index);
+ SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index);
if (n->value == UINT_MAX)
n->value = SparseArrayData::allocate(o, isAccessor);
- return reinterpret_cast<Property *>(o->arrayData->data + n->value);
+ return reinterpret_cast<Property *>(o->arrayData()->arrayData() + n->value);
}
class ArrayElementLessThan
{
public:
- inline ArrayElementLessThan(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn)
+ inline ArrayElementLessThan(ExecutionContext *context, Object *thisObject, const ValueRef comparefn)
: m_context(context), thisObject(thisObject), m_comparefn(comparefn) {}
bool operator()(const Value &v1, const Value &v2) const;
private:
ExecutionContext *m_context;
- ObjectRef thisObject;
+ Object *thisObject;
const ValueRef m_comparefn;
};
@@ -674,12 +686,12 @@ bool ArrayElementLessThan::operator()(const Value &v1, const Value &v2) const
return p1s->toQString() < p2s->toQString();
}
-void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len)
+void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint len)
{
if (!len)
return;
- if (!thisObject->arrayData->length())
+ if (!thisObject->arrayData()->length())
return;
if (!(comparefn->isUndefined() || comparefn->asObject())) {
@@ -690,50 +702,50 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
// The spec says the sorting goes through a series of get,put and delete operations.
// this implies that the attributes don't get sorted around.
- if (thisObject->arrayData->type == ArrayData::Sparse) {
+ if (thisObject->arrayData()->type() == ArrayData::Sparse) {
// since we sort anyway, we can simply iterate over the entries in the sparse
// array and append them one by one to a regular one.
- SparseArrayData *sparse = static_cast<SparseArrayData *>(thisObject->arrayData);
+ SparseArrayData *sparse = static_cast<SparseArrayData *>(thisObject->arrayData());
- if (!sparse->sparse->nEntries())
+ if (!sparse->sparse()->nEntries())
return;
- thisObject->arrayData = 0;
- ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse->nEntries(), sparse->attrs ? true : false);
- SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData);
+ thisObject->setArrayData(0);
+ ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse()->nEntries(), sparse->attrs() ? true : false);
+ SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData());
- SparseArrayNode *n = sparse->sparse->begin();
+ SparseArrayNode *n = sparse->sparse()->begin();
uint i = 0;
- if (sparse->attrs) {
- while (n != sparse->sparse->end()) {
+ if (sparse->attrs()) {
+ while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- PropertyAttributes a = sparse->attrs ? sparse->attrs[n->value] : Attr_Data;
- d->data[i] = thisObject->getValue(reinterpret_cast<Property *>(sparse->data + n->value), a);
- d->attrs[i] = a.isAccessor() ? Attr_Data : a;
+ PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
+ d->arrayData()[i] = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
+ d->attrs()[i] = a.isAccessor() ? Attr_Data : a;
n = n->nextNode();
++i;
}
} else {
- while (n != sparse->sparse->end()) {
+ while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- d->data[i] = sparse->data[n->value];
+ d->arrayData()[i] = sparse->arrayData()[n->value];
n = n->nextNode();
++i;
}
}
- d->len = i;
+ d->len() = i;
if (len > i)
len = i;
- if (n != sparse->sparse->end()) {
+ if (n != sparse->sparse()->end()) {
// have some entries outside the sort range that we need to ignore when sorting
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->data + n->value), a);
+ 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);
n = n->nextNode();
}
@@ -741,19 +753,19 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
}
// ### explicitly delete sparse
} else {
- SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData);
- if (len > d->len)
- len = d->len;
+ SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData());
+ if (len > d->len())
+ len = d->len();
// sort empty values to the end
for (uint i = 0; i < len; i++) {
- if (thisObject->arrayData->data[i].isEmpty()) {
+ if (thisObject->arrayData()->arrayData()[i].isEmpty()) {
while (--len > i)
- if (!thisObject->arrayData->data[len].isEmpty())
+ if (!thisObject->arrayData()->arrayData()[len].isEmpty())
break;
- Q_ASSERT(!thisObject->arrayData->attrs || !thisObject->arrayData->attrs[len].isAccessor());
- thisObject->arrayData->data[i] = thisObject->arrayData->data[len];
- thisObject->arrayData->data[len] = Primitive::emptyValue();
+ Q_ASSERT(!thisObject->arrayData()->attrs() || !thisObject->arrayData()->attrs()[len].isAccessor());
+ thisObject->arrayData()->arrayData()[i] = thisObject->arrayData()->arrayData()[len];
+ thisObject->arrayData()->arrayData()[len] = Primitive::emptyValue();
}
}
@@ -764,7 +776,7 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu
ArrayElementLessThan lessThan(context, thisObject, comparefn);
- Value *begin = thisObject->arrayData->data;
+ Value *begin = thisObject->arrayData()->arrayData();
std::sort(begin, begin + len, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 50b7b8a947..aab9157ced 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -57,6 +57,10 @@ namespace QV4 {
static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \
template <typename T> \
QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \
+ V4_MANAGED_SIZE_TEST \
+ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \
+ Data *d() { return &static_cast<Data &>(Managed::data); }
+
struct ArrayData;
@@ -80,11 +84,6 @@ struct ArrayVTable
struct Q_QML_EXPORT ArrayData : public Managed
{
- ArrayData(InternalClass *ic)
- : Managed(ic)
- {
- }
-
enum Type {
Simple = 0,
Complex = 1,
@@ -92,13 +91,30 @@ struct Q_QML_EXPORT ArrayData : public Managed
Custom = 3
};
- uint alloc;
- Type type;
- PropertyAttributes *attrs;
- Value *data;
-
- const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); }
- bool isSparse() const { return this && type == Sparse; }
+ struct Data : public Managed::Data {
+ Data(InternalClass *ic)
+ : Managed::Data(ic)
+ {}
+ uint alloc;
+ Type type;
+ PropertyAttributes *attrs;
+ Value *arrayData;
+ };
+ V4_MANAGED(Managed)
+
+ uint alloc() const { return d()->alloc; }
+ uint &alloc() { return d()->alloc; }
+ void setAlloc(uint a) { d()->alloc = a; }
+ Type type() const { return d()->type; }
+ void setType(Type t) { d()->type = t; }
+ PropertyAttributes *attrs() const { return d()->attrs; }
+ void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
+ Value *arrayData() const { return d()->arrayData; }
+ Value *&arrayData() { return d()->arrayData; }
+ void setArrayData(Value *v) { d()->arrayData = v; }
+
+ const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass()->vtable); }
+ bool isSparse() const { return this && type() == Sparse; }
uint length() const {
if (!this)
@@ -107,11 +123,11 @@ struct Q_QML_EXPORT ArrayData : public Managed
}
bool hasAttributes() const {
- return this && attrs;
+ return this && attrs();
}
PropertyAttributes attributes(int i) const {
Q_ASSERT(this);
- return attrs ? vtable()->attribute(this, i) : Attr_Data;
+ return attrs() ? vtable()->attribute(this, i) : Attr_Data;
}
bool isEmpty(uint i) const {
@@ -130,26 +146,31 @@ struct Q_QML_EXPORT ArrayData : public Managed
static void ensureAttributes(Object *o);
static void realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes);
- static void sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint dataLen);
+ static void sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint dataLen);
static uint append(Object *obj, const ArrayObject *otherObj, uint n);
static Property *insert(Object *o, uint index, bool isAccessor = false);
};
struct Q_QML_EXPORT SimpleArrayData : public ArrayData
{
- V4_ARRAYDATA
- SimpleArrayData(ExecutionEngine *engine)
- : ArrayData(engine->simpleArrayDataClass)
- {}
+ struct Data : public ArrayData::Data {
+ Data(ExecutionEngine *engine)
+ : ArrayData::Data(engine->simpleArrayDataClass)
+ {}
+ uint len;
+ uint offset;
+ };
+ V4_ARRAYDATA
- uint len;
- uint offset;
+ uint &len() { return d()->len; }
+ uint len() const { return d()->len; }
+ uint &offset() { return d()->offset; }
+ uint offset() const { return d()->offset; }
static void getHeadRoom(Object *o);
static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
- static void destroy(Managed *d);
static void markObjects(Managed *d, ExecutionEngine *e);
static ReturnedValue get(const ArrayData *d, uint index);
@@ -166,14 +187,20 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
struct Q_QML_EXPORT SparseArrayData : public ArrayData
{
- V4_ARRAYDATA
+ struct Data : public ArrayData::Data {
+ Data(ExecutionEngine *engine)
+ : ArrayData::Data(engine->emptyClass)
+ { setVTable(staticVTable()); }
- SparseArrayData(ExecutionEngine *engine)
- : ArrayData(engine->emptyClass)
- { setVTable(staticVTable()); }
+ uint freeList;
+ SparseArray *sparse;
+ };
+ V4_ARRAYDATA
- uint freeList;
- SparseArray *sparse;
+ uint &freeList() { return d()->freeList; }
+ uint freeList() const { return d()->freeList; }
+ SparseArray *sparse() const { return d()->sparse; }
+ void setSparse(SparseArray *s) { d()->sparse = s; }
static uint allocate(Object *o, bool doubleSlot = false);
static void free(ArrayData *d, uint idx);
@@ -199,16 +226,16 @@ inline Property *ArrayData::getProperty(uint index) const
{
if (!this)
return 0;
- if (type != Sparse) {
+ if (type() != Sparse) {
const SimpleArrayData *that = static_cast<const SimpleArrayData *>(this);
- if (index >= that->len || data[index].isEmpty())
+ if (index >= that->len() || arrayData()[index].isEmpty())
return 0;
- return reinterpret_cast<Property *>(data + index);
+ return reinterpret_cast<Property *>(arrayData() + index);
} else {
- SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse->findNode(index);
+ SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse()->findNode(index);
if (!n)
return 0;
- return reinterpret_cast<Property *>(data + n->value);
+ return reinterpret_cast<Property *>(arrayData() + n->value);
}
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index fbd757a829..abe8a44065 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -48,8 +48,8 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArrayCtor);
-ArrayCtor::ArrayCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Array"))
+ArrayCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Array"))
{
setVTable(staticVTable());
}
@@ -84,12 +84,7 @@ ReturnedValue ArrayCtor::call(Managed *that, CallData *callData)
return construct(that, callData);
}
-ArrayPrototype::ArrayPrototype(InternalClass *ic)
- : ArrayObject(ic)
-{
-}
-
-void ArrayPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -122,21 +117,21 @@ void ArrayPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx)
{
- bool isArray = ctx->callData->argc && ctx->callData->args[0].asArrayObject();
+ bool isArray = ctx->d()->callData->argc && ctx->d()->callData->args[0].asArrayObject();
return Encode(isArray);
}
ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject o(scope, ctx->callData->thisObject, ScopedObject::Convert);
- if (ctx->engine->hasException)
+ ScopedObject o(scope, ctx->d()->callData->thisObject, ScopedObject::Convert);
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
- ScopedString s(scope, ctx->engine->newString(QStringLiteral("join")));
- ScopedFunctionObject f(scope, o->get(s));
+ ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join")));
+ ScopedFunctionObject f(scope, o->get(s.getPointer()));
if (!!f) {
ScopedCallData d(scope, 0);
- d->thisObject = ctx->callData->thisObject;
+ d->thisObject = ctx->d()->callData->thisObject;
return f->call(d);
}
return ObjectPrototype::method_toString(ctx);
@@ -150,9 +145,9 @@ ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx)
ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject result(scope, ctx->engine->newArrayObject());
+ ScopedObject result(scope, ctx->d()->engine->newArrayObject());
- ScopedObject thisObject(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject thisObject(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!thisObject)
return Encode::undefined();
ScopedArrayObject instance(scope, thisObject);
@@ -165,9 +160,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
ScopedArrayObject elt(scope);
ScopedObject eltAsObj(scope);
ScopedValue entry(scope);
- for (int i = 0; i < ctx->callData->argc; ++i) {
- eltAsObj = ctx->callData->args[i];
- elt = ctx->callData->args[i];
+ for (int i = 0; i < ctx->d()->callData->argc; ++i) {
+ eltAsObj = ctx->d()->callData->args[i];
+ elt = ctx->d()->callData->args[i];
if (elt) {
uint n = elt->getLength();
uint newLen = ArrayData::append(result.getPointer(), elt.getPointer(), n);
@@ -179,7 +174,7 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
result->putIndexed(startIndex + i, entry);
}
} else {
- result->arraySet(result->getLength(), ValueRef(ctx->callData->args[i]));
+ result->arraySet(result->getLength(), ValueRef(ctx->d()->callData->args[i]));
}
}
@@ -197,12 +192,12 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
else
r4 = arg->toQString();
- ScopedObject self(scope, ctx->callData->thisObject);
- ScopedValue length(scope, self->get(ctx->engine->id_length));
+ ScopedObject self(scope, ctx->d()->callData->thisObject);
+ ScopedValue length(scope, self->get(ctx->d()->engine->id_length));
const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
if (!r2)
- return ctx->engine->newString(QString())->asReturnedValue();
+ return ctx->d()->engine->newString(QString())->asReturnedValue();
QString R;
@@ -223,8 +218,8 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
//
// crazy!
//
- ScopedString name(scope, ctx->engine->newString(QStringLiteral("0")));
- ScopedValue r6(scope, self->get(name));
+ ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0")));
+ ScopedValue r6(scope, self->get(name.getPointer()));
if (!r6->isNullOrUndefined())
R = r6->toString(ctx)->toQString();
@@ -233,7 +228,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
R += r4;
name = Primitive::fromDouble(k).toString(ctx);
- r12 = self->get(name);
+ r12 = self->get(name.getPointer());
if (scope.hasException())
return Encode::undefined();
@@ -242,20 +237,20 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
}
}
- return ctx->engine->newString(R)->asReturnedValue();
+ return ctx->d()->engine->newString(R)->asReturnedValue();
}
ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
uint len = instance->getLength();
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0)));
return Encode::undefined();
}
@@ -269,14 +264,14 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
if (instance->isArrayObject())
instance->setArrayLength(len - 1);
else
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1)));
return result.asReturnedValue();
}
ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -284,38 +279,38 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
uint len = instance->getLength();
- if (len + ctx->callData->argc < len) {
+ if (len + ctx->d()->callData->argc < len) {
// ughh...
double l = len;
ScopedString s(scope);
- for (int i = 0; i < ctx->callData->argc; ++i) {
+ for (int i = 0; i < ctx->d()->callData->argc; ++i) {
s = Primitive::fromDouble(l + i).toString(ctx);
- instance->put(s, ctx->callData->args[i]);
+ instance->put(s.getPointer(), ctx->d()->callData->args[i]);
}
- double newLen = l + ctx->callData->argc;
+ double newLen = l + ctx->d()->callData->argc;
if (!instance->isArrayObject())
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen)));
else {
- ScopedString str(scope, ctx->engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
+ ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
return ctx->throwRangeError(str);
}
return Encode(newLen);
}
- if (!ctx->callData->argc) {
+ if (!ctx->d()->callData->argc) {
;
- } else if (!instance->protoHasArray() && instance->arrayData->length() <= len && instance->arrayType() == ArrayData::Simple) {
- instance->arrayData->vtable()->putArray(instance.getPointer(), len, ctx->callData->args, ctx->callData->argc);
- len = instance->arrayData->length();
+ } else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayType() == ArrayData::Simple) {
+ instance->arrayData()->vtable()->putArray(instance.getPointer(), len, ctx->d()->callData->args, ctx->d()->callData->argc);
+ len = instance->arrayData()->length();
} else {
- for (int i = 0; i < ctx->callData->argc; ++i)
- instance->putIndexed(len + i, ctx->callData->args[i]);
- len += ctx->callData->argc;
+ for (int i = 0; i < ctx->d()->callData->argc; ++i)
+ instance->putIndexed(len + i, ctx->d()->callData->args[i]);
+ len += ctx->d()->callData->argc;
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len);
else
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len)));
return Encode(len);
}
@@ -323,7 +318,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
uint length = instance->getLength();
@@ -355,7 +350,7 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -365,14 +360,14 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0)));
return Encode::undefined();
}
ScopedValue result(scope);
- if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len && instance->arrayData->type != ArrayData::Custom) {
- result = instance->arrayData->vtable()->pop_front(instance.getPointer());
+ if (!instance->protoHasArray() && !instance->arrayData()->hasAttributes() && instance->arrayData()->length() <= len && instance->arrayData()->type() != ArrayData::Custom) {
+ result = instance->arrayData()->vtable()->pop_front(instance.getPointer());
} else {
result = instance->getIndexed(0);
if (scope.hasException())
@@ -399,18 +394,18 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len - 1);
else
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1)));
return result.asReturnedValue();
}
ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject o(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!o)
return Encode::undefined();
- Scoped<ArrayObject> result(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> result(scope, ctx->d()->engine->newArrayObject());
uint len = o->getLength();
double s = ScopedValue(scope, ctx->argument(0))->toInteger();
uint start;
@@ -421,8 +416,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
else
start = (uint) s;
uint end = len;
- if (ctx->callData->argc > 1 && !ctx->callData->args[1].isUndefined()) {
- double e = ctx->callData->args[1].toInteger();
+ if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isUndefined()) {
+ double e = ctx->d()->callData->args[1].toInteger();
if (e < 0)
end = (uint)qMax(len + e, 0.);
else if (e > len)
@@ -448,7 +443,7 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -456,18 +451,18 @@ ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
ScopedValue comparefn(scope, ctx->argument(0));
ArrayData::sort(ctx, instance, comparefn, len);
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
uint len = instance->getLength();
- Scoped<ArrayObject> newArray(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> newArray(scope, ctx->d()->engine->newArrayObject());
double rs = ScopedValue(scope, ctx->argument(0))->toInteger();
uint start;
@@ -490,7 +485,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = ctx->callData->argc < 2 ? 0 : ctx->callData->argc - 2;
+ uint itemCount = ctx->d()->callData->argc < 2 ? 0 : ctx->d()->callData->argc - 2;
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
@@ -528,13 +523,13 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
}
for (uint i = 0; i < itemCount; ++i) {
- instance->putIndexed(start + i, ctx->callData->args[i + 2]);
+ instance->putIndexed(start + i, ctx->d()->callData->args[i + 2]);
if (scope.hasException())
return Encode::undefined();
}
- ctx->strictMode = true;
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
+ ctx->d()->strictMode = true;
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
return newArray.asReturnedValue();
}
@@ -542,7 +537,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -550,27 +545,27 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
uint len = instance->getLength();
- if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len && instance->arrayData->type != ArrayData::Custom) {
- instance->arrayData->vtable()->push_front(instance.getPointer(), ctx->callData->args, ctx->callData->argc);
+ if (!instance->protoHasArray() && !instance->arrayData()->hasAttributes() && instance->arrayData()->length() <= len && instance->arrayData()->type() != ArrayData::Custom) {
+ instance->arrayData()->vtable()->push_front(instance.getPointer(), ctx->d()->callData->args, ctx->d()->callData->argc);
} else {
ScopedValue v(scope);
for (uint k = len; k > 0; --k) {
bool exists;
v = instance->getIndexed(k - 1, &exists);
if (exists)
- instance->putIndexed(k + ctx->callData->argc - 1, v);
+ instance->putIndexed(k + ctx->d()->callData->argc - 1, v);
else
- instance->deleteIndexedProperty(k + ctx->callData->argc - 1);
+ instance->deleteIndexedProperty(k + ctx->d()->callData->argc - 1);
}
- for (int i = 0; i < ctx->callData->argc; ++i)
- instance->putIndexed(i, ctx->callData->args[i]);
+ for (int i = 0; i < ctx->d()->callData->argc; ++i)
+ instance->putIndexed(i, ctx->d()->callData->args[i]);
}
- uint newLen = len + ctx->callData->argc;
+ uint newLen = len + ctx->d()->callData->argc;
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(newLen);
else
- instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen)));
return Encode(newLen);
}
@@ -579,18 +574,18 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
uint len = instance->getLength();
if (!len)
return Encode(-1);
- ScopedValue searchValue(scope, ctx->callData->argument(0));
+ ScopedValue searchValue(scope, ctx->d()->callData->argument(0));
uint fromIndex = 0;
- if (ctx->callData->argc >= 2) {
- double f = ctx->callData->args[1].toInteger();
+ if (ctx->d()->callData->argc >= 2) {
+ double f = ctx->d()->callData->args[1].toInteger();
if (scope.hasException())
return Encode::undefined();
if (f >= len)
@@ -613,7 +608,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
ScopedValue value(scope);
- if (instance->hasAccessorProperty || (instance->arrayType() >= ArrayData::Sparse) || instance->protoHasArray()) {
+ if (instance->hasAccessorProperty() || (instance->arrayType() >= ArrayData::Sparse) || instance->protoHasArray()) {
// lets be safe and slow
for (uint i = fromIndex; i < len; ++i) {
bool exists;
@@ -623,13 +618,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
if (exists && RuntimeHelpers::strictEqual(value, searchValue))
return Encode(i);
}
- } else if (!instance->arrayData) {
+ } else if (!instance->arrayData()) {
return Encode(-1);
} else {
Q_ASSERT(instance->arrayType() == ArrayData::Simple || instance->arrayType() == ArrayData::Complex);
- if (len > instance->arrayData->length())
- len = instance->arrayData->length();
- Value *val = instance->arrayData->data;
+ if (len > instance->arrayData()->length())
+ len = instance->arrayData()->length();
+ Value *val = instance->arrayData()->arrayData();
Value *end = val + len;
val += fromIndex;
while (val < end) {
@@ -638,7 +633,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
if (scope.hasException())
return Encode::undefined();
if (RuntimeHelpers::strictEqual(value, searchValue))
- return Encode((uint)(val - instance->arrayData->data));
+ return Encode((uint)(val - instance->arrayData()->arrayData()));
}
++val;
}
@@ -650,7 +645,7 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
uint len = instance->getLength();
@@ -660,13 +655,13 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
ScopedValue searchValue(scope);
uint fromIndex = len;
- if (ctx->callData->argc >= 1)
+ if (ctx->d()->callData->argc >= 1)
searchValue = ctx->argument(0);
else
searchValue = Primitive::undefinedValue();
- if (ctx->callData->argc >= 2) {
- double f = ctx->callData->args[1].toInteger();
+ if (ctx->d()->callData->argc >= 2) {
+ double f = ctx->d()->callData->args[1].toInteger();
if (scope.hasException())
return Encode::undefined();
if (f > 0)
@@ -695,7 +690,7 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -729,7 +724,7 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -763,7 +758,7 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -794,7 +789,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -804,7 +799,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
if (!callback)
return ctx->throwTypeError();
- Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject());
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
@@ -831,7 +826,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -841,7 +836,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
if (!callback)
return ctx->throwTypeError();
- Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject());
a->arrayReserve(len);
ScopedValue selected(scope);
@@ -872,7 +867,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -886,7 +881,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
ScopedValue acc(scope);
ScopedValue v(scope);
- if (ctx->callData->argc > 1) {
+ if (ctx->d()->callData->argc > 1) {
acc = ctx->argument(1);
} else {
bool kPresent = false;
@@ -922,7 +917,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx));
+ Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!instance)
return Encode::undefined();
@@ -933,7 +928,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
return ctx->throwTypeError();
if (len == 0) {
- if (ctx->callData->argc == 1)
+ if (ctx->d()->callData->argc == 1)
return ctx->throwTypeError();
return ctx->argument(1);
}
@@ -941,7 +936,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
uint k = len;
ScopedValue acc(scope);
ScopedValue v(scope);
- if (ctx->callData->argc > 1) {
+ if (ctx->d()->callData->argc > 1) {
acc = ctx->argument(1);
} else {
bool kPresent = false;
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index e7f8ba711f..dccda2896e 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -51,8 +51,11 @@ namespace QV4 {
struct ArrayCtor: FunctionObject
{
- V4_OBJECT
- ArrayCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *m, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -60,9 +63,7 @@ struct ArrayCtor: FunctionObject
struct ArrayPrototype: ArrayObject
{
- ArrayPrototype(InternalClass *ic);
-
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_isArray(CallContext *ctx);
static ReturnedValue method_toString(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 662ec64efb..38a0f7f549 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -46,8 +46,8 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(BooleanCtor);
DEFINE_OBJECT_VTABLE(BooleanObject);
-BooleanCtor::BooleanCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Boolean"))
+BooleanCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Boolean"))
{
setVTable(staticVTable());
}
@@ -66,7 +66,7 @@ ReturnedValue BooleanCtor::call(Managed *, CallData *callData)
return Encode(value);
}
-void BooleanPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -80,28 +80,28 @@ void BooleanPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
ReturnedValue BooleanPrototype::method_toString(CallContext *ctx)
{
bool result;
- if (ctx->callData->thisObject.isBoolean()) {
- result = ctx->callData->thisObject.booleanValue();
+ if (ctx->d()->callData->thisObject.isBoolean()) {
+ result = ctx->d()->callData->thisObject.booleanValue();
} else {
Scope scope(ctx);
- Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject);
+ Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject);
if (!thisObject)
return ctx->throwTypeError();
- result = thisObject->value.booleanValue();
+ result = thisObject->value().booleanValue();
}
- return Encode(ctx->engine->newString(QLatin1String(result ? "true" : "false")));
+ return Encode(ctx->d()->engine->newString(QLatin1String(result ? "true" : "false")));
}
ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx)
{
- if (ctx->callData->thisObject.isBoolean())
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->thisObject.isBoolean())
+ return ctx->d()->callData->thisObject.asReturnedValue();
Scope scope(ctx);
- Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject);
+ Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject);
if (!thisObject)
return ctx->throwTypeError();
- return thisObject->value.asReturnedValue();
+ return thisObject->value().asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 617f7f6b01..35cfd5729e 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -51,8 +51,11 @@ namespace QV4 {
struct BooleanCtor: FunctionObject
{
- V4_OBJECT
- BooleanCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -60,8 +63,7 @@ struct BooleanCtor: FunctionObject
struct BooleanPrototype: BooleanObject
{
- BooleanPrototype(InternalClass *ic): BooleanObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_valueOf(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index b43b4893a3..62d5859e87 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -52,27 +52,30 @@
using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
+DEFINE_MANAGED_VTABLE(CallContext);
+DEFINE_MANAGED_VTABLE(WithContext);
+DEFINE_MANAGED_VTABLE(GlobalContext);
-CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
+HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
{
- Q_ASSERT(function->function);
+ Q_ASSERT(function->function());
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
- new (c) CallContext(engine, Type_CallContext);
+ CallContext::Data *c = reinterpret_cast<CallContext::Data *>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
+ new (c) CallContext::Data(d()->engine, Type_CallContext);
c->function = function;
c->realArgumentCount = callData->argc;
- c->strictMode = function->strictMode;
- c->outer = function->scope;
+ c->strictMode = function->strictMode();
+ c->outer = function->scope();
c->activation = 0;
- c->compilationUnit = function->function->compilationUnit;
+ c->compilationUnit = function->function()->compilationUnit;
c->lookups = c->compilationUnit->runtimeLookups;
c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
- const CompiledData::Function *compiledFunction = function->function->compiledFunction;
+ const CompiledData::Function *compiledFunction = function->function()->compiledFunction;
int nLocals = compiledFunction->nLocals;
if (nLocals)
std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue());
@@ -86,43 +89,41 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
return c;
}
-WithContext *ExecutionContext::newWithContext(ObjectRef with)
+WithContext *ExecutionContext::newWithContext(Object *with)
{
- WithContext *w = new (engine->memoryManager) WithContext(engine, with);
- return w;
+ return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with);
}
-CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue)
+CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue)
{
- CatchContext *c = new (engine->memoryManager) CatchContext(engine, exceptionVarName, exceptionValue);
- return c;
+ return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue);
}
-CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml)
+CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
- new (c) CallContext(engine, qml, f);
+ CallContext *c = reinterpret_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
+ new (c->d()) CallContext::Data(d()->engine, qml, f);
return c;
}
-void ExecutionContext::createMutableBinding(const StringRef name, bool deletable)
+void ExecutionContext::createMutableBinding(String *name, bool deletable)
{
Scope scope(this);
// find the right context to create the binding on
- ScopedObject activation(scope, engine->globalObject);
+ ScopedObject activation(scope, d()->engine->globalObject);
ExecutionContext *ctx = this;
while (ctx) {
- if (ctx->type >= Type_CallContext) {
+ if (ctx->d()->type >= Type_CallContext) {
CallContext *c = static_cast<CallContext *>(ctx);
- if (!c->activation)
- c->activation = engine->newObject()->getPointer();
- activation = c->activation;
+ if (!c->d()->activation)
+ c->d()->activation = d()->engine->newObject()->getPointer();
+ activation = c->d()->activation;
break;
}
- ctx = ctx->outer;
+ ctx = ctx->d()->outer;
}
if (activation->hasProperty(name))
@@ -134,38 +135,38 @@ void ExecutionContext::createMutableBinding(const StringRef name, bool deletable
}
-GlobalContext::GlobalContext(ExecutionEngine *eng)
- : ExecutionContext(eng, Type_GlobalContext)
+GlobalContext::Data::Data(ExecutionEngine *eng)
+ : ExecutionContext::Data(eng, Type_GlobalContext)
{
global = eng->globalObject;
}
-WithContext::WithContext(ExecutionEngine *engine, ObjectRef with)
- : ExecutionContext(engine, Type_WithContext)
+WithContext::Data::Data(ExecutionEngine *engine, Object *with)
+ : ExecutionContext::Data(engine, Type_WithContext)
{
- callData = parent->callData;
+ callData = parent->d()->callData;
outer = parent;
- lookups = parent->lookups;
- compilationUnit = parent->compilationUnit;
+ lookups = parent->d()->lookups;
+ compilationUnit = parent->d()->compilationUnit;
- withObject = with.getPointer();
+ withObject = with;
}
-CatchContext::CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue)
- : ExecutionContext(engine, Type_CatchContext)
+CatchContext::Data::Data(ExecutionEngine *engine, String *exceptionVarName, const ValueRef exceptionValue)
+ : ExecutionContext::Data(engine, Type_CatchContext)
{
- strictMode = parent->strictMode;
- callData = parent->callData;
+ strictMode = parent->d()->strictMode;
+ callData = parent->d()->callData;
outer = parent;
- lookups = parent->lookups;
- compilationUnit = parent->compilationUnit;
+ lookups = parent->d()->lookups;
+ compilationUnit = parent->d()->compilationUnit;
this->exceptionVarName = exceptionVarName;
this->exceptionValue = exceptionValue;
}
-CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject *function)
- : ExecutionContext(engine, Type_QmlContext)
+CallContext::Data::Data(ExecutionEngine *engine, Object *qml, FunctionObject *function)
+ : ExecutionContext::Data(engine, Type_QmlContext)
{
this->function = function;
callData = reinterpret_cast<CallData *>(this + 1);
@@ -174,12 +175,12 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject
callData->thisObject = Primitive::undefinedValue();
strictMode = true;
- outer = function->scope;
+ outer = function->scope();
- activation = qml.getPointer();
+ activation = qml;
- if (function->function) {
- compilationUnit = function->function->compilationUnit;
+ if (function->function()) {
+ compilationUnit = function->function()->compilationUnit;
lookups = compilationUnit->runtimeLookups;
}
@@ -190,170 +191,170 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject
String * const *CallContext::formals() const
{
- return (function && function->function) ? function->function->internalClass->nameMap.constData() : 0;
+ return (d()->function && d()->function->function()) ? d()->function->function()->internalClass->nameMap.constData() : 0;
}
unsigned int CallContext::formalCount() const
{
- return function ? function->formalParameterCount() : 0;
+ return d()->function ? d()->function->formalParameterCount() : 0;
}
String * const *CallContext::variables() const
{
- return (function && function->function) ? function->function->internalClass->nameMap.constData() + function->function->compiledFunction->nFormals : 0;
+ return (d()->function && d()->function->function()) ? d()->function->function()->internalClass->nameMap.constData() + d()->function->function()->compiledFunction->nFormals : 0;
}
unsigned int CallContext::variableCount() const
{
- return function ? function->varCount() : 0;
+ return d()->function ? d()->function->varCount() : 0;
}
-bool ExecutionContext::deleteProperty(const StringRef name)
+bool ExecutionContext::deleteProperty(String *name)
{
Scope scope(this);
bool hasWith = false;
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) {
+ if (ctx->d()->type == Type_WithContext) {
hasWith = true;
WithContext *w = static_cast<WithContext *>(ctx);
- if (w->withObject->hasProperty(name))
- return w->withObject->deleteProperty(name);
- } else if (ctx->type == Type_CatchContext) {
+ if (w->d()->withObject->hasProperty(name))
+ return w->d()->withObject->deleteProperty(name);
+ } else if (ctx->d()->type == Type_CatchContext) {
CatchContext *c = static_cast<CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name))
+ if (c->d()->exceptionVarName->isEqualTo(name))
return false;
- } else if (ctx->type >= Type_CallContext) {
+ } else if (ctx->d()->type >= Type_CallContext) {
CallContext *c = static_cast<CallContext *>(ctx);
- FunctionObject *f = c->function;
- if (f->needsActivation || hasWith) {
- uint index = f->function->internalClass->find(name);
+ FunctionObject *f = c->d()->function;
+ if (f->needsActivation() || hasWith) {
+ uint index = f->function()->internalClass->find(name);
if (index < UINT_MAX)
// ### throw in strict mode?
return false;
}
- if (c->activation && c->activation->hasProperty(name))
- return c->activation->deleteProperty(name);
- } else if (ctx->type == Type_GlobalContext) {
+ if (c->d()->activation && c->d()->activation->hasProperty(name))
+ return c->d()->activation->deleteProperty(name);
+ } else if (ctx->d()->type == Type_GlobalContext) {
GlobalContext *g = static_cast<GlobalContext *>(ctx);
- if (g->global->hasProperty(name))
- return g->global->deleteProperty(name);
+ if (g->d()->global->hasProperty(name))
+ return g->d()->global->deleteProperty(name);
}
}
- if (strictMode)
+ if (d()->strictMode)
throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString()));
return true;
}
bool CallContext::needsOwnArguments() const
{
- return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount());
+ return d()->function->needsActivation() || d()->callData->argc < static_cast<int>(d()->function->formalParameterCount());
}
void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine)
{
ExecutionContext *ctx = static_cast<ExecutionContext *>(m);
- if (ctx->outer)
- ctx->outer->mark(engine);
+ if (ctx->d()->outer)
+ ctx->d()->outer->mark(engine);
// ### shouldn't need these 3 lines
- ctx->callData->thisObject.mark(engine);
- for (int arg = 0; arg < ctx->callData->argc; ++arg)
- ctx->callData->args[arg].mark(engine);
+ ctx->d()->callData->thisObject.mark(engine);
+ for (int arg = 0; arg < ctx->d()->callData->argc; ++arg)
+ ctx->d()->callData->args[arg].mark(engine);
- if (ctx->type >= Type_CallContext) {
+ if (ctx->d()->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
- for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local)
- c->locals[local].mark(engine);
- if (c->activation)
- c->activation->mark(engine);
- c->function->mark(engine);
- } else if (ctx->type == Type_WithContext) {
+ for (unsigned local = 0, lastLocal = c->d()->function->varCount(); local < lastLocal; ++local)
+ c->d()->locals[local].mark(engine);
+ if (c->d()->activation)
+ c->d()->activation->mark(engine);
+ c->d()->function->mark(engine);
+ } else if (ctx->d()->type == Type_WithContext) {
WithContext *w = static_cast<WithContext *>(ctx);
- w->withObject->mark(engine);
- } else if (ctx->type == Type_CatchContext) {
+ w->d()->withObject->mark(engine);
+ } else if (ctx->d()->type == Type_CatchContext) {
CatchContext *c = static_cast<CatchContext *>(ctx);
- c->exceptionVarName->mark(engine);
- c->exceptionValue.mark(engine);
- } else if (ctx->type == Type_GlobalContext) {
+ c->d()->exceptionVarName->mark(engine);
+ c->d()->exceptionValue.mark(engine);
+ } else if (ctx->d()->type == Type_GlobalContext) {
GlobalContext *g = static_cast<GlobalContext *>(ctx);
- g->global->mark(engine);
+ g->d()->global->mark(engine);
}
}
-void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
+void ExecutionContext::setProperty(String *name, const ValueRef value)
{
Scope scope(this);
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
- ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject);
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) {
+ if (ctx->d()->type == Type_WithContext) {
+ ScopedObject w(scope, static_cast<WithContext *>(ctx)->d()->withObject);
if (w->hasProperty(name)) {
w->put(name, value);
return;
}
- } else if (ctx->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->exceptionVarName->isEqualTo(name)) {
- static_cast<CatchContext *>(ctx)->exceptionValue = *value;
+ } else if (ctx->d()->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->d()->exceptionVarName->isEqualTo(name)) {
+ static_cast<CatchContext *>(ctx)->d()->exceptionValue = *value;
return;
} else {
ScopedObject activation(scope, (Object *)0);
- if (ctx->type >= Type_CallContext) {
+ if (ctx->d()->type >= Type_CallContext) {
CallContext *c = static_cast<CallContext *>(ctx);
- if (c->function->function) {
- uint index = c->function->function->internalClass->find(name);
+ if (c->d()->function->function()) {
+ uint index = c->d()->function->function()->internalClass->find(name);
if (index < UINT_MAX) {
- if (index < c->function->formalParameterCount()) {
- c->callData->args[c->function->formalParameterCount() - index - 1] = *value;
+ if (index < c->d()->function->formalParameterCount()) {
+ c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1] = *value;
} else {
- index -= c->function->formalParameterCount();
- c->locals[index] = *value;
+ index -= c->d()->function->formalParameterCount();
+ c->d()->locals[index] = *value;
}
return;
}
}
- activation = c->activation;
- } else if (ctx->type == Type_GlobalContext) {
- activation = static_cast<GlobalContext *>(ctx)->global;
+ activation = c->d()->activation;
+ } else if (ctx->d()->type == Type_GlobalContext) {
+ activation = static_cast<GlobalContext *>(ctx)->d()->global;
}
if (activation) {
- if (ctx->type == Type_QmlContext) {
+ if (ctx->d()->type == Type_QmlContext) {
activation->put(name, value);
return;
} else {
- uint member = activation->internalClass->find(name);
+ uint member = activation->internalClass()->find(name);
if (member < UINT_MAX) {
- activation->putValue(activation->propertyAt(member), activation->internalClass->propertyData[member], value);
+ activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value);
return;
}
}
}
}
}
- if (strictMode || name->equals(engine->id_this)) {
- ScopedValue n(scope, name.asReturnedValue());
+ if (d()->strictMode || name->equals(d()->engine->id_this.getPointer())) {
+ ScopedValue n(scope, name->asReturnedValue());
throwReferenceError(n);
return;
}
- engine->globalObject->put(name, value);
+ d()->engine->globalObject->put(name, value);
}
-ReturnedValue ExecutionContext::getProperty(const StringRef name)
+ReturnedValue ExecutionContext::getProperty(String *name)
{
Scope scope(this);
ScopedValue v(scope);
name->makeIdentifier();
- if (name->equals(engine->id_this))
- return callData->thisObject.asReturnedValue();
+ if (name->equals(d()->engine->id_this.getPointer()))
+ return d()->callData->thisObject.asReturnedValue();
bool hasWith = false;
bool hasCatchScope = false;
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
- ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject);
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) {
+ if (ctx->d()->type == Type_WithContext) {
+ ScopedObject w(scope, static_cast<WithContext *>(ctx)->d()->withObject);
hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
@@ -363,62 +364,62 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name)
continue;
}
- else if (ctx->type == Type_CatchContext) {
+ else if (ctx->d()->type == Type_CatchContext) {
hasCatchScope = true;
CatchContext *c = static_cast<CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name))
- return c->exceptionValue.asReturnedValue();
+ if (c->d()->exceptionVarName->isEqualTo(name))
+ return c->d()->exceptionValue.asReturnedValue();
}
- else if (ctx->type >= Type_CallContext) {
+ else if (ctx->d()->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
- ScopedFunctionObject f(scope, c->function);
- if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
- uint index = f->function->internalClass->find(name);
+ ScopedFunctionObject f(scope, c->d()->function);
+ if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) {
+ uint index = f->function()->internalClass->find(name);
if (index < UINT_MAX) {
- if (index < c->function->formalParameterCount())
- return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue();
- return c->locals[index - c->function->formalParameterCount()].asReturnedValue();
+ if (index < c->d()->function->formalParameterCount())
+ return c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1].asReturnedValue();
+ return c->d()->locals[index - c->d()->function->formalParameterCount()].asReturnedValue();
}
}
- if (c->activation) {
+ if (c->d()->activation) {
bool hasProperty = false;
- v = c->activation->get(name, &hasProperty);
+ v = c->d()->activation->get(name, &hasProperty);
if (hasProperty)
return v.asReturnedValue();
}
- if (f->function && f->function->isNamedExpression()
- && name->equals(f->function->name()))
+ if (f->function() && f->function()->isNamedExpression()
+ && name->equals(f->function()->name()))
return f.asReturnedValue();
}
- else if (ctx->type == Type_GlobalContext) {
+ else if (ctx->d()->type == Type_GlobalContext) {
GlobalContext *g = static_cast<GlobalContext *>(ctx);
bool hasProperty = false;
- v = g->global->get(name, &hasProperty);
+ v = g->d()->global->get(name, &hasProperty);
if (hasProperty)
return v.asReturnedValue();
}
}
- ScopedValue n(scope, name.asReturnedValue());
+ ScopedValue n(scope, name);
return throwReferenceError(n);
}
-ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectRef base)
+ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base)
{
Scope scope(this);
ScopedValue v(scope);
base = (Object *)0;
name->makeIdentifier();
- if (name->equals(engine->id_this))
- return callData->thisObject.asReturnedValue();
+ if (name->equals(d()->engine->id_this.getPointer()))
+ return d()->callData->thisObject.asReturnedValue();
bool hasWith = false;
bool hasCatchScope = false;
- for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
- if (ctx->type == Type_WithContext) {
- Object *w = static_cast<WithContext *>(ctx)->withObject;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) {
+ if (ctx->d()->type == Type_WithContext) {
+ Object *w = static_cast<WithContext *>(ctx)->d()->withObject;
hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
@@ -429,103 +430,103 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR
continue;
}
- else if (ctx->type == Type_CatchContext) {
+ else if (ctx->d()->type == Type_CatchContext) {
hasCatchScope = true;
CatchContext *c = static_cast<CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name))
- return c->exceptionValue.asReturnedValue();
+ if (c->d()->exceptionVarName->isEqualTo(name))
+ return c->d()->exceptionValue.asReturnedValue();
}
- else if (ctx->type >= Type_CallContext) {
+ else if (ctx->d()->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
- FunctionObject *f = c->function;
- if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
- uint index = f->function->internalClass->find(name);
+ FunctionObject *f = c->d()->function;
+ if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) {
+ uint index = f->function()->internalClass->find(name);
if (index < UINT_MAX) {
- if (index < c->function->formalParameterCount())
- return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue();
- return c->locals[index - c->function->formalParameterCount()].asReturnedValue();
+ if (index < c->d()->function->formalParameterCount())
+ return c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1].asReturnedValue();
+ return c->d()->locals[index - c->d()->function->formalParameterCount()].asReturnedValue();
}
}
- if (c->activation) {
+ if (c->d()->activation) {
bool hasProperty = false;
- v = c->activation->get(name, &hasProperty);
+ v = c->d()->activation->get(name, &hasProperty);
if (hasProperty) {
- if (ctx->type == Type_QmlContext)
- base = c->activation;
+ if (ctx->d()->type == Type_QmlContext)
+ base = c->d()->activation;
return v.asReturnedValue();
}
}
- if (f->function && f->function->isNamedExpression()
- && name->equals(f->function->name()))
- return c->function->asReturnedValue();
+ if (f->function() && f->function()->isNamedExpression()
+ && name->equals(f->function()->name()))
+ return c->d()->function->asReturnedValue();
}
- else if (ctx->type == Type_GlobalContext) {
+ else if (ctx->d()->type == Type_GlobalContext) {
GlobalContext *g = static_cast<GlobalContext *>(ctx);
bool hasProperty = false;
- v = g->global->get(name, &hasProperty);
+ v = g->d()->global->get(name, &hasProperty);
if (hasProperty)
return v.asReturnedValue();
}
}
- ScopedValue n(scope, name.asReturnedValue());
+ ScopedValue n(scope, name);
return throwReferenceError(n);
}
ReturnedValue ExecutionContext::throwError(const ValueRef value)
{
- return engine->throwException(value);
+ return d()->engine->throwException(value);
}
ReturnedValue ExecutionContext::throwError(const QString &message)
{
Scope scope(this);
- ScopedValue v(scope, engine->newString(message));
- v = engine->newErrorObject(v);
+ ScopedValue v(scope, d()->engine->newString(message));
+ v = d()->engine->newErrorObject(v);
return throwError(v);
}
ReturnedValue ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
{
Scope scope(this);
- Scoped<Object> error(scope, engine->newSyntaxErrorObject(message, fileName, line, column));
+ Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message, fileName, line, column));
return throwError(error);
}
ReturnedValue ExecutionContext::throwSyntaxError(const QString &message)
{
Scope scope(this);
- Scoped<Object> error(scope, engine->newSyntaxErrorObject(message));
+ Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message));
return throwError(error);
}
ReturnedValue ExecutionContext::throwTypeError()
{
Scope scope(this);
- Scoped<Object> error(scope, engine->newTypeErrorObject(QStringLiteral("Type error")));
+ Scoped<Object> error(scope, d()->engine->newTypeErrorObject(QStringLiteral("Type error")));
return throwError(error);
}
ReturnedValue ExecutionContext::throwTypeError(const QString &message)
{
Scope scope(this);
- Scoped<Object> error(scope, engine->newTypeErrorObject(message));
+ Scoped<Object> error(scope, d()->engine->newTypeErrorObject(message));
return throwError(error);
}
ReturnedValue ExecutionContext::throwUnimplemented(const QString &message)
{
Scope scope(this);
- ScopedValue v(scope, engine->newString(QStringLiteral("Unimplemented ") + message));
- v = engine->newErrorObject(v);
+ ScopedValue v(scope, d()->engine->newString(QStringLiteral("Unimplemented ") + message));
+ v = d()->engine->newErrorObject(v);
return throwError(v);
}
ReturnedValue ExecutionContext::catchException(StackTrace *trace)
{
- return engine->catchException(this, trace);
+ return d()->engine->catchException(this, trace);
}
ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value)
@@ -533,7 +534,7 @@ ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value)
Scope scope(this);
Scoped<String> s(scope, value->toString(this));
QString msg = s->toQString() + QStringLiteral(" is not defined");
- Scoped<Object> error(scope, engine->newReferenceErrorObject(msg));
+ Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg));
return throwError(error);
}
@@ -541,7 +542,7 @@ ReturnedValue ExecutionContext::throwReferenceError(const QString &message, cons
{
Scope scope(this);
QString msg = message;
- Scoped<Object> error(scope, engine->newReferenceErrorObject(msg, fileName, line, column));
+ Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg, fileName, line, column));
return throwError(error);
}
@@ -550,20 +551,20 @@ ReturnedValue ExecutionContext::throwRangeError(const ValueRef value)
Scope scope(this);
ScopedString s(scope, value->toString(this));
QString msg = s->toQString() + QStringLiteral(" out of range");
- ScopedObject error(scope, engine->newRangeErrorObject(msg));
+ ScopedObject error(scope, d()->engine->newRangeErrorObject(msg));
return throwError(error);
}
ReturnedValue ExecutionContext::throwRangeError(const QString &message)
{
Scope scope(this);
- ScopedObject error(scope, engine->newRangeErrorObject(message));
+ ScopedObject error(scope, d()->engine->newRangeErrorObject(message));
return throwError(error);
}
ReturnedValue ExecutionContext::throwURIError(const ValueRef msg)
{
Scope scope(this);
- ScopedObject error(scope, engine->newURIErrorObject(msg));
+ ScopedObject error(scope, d()->engine->newURIErrorObject(msg));
return throwError(error);
}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index a07cbf2da5..7e67028364 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -69,8 +69,6 @@ struct WithContext;
struct Q_QML_EXPORT ExecutionContext : public Managed
{
- V4_MANAGED
- Q_MANAGED_TYPE(ExecutionContext)
enum {
IsExecutionContext = true
};
@@ -83,48 +81,66 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
Type_CallContext = 0x5,
Type_QmlContext = 0x6
};
-
- ExecutionContext(ExecutionEngine *engine, ContextType t)
- : Managed(engine->executionContextClass)
- {
- this->type = t;
- strictMode = false;
- this->engine = engine;
- this->parent = engine->currentContext();
- outer = 0;
- lookups = 0;
- compilationUnit = 0;
- currentEvalCode = 0;
- lineNumber = -1;
- engine->current = this;
- }
-
- ContextType type;
- bool strictMode;
-
- CallData *callData;
-
- ExecutionEngine *engine;
- ExecutionContext *parent;
- ExecutionContext *outer;
- Lookup *lookups;
- CompiledData::CompilationUnit *compilationUnit;
-
struct EvalCode
{
Function *function;
EvalCode *next;
};
- EvalCode *currentEvalCode;
- int lineNumber;
+ struct Data : Managed::Data {
+ Data(ExecutionEngine *engine, ContextType t)
+ : Managed::Data(engine->executionContextClass)
+ , type(t)
+ , strictMode(false)
+ , engine(engine)
+ , parent(engine->currentContext())
+ , outer(0)
+ , lookups(0)
+ , compilationUnit(0)
+ , currentEvalCode(0)
+ , lineNumber(-1)
+ {
+ engine->current = reinterpret_cast<ExecutionContext *>(this);
+ }
+ ContextType type;
+ bool strictMode;
+
+ CallData *callData;
+
+ ExecutionEngine *engine;
+ ExecutionContext *parent;
+ ExecutionContext *outer;
+ Lookup *lookups;
+ CompiledData::CompilationUnit *compilationUnit;
+ EvalCode *currentEvalCode;
+
+ int lineNumber;
- CallContext *newCallContext(FunctionObject *f, CallData *callData);
- WithContext *newWithContext(ObjectRef with);
- CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue);
- CallContext *newQmlContext(FunctionObject *f, ObjectRef qml);
+ };
+ V4_MANAGED(Managed)
+ Q_MANAGED_TYPE(ExecutionContext)
- void createMutableBinding(const StringRef name, bool deletable);
+ ExecutionContext(ExecutionEngine *engine, ContextType t)
+ : Managed(engine->executionContextClass)
+ {
+ d()->type = t;
+ d()->strictMode = false;
+ d()->engine = engine;
+ d()->parent = engine->currentContext();
+ d()->outer = 0;
+ d()->lookups = 0;
+ d()->compilationUnit = 0;
+ d()->currentEvalCode = 0;
+ d()->lineNumber = -1;
+ engine->current = this;
+ }
+
+ HeapObject *newCallContext(FunctionObject *f, CallData *callData);
+ WithContext *newWithContext(Object *with);
+ CatchContext *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue);
+ CallContext *newQmlContext(FunctionObject *f, Object *qml);
+
+ void createMutableBinding(String *name, bool deletable);
ReturnedValue throwError(const QV4::ValueRef value);
ReturnedValue throwError(const QString &message);
@@ -139,10 +155,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ReturnedValue throwURIError(const ValueRef msg);
ReturnedValue throwUnimplemented(const QString &message);
- void setProperty(const StringRef name, const ValueRef value);
- ReturnedValue getProperty(const StringRef name);
- ReturnedValue getPropertyAndBase(const StringRef name, ObjectRef base);
- bool deleteProperty(const StringRef name);
+ void setProperty(String *name, const ValueRef value);
+ ReturnedValue getProperty(String *name);
+ ReturnedValue getPropertyAndBase(String *name, Object *&base);
+ bool deleteProperty(String *name);
// Can only be called from within catch(...), rethrows if no JS exception.
ReturnedValue catchException(StackTrace *trace = 0);
@@ -155,19 +171,22 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
struct CallContext : public ExecutionContext
{
- CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
- : ExecutionContext(engine, t)
- {
- function = 0;
- locals = 0;
- activation = 0;
- }
- CallContext(ExecutionEngine *engine, ObjectRef qml, QV4::FunctionObject *function);
-
- FunctionObject *function;
- int realArgumentCount;
- Value *locals;
- Object *activation;
+ struct Data : ExecutionContext::Data {
+ Data(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
+ : ExecutionContext::Data(engine, t)
+ {
+ function = 0;
+ locals = 0;
+ activation = 0;
+ }
+ Data(ExecutionEngine *engine, Object *qml, QV4::FunctionObject *function);
+
+ FunctionObject *function;
+ int realArgumentCount;
+ Value *locals;
+ Object *activation;
+ };
+ V4_MANAGED(ExecutionContext)
// formals are in reverse order
String * const *formals() const;
@@ -180,52 +199,60 @@ struct CallContext : public ExecutionContext
};
inline ReturnedValue CallContext::argument(int i) {
- return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
+ return i < d()->callData->argc ? d()->callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
struct GlobalContext : public ExecutionContext
{
- GlobalContext(ExecutionEngine *engine);
+ struct Data : ExecutionContext::Data {
+ Data(ExecutionEngine *engine);
+ Object *global;
+ };
+ V4_MANAGED(ExecutionContext)
- Object *global;
};
struct CatchContext : public ExecutionContext
{
- CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue);
-
- StringValue exceptionVarName;
- Value exceptionValue;
+ struct Data : ExecutionContext::Data {
+ Data(ExecutionEngine *engine, String *exceptionVarName, const ValueRef exceptionValue);
+ StringValue exceptionVarName;
+ Value exceptionValue;
+ };
+ V4_MANAGED(ExecutionContext)
};
struct WithContext : public ExecutionContext
{
- WithContext(ExecutionEngine *engine, ObjectRef with);
- Object *withObject;
+ struct Data : ExecutionContext::Data {
+ Data(ExecutionEngine *engine, Object *with);
+ Object *withObject;
+ };
+ V4_MANAGED(ExecutionContext)
};
inline CallContext *ExecutionContext::asCallContext()
{
- return type >= Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
+ return d()->type >= Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
}
inline const CallContext *ExecutionContext::asCallContext() const
{
- return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
+ return d()->type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
}
inline void ExecutionEngine::pushContext(CallContext *context)
{
- context->parent = current;
+ context->d()->parent = current;
current = context;
- current->currentEvalCode = 0;
+ current->d()->currentEvalCode = 0;
}
inline ExecutionContext *ExecutionEngine::popContext()
{
- Q_ASSERT(current->parent);
- current = current->parent;
+ Q_ASSERT(current->d()->parent);
+ current = current->d()->parent;
return current;
}
@@ -235,7 +262,7 @@ struct ExecutionContextSaver
ExecutionContext *savedContext;
ExecutionContextSaver(ExecutionContext *context)
- : engine(context->engine)
+ : engine(context->d()->engine)
, savedContext(context)
{
}
@@ -246,7 +273,7 @@ struct ExecutionContextSaver
};
inline Scope::Scope(ExecutionContext *ctx)
- : engine(ctx->engine)
+ : engine(ctx->d()->engine)
#ifndef QT_NO_DEBUG
, size(0)
#endif
@@ -256,7 +283,7 @@ inline Scope::Scope(ExecutionContext *ctx)
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
- ((sizeof(CallContext) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData)
+ ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData)
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index ceef88455b..b7fac9432f 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -643,8 +643,8 @@ static double getLocalTZA()
DEFINE_OBJECT_VTABLE(DateObject);
-DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
- : Object(engine->dateClass)
+DateObject::Data::Data(ExecutionEngine *engine, const QDateTime &date)
+ : Object::Data(engine->dateClass)
{
setVTable(staticVTable());
value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN());
@@ -652,13 +652,13 @@ DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
QDateTime DateObject::toQDateTime() const
{
- return ToDateTime(value.asDouble(), Qt::LocalTime);
+ return ToDateTime(date().asDouble(), Qt::LocalTime);
}
DEFINE_OBJECT_VTABLE(DateCtor);
-DateCtor::DateCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Date"))
+DateCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Date"))
{
setVTable(staticVTable());
}
@@ -674,7 +674,7 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData)
Scope scope(m->engine());
ScopedValue arg(scope, callData->args[0]);
if (DateObject *d = arg->asDateObject())
- arg = d->value;
+ arg = d->date();
else
arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT);
@@ -707,7 +707,7 @@ ReturnedValue DateCtor::call(Managed *m, CallData *)
return m->engine()->newString(ToString(t))->asReturnedValue();
}
-void DatePrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -770,8 +770,8 @@ void DatePrototype::init(ExecutionEngine *engine, ObjectRef ctor)
double DatePrototype::getThisDate(ExecutionContext *ctx)
{
- if (DateObject *thisObject = ctx->callData->thisObject.asDateObject())
- return thisObject->value.asDouble();
+ if (DateObject *thisObject = ctx->d()->callData->thisObject.asDateObject())
+ return thisObject->date().asDouble();
else {
ctx->throwTypeError();
return 0;
@@ -780,22 +780,22 @@ double DatePrototype::getThisDate(ExecutionContext *ctx)
ReturnedValue DatePrototype::method_parse(CallContext *ctx)
{
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return Encode(qSNaN());
- return Encode(ParseString(ctx->callData->args[0].toString(ctx)->toQString()));
+ return Encode(ParseString(ctx->d()->callData->args[0].toString(ctx)->toQString()));
}
ReturnedValue DatePrototype::method_UTC(CallContext *ctx)
{
- const int numArgs = ctx->callData->argc;
+ const int numArgs = ctx->d()->callData->argc;
if (numArgs >= 2) {
- double year = ctx->callData->args[0].toNumber();
- double month = ctx->callData->args[1].toNumber();
- double day = numArgs >= 3 ? ctx->callData->args[2].toNumber() : 1;
- double hours = numArgs >= 4 ? ctx->callData->args[3].toNumber() : 0;
- double mins = numArgs >= 5 ? ctx->callData->args[4].toNumber() : 0;
- double secs = numArgs >= 6 ? ctx->callData->args[5].toNumber() : 0;
- double ms = numArgs >= 7 ? ctx->callData->args[6].toNumber() : 0;
+ double year = ctx->d()->callData->args[0].toNumber();
+ double month = ctx->d()->callData->args[1].toNumber();
+ double day = numArgs >= 3 ? ctx->d()->callData->args[2].toNumber() : 1;
+ double hours = numArgs >= 4 ? ctx->d()->callData->args[3].toNumber() : 0;
+ double mins = numArgs >= 5 ? ctx->d()->callData->args[4].toNumber() : 0;
+ double secs = numArgs >= 6 ? ctx->d()->callData->args[5].toNumber() : 0;
+ double ms = numArgs >= 7 ? ctx->d()->callData->args[6].toNumber() : 0;
if (year >= 0 && year <= 99)
year += 1900;
double t = MakeDate(MakeDay(year, month, day),
@@ -815,37 +815,37 @@ ReturnedValue DatePrototype::method_now(CallContext *ctx)
ReturnedValue DatePrototype::method_toString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_toDateString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToDateString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToDateString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToTimeString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToTimeString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToLocaleString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToLocaleString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToLocaleDateString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToLocaleDateString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx)
{
double t = getThisDate(ctx);
- return ctx->engine->newString(ToLocaleTimeString(t))->asReturnedValue();
+ return ctx->d()->engine->newString(ToLocaleTimeString(t))->asReturnedValue();
}
ReturnedValue DatePrototype::method_valueOf(CallContext *ctx)
@@ -1007,196 +1007,196 @@ ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx)
ReturnedValue DatePrototype::method_setTime(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->callData->thisObject);
+ Scoped<DateObject> self(scope, ctx->d()->callData->thisObject);
if (!self)
return ctx->throwTypeError();
- double t = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- self->value.setDouble(TimeClip(t));
- return self->value.asReturnedValue();
+ double t = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ self->date().setDouble(TimeClip(t));
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->callData->thisObject);
+ Scoped<DateObject> self(scope, ctx->d()->callData->thisObject);
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
- return self->value.asReturnedValue();
+ double t = LocalTime(self->date().asDouble());
+ double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
- return self->value.asReturnedValue();
+ double t = self->date().asDouble();
+ double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double ms = (ctx->callData->argc < 2) ? msFromTime(t) : ctx->callData->args[1].toNumber();
+ double t = LocalTime(self->date().asDouble());
+ double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double ms = (ctx->d()->callData->argc < 2) ? msFromTime(t) : ctx->d()->callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double ms = (ctx->callData->argc < 2) ? msFromTime(t) : ctx->callData->args[1].toNumber();
+ double t = self->date().asDouble();
+ double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double ms = (ctx->d()->callData->argc < 2) ? msFromTime(t) : ctx->d()->callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double sec = (ctx->callData->argc < 2) ? SecFromTime(t) : ctx->callData->args[1].toNumber();
- double ms = (ctx->callData->argc < 3) ? msFromTime(t) : ctx->callData->args[2].toNumber();
+ double t = LocalTime(self->date().asDouble());
+ double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double sec = (ctx->d()->callData->argc < 2) ? SecFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double ms = (ctx->d()->callData->argc < 3) ? msFromTime(t) : ctx->d()->callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double sec = (ctx->callData->argc < 2) ? SecFromTime(t) : ctx->callData->args[1].toNumber();
- double ms = (ctx->callData->argc < 3) ? msFromTime(t) : ctx->callData->args[2].toNumber();
+ double t = self->date().asDouble();
+ double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double sec = (ctx->d()->callData->argc < 2) ? SecFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double ms = (ctx->d()->callData->argc < 3) ? msFromTime(t) : ctx->d()->callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setHours(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double min = (ctx->callData->argc < 2) ? MinFromTime(t) : ctx->callData->args[1].toNumber();
- double sec = (ctx->callData->argc < 3) ? SecFromTime(t) : ctx->callData->args[2].toNumber();
- double ms = (ctx->callData->argc < 4) ? msFromTime(t) : ctx->callData->args[3].toNumber();
+ double t = LocalTime(self->date().asDouble());
+ double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double min = (ctx->d()->callData->argc < 2) ? MinFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double sec = (ctx->d()->callData->argc < 3) ? SecFromTime(t) : ctx->d()->callData->args[2].toNumber();
+ double ms = (ctx->d()->callData->argc < 4) ? msFromTime(t) : ctx->d()->callData->args[3].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double min = (ctx->callData->argc < 2) ? MinFromTime(t) : ctx->callData->args[1].toNumber();
- double sec = (ctx->callData->argc < 3) ? SecFromTime(t) : ctx->callData->args[2].toNumber();
- double ms = (ctx->callData->argc < 4) ? msFromTime(t) : ctx->callData->args[3].toNumber();
+ double t = self->date().asDouble();
+ double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double min = (ctx->d()->callData->argc < 2) ? MinFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double sec = (ctx->d()->callData->argc < 3) ? SecFromTime(t) : ctx->d()->callData->args[2].toNumber();
+ double ms = (ctx->d()->callData->argc < 4) ? msFromTime(t) : ctx->d()->callData->args[3].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setDate(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
+ double t = LocalTime(self->date().asDouble());
+ double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
+ double t = self->date().asDouble();
+ double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setMonth(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
- double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double date = (ctx->callData->argc < 2) ? DateFromTime(t) : ctx->callData->args[1].toNumber();
+ double t = LocalTime(self->date().asDouble());
+ double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double date = (ctx->d()->callData->argc < 2) ? DateFromTime(t) : ctx->d()->callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double date = (ctx->callData->argc < 2) ? DateFromTime(t) : ctx->callData->args[1].toNumber();
+ double t = self->date().asDouble();
+ double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double date = (ctx->d()->callData->argc < 2) ? DateFromTime(t) : ctx->d()->callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
+ double t = self->date().asDouble();
if (std::isnan(t))
t = 0;
else
t = LocalTime(t);
- double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
+ double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
double r;
if (std::isnan(year)) {
r = qSNaN();
@@ -1207,50 +1207,50 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
r = UTC(MakeDate(r, TimeWithinDay(t)));
r = TimeClip(r);
}
- self->value.setDouble(r);
- return self->value.asReturnedValue();
+ self->date().setDouble(r);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double month = (ctx->callData->argc < 2) ? MonthFromTime(t) : ctx->callData->args[1].toNumber();
- double date = (ctx->callData->argc < 3) ? DateFromTime(t) : ctx->callData->args[2].toNumber();
+ double t = self->date().asDouble();
+ double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double month = (ctx->d()->callData->argc < 2) ? MonthFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double date = (ctx->d()->callData->argc < 3) ? DateFromTime(t) : ctx->d()->callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = LocalTime(self->value.asDouble());
+ double t = LocalTime(self->date().asDouble());
if (std::isnan(t))
t = 0;
- double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- double month = (ctx->callData->argc < 2) ? MonthFromTime(t) : ctx->callData->args[1].toNumber();
- double date = (ctx->callData->argc < 3) ? DateFromTime(t) : ctx->callData->args[2].toNumber();
+ double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ double month = (ctx->d()->callData->argc < 2) ? MonthFromTime(t) : ctx->d()->callData->args[1].toNumber();
+ double date = (ctx->d()->callData->argc < 3) ? DateFromTime(t) : ctx->d()->callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
- self->value.setDouble(t);
- return self->value.asReturnedValue();
+ self->date().setDouble(t);
+ return self->date().asReturnedValue();
}
ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
- return ctx->engine->newString(ToUTCString(t))->asReturnedValue();
+ double t = self->date().asDouble();
+ return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue();
}
static void addZeroPrefixedInt(QString &str, int num, int nDigits)
@@ -1268,19 +1268,19 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits)
ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
{
- DateObject *self = ctx->callData->thisObject.asDateObject();
+ DateObject *self = ctx->d()->callData->thisObject.asDateObject();
if (!self)
return ctx->throwTypeError();
- double t = self->value.asDouble();
+ double t = self->date().asDouble();
if (!std::isfinite(t))
- return ctx->throwRangeError(ctx->callData->thisObject);
+ return ctx->throwRangeError(ctx->d()->callData->thisObject);
QString result;
int year = (int)YearFromTime(t);
if (year < 0 || year > 9999) {
if (qAbs(year) >= 1000000)
- return ctx->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue();
+ return ctx->d()->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue();
result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
year = qAbs(year);
addZeroPrefixedInt(result, year, 6);
@@ -1301,27 +1301,27 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
addZeroPrefixedInt(result, msFromTime(t), 3);
result += QLatin1Char('Z');
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
{
Scope scope(ctx);
- ScopedValue O(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->callData->thisObject)));
+ ScopedValue O(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->d()->callData->thisObject)));
ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT));
if (tv->isNumber() && !std::isfinite(tv->toNumber()))
return Encode::null();
- ScopedString s(scope, ctx->engine->newString(QStringLiteral("toISOString")));
- ScopedValue v(scope, O->objectValue()->get(s));
+ ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString")));
+ ScopedValue v(scope, O->objectValue()->get(s.getPointer()));
FunctionObject *toIso = v->asFunctionObject();
if (!toIso)
return ctx->throwTypeError();
ScopedCallData callData(scope, 0);
- callData->thisObject = ctx->callData->thisObject;
+ callData->thisObject = ctx->d()->callData->thisObject;
return toIso->call(callData);
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index c52e8c3ee1..6df4da45c9 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -52,27 +52,38 @@ class QDateTime;
namespace QV4 {
struct DateObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, const ValueRef date)
+ : Object::Data(engine->dateClass)
+ {
+ value = date;
+ }
+ Data(ExecutionEngine *engine, const QDateTime &date);
+ Data(InternalClass *ic)
+ : Object::Data(ic)
+ {
+ Q_ASSERT(internalClass->vtable == staticVTable());
+ value = Primitive::fromDouble(qSNaN());
+ }
+ Value value;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(DateObject)
- Value value;
- DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) {
- value = date;
- }
- DateObject(ExecutionEngine *engine, const QDateTime &value);
- QDateTime toQDateTime() const;
-protected:
- DateObject(InternalClass *ic): Object(ic) {
- Q_ASSERT(internalClass->vtable == staticVTable());
- value = Primitive::fromDouble(qSNaN());
- }
+ Value date() const { return d()->value; }
+ Value &date() { return d()->value; }
+ void setDate(const ValueRef date) { d()->value = date; }
+
+ QDateTime toQDateTime() const;
};
struct DateCtor: FunctionObject
{
- V4_OBJECT
- DateCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *, CallData *callData);
static ReturnedValue call(Managed *that, CallData *);
@@ -80,8 +91,7 @@ struct DateCtor: FunctionObject
struct DatePrototype: DateObject
{
- DatePrototype(InternalClass *ic): DateObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static double getThisDate(ExecutionContext *ctx);
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 06c6dbb4d9..78de614664 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -45,6 +45,7 @@
#include "qv4function_p.h"
#include "qv4instr_moth_p.h"
#include "qv4runtime_p.h"
+#include "qv4script_p.h"
#include <iostream>
#include <algorithm>
@@ -53,29 +54,74 @@ using namespace QV4;
using namespace QV4::Debugging;
namespace {
-class EvalJob: public Debugger::Job
+class JavaScriptJob: public Debugger::Job
{
QV4::ExecutionEngine *engine;
const QString &script;
public:
- EvalJob(QV4::ExecutionEngine *engine, const QString &script)
+ JavaScriptJob(QV4::ExecutionEngine *engine, const QString &script)
: engine(engine)
, script(script)
{}
- ~EvalJob() {}
-
void run()
{
- // TODO
- qDebug() << "Evaluating script:" << script;
- Q_UNUSED(engine);
+ QV4::Scope scope(engine);
+ QV4::ExecutionContext *ctx = engine->currentContext();
+ ContextStateSaver ctxSaver(ctx);
+ QV4::ScopedValue result(scope);
+
+ QV4::Script script(ctx, this->script);
+ script.strictMode = ctx->d()->strictMode;
+ script.inheritContext = false;
+ script.parse();
+ if (!scope.engine->hasException)
+ result = script.run();
+ if (scope.engine->hasException)
+ result = ctx->catchException();
+ handleResult(result);
+ }
+
+protected:
+ virtual void handleResult(QV4::ScopedValue &result) = 0;
+};
+
+class EvalJob: public JavaScriptJob
+{
+ bool result;
+
+public:
+ EvalJob(QV4::ExecutionEngine *engine, const QString &script)
+ : JavaScriptJob(engine, script)
+ , result(false)
+ {}
+
+ virtual void handleResult(QV4::ScopedValue &result)
+ {
+ this->result = result->toBoolean();
}
bool resultAsBoolean() const
{
- return true;
+ return result;
+ }
+};
+
+class ExpressionEvalJob: public JavaScriptJob
+{
+ Debugger::Collector *collector;
+
+public:
+ ExpressionEvalJob(ExecutionEngine *engine, const QString &expression, Debugger::Collector *collector)
+ : JavaScriptJob(engine, expression)
+ , collector(collector)
+ {
+ }
+
+ virtual void handleResult(QV4::ScopedValue &result)
+ {
+ collector->collect(QStringLiteral("body"), result);
}
};
@@ -210,7 +256,7 @@ Debugger::ExecutionState Debugger::currentExecutionState() const
{
ExecutionState state;
state.fileName = getFunction()->sourceFile();
- state.lineNumber = engine()->currentContext()->lineNumber;
+ state.lineNumber = engine()->currentContext()->d()->lineNumber;
return state;
}
@@ -224,12 +270,12 @@ static inline CallContext *findContext(ExecutionContext *ctxt, int frame)
{
while (ctxt) {
CallContext *cCtxt = ctxt->asCallContext();
- if (cCtxt && cCtxt->function) {
+ if (cCtxt && cCtxt->d()->function) {
if (frame < 1)
return cCtxt;
--frame;
}
- ctxt = ctxt->parent;
+ ctxt = ctxt->d()->parent;
}
return 0;
@@ -238,7 +284,7 @@ static inline CallContext *findContext(ExecutionContext *ctxt, int frame)
static inline CallContext *findScope(ExecutionContext *ctxt, int scope)
{
for (; scope > 0 && ctxt; --scope)
- ctxt = ctxt->outer;
+ ctxt = ctxt->d()->outer;
return ctxt ? ctxt->asCallContext() : 0;
}
@@ -327,7 +373,7 @@ void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int sco
QString qName;
if (String *name = ctxt->variables()[i])
qName = name->toQString();
- v = ctxt->locals[i];
+ v = ctxt->d()->locals[i];
collector->collect(qName, v);
}
}
@@ -367,16 +413,16 @@ bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame)
ExecutionContext *ctxt = findContext(engine->currentContext(), frameNr);
while (ctxt) {
if (CallContext *cCtxt = ctxt->asCallContext())
- if (cCtxt->activation)
+ if (cCtxt->d()->activation)
break;
- ctxt = ctxt->outer;
+ ctxt = ctxt->d()->outer;
}
if (!ctxt)
return false;
Scope scope(engine);
- ScopedObject o(scope, ctxt->asCallContext()->activation);
+ ScopedObject o(scope, ctxt->asCallContext()->d()->activation);
collector->collect(o);
return true;
}
@@ -434,23 +480,36 @@ QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const
return types;
CallContext *sctxt = findContext(m_engine->currentContext(), frame);
- if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext)
+ if (!sctxt || sctxt->d()->type < ExecutionContext::Type_SimpleCallContext)
return types;
CallContext *ctxt = static_cast<CallContext *>(sctxt);
- for (ExecutionContext *it = ctxt; it; it = it->outer)
- types.append(it->type);
+ for (ExecutionContext *it = ctxt; it; it = it->d()->outer)
+ types.append(it->d()->type);
return types;
}
+
+void Debugger::evaluateExpression(int frameNr, const QString &expression, Debugger::Collector *resultsCollector)
+{
+ Q_ASSERT(state() == Paused);
+ Q_UNUSED(frameNr);
+
+ Q_ASSERT(m_runningJob == 0);
+ ExpressionEvalJob job(m_engine, expression, resultsCollector);
+ m_runningJob = &job;
+ m_runningJob->run();
+ m_runningJob = 0;
+}
+
void Debugger::maybeBreakAtInstruction()
{
if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
return;
QMutexLocker locker(&m_lock);
- int lineNumber = engine()->currentContext()->lineNumber;
+ int lineNumber = engine()->currentContext()->d()->lineNumber;
if (m_gatherSources) {
m_gatherSources->run();
@@ -481,6 +540,8 @@ void Debugger::maybeBreakAtInstruction()
void Debugger::enteringFunction()
{
+ if (m_runningJob)
+ return;
QMutexLocker locker(&m_lock);
if (m_stepping == StepIn) {
@@ -490,12 +551,14 @@ void Debugger::enteringFunction()
void Debugger::leavingFunction(const ReturnedValue &retVal)
{
+ if (m_runningJob)
+ return;
Q_UNUSED(retVal); // TODO
QMutexLocker locker(&m_lock);
if (m_stepping != NotStepping && m_currentContext == m_engine->currentContext()) {
- m_currentContext = m_engine->currentContext()->parent;
+ m_currentContext = m_engine->currentContext()->d()->parent;
m_stepping = StepOver;
m_returnedValue = retVal;
}
@@ -517,10 +580,10 @@ Function *Debugger::getFunction() const
{
ExecutionContext *context = m_engine->currentContext();
if (CallContext *callCtx = context->asCallContext())
- return callCtx->function->function;
+ return callCtx->d()->function->function();
else {
- Q_ASSERT(context->type == QV4::ExecutionContext::Type_GlobalContext);
- return context->engine->globalCode;
+ Q_ASSERT(context->d()->type == QV4::ExecutionContext::Type_GlobalContext);
+ return context->d()->engine->globalCode;
}
}
@@ -560,6 +623,7 @@ bool Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
EvalJob evilJob(m_engine, condition);
m_runningJob = &evilJob;
m_runningJob->run();
+ m_runningJob = 0;
return evilJob.resultAsBoolean();
}
@@ -726,7 +790,7 @@ void Debugger::Collector::collect(const QString &name, const ScopedValue &value)
}
}
-void Debugger::Collector::collect(const ObjectRef object)
+void Debugger::Collector::collect(Object *object)
{
bool property = true;
qSwap(property, m_isProperty);
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 47a7d77b28..cedfee7f90 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -105,7 +105,7 @@ public:
virtual ~Collector();
void collect(const QString &name, const ScopedValue &value);
- void collect(const ObjectRef object);
+ void collect(Object *object);
protected:
virtual void addUndefined(const QString &name) = 0;
@@ -181,6 +181,8 @@ public:
void collectReturnedValue(Collector *collector) const;
QVector<ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
+ void evaluateExpression(int frameNr, const QString &expression, Collector *resultsCollector);
+
public: // compile-time interface
void maybeBreakAtInstruction();
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 72be889e72..7be518916d 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -71,6 +71,7 @@
#include "qv4memberdata_p.h"
#include <QtCore/QTextStream>
+#include <QDateTime>
#ifdef V4_ENABLE_JIT
#include "qv4isel_masm_p.h"
@@ -258,13 +259,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0);
- ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, ObjectPrototype::staticVTable(), 0));
+ ScopedObject objectPrototype(scope, memoryManager->alloc<ObjectPrototype>(InternalClass::create(this, ObjectPrototype::staticVTable(), 0)));
objectClass = InternalClass::create(this, Object::staticVTable(), objectPrototype);
Q_ASSERT(objectClass->vtable == Object::staticVTable());
arrayClass = InternalClass::create(this, ArrayObject::staticVTable(), objectPrototype);
arrayClass = arrayClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
- ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass);
+ ScopedObject arrayPrototype(scope, memoryManager->alloc<ArrayPrototype>(arrayClass));
arrayClass = arrayClass->changePrototype(arrayPrototype);
simpleArrayDataClass = InternalClass::create(this, SimpleArrayData::staticVTable(), 0);
@@ -279,100 +280,100 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
initRootContext();
- StringPrototype *stringPrototype = new (memoryManager) StringPrototype(InternalClass::create(this, StringPrototype::staticVTable(), objectPrototype));
+ ScopedObject stringPrototype(scope, memoryManager->alloc<StringPrototype>(InternalClass::create(this, StringPrototype::staticVTable(), objectPrototype)));
stringObjectClass = InternalClass::create(this, String::staticVTable(), stringPrototype);
- NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(InternalClass::create(this, NumberPrototype::staticVTable(), objectPrototype));
+ ScopedObject numberPrototype(scope, memoryManager->alloc<NumberPrototype>(InternalClass::create(this, NumberPrototype::staticVTable(), objectPrototype)));
numberClass = InternalClass::create(this, NumberObject::staticVTable(), numberPrototype);
- BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(InternalClass::create(this, BooleanPrototype::staticVTable(), objectPrototype));
+ ScopedObject booleanPrototype(scope, memoryManager->alloc<BooleanPrototype>(InternalClass::create(this, BooleanPrototype::staticVTable(), objectPrototype)));
booleanClass = InternalClass::create(this, BooleanObject::staticVTable(), booleanPrototype);
- DatePrototype *datePrototype = new (memoryManager) DatePrototype(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype));
+ ScopedObject datePrototype(scope, memoryManager->alloc<DatePrototype>(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype)));
dateClass = InternalClass::create(this, DateObject::staticVTable(), datePrototype);
InternalClass *functionProtoClass = InternalClass::create(this, FunctionObject::staticVTable(), objectPrototype);
uint index;
functionProtoClass = functionProtoClass->addMember(id_prototype, Attr_NotEnumerable, &index);
Q_ASSERT(index == FunctionObject::Index_Prototype);
- FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(functionProtoClass);
+ ScopedObject functionPrototype(scope, memoryManager->alloc<FunctionPrototype>(functionProtoClass));
functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype);
functionClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == FunctionObject::Index_Prototype);
protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index);
Q_ASSERT(index == FunctionObject::Index_ProtoConstructor);
- RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(InternalClass::create(this, RegExpPrototype::staticVTable(), objectPrototype));
- regExpClass = InternalClass::create(this, RegExpObject::staticVTable(), regExpPrototype);
+ Scoped<RegExpPrototype> regExpPrototype(scope, memoryManager->alloc<RegExpPrototype>(InternalClass::create(this, RegExpPrototype::staticVTable(), objectPrototype)));
+ regExpClass = InternalClass::create(this, RegExpObject::staticVTable(), regExpPrototype.getPointer());
regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
- ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(InternalClass::create(this, ErrorObject::staticVTable(), objectPrototype));
+ ScopedObject errorPrototype(scope, memoryManager->alloc<ErrorPrototype>(InternalClass::create(this, ErrorObject::staticVTable(), objectPrototype)));
errorClass = InternalClass::create(this, ErrorObject::staticVTable(), errorPrototype);
- EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass);
+ ScopedObject evalErrorPrototype(scope, memoryManager->alloc<EvalErrorPrototype>(errorClass));
evalErrorClass = InternalClass::create(this, EvalErrorObject::staticVTable(), evalErrorPrototype);
- RangeErrorPrototype *rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(errorClass);
+ ScopedObject rangeErrorPrototype(scope, memoryManager->alloc<RangeErrorPrototype>(errorClass));
rangeErrorClass = InternalClass::create(this, RangeErrorObject::staticVTable(), rangeErrorPrototype);
- ReferenceErrorPrototype *referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(errorClass);
+ ScopedObject referenceErrorPrototype(scope, memoryManager->alloc<ReferenceErrorPrototype>(errorClass));
referenceErrorClass = InternalClass::create(this, ReferenceErrorObject::staticVTable(), referenceErrorPrototype);
- SyntaxErrorPrototype *syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(errorClass);
+ ScopedObject syntaxErrorPrototype(scope, memoryManager->alloc<SyntaxErrorPrototype>(errorClass));
syntaxErrorClass = InternalClass::create(this, SyntaxErrorObject::staticVTable(), syntaxErrorPrototype);
- TypeErrorPrototype *typeErrorPrototype = new (memoryManager) TypeErrorPrototype(errorClass);
+ ScopedObject typeErrorPrototype(scope, memoryManager->alloc<TypeErrorPrototype>(errorClass));
typeErrorClass = InternalClass::create(this, TypeErrorObject::staticVTable(), typeErrorPrototype);
- URIErrorPrototype *uRIErrorPrototype = new (memoryManager) URIErrorPrototype(errorClass);
+ ScopedObject uRIErrorPrototype(scope, memoryManager->alloc<URIErrorPrototype>(errorClass));
uriErrorClass = InternalClass::create(this, URIErrorObject::staticVTable(), uRIErrorPrototype);
- VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(InternalClass::create(this, VariantPrototype::staticVTable(), objectPrototype));
+ ScopedObject variantPrototype(scope, memoryManager->alloc<VariantPrototype>(InternalClass::create(this, VariantPrototype::staticVTable(), objectPrototype)));
variantClass = InternalClass::create(this, VariantObject::staticVTable(), variantPrototype);
Q_ASSERT(variantClass->prototype == variantPrototype);
- Q_ASSERT(variantPrototype->internalClass->prototype == objectPrototype);
-
- sequencePrototype = new (memoryManager) SequencePrototype(arrayClass);
-
- objectCtor = new (memoryManager) ObjectCtor(rootContext);
- stringCtor = new (memoryManager) StringCtor(rootContext);
- numberCtor = new (memoryManager) NumberCtor(rootContext);
- booleanCtor = new (memoryManager) BooleanCtor(rootContext);
- arrayCtor = new (memoryManager) ArrayCtor(rootContext);
- functionCtor = new (memoryManager) FunctionCtor(rootContext);
- dateCtor = new (memoryManager) DateCtor(rootContext);
- regExpCtor = new (memoryManager) RegExpCtor(rootContext);
- errorCtor = new (memoryManager) ErrorCtor(rootContext);
- evalErrorCtor = new (memoryManager) EvalErrorCtor(rootContext);
- rangeErrorCtor = new (memoryManager) RangeErrorCtor(rootContext);
- referenceErrorCtor = new (memoryManager) ReferenceErrorCtor(rootContext);
- syntaxErrorCtor = new (memoryManager) SyntaxErrorCtor(rootContext);
- typeErrorCtor = new (memoryManager) TypeErrorCtor(rootContext);
- uRIErrorCtor = new (memoryManager) URIErrorCtor(rootContext);
-
- objectPrototype->init(this, objectCtor);
- stringPrototype->init(this, stringCtor);
- numberPrototype->init(this, numberCtor);
- booleanPrototype->init(this, booleanCtor);
- arrayPrototype->init(this, arrayCtor);
- datePrototype->init(this, dateCtor);
- functionPrototype->init(this, functionCtor);
- regExpPrototype->init(this, regExpCtor);
- errorPrototype->init(this, errorCtor);
- evalErrorPrototype->init(this, evalErrorCtor);
- rangeErrorPrototype->init(this, rangeErrorCtor);
- referenceErrorPrototype->init(this, referenceErrorCtor);
- syntaxErrorPrototype->init(this, syntaxErrorCtor);
- typeErrorPrototype->init(this, typeErrorCtor);
- uRIErrorPrototype->init(this, uRIErrorCtor);
-
- variantPrototype->init();
+ Q_ASSERT(variantPrototype->internalClass()->prototype == objectPrototype);
+
+ sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass));
+
+ objectCtor = memoryManager->alloc<ObjectCtor>(rootContext);
+ stringCtor = memoryManager->alloc<StringCtor>(rootContext);
+ numberCtor = memoryManager->alloc<NumberCtor>(rootContext);
+ booleanCtor = memoryManager->alloc<BooleanCtor>(rootContext);
+ arrayCtor = memoryManager->alloc<ArrayCtor>(rootContext);
+ functionCtor = memoryManager->alloc<FunctionCtor>(rootContext);
+ dateCtor = memoryManager->alloc<DateCtor>(rootContext);
+ regExpCtor = memoryManager->alloc<RegExpCtor>(rootContext);
+ errorCtor = memoryManager->alloc<ErrorCtor>(rootContext);
+ evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(rootContext);
+ rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(rootContext);
+ referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(rootContext);
+ syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(rootContext);
+ typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(rootContext);
+ uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(rootContext);
+
+ static_cast<ObjectPrototype *>(objectPrototype.getPointer())->init(this, objectCtor.asObject());
+ static_cast<StringPrototype *>(stringPrototype.getPointer())->init(this, stringCtor.asObject());
+ static_cast<NumberPrototype *>(numberPrototype.getPointer())->init(this, numberCtor.asObject());
+ static_cast<BooleanPrototype *>(booleanPrototype.getPointer())->init(this, booleanCtor.asObject());
+ static_cast<ArrayPrototype *>(arrayPrototype.getPointer())->init(this, arrayCtor.asObject());
+ static_cast<DatePrototype *>(datePrototype.getPointer())->init(this, dateCtor.asObject());
+ static_cast<FunctionPrototype *>(functionPrototype.getPointer())->init(this, functionCtor.asObject());
+ static_cast<RegExpPrototype *>(regExpPrototype.getPointer())->init(this, regExpCtor.asObject());
+ static_cast<ErrorPrototype *>(errorPrototype.getPointer())->init(this, errorCtor.asObject());
+ static_cast<EvalErrorPrototype *>(evalErrorPrototype.getPointer())->init(this, evalErrorCtor.asObject());
+ static_cast<RangeErrorPrototype *>(rangeErrorPrototype.getPointer())->init(this, rangeErrorCtor.asObject());
+ static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.getPointer())->init(this, referenceErrorCtor.asObject());
+ static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.getPointer())->init(this, syntaxErrorCtor.asObject());
+ static_cast<TypeErrorPrototype *>(typeErrorPrototype.getPointer())->init(this, typeErrorCtor.asObject());
+ static_cast<URIErrorPrototype *>(uRIErrorPrototype.getPointer())->init(this, uRIErrorCtor.asObject());
+
+ static_cast<VariantPrototype *>(variantPrototype.getPointer())->init();
static_cast<SequencePrototype *>(sequencePrototype.managed())->init();
//
// set up the global object
//
globalObject = newObject()->getPointer();
- rootContext->global = globalObject;
- rootContext->callData->thisObject = globalObject;
- Q_ASSERT(globalObject->internalClass->vtable);
+ rootContext->d()->global = globalObject;
+ rootContext->d()->callData->thisObject = globalObject;
+ Q_ASSERT(globalObject->internalClass()->vtable);
globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor);
globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor);
@@ -390,14 +391,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor);
ScopedObject o(scope);
- globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = new (memoryManager) MathObject(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype))));
- globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = new (memoryManager) JsonObject(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype))));
+ globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype))));
+ globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype))));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN()));
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY));
- evalFunction = new (memoryManager) EvalFunction(rootContext);
+
+ evalFunction = Scoped<EvalFunction>(scope, memoryManager->alloc<EvalFunction>(rootContext));
globalObject->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction));
globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
@@ -412,13 +414,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
Scoped<String> name(scope, newString(QStringLiteral("thrower")));
- thrower = newBuiltinFunction(rootContext, name, throwTypeError)->getPointer();
+ thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), throwTypeError)).getPointer();
}
ExecutionEngine::~ExecutionEngine()
{
delete debugger;
+ debugger = 0;
delete profiler;
+ profiler = 0;
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = 0;
delete identifierTable;
@@ -451,18 +455,20 @@ void ExecutionEngine::enableDebugger()
void ExecutionEngine::enableProfiler()
{
Q_ASSERT(!profiler);
- profiler = new QV4::Profiling::Profiler();
+ profiler = new QV4::Profiling::Profiler(this);
}
void ExecutionEngine::initRootContext()
{
- rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData)));
- new (rootContext) GlobalContext(this);
- rootContext->callData = reinterpret_cast<CallData *>(rootContext + 1);
- rootContext->callData->tag = QV4::Value::_Integer_Type;
- rootContext->callData->argc = 0;
- rootContext->callData->thisObject = globalObject;
- rootContext->callData->args[0] = Encode::undefined();
+ GlobalContext *r = static_cast<GlobalContext*>(memoryManager->allocManaged(sizeof(GlobalContext::Data) + sizeof(CallData)));
+ new (r->d()) GlobalContext::Data(this);
+ r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
+ r->d()->callData->tag = QV4::Value::_Integer_Type;
+ r->d()->callData->argc = 0;
+ r->d()->callData->thisObject = globalObject;
+ r->d()->callData->args[0] = Encode::undefined();
+
+ rootContext = r;
}
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
@@ -472,43 +478,32 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
ExecutionContext *ExecutionEngine::pushGlobalContext()
{
- GlobalContext *g = new (memoryManager) GlobalContext(this);
- g->callData = rootContext->callData;
+ GlobalContext *g = memoryManager->alloc<GlobalContext>(this);
+ g->d()->callData = rootContext->d()->callData;
Q_ASSERT(currentContext() == g);
return g;
}
-Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
-{
- BuiltinFunction *f = new (memoryManager) BuiltinFunction(scope, name, code);
- return f->asReturned<FunctionObject>();
-}
-
-Returned<BoundFunction> *ExecutionEngine::newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs)
-{
- Q_ASSERT(target);
-
- BoundFunction *f = new (memoryManager) BoundFunction(scope, target, boundThis, boundArgs);
- return f->asReturned<BoundFunction>();
-}
-
Returned<Object> *ExecutionEngine::newObject()
{
- Object *object = new (memoryManager) Object(this);
+ Scope scope(this);
+ ScopedObject object(scope, memoryManager->alloc<Object>(this));
return object->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newObject(InternalClass *internalClass)
{
- Object *object = new (memoryManager) Object(internalClass);
+ Scope scope(this);
+ ScopedObject object(scope, memoryManager->alloc<Object>(internalClass));
return object->asReturned<Object>();
}
Returned<String> *ExecutionEngine::newString(const QString &s)
{
- return (new (memoryManager) String(this, s))->asReturned<String>();
+ Scope scope(this);
+ return ScopedString(scope, memoryManager->alloc<String>(this, s))->asReturned<String>();
}
String *ExecutionEngine::newIdentifier(const QString &text)
@@ -518,29 +513,31 @@ String *ExecutionEngine::newIdentifier(const QString &text)
Returned<Object> *ExecutionEngine::newStringObject(const ValueRef value)
{
- StringObject *object = new (memoryManager) StringObject(this, value);
+ Scope scope(this);
+ Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value));
return object->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newNumberObject(const ValueRef value)
{
- NumberObject *object = new (memoryManager) NumberObject(this, value);
+ Scope scope(this);
+ Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value));
return object->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newBooleanObject(const ValueRef value)
{
- Object *object = new (memoryManager) BooleanObject(this, value);
+ Scope scope(this);
+ ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, value));
return object->asReturned<Object>();
}
Returned<ArrayObject> *ExecutionEngine::newArrayObject(int count)
{
- ArrayObject *object = new (memoryManager) ArrayObject(this);
+ Scope scope(this);
+ ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this));
if (count) {
- Scope scope(this);
- ScopedValue protectArray(scope, object);
if (count < 0x1000)
object->arrayReserve(count);
object->setArrayLengthUnchecked(count);
@@ -550,26 +547,30 @@ Returned<ArrayObject> *ExecutionEngine::newArrayObject(int count)
Returned<ArrayObject> *ExecutionEngine::newArrayObject(const QStringList &list)
{
- ArrayObject *object = new (memoryManager) ArrayObject(this, list);
+ Scope scope(this);
+ ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list));
return object->asReturned<ArrayObject>();
}
Returned<ArrayObject> *ExecutionEngine::newArrayObject(InternalClass *ic)
{
- ArrayObject *object = new (memoryManager) ArrayObject(ic);
+ Scope scope(this);
+ ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic));
return object->asReturned<ArrayObject>();
}
Returned<DateObject> *ExecutionEngine::newDateObject(const ValueRef value)
{
- DateObject *object = new (memoryManager) DateObject(this, value);
+ Scope scope(this);
+ Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value));
return object->asReturned<DateObject>();
}
Returned<DateObject> *ExecutionEngine::newDateObject(const QDateTime &dt)
{
- DateObject *object = new (memoryManager) DateObject(this, dt);
+ Scope scope(this);
+ Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt));
return object->asReturned<DateObject>();
}
@@ -588,21 +589,24 @@ Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QString &pattern,
return newRegExpObject(re, global);
}
-Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExpRef re, bool global)
+Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExp *re, bool global)
{
- RegExpObject *object = new (memoryManager) RegExpObject(this, re, global);
+ Scope scope(this);
+ Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global));
return object->asReturned<RegExpObject>();
}
Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QRegExp &re)
{
- RegExpObject *object = new (memoryManager) RegExpObject(this, re);
+ Scope scope(this);
+ Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re));
return object->asReturned<RegExpObject>();
}
Returned<Object> *ExecutionEngine::newErrorObject(const ValueRef value)
{
- ErrorObject *object = new (memoryManager) ErrorObject(errorClass, value);
+ Scope scope(this);
+ ScopedObject object(scope, memoryManager->alloc<ErrorObject>(errorClass, value));
return object->asReturned<Object>();
}
@@ -610,57 +614,65 @@ Returned<Object> *ExecutionEngine::newSyntaxErrorObject(const QString &message)
{
Scope scope(this);
ScopedString s(scope, newString(message));
- Object *error = new (memoryManager) SyntaxErrorObject(this, s);
+ ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s));
return error->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
{
- Object *error = new (memoryManager) SyntaxErrorObject(this, message, fileName, line, column);
+ Scope scope(this);
+ ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column));
return error->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newReferenceErrorObject(const QString &message)
{
- Object *o = new (memoryManager) ReferenceErrorObject(this, message);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message));
return o->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber)
{
- Object *o = new (memoryManager) ReferenceErrorObject(this, message, fileName, lineNumber, columnNumber);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber));
return o->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newTypeErrorObject(const QString &message)
{
- Object *o = new (memoryManager) TypeErrorObject(this, message);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message));
return o->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newRangeErrorObject(const QString &message)
{
- Object *o = new (memoryManager) RangeErrorObject(this, message);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message));
return o->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newURIErrorObject(const ValueRef message)
{
- Object *o = new (memoryManager) URIErrorObject(this, message);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message));
return o->asReturned<Object>();
}
Returned<Object> *ExecutionEngine::newVariantObject(const QVariant &v)
{
- Object *o = new (memoryManager) VariantObject(this, v);
+ Scope scope(this);
+ ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v));
return o->asReturned<Object>();
}
-Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
+Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o)
{
- Object *obj = new (memoryManager) ForEachIteratorObject(ctx, o);
+ Scope scope(this);
+ ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(ctx, o));
return obj->asReturned<Object>();
}
@@ -668,20 +680,20 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const
{
ExecutionContext *ctx = currentContext();
- if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
- ctx = ctx->parent;
+ if (ctx->d()->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->d()->outer)
+ ctx = ctx->d()->parent;
- if (!ctx->outer)
+ if (!ctx->d()->outer)
return 0;
- while (ctx->outer && ctx->outer->type != ExecutionContext::Type_GlobalContext)
- ctx = ctx->outer;
+ while (ctx->d()->outer && ctx->d()->outer->d()->type != ExecutionContext::Type_GlobalContext)
+ ctx = ctx->d()->outer;
Q_ASSERT(ctx);
- if (ctx->type != ExecutionContext::Type_QmlContext)
+ if (ctx->d()->type != ExecutionContext::Type_QmlContext)
return 0;
- return static_cast<CallContext *>(ctx)->activation->asReturned<Object>();
+ return static_cast<CallContext *>(ctx)->d()->activation->asReturned<Object>();
}
QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
@@ -693,30 +705,30 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
QV4::ExecutionContext *c = currentContext();
while (c && frameLimit) {
CallContext *callCtx = c->asCallContext();
- if (callCtx && callCtx->function) {
+ if (callCtx && callCtx->d()->function) {
StackFrame frame;
- if (callCtx->function->function)
- frame.source = callCtx->function->function->sourceFile();
- name = callCtx->function->name();
+ if (callCtx->d()->function->function())
+ frame.source = callCtx->d()->function->function()->sourceFile();
+ name = callCtx->d()->function->name();
frame.function = name->toQString();
frame.line = -1;
frame.column = -1;
- if (callCtx->function->function)
+ if (callCtx->d()->function->function())
// line numbers can be negative for places where you can't set a real breakpoint
- frame.line = qAbs(callCtx->lineNumber);
+ frame.line = qAbs(callCtx->d()->lineNumber);
stack.append(frame);
--frameLimit;
}
- c = c->parent;
+ c = c->d()->parent;
}
if (frameLimit && globalCode) {
StackFrame frame;
frame.source = globalCode->sourceFile();
frame.function = globalCode->name()->toQString();
- frame.line = rootContext->lineNumber;
+ frame.line = rootContext->d()->lineNumber;
frame.column = -1;
@@ -750,8 +762,8 @@ static inline char *v4StackTrace(const ExecutionContext *context)
QString result;
QTextStream str(&result);
str << "stack=[";
- if (context && context->engine) {
- const QVector<StackFrame> stackTrace = context->engine->stackTrace(20);
+ if (context && context->d()->engine) {
+ const QVector<StackFrame> stackTrace = context->d()->engine->stackTrace(20);
for (int i = 0; i < stackTrace.size(); ++i) {
if (i)
str << ',';
@@ -781,12 +793,12 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
QV4::ExecutionContext *c = currentContext();
while (c) {
CallContext *callCtx = c->asCallContext();
- if (callCtx && callCtx->function) {
- if (callCtx->function->function)
- base.setUrl(callCtx->function->function->sourceFile());
+ if (callCtx && callCtx->d()->function) {
+ if (callCtx->d()->function->function())
+ base.setUrl(callCtx->d()->function->function()->sourceFile());
break;
}
- c = c->parent;
+ c = c->d()->parent;
}
if (base.isEmpty() && globalCode)
@@ -817,8 +829,8 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
delete [] oldAccessors;
}
for (int i = oldSize; i < nArgumentsAccessors; ++i) {
- argumentsAccessors[i].value = Value::fromManaged(new (memoryManager) ArgumentsGetterFunction(rootContext, i));
- argumentsAccessors[i].set = Value::fromManaged(new (memoryManager) ArgumentsSetterFunction(rootContext, i));
+ argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(rootContext, i));
+ argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(rootContext, i));
}
}
}
@@ -839,12 +851,12 @@ void ExecutionEngine::markObjects()
ExecutionContext *c = currentContext();
while (c) {
- Q_ASSERT(c->inUse);
- if (!c->markBit) {
- c->markBit = 1;
+ Q_ASSERT(c->inUse());
+ if (!c->markBit()) {
+ c->d()->markBit = 1;
c->markObjects(c, this);
}
- c = c->parent;
+ c = c->d()->parent;
}
id_empty->mark(this);
@@ -932,7 +944,7 @@ ReturnedValue ExecutionEngine::throwException(const ValueRef value)
QV4::Scope scope(this);
QV4::Scoped<ErrorObject> error(scope, value);
if (!!error)
- exceptionStackTrace = error->stackTrace;
+ exceptionStackTrace = error->d()->stackTrace;
else
exceptionStackTrace = stackTrace();
@@ -971,7 +983,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError(ExecutionContext *context)
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
if (!!errorObj && errorObj->asSyntaxError()) {
QV4::ScopedString m(scope, errorObj->engine()->newString(QStringLiteral("message")));
- QV4::ScopedValue v(scope, errorObj->get(m));
+ QV4::ScopedValue v(scope, errorObj->get(m.getPointer()));
error.setDescription(v->toQStringNoThrow());
} else
error.setDescription(exception->toQStringNoThrow());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index d678d6595e..a3f83de338 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -86,6 +86,7 @@ struct SyntaxErrorObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
+struct Members;
class MemoryManager;
class ExecutableAllocator;
@@ -111,7 +112,7 @@ struct IdentifierTable;
struct InternalClass;
struct InternalClassPool;
class MultiplyWrappedQObjectMap;
-class RegExp;
+struct RegExp;
class RegExpCache;
struct QmlExtensions;
struct Exception;
@@ -169,7 +170,6 @@ public:
return jsStackTop->managed();
}
-
IdentifierTable *identifierTable;
QV4::Debugging::Debugger *debugger;
@@ -285,7 +285,7 @@ public:
// calling preserve() on the object which removes it from this scarceResource list.
class ScarceResourceData {
public:
- ScarceResourceData(const QVariant &data) : data(data) {}
+ ScarceResourceData(const QVariant &data = QVariant()) : data(data) {}
QVariant data;
QIntrusiveListNode node;
};
@@ -306,9 +306,6 @@ public:
void pushContext(CallContext *context);
ExecutionContext *popContext();
- Returned<FunctionObject> *newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *));
- Returned<BoundFunction> *newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs);
-
Returned<Object> *newObject();
Returned<Object> *newObject(InternalClass *internalClass);
@@ -327,7 +324,7 @@ public:
Returned<DateObject> *newDateObject(const QDateTime &dt);
Returned<RegExpObject> *newRegExpObject(const QString &pattern, int flags);
- Returned<RegExpObject> *newRegExpObject(RegExpRef re, bool global);
+ Returned<RegExpObject> *newRegExpObject(RegExp *re, bool global);
Returned<RegExpObject> *newRegExpObject(const QRegExp &re);
Returned<Object> *newErrorObject(const ValueRef value);
@@ -341,7 +338,7 @@ public:
Returned<Object> *newVariantObject(const QVariant &v);
- Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o);
+ Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, Object *o);
Returned<Object> *qmlContextObject() const;
@@ -378,10 +375,10 @@ private:
inline
void Managed::mark(QV4::ExecutionEngine *engine)
{
- Q_ASSERT(inUse);
- if (markBit)
+ Q_ASSERT(inUse());
+ if (markBit())
return;
- markBit = 1;
+ d()->markBit = 1;
engine->pushForGC(this);
}
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 9d6403e7dd..b99a82a1f5 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -71,104 +71,100 @@
using namespace QV4;
-ErrorObject::ErrorObject(InternalClass *ic)
- : Object(ic)
- , stack(0)
+ErrorObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
- Scope scope(engine());
- ScopedValue protectThis(scope, this);
+ Scope scope(ic->engine);
+ Scoped<ErrorObject> e(scope, this);
- ScopedString s(scope, ic->engine->newString(QStringLiteral("Error")));
- defineDefaultProperty(QStringLiteral("name"), s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("Error")));
+ e->defineDefaultProperty(QStringLiteral("name"), s);
}
-ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t)
- : Object(ic)
- , stack(0)
+ErrorObject::Data::Data(InternalClass *ic, const ValueRef message, ErrorType t)
+ : Object::Data(ic)
{
subtype = t;
- Scope scope(engine());
- ScopedValue protectThis(scope, this);
+ Scope scope(ic->engine);
+ Scoped<ErrorObject> e(scope, this);
- defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
+ e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
if (!message->isUndefined())
- defineDefaultProperty(QStringLiteral("message"), message);
+ e->defineDefaultProperty(QStringLiteral("message"), message);
ScopedString s(scope);
- defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className())));
+ e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className())));
- stackTrace = ic->engine->stackTrace();
- if (!stackTrace.isEmpty()) {
- defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source)));
- defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line));
+ e->d()->stackTrace = scope.engine->stackTrace();
+ if (!e->d()->stackTrace.isEmpty()) {
+ e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source)));
+ e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line));
}
}
-ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject::ErrorType t)
- : Object(ic)
- , stack(0)
+ErrorObject::Data::Data(InternalClass *ic, const QString &message, ErrorObject::ErrorType t)
+ : Object::Data(ic)
{
subtype = t;
- Scope scope(engine());
- ScopedValue protectThis(scope, this);
+ Scope scope(ic->engine);
+ Scoped<ErrorObject> e(scope, this);
ScopedString s(scope);
- defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
+ e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
- ScopedValue v(scope, ic->engine->newString(message));
- defineDefaultProperty(QStringLiteral("message"), v);
- defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className())));
+ ScopedValue v(scope, scope.engine->newString(message));
+ e->defineDefaultProperty(QStringLiteral("message"), v);
+ e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className())));
- stackTrace = ic->engine->stackTrace();
- if (!stackTrace.isEmpty()) {
- defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source)));
- defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line));
+ e->d()->stackTrace = scope.engine->stackTrace();
+ if (!e->d()->stackTrace.isEmpty()) {
+ e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source)));
+ e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line));
}
}
-ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
- : Object(ic)
- , stack(0)
+ErrorObject::Data::Data(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
+ : Object::Data(ic)
{
subtype = t;
- Scope scope(engine());
- ScopedValue protectThis(scope, this);
+ Scope scope(ic->engine);
+ Scoped<ErrorObject> e(scope, this);
ScopedString s(scope);
- defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
- defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className())));
+ e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
+ e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className())));
- stackTrace = ic->engine->stackTrace();
+ e->d()->stackTrace = scope.engine->stackTrace();
StackFrame frame;
frame.source = fileName;
frame.line = line;
frame.column = column;
- stackTrace.prepend(frame);
+ e->d()->stackTrace.prepend(frame);
- if (!stackTrace.isEmpty()) {
- defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source)));
- defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line));
+ if (!e->d()->stackTrace.isEmpty()) {
+ e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source)));
+ e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line));
}
- ScopedValue v(scope, ic->engine->newString(message));
- defineDefaultProperty(QStringLiteral("message"), v);
+ ScopedValue v(scope, scope.engine->newString(message));
+ e->defineDefaultProperty(QStringLiteral("message"), v);
}
ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<ErrorObject> This(scope, ctx->callData->thisObject);
+ Scoped<ErrorObject> This(scope, ctx->d()->callData->thisObject);
if (!This)
return ctx->throwTypeError();
- if (!This->stack) {
+ if (!This->d()->stack) {
QString trace;
- for (int i = 0; i < This->stackTrace.count(); ++i) {
+ for (int i = 0; i < This->d()->stackTrace.count(); ++i) {
if (i > 0)
trace += QLatin1Char('\n');
- const StackFrame &frame = This->stackTrace[i];
+ const StackFrame &frame = This->d()->stackTrace[i];
trace += frame.function;
trace += QLatin1Char('@');
trace += frame.source;
@@ -177,16 +173,16 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
trace += QString::number(frame.line);
}
}
- This->stack = ctx->engine->newString(trace)->getPointer();
+ This->d()->stack = ctx->d()->engine->newString(trace)->getPointer();
}
- return This->stack->asReturnedValue();
+ return This->d()->stack->asReturnedValue();
}
void ErrorObject::markObjects(Managed *that, ExecutionEngine *e)
{
ErrorObject *This = that->asErrorObject();
- if (This->stack)
- This->stack->mark(e);
+ if (This->d()->stack)
+ This->d()->stack->mark(e);
Object::markObjects(that, e);
}
@@ -194,58 +190,58 @@ DEFINE_OBJECT_VTABLE(ErrorObject);
DEFINE_OBJECT_VTABLE(SyntaxErrorObject);
-SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg)
- : ErrorObject(engine->syntaxErrorClass, msg, SyntaxError)
+SyntaxErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef msg)
+ : ErrorObject::Data(engine->syntaxErrorClass, msg, SyntaxError)
{
}
-SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
- : ErrorObject(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError)
+SyntaxErrorObject::Data::Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
+ : ErrorObject::Data(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError)
{
}
-EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const ValueRef message)
- : ErrorObject(engine->evalErrorClass, message, EvalError)
+EvalErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message)
+ : ErrorObject::Data(engine->evalErrorClass, message, EvalError)
{
}
-RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const ValueRef message)
- : ErrorObject(engine->rangeErrorClass, message, RangeError)
+RangeErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message)
+ : ErrorObject::Data(engine->rangeErrorClass, message, RangeError)
{
}
-RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message)
- : ErrorObject(engine->rangeErrorClass, message, RangeError)
+RangeErrorObject::Data::Data(ExecutionEngine *engine, const QString &message)
+ : ErrorObject::Data(engine->rangeErrorClass, message, RangeError)
{
}
-ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const ValueRef message)
- : ErrorObject(engine->referenceErrorClass, message, ReferenceError)
+ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message)
+ : ErrorObject::Data(engine->referenceErrorClass, message, ReferenceError)
{
}
-ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message)
- : ErrorObject(engine->referenceErrorClass, message, ReferenceError)
+ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const QString &message)
+ : ErrorObject::Data(engine->referenceErrorClass, message, ReferenceError)
{
}
-ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
- : ErrorObject(engine->referenceErrorClass, msg, fileName, lineNumber, columnNumber, ReferenceError)
+ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
+ : ErrorObject::Data(engine->referenceErrorClass, msg, fileName, lineNumber, columnNumber, ReferenceError)
{
}
-TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const ValueRef message)
- : ErrorObject(engine->typeErrorClass, message, TypeError)
+TypeErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message)
+ : ErrorObject::Data(engine->typeErrorClass, message, TypeError)
{
}
-TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message)
- : ErrorObject(engine->typeErrorClass, message, TypeError)
+TypeErrorObject::Data::Data(ExecutionEngine *engine, const QString &message)
+ : ErrorObject::Data(engine->typeErrorClass, message, TypeError)
{
}
-URIErrorObject::URIErrorObject(ExecutionEngine *engine, const ValueRef message)
- : ErrorObject(engine->uriErrorClass, message, URIError)
+URIErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message)
+ : ErrorObject::Data(engine->uriErrorClass, message, URIError)
{
}
@@ -257,14 +253,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor);
DEFINE_OBJECT_VTABLE(TypeErrorCtor);
DEFINE_OBJECT_VTABLE(URIErrorCtor);
-ErrorCtor::ErrorCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Error"))
+ErrorCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Error"))
{
setVTable(staticVTable());
}
-ErrorCtor::ErrorCtor(ExecutionContext *scope, const QString &name)
- : FunctionObject(scope, name)
+ErrorCtor::Data::Data(ExecutionContext *scope, const QString &name)
+ : FunctionObject::Data(scope, name)
{
setVTable(staticVTable());
}
@@ -281,8 +277,8 @@ ReturnedValue ErrorCtor::call(Managed *that, CallData *callData)
return static_cast<Object *>(that)->construct(callData);
}
-EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("EvalError"))
+EvalErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("EvalError"))
{
setVTable(staticVTable());
}
@@ -291,11 +287,11 @@ ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) EvalErrorObject(m->engine(), v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<EvalErrorObject>(m->engine(), v))->asReturnedValue();
}
-RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("RangeError"))
+RangeErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("RangeError"))
{
setVTable(staticVTable());
}
@@ -304,11 +300,11 @@ ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) RangeErrorObject(scope.engine, v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue();
}
-ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("ReferenceError"))
+ReferenceErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("ReferenceError"))
{
setVTable(staticVTable());
}
@@ -317,11 +313,11 @@ ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) ReferenceErrorObject(scope.engine, v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue();
}
-SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("SyntaxError"))
+SyntaxErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("SyntaxError"))
{
setVTable(staticVTable());
}
@@ -330,11 +326,11 @@ ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) SyntaxErrorObject(scope.engine, v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue();
}
-TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("TypeError"))
+TypeErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("TypeError"))
{
setVTable(staticVTable());
}
@@ -343,11 +339,11 @@ ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) TypeErrorObject(scope.engine, v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue();
}
-URIErrorCtor::URIErrorCtor(ExecutionContext *scope)
- : ErrorCtor(scope, QStringLiteral("URIError"))
+URIErrorCtor::Data::Data(ExecutionContext *scope)
+ : ErrorCtor::Data(scope, QStringLiteral("URIError"))
{
setVTable(staticVTable());
}
@@ -356,10 +352,10 @@ ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData)
{
Scope scope(m->engine());
ScopedValue v(scope, callData->argument(0));
- return (new (m->engine()->memoryManager) URIErrorObject(scope.engine, v))->asReturnedValue();
+ return (m->engine()->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue();
}
-void ErrorPrototype::init(ExecutionEngine *engine, ObjectRef ctor, Object *obj)
+void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj)
{
Scope scope(engine);
ScopedString s(scope);
@@ -375,19 +371,19 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
- Object *o = ctx->callData->thisObject.asObject();
+ Object *o = ctx->d()->callData->thisObject.asObject();
if (!o)
return ctx->throwTypeError();
- ScopedValue name(scope, o->get(ctx->engine->id_name));
+ ScopedValue name(scope, o->get(ctx->d()->engine->id_name));
QString qname;
if (name->isUndefined())
qname = QString::fromLatin1("Error");
else
qname = name->toQString();
- ScopedString s(scope, ctx->engine->newString(QString::fromLatin1("message")));
- ScopedValue message(scope, o->get(s));
+ ScopedString s(scope, ctx->d()->engine->newString(QString::fromLatin1("message")));
+ ScopedValue message(scope, o->get(s.getPointer()));
QString qmessage;
if (!message->isUndefined())
qmessage = message->toQString();
@@ -401,5 +397,5 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
str = qname + QLatin1String(": ") + qmessage;
}
- return ctx->engine->newString(str)->asReturnedValue();
+ return ctx->d()->engine->newString(str)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index c44cc5cdb2..ddf30d2059 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -51,8 +51,6 @@ namespace QV4 {
struct SyntaxErrorObject;
struct ErrorObject: Object {
- V4_OBJECT
- Q_MANAGED_TYPE(ErrorObject)
enum {
IsErrorObject = true
};
@@ -66,17 +64,19 @@ struct ErrorObject: Object {
TypeError,
URIError
};
-
- ErrorObject(InternalClass *ic);
- ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t = Error);
- ErrorObject(InternalClass *ic, const QString &message, ErrorType t = Error);
- ErrorObject(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error);
+ struct Data : Object::Data {
+ Data(InternalClass *ic);
+ Data(InternalClass *ic, const ValueRef message, ErrorType t = Error);
+ Data(InternalClass *ic, const QString &message, ErrorType t = Error);
+ Data(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error);
+ StackTrace stackTrace;
+ String *stack;
+ };
+ V4_OBJECT(Object)
+ Q_MANAGED_TYPE(ErrorObject)
SyntaxErrorObject *asSyntaxError();
- StackTrace stackTrace;
- String *stack;
-
static ReturnedValue method_get_stack(CallContext *ctx);
static void markObjects(Managed *that, ExecutionEngine *e);
static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->~ErrorObject(); }
@@ -88,40 +88,55 @@ inline ErrorObject *value_cast(const Value &v) {
}
struct EvalErrorObject: ErrorObject {
- EvalErrorObject(ExecutionEngine *engine, const ValueRef message);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ };
};
struct RangeErrorObject: ErrorObject {
- RangeErrorObject(ExecutionEngine *engine, const ValueRef message);
- RangeErrorObject(ExecutionEngine *engine, const QString &msg);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ Data(ExecutionEngine *engine, const QString &msg);
+ };
};
struct ReferenceErrorObject: ErrorObject {
- ReferenceErrorObject(ExecutionEngine *engine, const ValueRef message);
- ReferenceErrorObject(ExecutionEngine *engine, const QString &msg);
- ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ Data(ExecutionEngine *engine, const QString &msg);
+ Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
+ };
};
struct SyntaxErrorObject: ErrorObject {
- V4_OBJECT
- SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg);
- SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber);
+ };
+ V4_OBJECT(ErrorObject)
};
struct TypeErrorObject: ErrorObject {
- TypeErrorObject(ExecutionEngine *engine, const ValueRef message);
- TypeErrorObject(ExecutionEngine *engine, const QString &msg);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ Data(ExecutionEngine *engine, const QString &msg);
+ };
};
struct URIErrorObject: ErrorObject {
- URIErrorObject(ExecutionEngine *engine, const ValueRef message);
+ struct Data : ErrorObject::Data {
+ Data(ExecutionEngine *engine, const ValueRef message);
+ };
};
struct ErrorCtor: FunctionObject
{
- V4_OBJECT
- ErrorCtor(ExecutionContext *scope);
- ErrorCtor(ExecutionContext *scope, const QString &name);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ Data(ExecutionContext *scope, const QString &name);
+ };
+
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -129,103 +144,107 @@ struct ErrorCtor: FunctionObject
struct EvalErrorCtor: ErrorCtor
{
- V4_OBJECT
- EvalErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
struct RangeErrorCtor: ErrorCtor
{
- V4_OBJECT
- RangeErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
struct ReferenceErrorCtor: ErrorCtor
{
- V4_OBJECT
- ReferenceErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
struct SyntaxErrorCtor: ErrorCtor
{
- V4_OBJECT
- SyntaxErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
struct TypeErrorCtor: ErrorCtor
{
- V4_OBJECT
- TypeErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
struct URIErrorCtor: ErrorCtor
{
- V4_OBJECT
- URIErrorCtor(ExecutionContext *scope);
+ struct Data : ErrorCtor::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(ErrorCtor)
static ReturnedValue construct(Managed *m, CallData *callData);
};
-struct ErrorPrototype: ErrorObject
+struct ErrorPrototype : ErrorObject
{
- // ### shouldn't be undefined
- ErrorPrototype(InternalClass *ic): ErrorObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor) { init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this); }
- static void init(ExecutionEngine *engine, ObjectRef ctor, Object *obj);
+ static void init(ExecutionEngine *engine, Object *ctor, Object *obj);
static ReturnedValue method_toString(CallContext *ctx);
};
-struct EvalErrorPrototype: ErrorObject
+struct EvalErrorPrototype : ErrorObject
{
- EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
-struct RangeErrorPrototype: ErrorObject
+struct RangeErrorPrototype : ErrorObject
{
- RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
-struct ReferenceErrorPrototype: ErrorObject
+struct ReferenceErrorPrototype : ErrorObject
{
- ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
-struct SyntaxErrorPrototype: ErrorObject
+struct SyntaxErrorPrototype : ErrorObject
{
- SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
-struct TypeErrorPrototype: ErrorObject
+struct TypeErrorPrototype : ErrorObject
{
- TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
-struct URIErrorPrototype: ErrorObject
+struct URIErrorPrototype : ErrorObject
{
- URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); }
- void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
+ void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); }
};
inline SyntaxErrorObject *ErrorObject::asSyntaxError()
{
- return subtype == SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0;
+ return subtype() == SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0;
}
}
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 6fdf61f2c3..bf77b4434c 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -45,6 +45,7 @@
#include "qv4value_inl_p.h"
#include "qv4engine_p.h"
#include "qv4lookup_p.h"
+#include "qv4mm_p.h"
QT_BEGIN_NAMESPACE
@@ -62,6 +63,8 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
internalClass = engine->emptyClass;
const quint32 *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
+ Scope scope(engine);
+ ScopedString s(scope);
for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) {
String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
while (1) {
@@ -71,7 +74,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
break;
}
// duplicate arguments, need some trick to store them
- arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer());
+ arg = (s = engine->memoryManager->alloc<String>(engine, arg, engine->newString(QString(0xfffe))->getPointer())).getPointer();
}
}
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index e6385d861c..482f247319 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -94,8 +94,8 @@ struct Q_QML_EXPORT Function {
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *));
~Function();
- inline StringRef name() {
- return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
+ inline String *name() {
+ return compilationUnit->runtimeStrings[compiledFunction->nameIndex].getPointer();
}
inline QString sourceFile() const { return compilationUnit->fileName(); }
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 39a123c4d2..29628eb3ee 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -74,88 +74,88 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto)
- : Object(scope->engine->functionClass)
+FunctionObject::Data::Data(ExecutionContext *scope, String *name, bool createProto)
+ : Object::Data(scope->d()->engine->functionClass)
, scope(scope)
- , function(0)
{
- init(name, createProto);
+ Scope s(scope);
+ ScopedFunctionObject f(s, this);
+ f->init(name, createProto);
}
-FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
- : Object(scope->engine->functionClass)
+
+FunctionObject::Data::Data(ExecutionContext *scope, const QString &name, bool createProto)
+ : Object::Data(scope->d()->engine->functionClass)
, scope(scope)
- , function(0)
{
Scope s(scope);
- ScopedValue protectThis(s, this);
+ ScopedFunctionObject f(s, this);
ScopedString n(s, s.engine->newString(name));
- init(n, createProto);
+ f->init(n.getPointer(), createProto);
}
-FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name)
- : Object(scope->engine->functionClass)
+FunctionObject::Data::Data(ExecutionContext *scope, const ReturnedValue name)
+ : Object::Data(scope->d()->engine->functionClass)
, scope(scope)
- , function(0)
{
Scope s(scope);
- ScopedValue protectThis(s, this);
+ ScopedFunctionObject f(s, this);
ScopedString n(s, name);
- init(n, false);
+ f->init(n.getPointer(), false);
}
-FunctionObject::FunctionObject(InternalClass *ic)
- : Object(ic)
+FunctionObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
, scope(ic->engine->rootContext)
- , function(0)
{
- needsActivation = false;
- strictMode = false;
+ memberData.ensureIndex(ic->engine, Index_Prototype);
memberData[Index_Prototype] = Encode::undefined();
}
-FunctionObject::~FunctionObject()
+
+FunctionObject::Data::~Data()
{
if (function)
function->compilationUnit->deref();
}
-void FunctionObject::init(const StringRef n, bool createProto)
+void FunctionObject::init(String *n, bool createProto)
{
- Scope s(internalClass->engine);
+ Scope s(internalClass()->engine);
ScopedValue protectThis(s, this);
- needsActivation = true;
- strictMode = false;
+ d()->needsActivation = true;
+ d()->strictMode = false;
+ memberData().ensureIndex(s.engine, Index_Prototype);
if (createProto) {
- Scoped<Object> proto(s, scope->engine->newObject(scope->engine->protoClass));
- proto->memberData[Index_ProtoConstructor] = this->asReturnedValue();
- memberData[Index_Prototype] = proto.asReturnedValue();
+ Scoped<Object> proto(s, scope()->d()->engine->newObject(scope()->d()->engine->protoClass));
+ proto->memberData()[Index_ProtoConstructor] = this->asReturnedValue();
+ memberData()[Index_Prototype] = proto.asReturnedValue();
} else {
- memberData[Index_Prototype] = Encode::undefined();
+ memberData()[Index_Prototype] = Encode::undefined();
}
- ScopedValue v(s, n.asReturnedValue());
- defineReadonlyProperty(scope->engine->id_name, v);
+ ScopedValue v(s, n);
+ defineReadonlyProperty(s.engine->id_name, v);
}
ReturnedValue FunctionObject::name()
{
- return get(scope->engine->id_name);
+ return get(scope()->d()->engine->id_name);
}
ReturnedValue FunctionObject::newInstance()
{
- Scope scope(internalClass->engine);
+ Scope scope(internalClass()->engine);
ScopedCallData callData(scope, 0);
return construct(callData);
}
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
{
- that->internalClass->engine->currentContext()->throwTypeError();
+ that->internalClass()->engine->currentContext()->throwTypeError();
return Encode::undefined();
}
@@ -167,8 +167,8 @@ ReturnedValue FunctionObject::call(Managed *, CallData *)
void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
{
FunctionObject *o = static_cast<FunctionObject *>(that);
- if (o->scope)
- o->scope->mark(e);
+ if (o->scope())
+ o->scope()->mark(e);
Object::markObjects(that, e);
}
@@ -179,14 +179,14 @@ FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Fu
function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
function->isNamedExpression())
- return new (scope->engine->memoryManager) ScriptFunction(scope, function);
- return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function, createProto);
+ return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function);
+ return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto);
}
DEFINE_OBJECT_VTABLE(FunctionCtor);
-FunctionCtor::FunctionCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Function"))
+FunctionCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Function"))
{
setVTable(staticVTable());
}
@@ -195,7 +195,7 @@ FunctionCtor::FunctionCtor(ExecutionContext *scope)
ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
{
FunctionCtor *f = static_cast<FunctionCtor *>(that);
- ExecutionEngine *v4 = f->internalClass->engine;
+ ExecutionEngine *v4 = f->internalClass()->engine;
ExecutionContext *ctx = v4->currentContext();
QString arguments;
QString body;
@@ -207,7 +207,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
}
body = callData->args[callData->argc - 1].toString(ctx)->toQString();
}
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
@@ -229,7 +229,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
IR::Module module(v4->debugger != 0);
- QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode);
+ QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode());
cg.generateFromFunctionExpression(QString(), function, fe, &module);
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
@@ -246,12 +246,14 @@ ReturnedValue FunctionCtor::call(Managed *that, CallData *callData)
return construct(that, callData);
}
-FunctionPrototype::FunctionPrototype(InternalClass *ic)
- : FunctionObject(ic)
+DEFINE_OBJECT_VTABLE(FunctionPrototype);
+
+FunctionPrototype::Data::Data(InternalClass *ic)
+ : FunctionObject::Data(ic)
{
}
-void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -270,17 +272,17 @@ void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
{
- FunctionObject *fun = ctx->callData->thisObject.asFunctionObject();
+ FunctionObject *fun = ctx->d()->callData->thisObject.asFunctionObject();
if (!fun)
return ctx->throwTypeError();
- return ctx->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
+ return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
}
ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
{
Scope scope(ctx);
- FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
+ FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject();
if (!o)
return ctx->throwTypeError();
@@ -300,13 +302,13 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
ScopedCallData callData(scope, len);
if (len) {
- if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty()) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
- int alen = qMin(len, arr->arrayData->length());
+ int alen = qMin(len, arr->arrayData()->length());
if (alen)
- memcpy(callData->args, arr->arrayData->data, alen*sizeof(Value));
+ memcpy(callData->args, arr->arrayData()->arrayData(), alen*sizeof(Value));
for (quint32 i = alen; i < len; ++i)
callData->args[i] = Primitive::undefinedValue();
}
@@ -320,14 +322,14 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
{
Scope scope(ctx);
- FunctionObject *o = ctx->callData->thisObject.asFunctionObject();
+ FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject();
if (!o)
return ctx->throwTypeError();
- ScopedCallData callData(scope, ctx->callData->argc ? ctx->callData->argc - 1 : 0);
- if (ctx->callData->argc) {
- for (int i = 1; i < ctx->callData->argc; ++i)
- callData->args[i - 1] = ctx->callData->args[i];
+ ScopedCallData callData(scope, ctx->d()->callData->argc ? ctx->d()->callData->argc - 1 : 0);
+ if (ctx->d()->callData->argc) {
+ for (int i = 1; i < ctx->d()->callData->argc; ++i)
+ callData->args[i - 1] = ctx->d()->callData->args[i];
}
callData->thisObject = ctx->argument(0);
return o->call(callData);
@@ -336,49 +338,34 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<FunctionObject> target(scope, ctx->callData->thisObject);
+ Scoped<FunctionObject> target(scope, ctx->d()->callData->thisObject);
if (!target)
return ctx->throwTypeError();
ScopedValue boundThis(scope, ctx->argument(0));
- QVector<Value> boundArgs;
- for (int i = 1; i < ctx->callData->argc; ++i)
- boundArgs += ctx->callData->args[i];
+ Members boundArgs;
+ boundArgs.reset();
+ if (ctx->d()->callData->argc > 1) {
+ boundArgs.ensureIndex(scope.engine, ctx->d()->callData->argc - 1);
+ boundArgs.d()->d()->size = ctx->d()->callData->argc - 1;
+ memcpy(boundArgs.data(), ctx->d()->callData->args + 1, (ctx->d()->callData->argc - 1)*sizeof(Value));
+ }
+ ScopedValue protectBoundArgs(scope, boundArgs.d());
- return ctx->engine->newBoundFunction(ctx->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue();
+ return BoundFunction::create(ctx->d()->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
-ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
- : SimpleScriptFunction(scope, function, true)
+ScriptFunction::Data::Data(ExecutionContext *scope, Function *function)
+ : SimpleScriptFunction::Data(scope, function, true)
{
setVTable(staticVTable());
-
- Scope s(scope);
- ScopedValue protectThis(s, this);
-
- // global function
- if (!scope)
- return;
-
- ExecutionEngine *v4 = scope->engine;
-
- needsActivation = function->needsActivation();
- strictMode = function->isStrict();
-
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount()));
-
- if (scope->strictMode) {
- Property pd(v4->thrower, v4->thrower);
- insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- }
}
ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->internalClass->engine;
+ ExecutionEngine *v4 = that->engine();
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -391,13 +378,16 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
callData->thisObject = obj.asReturnedValue();
- ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
+ ExecutionContext *ctx = reinterpret_cast<ExecutionContext *>(context->newCallContext(f.getPointer(), callData));
ExecutionContextSaver ctxSaver(context);
- ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function));
+ ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function()));
- if (f->function->compiledFunction->hasQmlDependencies())
- QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+ if (f->function()->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
+
+ if (v4->hasException)
+ return Encode::undefined();
if (result->isObject())
return result.asReturnedValue();
@@ -407,7 +397,7 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
{
ScriptFunction *f = static_cast<ScriptFunction *>(that);
- ExecutionEngine *v4 = f->internalClass->engine;
+ ExecutionEngine *v4 = f->engine();
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -415,53 +405,51 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
Scope scope(context);
- CallContext *ctx = context->newCallContext(f, callData);
+ CallContext *ctx = reinterpret_cast<CallContext *>(context->newCallContext(f, callData));
ExecutionContextSaver ctxSaver(context);
- ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function));
+ ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function()));
- if (f->function->compiledFunction->hasQmlDependencies())
- QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction);
+ if (f->function()->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction);
return result.asReturnedValue();
}
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
-SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
- : FunctionObject(scope, function->name(), createProto)
+SimpleScriptFunction::Data::Data(ExecutionContext *scope, Function *function, bool createProto)
+ : FunctionObject::Data(scope, function->name(), createProto)
{
setVTable(staticVTable());
- Scope s(scope);
- ScopedValue protectThis(s, this);
-
this->function = function;
- this->function->compilationUnit->ref();
+ function->compilationUnit->ref();
Q_ASSERT(function);
Q_ASSERT(function->code);
+ needsActivation = function->needsActivation();
+ strictMode = function->isStrict();
+
// global function
if (!scope)
return;
- ExecutionEngine *v4 = scope->engine;
-
- needsActivation = function->needsActivation();
- strictMode = function->isStrict();
+ Scope s(scope);
+ ScopedFunctionObject f(s, this);
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount()));
+ f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount()));
- if (scope->strictMode) {
- Property pd(v4->thrower, v4->thrower);
- insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ if (scope->d()->strictMode) {
+ Property pd(s.engine->thrower, s.engine->thrower);
+ f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
}
ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->internalClass->engine;
+ ExecutionEngine *v4 = that->engine();
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -475,24 +463,24 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
ExecutionContextSaver ctxSaver(context);
- CallContext ctx(v4);
- ctx.strictMode = f->strictMode;
+ CallContext::Data ctx(v4);
+ ctx.strictMode = f->strictMode();
ctx.callData = callData;
ctx.function = f.getPointer();
- ctx.compilationUnit = f->function->compilationUnit;
+ ctx.compilationUnit = f->function()->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
- ctx.outer = f->scope;
+ ctx.outer = f->scope();
ctx.locals = v4->stackPush(f->varCount());
while (callData->argc < (int)f->formalParameterCount()) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- Q_ASSERT(v4->currentContext() == &ctx);
+ Q_ASSERT(v4->currentContext()->d() == &ctx);
- Scoped<Object> result(scope, Q_V4_PROFILE(v4, &ctx, f->function));
+ Scoped<Object> result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function()));
- if (f->function->compiledFunction->hasQmlDependencies())
- QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+ if (f->function()->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
if (!result)
return callData->thisObject.asReturnedValue();
@@ -501,7 +489,7 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
{
- ExecutionEngine *v4 = that->internalClass->engine;
+ ExecutionEngine *v4 = that->internalClass()->engine;
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -512,24 +500,24 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
ExecutionContextSaver ctxSaver(context);
- CallContext ctx(v4);
- ctx.strictMode = f->strictMode;
+ CallContext::Data ctx(v4);
+ ctx.strictMode = f->strictMode();
ctx.callData = callData;
ctx.function = f;
- ctx.compilationUnit = f->function->compilationUnit;
+ ctx.compilationUnit = f->function()->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
- ctx.outer = f->scope;
+ ctx.outer = f->scope();
ctx.locals = v4->stackPush(f->varCount());
while (callData->argc < (int)f->formalParameterCount()) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- Q_ASSERT(v4->currentContext() == &ctx);
+ Q_ASSERT(v4->currentContext()->d() == &ctx);
- ScopedValue result(scope, Q_V4_PROFILE(v4, &ctx, f->function));
+ ScopedValue result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function()));
- if (f->function->compiledFunction->hasQmlDependencies())
- QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
+ if (f->function()->compiledFunction->hasQmlDependencies())
+ QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction);
return result.asReturnedValue();
}
@@ -538,10 +526,10 @@ InternalClass *SimpleScriptFunction::internalClassForConstructor()
{
ReturnedValue proto = protoProperty();
InternalClass *classForConstructor;
- Scope scope(internalClass->engine);
+ Scope scope(internalClass()->engine);
ScopedObject p(scope, proto);
if (p)
- classForConstructor = internalClass->engine->constructClass->changePrototype(p.getPointer());
+ classForConstructor = internalClass()->engine->constructClass->changePrototype(p.getPointer());
else
classForConstructor = scope.engine->objectClass;
@@ -552,8 +540,8 @@ InternalClass *SimpleScriptFunction::internalClassForConstructor()
DEFINE_OBJECT_VTABLE(BuiltinFunction);
-BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
- : FunctionObject(scope, name)
+BuiltinFunction::Data::Data(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
+ : FunctionObject::Data(scope, name)
, code(code)
{
setVTable(staticVTable());
@@ -561,13 +549,13 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
{
- return f->internalClass->engine->currentContext()->throwTypeError();
+ return f->internalClass()->engine->currentContext()->throwTypeError();
}
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
{
BuiltinFunction *f = static_cast<BuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass->engine;
+ ExecutionEngine *v4 = f->internalClass()->engine;
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -575,18 +563,18 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
ExecutionContextSaver ctxSaver(context);
- CallContext ctx(v4);
- ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
+ CallContext::Data ctx(v4);
+ ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- Q_ASSERT(v4->currentContext() == &ctx);
+ Q_ASSERT(v4->currentContext()->d() == &ctx);
- return f->code(&ctx);
+ return f->d()->code(reinterpret_cast<CallContext *>(&ctx));
}
ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
{
IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that);
- ExecutionEngine *v4 = f->internalClass->engine;
+ ExecutionEngine *v4 = f->internalClass()->engine;
if (v4->hasException)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
@@ -594,82 +582,76 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
ExecutionContext *context = v4->currentContext();
ExecutionContextSaver ctxSaver(context);
- CallContext ctx(v4);
- ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
+ CallContext::Data ctx(v4);
+ ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- Q_ASSERT(v4->currentContext() == &ctx);
+ Q_ASSERT(v4->currentContext()->d() == &ctx);
- return f->code(&ctx, f->index);
+ return f->d()->code(reinterpret_cast<CallContext *>(&ctx), f->d()->index);
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
DEFINE_OBJECT_VTABLE(BoundFunction);
-BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs)
- : FunctionObject(scope, QStringLiteral("__bound function__"))
+BoundFunction::Data::Data(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const Members &boundArgs)
+ : FunctionObject::Data(scope, QStringLiteral("__bound function__"))
, target(target)
, boundArgs(boundArgs)
{
+ this->boundThis = boundThis;
setVTable(staticVTable());
subtype = FunctionObject::BoundFunction;
- this->boundThis = boundThis;
Scope s(scope);
- ScopedValue protectThis(s, this);
+ ScopedObject f(s, this);
- ScopedValue l(s, target->get(scope->engine->id_length));
+ ScopedValue l(s, target->get(s.engine->id_length));
int len = l->toUInt32();
len -= boundArgs.size();
if (len < 0)
len = 0;
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(len));
+ f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len));
- ExecutionEngine *v4 = scope->engine;
+ ExecutionEngine *v4 = s.engine;
Property pd(v4->thrower, v4->thrower);
- insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
-}
-
-void BoundFunction::destroy(Managed *that)
-{
- static_cast<BoundFunction *>(that)->~BoundFunction();
+ f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
ReturnedValue BoundFunction::call(Managed *that, CallData *dd)
{
BoundFunction *f = static_cast<BoundFunction *>(that);
- Scope scope(f->scope->engine);
+ Scope scope(f->scope()->d()->engine);
if (scope.hasException())
return Encode::undefined();
- ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
- callData->thisObject = f->boundThis;
- memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
- memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
- return f->target->call(callData);
+ ScopedCallData callData(scope, f->boundArgs().size() + dd->argc);
+ callData->thisObject = f->boundThis();
+ memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value));
+ memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value));
+ return f->target()->call(callData);
}
ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
{
BoundFunction *f = static_cast<BoundFunction *>(that);
- Scope scope(f->scope->engine);
+ Scope scope(f->scope()->d()->engine);
if (scope.hasException())
return Encode::undefined();
- ScopedCallData callData(scope, f->boundArgs.size() + dd->argc);
- memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
- memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value));
- return f->target->construct(callData);
+ ScopedCallData callData(scope, f->boundArgs().size() + dd->argc);
+ memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value));
+ memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value));
+ return f->target()->construct(callData);
}
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
{
BoundFunction *o = static_cast<BoundFunction *>(that);
- o->target->mark(e);
- o->boundThis.mark(e);
- for (int i = 0; i < o->boundArgs.size(); ++i)
- o->boundArgs.at(i).mark(e);
+ o->target()->mark(e);
+ o->boundThis().mark(e);
+ 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 5b832d0595..907b660911 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -51,6 +51,7 @@
#include "qv4property_p.h"
#include "qv4function_p.h"
#include "qv4objectiterator_p.h"
+#include "qv4mm_p.h"
#include <QtCore/QString>
#include <QtCore/QHash>
@@ -94,7 +95,17 @@ struct InternalClass;
struct Lookup;
struct Q_QML_EXPORT FunctionObject: Object {
- V4_OBJECT
+ struct Q_QML_PRIVATE_EXPORT Data : Object::Data {
+ Data(ExecutionContext *scope, String *name, bool createProto = false);
+ Data(ExecutionContext *scope, const QString &name = QString(), bool createProto = false);
+ Data(ExecutionContext *scope, const ReturnedValue name);
+ Data(InternalClass *ic);
+ ~Data();
+
+ ExecutionContext *scope;
+ Function *function;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(FunctionObject)
enum {
IsFunctionObject = true
@@ -111,18 +122,15 @@ struct Q_QML_EXPORT FunctionObject: Object {
Index_ProtoConstructor = 0
};
- ExecutionContext *scope;
- ReturnedValue name();
- unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; }
- unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
- Function *function;
- FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false);
- FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false);
- FunctionObject(ExecutionContext *scope, const ReturnedValue name);
- ~FunctionObject();
+ ExecutionContext *scope() { return d()->scope; }
+ Function *function() { return d()->function; }
+
+ ReturnedValue name();
+ unsigned int formalParameterCount() { return function() ? function()->compiledFunction->nFormals : 0; }
+ unsigned int varCount() { return function() ? function()->compiledFunction->nLocals : 0; }
- void init(const StringRef name, bool createProto);
+ void init(String *name, bool createProto);
ReturnedValue newInstance();
@@ -130,6 +138,9 @@ struct Q_QML_EXPORT FunctionObject: Object {
using Object::call;
static ReturnedValue construct(Managed *that, CallData *);
static ReturnedValue call(Managed *that, CallData *d);
+ static void destroy(Managed *m) {
+ static_cast<FunctionObject *>(m)->d()->~Data();
+ }
static FunctionObject *cast(const Value &v) {
return v.asFunctionObject();
@@ -137,14 +148,13 @@ struct Q_QML_EXPORT FunctionObject: Object {
static FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true);
- ReturnedValue protoProperty() { return memberData[Index_Prototype].asReturnedValue(); }
+ ReturnedValue protoProperty() { return memberData()[Index_Prototype].asReturnedValue(); }
-protected:
- FunctionObject(InternalClass *ic);
+ bool needsActivation() const { return d()->needsActivation; }
+ bool strictMode() const { return d()->strictMode; }
+ bool bindingKeyFlag() const { return d()->bindingKeyFlag; }
static void markObjects(Managed *that, ExecutionEngine *e);
- static void destroy(Managed *that)
- { static_cast<FunctionObject*>(that)->~FunctionObject(); }
};
template<>
@@ -152,12 +162,13 @@ inline FunctionObject *value_cast(const Value &v) {
return v.asFunctionObject();
}
-DEFINE_REF(FunctionObject, Object);
-
struct FunctionCtor: FunctionObject
{
- V4_OBJECT
- FunctionCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *that, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -165,8 +176,12 @@ struct FunctionCtor: FunctionObject
struct FunctionPrototype: FunctionObject
{
- FunctionPrototype(InternalClass *ic);
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ struct Data : FunctionObject::Data {
+ Data(InternalClass *ic);
+ };
+ V4_OBJECT(FunctionObject)
+
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_apply(CallContext *ctx);
@@ -174,11 +189,17 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_bind(CallContext *ctx);
};
-struct BuiltinFunction: FunctionObject {
- V4_OBJECT
- ReturnedValue (*code)(CallContext *);
+struct Q_QML_EXPORT BuiltinFunction: FunctionObject {
+ struct Q_QML_EXPORT Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *));
+ ReturnedValue (*code)(CallContext *);
+ };
+ V4_OBJECT(FunctionObject)
- BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *));
+ static BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
+ {
+ return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code);
+ }
static ReturnedValue construct(Managed *, CallData *);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -186,18 +207,18 @@ struct BuiltinFunction: FunctionObject {
struct IndexedBuiltinFunction: FunctionObject
{
- V4_OBJECT
-
- ReturnedValue (*code)(CallContext *ctx, uint index);
- uint index;
-
- IndexedBuiltinFunction(ExecutionContext *scope, uint index, ReturnedValue (*code)(CallContext *ctx, uint index))
- : FunctionObject(scope)
- , code(code)
- , index(index)
- {
- setVTable(staticVTable());
- }
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, uint index, ReturnedValue (*code)(CallContext *ctx, uint index))
+ : FunctionObject::Data(scope),
+ code(code)
+ , index(index)
+ {
+ setVTable(staticVTable());
+ }
+ ReturnedValue (*code)(CallContext *, uint index);
+ uint index;
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *m, CallData *)
{
@@ -209,8 +230,10 @@ struct IndexedBuiltinFunction: FunctionObject
struct SimpleScriptFunction: FunctionObject {
- V4_OBJECT
- SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, Function *function, bool createProto);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -219,8 +242,10 @@ struct SimpleScriptFunction: FunctionObject {
};
struct ScriptFunction: SimpleScriptFunction {
- V4_OBJECT
- ScriptFunction(ExecutionContext *scope, Function *function);
+ struct Data : SimpleScriptFunction::Data {
+ Data(ExecutionContext *scope, Function *function);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -228,19 +253,26 @@ struct ScriptFunction: SimpleScriptFunction {
struct BoundFunction: FunctionObject {
- V4_OBJECT
- FunctionObject *target;
- Value boundThis;
- QVector<Value> boundArgs;
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const Members &boundArgs);
+ FunctionObject *target;
+ Value boundThis;
+ Members boundArgs;
+ };
+ V4_OBJECT(FunctionObject)
- BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs);
- ~BoundFunction() {}
+ static BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs)
+ {
+ return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs);
+ }
+ FunctionObject *target() { return d()->target; }
+ Value boundThis() const { return d()->boundThis; }
+ Members boundArgs() const { return d()->boundArgs; }
static ReturnedValue construct(Managed *, CallData *d);
static ReturnedValue call(Managed *that, CallData *dd);
- static void destroy(Managed *);
static void markObjects(Managed *that, ExecutionEngine *e);
};
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index a00231c3a1..039f5c1e78 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -74,15 +74,19 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
// Decide whether to enable or disable the JIT
// White list architectures
+//
+// NOTE: This should match the logic in qv4targetplatform_p.h!
-#if defined(Q_PROCESSOR_X86)
+#if defined(Q_PROCESSOR_X86) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD))
#define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_X86_64)
+#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
#define V4_ENABLE_JIT
#elif defined(Q_PROCESSOR_ARM_32)
#if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4)
#define V4_ENABLE_JIT
+#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 // clang 3.5 and later will set this if the core supports the Thumb-2 ISA.
+#define V4_ENABLE_JIT
#endif
#endif
@@ -161,12 +165,6 @@ template<typename T> struct Returned;
typedef Returned<String> ReturnedString;
typedef Returned<Object> ReturnedObject;
typedef Returned<FunctionObject> ReturnedFunctionObject;
-struct ManagedRef;
-struct StringRef;
-struct ObjectRef;
-struct ArrayObjectRef;
-struct FunctionObjectRef;
-struct RegExpRef;
struct PersistentValuePrivate;
class PersistentValue;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index eb0994c1e6..a699442273 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -346,36 +346,17 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
DEFINE_OBJECT_VTABLE(EvalFunction);
-EvalFunction::EvalFunction(ExecutionContext *scope)
- : FunctionObject(scope, scope->engine->id_eval)
+EvalFunction::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, scope->d()->engine->id_eval)
{
setVTable(staticVTable());
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
+ Scope s(scope);
+ ScopedFunctionObject f(s, this);
+ f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(1));
}
ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
{
- struct ContextStateSaver {
- ExecutionContext *savedContext;
- bool strictMode;
- ExecutionContext::EvalCode *evalCode;
- CompiledData::CompilationUnit *compilationUnit;
-
- ContextStateSaver(ExecutionContext *context)
- : savedContext(context)
- , strictMode(context->strictMode)
- , evalCode(context->currentEvalCode)
- , compilationUnit(context->compilationUnit)
- {}
-
- ~ContextStateSaver()
- {
- savedContext->strictMode = strictMode;
- savedContext->currentEvalCode = evalCode;
- savedContext->compilationUnit = compilationUnit;
- }
- };
-
if (callData->argc < 1)
return Encode::undefined();
@@ -396,10 +377,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
return callData->args[0].asReturnedValue();
const QString code = callData->args[0].stringValue()->toQString();
- bool inheritContext = !ctx->strictMode;
+ bool inheritContext = !ctx->d()->strictMode;
Script script(ctx, code, QStringLiteral("eval code"));
- script.strictMode = (directCall && parentContext->strictMode);
+ script.strictMode = (directCall && parentContext->d()->strictMode);
script.inheritContext = inheritContext;
script.parse();
if (scope.engine->hasException)
@@ -409,14 +390,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
if (!function)
return Encode::undefined();
- strictMode = function->isStrict() || (ctx->strictMode);
+ d()->strictMode = function->isStrict() || (ctx->d()->strictMode);
- needsActivation = function->needsActivation();
+ d()->needsActivation = function->needsActivation();
- if (strictMode) {
+ if (strictMode()) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedCallData callData(scope, 0);
- callData->thisObject = ctx->callData->thisObject;
+ callData->thisObject = ctx->d()->callData->thisObject;
return e->call(callData);
}
@@ -424,12 +405,12 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
ExecutionContext::EvalCode evalCode;
evalCode.function = function;
- evalCode.next = ctx->currentEvalCode;
- ctx->currentEvalCode = &evalCode;
+ evalCode.next = ctx->d()->currentEvalCode;
+ ctx->d()->currentEvalCode = &evalCode;
// set the correct strict mode flag on the context
- ctx->strictMode = strictMode;
- ctx->compilationUnit = function->compilationUnit;
+ ctx->d()->strictMode = strictMode();
+ ctx->d()->compilationUnit = function->compilationUnit;
return function->code(ctx, function->codeData);
}
@@ -470,7 +451,7 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
String *inputString = string->toString(ctx); // 1
QString trimmed = inputString->toQString().trimmed(); // 2
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
const QChar *pos = trimmed.constData();
@@ -574,117 +555,117 @@ ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
/// isNaN [15.1.2.4]
ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx)
{
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
// undefined gets converted to NaN
return Encode(true);
- if (ctx->callData->args[0].integerCompatible())
+ if (ctx->d()->callData->args[0].integerCompatible())
return Encode(false);
- double d = ctx->callData->args[0].toNumber();
+ double d = ctx->d()->callData->args[0].toNumber();
return Encode((bool)std::isnan(d));
}
/// isFinite [15.1.2.5]
ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx)
{
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
// undefined gets converted to NaN
return Encode(false);
- if (ctx->callData->args[0].integerCompatible())
+ if (ctx->d()->callData->args[0].integerCompatible())
return Encode(true);
- double d = ctx->callData->args[0].toNumber();
+ double d = ctx->d()->callData->args[0].toNumber();
return Encode((bool)std::isfinite(d));
}
/// decodeURI [15.1.3.1]
ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context)
{
- if (context->callData->argc == 0)
+ if (context->d()->callData->argc == 0)
return Encode::undefined();
- QString uriString = context->callData->args[0].toString(context)->toQString();
+ QString uriString = context->d()->callData->args[0].toString(context)->toQString();
bool ok;
QString out = decode(uriString, DecodeNonReserved, &ok);
if (!ok) {
Scope scope(context);
- ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
+ ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
return context->throwURIError(s);
}
- return context->engine->newString(out)->asReturnedValue();
+ return context->d()->engine->newString(out)->asReturnedValue();
}
/// decodeURIComponent [15.1.3.2]
ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context)
{
- if (context->callData->argc == 0)
+ if (context->d()->callData->argc == 0)
return Encode::undefined();
- QString uriString = context->callData->args[0].toString(context)->toQString();
+ QString uriString = context->d()->callData->args[0].toString(context)->toQString();
bool ok;
QString out = decode(uriString, DecodeAll, &ok);
if (!ok) {
Scope scope(context);
- ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
+ ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
return context->throwURIError(s);
}
- return context->engine->newString(out)->asReturnedValue();
+ return context->d()->engine->newString(out)->asReturnedValue();
}
/// encodeURI [15.1.3.3]
ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context)
{
- if (context->callData->argc == 0)
+ if (context->d()->callData->argc == 0)
return Encode::undefined();
- QString uriString = context->callData->args[0].toString(context)->toQString();
+ QString uriString = context->d()->callData->args[0].toString(context)->toQString();
bool ok;
QString out = encode(uriString, uriUnescapedReserved, &ok);
if (!ok) {
Scope scope(context);
- ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
+ ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
return context->throwURIError(s);
}
- return context->engine->newString(out)->asReturnedValue();
+ return context->d()->engine->newString(out)->asReturnedValue();
}
/// encodeURIComponent [15.1.3.4]
ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context)
{
- if (context->callData->argc == 0)
+ if (context->d()->callData->argc == 0)
return Encode::undefined();
- QString uriString = context->callData->args[0].toString(context)->toQString();
+ QString uriString = context->d()->callData->args[0].toString(context)->toQString();
bool ok;
QString out = encode(uriString, uriUnescaped, &ok);
if (!ok) {
Scope scope(context);
- ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence")));
+ ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
return context->throwURIError(s);
}
- return context->engine->newString(out)->asReturnedValue();
+ return context->d()->engine->newString(out)->asReturnedValue();
}
ReturnedValue GlobalFunctions::method_escape(CallContext *context)
{
- if (!context->callData->argc)
- return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!context->d()->callData->argc)
+ return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
- QString str = context->callData->args[0].toString(context)->toQString();
- return context->engine->newString(escape(str))->asReturnedValue();
+ QString str = context->d()->callData->args[0].toString(context)->toQString();
+ return context->d()->engine->newString(escape(str))->asReturnedValue();
}
ReturnedValue GlobalFunctions::method_unescape(CallContext *context)
{
- if (!context->callData->argc)
- return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!context->d()->callData->argc)
+ return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
- QString str = context->callData->args[0].toString(context)->toQString();
- return context->engine->newString(unescape(str))->asReturnedValue();
+ QString str = context->d()->callData->args[0].toString(context)->toQString();
+ return context->d()->engine->newString(unescape(str))->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 63823acc19..b3fcb0c89b 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -50,8 +50,11 @@ namespace QV4 {
struct Q_QML_EXPORT EvalFunction : FunctionObject
{
- V4_OBJECT
- EvalFunction(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+
+ V4_OBJECT(FunctionObject)
ReturnedValue evalCall(CallData *callData, bool directCall);
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 87fbd6f8e4..bbb756bab3 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -149,8 +149,8 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(String *str) const
{
if (!d)
return 0;
- if (str->identifier)
- return lookup(str->identifier);
+ if (str->d()->identifier)
+ return lookup(str->d()->identifier);
return lookup(str->toQString());
}
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index e300a4811e..8627438fe1 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -69,7 +69,7 @@ IdentifierTable::~IdentifierTable()
{
for (int i = 0; i < alloc; ++i)
if (entries[i])
- delete entries[i]->identifier;
+ delete entries[i]->d()->identifier;
free(entries);
}
@@ -77,12 +77,12 @@ void IdentifierTable::addEntry(String *str)
{
uint hash = str->hashValue();
- if (str->subtype == String::StringType_ArrayIndex)
+ if (str->subtype() == String::StringType_ArrayIndex)
return;
- str->identifier = new Identifier;
- str->identifier->string = str->toQString();
- str->identifier->hashValue = hash;
+ str->d()->identifier = new Identifier;
+ str->d()->identifier->string = str->toQString();
+ str->d()->identifier->hashValue = hash;
bool grow = (alloc <= size*2);
@@ -95,7 +95,7 @@ void IdentifierTable::addEntry(String *str)
String *e = entries[i];
if (!e)
continue;
- uint idx = e->stringHash % newAlloc;
+ uint idx = e->d()->stringHash % newAlloc;
while (newEntries[idx]) {
++idx;
idx %= newAlloc;
@@ -123,7 +123,7 @@ String *IdentifierTable::insertString(const QString &s)
uint hash = String::createHashValue(s.constData(), s.length());
uint idx = hash % alloc;
while (String *e = entries[idx]) {
- if (e->stringHash == hash && e->toQString() == s)
+ if (e->d()->stringHash == hash && e->toQString() == s)
return e;
++idx;
idx %= alloc;
@@ -137,29 +137,29 @@ String *IdentifierTable::insertString(const QString &s)
Identifier *IdentifierTable::identifierImpl(const String *str)
{
- if (str->identifier)
- return str->identifier;
+ if (str->d()->identifier)
+ return str->d()->identifier;
uint hash = str->hashValue();
- if (str->subtype == String::StringType_ArrayIndex)
+ if (str->subtype() == String::StringType_ArrayIndex)
return 0;
uint idx = hash % alloc;
while (String *e = entries[idx]) {
- if (e->stringHash == hash && e->isEqualTo(str)) {
- str->identifier = e->identifier;
- return e->identifier;
+ if (e->d()->stringHash == hash && e->isEqualTo(str)) {
+ str->d()->identifier = e->d()->identifier;
+ return e->d()->identifier;
}
++idx;
idx %= alloc;
}
addEntry(const_cast<QV4::String *>(str));
- return str->identifier;
+ return str->d()->identifier;
}
Identifier *IdentifierTable::identifier(const QString &s)
{
- return insertString(s)->identifier;
+ return insertString(s)->d()->identifier;
}
Identifier *IdentifierTable::identifier(const char *s, int len)
@@ -171,15 +171,15 @@ Identifier *IdentifierTable::identifier(const char *s, int len)
QLatin1String latin(s, len);
uint idx = hash % alloc;
while (String *e = entries[idx]) {
- if (e->stringHash == hash && e->toQString() == latin)
- return e->identifier;
+ if (e->d()->stringHash == hash && e->toQString() == latin)
+ return e->d()->identifier;
++idx;
idx %= alloc;
}
String *str = engine->newString(QString::fromLatin1(s, len))->getPointer();
addEntry(str);
- return str->identifier;
+ return str->d()->identifier;
}
}
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 09956fc342..7675d1642e 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -69,8 +69,8 @@ public:
String *insertString(const QString &s);
Identifier *identifier(const String *str) {
- if (str->identifier)
- return str->identifier;
+ if (str->d()->identifier)
+ return str->d()->identifier;
return identifierImpl(str);
}
@@ -82,11 +82,11 @@ public:
void mark(ExecutionEngine *e) {
for (int i = 0; i < alloc; ++i) {
String *entry = entries[i];
- if (!entry || entry->markBit)
+ if (!entry || entry->markBit())
continue;
- entry->markBit = 1;
- Q_ASSERT(entry->internalClass->vtable->markObjects);
- entry->internalClass->vtable->markObjects(entry, e);
+ entry->d()->markBit = 1;
+ Q_ASSERT(entry->internalClass()->vtable->markObjects);
+ entry->internalClass()->vtable->markObjects(entry, e);
}
}
};
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 2661ecc346..ece0cfa8b3 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -89,11 +89,11 @@ QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status stat
QV4::ScopedObject o(scope, v4->newObject());
QV4::ScopedString s(scope);
QV4::ScopedValue v(scope);
- o->put((s = v4->newString(QStringLiteral("OK"))), (v = QV4::Primitive::fromInt32(Ok)));
- o->put((s = v4->newString(QStringLiteral("LOADING"))), (v = QV4::Primitive::fromInt32(Loading)));
- o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Primitive::fromInt32(NetworkError)));
- o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Primitive::fromInt32(Exception)));
- o->put((s = v4->newString(QStringLiteral("status"))), (v = QV4::Primitive::fromInt32(status)));
+ o->put((s = v4->newString(QStringLiteral("OK"))).getPointer(), (v = QV4::Primitive::fromInt32(Ok)));
+ o->put((s = v4->newString(QStringLiteral("LOADING"))).getPointer(), (v = QV4::Primitive::fromInt32(Loading)));
+ o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))).getPointer(), (v = QV4::Primitive::fromInt32(NetworkError)));
+ o->put((s = v4->newString(QStringLiteral("EXCEPTION"))).getPointer(), (v = QV4::Primitive::fromInt32(Exception)));
+ o->put((s = v4->newString(QStringLiteral("status"))).getPointer(), (v = QV4::Primitive::fromInt32(status)));
return o.asReturnedValue();
}
@@ -160,13 +160,13 @@ void QV4Include::finished()
script.run();
if (scope.engine->hasException) {
QV4::ScopedValue ex(scope, ctx->catchException());
- resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception)));
- resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex);
+ resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception)));
+ resultObj->put(v4->newString(QStringLiteral("exception"))->getPointer(), ex);
} else {
- resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok)));
+ resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok)));
}
} else {
- resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("status"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
+ resultObj->put(v4->newString(QStringLiteral("status"))->getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError)));
}
QV4::ScopedValue cb(scope, m_callbackFunction.value());
@@ -181,27 +181,26 @@ void QV4Include::finished()
*/
QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
{
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return QV4::Encode::undefined();
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV8Engine *engine = v4->v8Engine;
- QQmlContextData *context = QV4::QmlContextWrapper::callingContext(v4);
+ QV4::Scope scope(ctx->engine());
+ QV8Engine *engine = scope.engine->v8Engine;
+ QQmlContextData *context = QV4::QmlContextWrapper::callingContext(scope.engine);
if (!context || !context->isJSContext)
V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
- QUrl url(ctx->engine->resolvedUrl(ctx->callData->args[0].toQStringNoThrow()));
+ QUrl url(scope.engine->resolvedUrl(ctx->d()->callData->args[0].toQStringNoThrow()));
QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue());
- if (ctx->callData->argc >= 2 && ctx->callData->args[1].asFunctionObject())
- callbackFunction = ctx->callData->args[1];
+ if (ctx->d()->callData->argc >= 2 && ctx->d()->callData->args[1].asFunctionObject())
+ callbackFunction = ctx->d()->callData->args[1];
QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
QV4::ScopedValue result(scope);
- QV4::ScopedObject qmlcontextobject(scope, v4->qmlContextObject());
+ QV4::ScopedObject qmlcontextobject(scope, scope.engine->qmlContextObject());
if (localFile.isEmpty()) {
QV4Include *i = new QV4Include(url, engine, context,
@@ -214,7 +213,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
if (const QQmlPrivate::CachedQmlUnit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url)) {
QV4::CompiledData::CompilationUnit *jsUnit = cachedUnit->createCompilationUnit();
- script.reset(new QV4::Script(v4, qmlcontextobject, jsUnit));
+ script.reset(new QV4::Script(scope.engine, qmlcontextobject, jsUnit));
} else {
QFile f(localFile);
@@ -223,24 +222,24 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
QString code = QString::fromUtf8(data);
QmlIR::Document::removeScriptPragmas(code);
- script.reset(new QV4::Script(v4, qmlcontextobject, code, url.toString()));
+ script.reset(new QV4::Script(scope.engine, qmlcontextobject, code, url.toString()));
}
}
if (!script.isNull()) {
- QV4::ExecutionContext *ctx = v4->currentContext();
+ QV4::ExecutionContext *ctx = scope.engine->currentContext();
script->parse();
- if (!v4->hasException)
+ if (!scope.engine->hasException)
script->run();
- if (v4->hasException) {
+ if (scope.engine->hasException) {
QV4::ScopedValue ex(scope, ctx->catchException());
- result = resultValue(v4, Exception);
- result->asObject()->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex);
+ result = resultValue(scope.engine, Exception);
+ result->asObject()->put(scope.engine->newString(QStringLiteral("exception"))->getPointer(), ex);
} else {
- result = resultValue(v4, Ok);
+ result = resultValue(scope.engine, Ok);
}
} else {
- result = resultValue(v4, NetworkError);
+ result = resultValue(scope.engine, NetworkError);
}
callback(callbackFunction, result);
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 3dc20b8e76..2edaf6fe96 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -155,18 +155,18 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
{
uint idx;
- InternalClass *newClass = object->internalClass->changeMember(string, data, &idx);
+ InternalClass *newClass = object->internalClass()->changeMember(string, data, &idx);
if (index)
*index = idx;
- if (newClass->size > object->internalClass->size) {
- Q_ASSERT(newClass->size == object->internalClass->size + 1);
- memmove(object->memberData.data() + idx + 2, object->memberData.data() + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value));
- } else if (newClass->size < object->internalClass->size) {
- Q_ASSERT(newClass->size == object->internalClass->size - 1);
- memmove(object->memberData.data() + idx + 1, object->memberData.data() + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value));
+ if (newClass->size > object->internalClass()->size) {
+ Q_ASSERT(newClass->size == object->internalClass()->size + 1);
+ memmove(object->memberData().data() + idx + 2, object->memberData().data() + idx + 1, (object->internalClass()->size - idx - 1)*sizeof(Value));
+ } else if (newClass->size < object->internalClass()->size) {
+ Q_ASSERT(newClass->size == object->internalClass()->size - 1);
+ memmove(object->memberData().data() + idx + 1, object->memberData().data() + idx + 2, (object->internalClass()->size - idx - 2)*sizeof(Value));
}
- object->internalClass = newClass;
+ object->setInternalClass(newClass);
}
InternalClass *InternalClass::changeMember(String *string, PropertyAttributes data, uint *index)
@@ -181,7 +181,7 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
if (data == propertyData.at(idx))
return this;
- Transition t = { { string->identifier }, (int)data.flags() };
+ Transition t = { { string->d()->identifier }, (int)data.flags() };
QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
if (tit != transitions.constEnd())
return tit.value();
@@ -271,40 +271,30 @@ InternalClass *InternalClass::changeVTable(const ManagedVTable *vt)
return newClass;
}
-void InternalClass::addMember(Object *object, StringRef string, PropertyAttributes data, uint *index)
-{
- return addMember(object, string.getPointer(), data, index);
-}
-
void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index)
{
data.resolve();
- object->internalClass->engine->identifierTable->identifier(string);
- if (object->internalClass->propertyTable.lookup(string->identifier) < object->internalClass->size) {
+ object->internalClass()->engine->identifierTable->identifier(string);
+ if (object->internalClass()->propertyTable.lookup(string->d()->identifier) < object->internalClass()->size) {
changeMember(object, string, data, index);
return;
}
uint idx;
- InternalClass *newClass = object->internalClass->addMemberImpl(string, data, &idx);
+ InternalClass *newClass = object->internalClass()->addMemberImpl(string, data, &idx);
if (index)
*index = idx;
- object->internalClass = newClass;
+ object->setInternalClass(newClass);
}
-InternalClass *InternalClass::addMember(StringRef string, PropertyAttributes data, uint *index)
-{
- return addMember(string.getPointer(), data, index);
-}
-
InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index)
{
data.resolve();
engine->identifierTable->identifier(string);
- if (propertyTable.lookup(string->identifier) < size)
+ if (propertyTable.lookup(string->d()->identifier) < size)
return changeMember(string, data, index);
return addMemberImpl(string, data, index);
@@ -312,7 +302,7 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes data, uint *index)
{
- Transition t = { { string->identifier }, (int)data.flags() };
+ Transition t = { { string->d()->identifier }, (int)data.flags() };
QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
if (index)
@@ -322,7 +312,7 @@ InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes d
// create a new class and add it to the tree
InternalClass *newClass = engine->newClass(*this);
- PropertyHash::Entry e = { string->identifier, newClass->size };
+ PropertyHash::Entry e = { string->d()->identifier, newClass->size };
newClass->propertyTable.addEntry(e, newClass->size);
// The incoming string can come from anywhere, so make sure to
@@ -346,15 +336,15 @@ InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes d
void InternalClass::removeMember(Object *object, Identifier *id)
{
- InternalClass *oldClass = object->internalClass;
+ InternalClass *oldClass = object->internalClass();
uint propIdx = oldClass->propertyTable.lookup(id);
Q_ASSERT(propIdx < oldClass->size);
Transition t = { { id } , -1 };
- QHash<Transition, InternalClass *>::const_iterator tit = object->internalClass->transitions.constFind(t);
+ QHash<Transition, InternalClass *>::const_iterator tit = object->internalClass()->transitions.constFind(t);
- if (tit != object->internalClass->transitions.constEnd()) {
- object->internalClass = tit.value();
+ if (tit != object->internalClass()->transitions.constEnd()) {
+ object->setInternalClass(tit.value());
} else {
// create a new class and add it to the tree
InternalClass *newClass = oldClass->engine->emptyClass->changeVTable(oldClass->vtable);
@@ -365,24 +355,19 @@ void InternalClass::removeMember(Object *object, Identifier *id)
if (!oldClass->propertyData.at(i).isEmpty())
newClass = newClass->addMember(oldClass->nameMap.at(i), oldClass->propertyData.at(i));
}
- object->internalClass = newClass;
+ object->setInternalClass(newClass);
}
// remove the entry in memberdata
- memmove(object->memberData.data() + propIdx, object->memberData.data() + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value));
-
- oldClass->transitions.insert(t, object->internalClass);
-}
+ memmove(object->memberData().data() + propIdx, object->memberData().data() + propIdx + 1, (object->internalClass()->size - propIdx)*sizeof(Value));
-uint InternalClass::find(const StringRef string)
-{
- return find(string.getPointer());
+ oldClass->transitions.insert(t, object->internalClass());
}
uint InternalClass::find(const String *string)
{
engine->identifierTable->identifier(string);
- const Identifier *id = string->identifier;
+ const Identifier *id = string->d()->identifier;
uint index = propertyTable.lookup(id);
if (index < size)
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index bd1828a146..830d5f792f 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -234,14 +234,11 @@ struct InternalClass : public QQmlJS::Managed {
static InternalClass *create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto);
InternalClass *changePrototype(Object *proto);
InternalClass *changeVTable(const ManagedVTable *vt);
- static void addMember(Object *object, StringRef string, PropertyAttributes data, uint *index);
static void addMember(Object *object, String *string, PropertyAttributes data, uint *index);
- InternalClass *addMember(StringRef string, PropertyAttributes data, uint *index = 0);
InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0);
static void removeMember(Object *object, Identifier *id);
- uint find(const StringRef string);
uint find(const String *s);
InternalClass *sealed();
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index ca82af1b30..2cbb72e15f 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -81,7 +81,7 @@ private:
ReturnedValue parseObject();
ReturnedValue parseArray();
- bool parseMember(ObjectRef o);
+ bool parseMember(Object *o);
bool parseString(QString *string);
bool parseValue(ValueRef val);
bool parseNumber(ValueRef val);
@@ -237,7 +237,7 @@ ReturnedValue JsonParser::parseObject()
BEGIN << "parseObject pos=" << json;
Scope scope(context);
- ScopedObject o(scope, context->engine->newObject());
+ ScopedObject o(scope, context->d()->engine->newObject());
QChar token = nextToken();
while (token == Quote) {
@@ -268,7 +268,7 @@ ReturnedValue JsonParser::parseObject()
/*
member = string name-separator value
*/
-bool JsonParser::parseMember(ObjectRef o)
+bool JsonParser::parseMember(Object *o)
{
BEGIN << "parseMember";
Scope scope(context);
@@ -285,12 +285,12 @@ bool JsonParser::parseMember(ObjectRef o)
if (!parseValue(val))
return false;
- ScopedString s(scope, context->engine->newIdentifier(key));
+ ScopedString s(scope, context->d()->engine->newIdentifier(key));
uint idx = s->asArrayIndex();
if (idx < UINT_MAX) {
o->putIndexed(idx, val);
} else {
- o->insertMember(s, val);
+ o->insertMember(s.getPointer(), val);
}
END;
@@ -304,7 +304,7 @@ ReturnedValue JsonParser::parseArray()
{
Scope scope(context);
BEGIN << "parseArray";
- Scoped<ArrayObject> array(scope, context->engine->newArrayObject());
+ Scoped<ArrayObject> array(scope, context->d()->engine->newArrayObject());
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
@@ -407,7 +407,7 @@ bool JsonParser::parseValue(ValueRef val)
return false;
DEBUG << "value: string";
END;
- val = context->engine->newString(value);
+ val = context->d()->engine->newString(value);
return true;
}
case BeginArray: {
@@ -656,8 +656,8 @@ struct Stringify
Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {}
QString Str(const QString &key, ValueRef v);
- QString JA(ArrayObjectRef a);
- QString JO(ObjectRef o);
+ QString JA(ArrayObject *a);
+ QString JO(Object *o);
QString makeMember(const QString &key, ValueRef v);
};
@@ -710,21 +710,21 @@ QString Stringify::Str(const QString &key, ValueRef v)
ScopedValue value(scope, *v);
ScopedObject o(scope, value);
if (o) {
- ScopedString s(scope, ctx->engine->newString(QStringLiteral("toJSON")));
- Scoped<FunctionObject> toJSON(scope, o->get(s));
+ ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON")));
+ Scoped<FunctionObject> toJSON(scope, o->get(s.getPointer()));
if (!!toJSON) {
ScopedCallData callData(scope, 1);
callData->thisObject = value;
- callData->args[0] = ctx->engine->newString(key);
+ callData->args[0] = ctx->d()->engine->newString(key);
value = toJSON->call(callData);
}
}
if (replacerFunction) {
- ScopedObject holder(scope, ctx->engine->newObject());
+ ScopedObject holder(scope, ctx->d()->engine->newObject());
holder->put(ctx, QString(), value);
ScopedCallData callData(scope, 2);
- callData->args[0] = ctx->engine->newString(key);
+ callData->args[0] = ctx->d()->engine->newString(key);
callData->args[1] = value;
callData->thisObject = holder;
value = replacerFunction->call(callData);
@@ -733,11 +733,11 @@ QString Stringify::Str(const QString &key, ValueRef v)
o = value.asReturnedValue();
if (o) {
if (NumberObject *n = o->asNumberObject())
- value = n->value;
+ value = n->value();
else if (StringObject *so = o->asStringObject())
- value = so->value;
+ value = so->d()->value;
else if (BooleanObject *b =o->asBooleanObject())
- value = b->value;
+ value = b->value();
}
if (value->isNull())
@@ -780,9 +780,9 @@ QString Stringify::makeMember(const QString &key, ValueRef v)
return QString();
}
-QString Stringify::JO(ObjectRef o)
+QString Stringify::JO(Object *o)
{
- if (stack.contains(o.getPointer())) {
+ if (stack.contains(o)) {
ctx->throwTypeError();
return QString();
}
@@ -790,7 +790,7 @@ QString Stringify::JO(ObjectRef o)
Scope scope(ctx);
QString result;
- stack.push(o.getPointer());
+ stack.push(o);
QString stepback = indent;
indent += gap;
@@ -814,7 +814,7 @@ QString Stringify::JO(ObjectRef o)
for (int i = 0; i < propertyList.size(); ++i) {
bool exists;
s = propertyList.at(i);
- ScopedValue v(scope, o->get(s, &exists));
+ ScopedValue v(scope, o->get(s.getPointer(), &exists));
if (!exists)
continue;
QString member = makeMember(s->toQString(), v);
@@ -837,9 +837,9 @@ QString Stringify::JO(ObjectRef o)
return result;
}
-QString Stringify::JA(ArrayObjectRef a)
+QString Stringify::JA(ArrayObject *a)
{
- if (stack.contains(a.getPointer())) {
+ if (stack.contains(a)) {
ctx->throwTypeError();
return QString();
}
@@ -847,7 +847,7 @@ QString Stringify::JA(ArrayObjectRef a)
Scope scope(a->engine());
QString result;
- stack.push(a.getPointer());
+ stack.push(a);
QString stepback = indent;
indent += gap;
@@ -883,14 +883,14 @@ QString Stringify::JA(ArrayObjectRef a)
}
-JsonObject::JsonObject(InternalClass *ic)
- : Object(ic)
+JsonObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
Scope scope(ic->engine);
- ScopedObject protectThis(scope, this);
+ ScopedObject o(scope, this);
- defineDefaultProperty(QStringLiteral("parse"), method_parse, 2);
- defineDefaultProperty(QStringLiteral("stringify"), method_stringify, 3);
+ o->defineDefaultProperty(QStringLiteral("parse"), method_parse, 2);
+ o->defineDefaultProperty(QStringLiteral("stringify"), method_stringify, 3);
}
@@ -939,9 +939,9 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
ScopedValue s(scope, ctx->argument(2));
if (NumberObject *n = s->asNumberObject())
- s = n->value;
+ s = n->value();
else if (StringObject *so = s->asStringObject())
- s = so->value;
+ s = so->d()->value;
if (s->isNumber()) {
stringify.gap = QString(qMin(10, (int)s->toInteger()), ' ');
@@ -954,7 +954,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
QString result = stringify.Str(QString(), arg0);
if (result.isEmpty() || scope.engine->hasException)
return Encode::undefined();
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
@@ -962,7 +962,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value)
{
if (value.isString())
- return engine->currentContext()->engine->newString(value.toString())->asReturnedValue();
+ return engine->currentContext()->d()->engine->newString(value.toString())->asReturnedValue();
else if (value.isDouble())
return Encode(value.toDouble());
else if (value.isBool())
@@ -1008,12 +1008,12 @@ QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine, const QJs
ScopedValue v(scope);
for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it) {
v = fromJsonValue(engine, it.value());
- o->put((s = engine->newString(it.key())), v);
+ o->put((s = engine->newString(it.key())).getPointer(), v);
}
return o.asReturnedValue();
}
-QJsonObject JsonObject::toJsonObject(ObjectRef o, V4ObjectSet &visitedObjects)
+QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects)
{
QJsonObject result;
if (!o || o->asFunctionObject())
@@ -1061,7 +1061,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso
return a.asReturnedValue();
}
-QJsonArray JsonObject::toJsonArray(ArrayObjectRef a, V4ObjectSet &visitedObjects)
+QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects)
{
QJsonArray result;
if (!a)
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index 34a4f4dd4b..03d5ad29c8 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -51,12 +51,14 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct JsonObject : Object {
+ struct Data : Object::Data {
+ Data(InternalClass *ic);
+ };
Q_MANAGED_TYPE(JsonObject)
- V4_OBJECT
+ V4_OBJECT(Object)
private:
typedef QSet<QV4::Object *> V4ObjectSet;
public:
- JsonObject(InternalClass *ic);
static ReturnedValue method_parse(CallContext *ctx);
static ReturnedValue method_stringify(CallContext *ctx);
@@ -67,15 +69,15 @@ public:
static inline QJsonValue toJsonValue(const QV4::ValueRef value)
{ V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); }
- static inline QJsonObject toJsonObject(QV4::ObjectRef o)
+ static inline QJsonObject toJsonObject(QV4::Object *o)
{ V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); }
- static inline QJsonArray toJsonArray(QV4::ArrayObjectRef a)
+ static inline QJsonArray toJsonArray(QV4::ArrayObject *a)
{ V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); }
private:
static QJsonValue toJsonValue(const QV4::ValueRef value, V4ObjectSet &visitedObjects);
- static QJsonObject toJsonObject(QV4::ObjectRef o, V4ObjectSet &visitedObjects);
- static QJsonArray toJsonArray(QV4::ArrayObjectRef a, V4ObjectSet &visitedObjects);
+ static QJsonObject toJsonObject(Object *o, V4ObjectSet &visitedObjects);
+ static QJsonArray toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects);
};
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 1155bbf9e9..57154c4779 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -51,13 +51,13 @@ ReturnedValue Lookup::lookup(ValueRef thisObject, Object *obj, PropertyAttribute
{
int i = 0;
while (i < Size && obj) {
- classList[i] = obj->internalClass;
+ classList[i] = obj->internalClass();
- index = obj->internalClass->find(name);
+ index = obj->internalClass()->find(name);
if (index != UINT_MAX) {
level = i;
- *attrs = obj->internalClass->propertyData.at(index);
- return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs);
+ *attrs = obj->internalClass()->propertyData.at(index);
+ return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs);
}
obj = obj->prototype();
@@ -66,10 +66,10 @@ ReturnedValue Lookup::lookup(ValueRef thisObject, Object *obj, PropertyAttribute
level = Size;
while (obj) {
- index = obj->internalClass->find(name);
+ index = obj->internalClass()->find(name);
if (index != UINT_MAX) {
- *attrs = obj->internalClass->propertyData.at(index);
- return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs);
+ *attrs = obj->internalClass()->propertyData.at(index);
+ return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs);
}
obj = obj->prototype();
@@ -82,13 +82,13 @@ ReturnedValue Lookup::lookup(Object *obj, PropertyAttributes *attrs)
Object *thisObject = obj;
int i = 0;
while (i < Size && obj) {
- classList[i] = obj->internalClass;
+ classList[i] = obj->internalClass();
- index = obj->internalClass->find(name);
+ index = obj->internalClass()->find(name);
if (index != UINT_MAX) {
level = i;
- *attrs = obj->internalClass->propertyData.at(index);
- return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs);
+ *attrs = obj->internalClass()->propertyData.at(index);
+ return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs);
}
obj = obj->prototype();
@@ -97,10 +97,10 @@ ReturnedValue Lookup::lookup(Object *obj, PropertyAttributes *attrs)
level = Size;
while (obj) {
- index = obj->internalClass->find(name);
+ index = obj->internalClass()->find(name);
if (index != UINT_MAX) {
- *attrs = obj->internalClass->propertyData.at(index);
- return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs);
+ *attrs = obj->internalClass()->propertyData.at(index);
+ return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs);
}
obj = obj->prototype();
@@ -147,8 +147,8 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co
}
if (idx < UINT_MAX) {
- if (!o->arrayData->hasAttributes()) {
- ScopedValue v(scope, o->arrayData->get(idx));
+ if (!o->arrayData()->hasAttributes()) {
+ ScopedValue v(scope, o->arrayData()->get(idx));
if (!v->isEmpty())
return v->asReturnedValue();
}
@@ -159,7 +159,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co
ScopedString name(scope, index->toString(ctx));
if (scope.hasException())
return Encode::undefined();
- return o->get(name);
+ return o->get(name.getPointer());
}
@@ -171,10 +171,10 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, c
return indexedGetterGeneric(l, object, index);
Object *o = object->objectValue();
- if (o->arrayData && o->arrayData->type == ArrayData::Simple) {
- if (idx < static_cast<SimpleArrayData *>(o->arrayData)->len)
- if (!o->arrayData->data[idx].isEmpty())
- return o->arrayData->data[idx].asReturnedValue();
+ if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
+ if (idx < static_cast<SimpleArrayData *>(o->arrayData())->len())
+ if (!o->arrayData()->arrayData()[idx].isEmpty())
+ return o->arrayData()->arrayData()[idx].asReturnedValue();
}
return indexedGetterFallback(l, object, index);
@@ -184,7 +184,7 @@ void Lookup::indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueR
{
if (object->isObject()) {
Object *o = object->objectValue();
- if (o->arrayData && o->arrayData->type == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) {
+ if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) {
l->indexedSetter = indexedSetterObjectInt;
indexedSetterObjectInt(l, object, index, v);
return;
@@ -203,10 +203,10 @@ void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const Value
uint idx = index->asArrayIndex();
if (idx < UINT_MAX) {
- if (o->arrayData && o->arrayData->type == ArrayData::Simple) {
- SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
- if (s && idx < s->len && !s->data[idx].isEmpty()) {
- s->data[idx] = value;
+ if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
+ if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) {
+ s->arrayData()[idx] = value;
return;
}
}
@@ -215,7 +215,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const Value
}
ScopedString name(scope, index->toString(ctx));
- o->put(name, value);
+ o->put(name.getPointer(), value);
}
void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v)
@@ -227,10 +227,10 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const Valu
}
Object *o = object->objectValue();
- if (o->arrayData && o->arrayData->type == ArrayData::Simple) {
- SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
- if (idx < s->len && !s->data[idx].isEmpty()) {
- s->data[idx] = v;
+ if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) {
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
+ if (idx < s->len() && !s->arrayData()[idx].isEmpty()) {
+ s->arrayData()[idx] = v;
return;
}
}
@@ -254,7 +254,7 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
case Value::Managed_Type:
Q_ASSERT(object->isString());
proto = engine->stringObjectClass->prototype;
- if (l->name->equals(engine->id_length)) {
+ if (l->name->equals(engine->id_length.getPointer())) {
// special case, as the property is on the object itself
l->getter = stringLengthGetter;
return stringLengthGetter(l, object);
@@ -331,7 +331,7 @@ ReturnedValue Lookup::getterFallback(Lookup *l, const ValueRef object)
if (!o)
return Encode::undefined();
QV4::ScopedString s(scope, l->name);
- return o->get(s);
+ return o->get(s.getPointer());
}
ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
@@ -340,8 +340,8 @@ ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
+ if (l->classList[0] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
}
return getterTwoClasses(l, object);
}
@@ -352,9 +352,9 @@ ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index].asReturnedValue();
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index].asReturnedValue();
}
return getterTwoClasses(l, object);
}
@@ -365,12 +365,12 @@ ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass) {
+ if (l->classList[0] == o->internalClass()) {
o = o->prototype();
- if (l->classList[1] == o->internalClass) {
+ if (l->classList[1] == o->internalClass()) {
o = o->prototype();
- if (l->classList[2] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
}
}
}
@@ -384,10 +384,10 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
- if (l->classList[2] == o->internalClass)
- return o->memberData[l->index2].asReturnedValue();
+ if (l->classList[0] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass())
+ return o->memberData()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, object);
@@ -399,11 +399,11 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
- if (l->classList[2] == o->internalClass &&
- l->classList[3] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index2].asReturnedValue();
+ if (l->classList[0] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass() &&
+ l->classList[3] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, object);
@@ -415,12 +415,12 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index].asReturnedValue();
- if (l->classList[2] == o->internalClass &&
- l->classList[3] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index2].asReturnedValue();
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass() &&
+ l->classList[3] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index2].asReturnedValue();
return getterFallback(l, object);
}
l->getter = getterFallback;
@@ -434,7 +434,7 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass) {
+ if (l->classList[0] == o->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->propertyAt(l->index)->getter();
if (!getter)
@@ -455,8 +455,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass) {
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter();
if (!getter)
@@ -477,11 +477,11 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, const ValueRef object)
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Object *o = object->objectValue();
- if (l->classList[0] == o->internalClass) {
+ if (l->classList[0] == o->internalClass()) {
o = o->prototype();
- if (l->classList[1] == o->internalClass) {
+ if (l->classList[1] == o->internalClass()) {
o = o->prototype();
- if (l->classList[2] == o->internalClass) {
+ if (l->classList[2] == o->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->propertyAt(l->index)->getter();
if (!getter)
@@ -502,8 +502,8 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, const ValueRef object)
{
if (object->type() == l->type) {
Object *o = l->proto;
- if (l->classList[0] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
+ if (l->classList[0] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, object);
@@ -513,9 +513,9 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, const ValueRef object)
{
if (object->type() == l->type) {
Object *o = l->proto;
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index].asReturnedValue();
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, object);
@@ -525,7 +525,7 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, const ValueRef object)
{
if (object->type() == l->type) {
Object *o = l->proto;
- if (l->classList[0] == o->internalClass) {
+ if (l->classList[0] == o->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->propertyAt(l->index)->getter();
if (!getter)
@@ -544,8 +544,8 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, const ValueRef object)
{
if (object->type() == l->type) {
Object *o = l->proto;
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass) {
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter();
if (!getter)
@@ -563,7 +563,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, const ValueRef object)
ReturnedValue Lookup::stringLengthGetter(Lookup *l, const ValueRef object)
{
if (String *s = object->asString())
- return Encode(s->length());
+ return Encode(s->d()->length());
l->getter = getterGeneric;
return getterGeneric(l, object);
@@ -572,7 +572,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, const ValueRef object)
ReturnedValue Lookup::arrayLengthGetter(Lookup *l, const ValueRef object)
{
if (ArrayObject *a = object->asArrayObject())
- return a->memberData[ArrayObject::LengthPropertyIndex].asReturnedValue();
+ return a->memberData()[ArrayObject::LengthPropertyIndex].asReturnedValue();
l->getter = getterGeneric;
return getterGeneric(l, object);
@@ -581,7 +581,7 @@ ReturnedValue Lookup::arrayLengthGetter(Lookup *l, const ValueRef object)
ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
+ Object *o = ctx->d()->engine->globalObject;
PropertyAttributes attrs;
ReturnedValue v = l->lookup(o, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
@@ -610,9 +610,9 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass)
- return o->memberData[l->index].asReturnedValue();
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass())
+ return o->memberData()[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, ctx);
@@ -620,10 +620,10 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass)
- return o->prototype()->memberData[l->index].asReturnedValue();
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass())
+ return o->prototype()->memberData()[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, ctx);
@@ -631,13 +631,13 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass) {
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass()) {
o = o->prototype();
- if (l->classList[1] == o->internalClass) {
+ if (l->classList[1] == o->internalClass()) {
o = o->prototype();
- if (l->classList[2] == o->internalClass) {
- return o->prototype()->memberData[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass()) {
+ return o->prototype()->memberData()[l->index].asReturnedValue();
}
}
}
@@ -647,8 +647,8 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass) {
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->propertyAt(l->index)->getter();
if (!getter)
@@ -664,9 +664,9 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass &&
- l->classList[1] == o->prototype()->internalClass) {
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass() &&
+ l->classList[1] == o->prototype()->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter();
if (!getter)
@@ -682,12 +682,12 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx)
ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionContext *ctx)
{
- Object *o = ctx->engine->globalObject;
- if (l->classList[0] == o->internalClass) {
+ Object *o = ctx->d()->engine->globalObject;
+ if (l->classList[0] == o->internalClass()) {
o = o->prototype();
- if (l->classList[1] == o->internalClass) {
+ if (l->classList[1] == o->internalClass()) {
o = o->prototype();
- if (l->classList[2] == o->internalClass) {
+ if (l->classList[2] == o->internalClass()) {
Scope scope(o->engine());
FunctionObject *getter = o->propertyAt(l->index)->getter();
if (!getter)
@@ -712,7 +712,7 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu
if (!o) // type error
return;
ScopedString s(scope, l->name);
- o->put(s, value);
+ o->put(s.getPointer(), value);
return;
}
o->setLookup(l, value);
@@ -743,15 +743,15 @@ void Lookup::setterFallback(Lookup *l, const ValueRef object, const ValueRef val
QV4::ScopedObject o(scope, object->toObject(scope.engine->currentContext()));
if (o) {
QV4::ScopedString s(scope, l->name);
- o->put(s, value);
+ o->put(s.getPointer(), value);
}
}
void Lookup::setter0(Lookup *l, const ValueRef object, const ValueRef value)
{
Object *o = static_cast<Object *>(object->asManaged());
- if (o && o->internalClass == l->classList[0]) {
- o->memberData[l->index] = *value;
+ if (o && o->internalClass() == l->classList[0]) {
+ o->memberData()[l->index] = *value;
return;
}
@@ -761,12 +761,12 @@ void Lookup::setter0(Lookup *l, const ValueRef object, const ValueRef value)
void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef value)
{
Object *o = static_cast<Object *>(object->asManaged());
- if (o && o->internalClass == l->classList[0]) {
+ if (o && o->internalClass() == l->classList[0]) {
if (!o->prototype()) {
- if (l->index >= o->memberData.size())
+ if (l->index >= o->memberData().size())
o->ensureMemberIndex(l->index);
- o->memberData[l->index] = *value;
- o->internalClass = l->classList[3];
+ o->memberData()[l->index] = *value;
+ o->setInternalClass(l->classList[3]);
return;
}
}
@@ -778,13 +778,13 @@ void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef valu
void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef value)
{
Object *o = static_cast<Object *>(object->asManaged());
- if (o && o->internalClass == l->classList[0]) {
+ if (o && o->internalClass() == l->classList[0]) {
Object *p = o->prototype();
- if (p && p->internalClass == l->classList[1]) {
- if (l->index >= o->memberData.size())
+ if (p && p->internalClass() == l->classList[1]) {
+ if (l->index >= o->memberData().size())
o->ensureMemberIndex(l->index);
- o->memberData[l->index] = *value;
- o->internalClass = l->classList[3];
+ o->memberData()[l->index] = *value;
+ o->setInternalClass(l->classList[3]);
return;
}
}
@@ -796,15 +796,15 @@ void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef valu
void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef value)
{
Object *o = static_cast<Object *>(object->asManaged());
- if (o && o->internalClass == l->classList[0]) {
+ if (o && o->internalClass() == l->classList[0]) {
Object *p = o->prototype();
- if (p && p->internalClass == l->classList[1]) {
+ if (p && p->internalClass() == l->classList[1]) {
p = p->prototype();
- if (p && p->internalClass == l->classList[2]) {
- if (l->index >= o->memberData.size())
+ if (p && p->internalClass() == l->classList[2]) {
+ if (l->index >= o->memberData().size())
o->ensureMemberIndex(l->index);
- o->memberData[l->index] = *value;
- o->internalClass = l->classList[3];
+ o->memberData()[l->index] = *value;
+ o->setInternalClass(l->classList[3]);
return;
}
}
@@ -818,12 +818,12 @@ void Lookup::setter0setter0(Lookup *l, const ValueRef object, const ValueRef val
{
Object *o = static_cast<Object *>(object->asManaged());
if (o) {
- if (o->internalClass == l->classList[0]) {
- o->memberData[l->index] = *value;
+ if (o->internalClass() == l->classList[0]) {
+ o->memberData()[l->index] = *value;
return;
}
- if (o->internalClass == l->classList[1]) {
- o->memberData[l->index2] = *value;
+ if (o->internalClass() == l->classList[1]) {
+ o->memberData()[l->index2] = *value;
return;
}
}
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 1f4030a4ed..6fc402e48f 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -45,8 +45,10 @@
using namespace QV4;
+
const ManagedVTable Managed::static_vtbl =
{
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
@@ -56,7 +58,7 @@ const ManagedVTable Managed::static_vtbl =
0,
Managed::MyType,
"Managed",
- destroy,
+ 0,
0 /*markObjects*/,
isEqualTo
};
@@ -69,33 +71,15 @@ void *Managed::operator new(size_t size, MemoryManager *mm)
return mm->allocManaged(size);
}
-void Managed::operator delete(void *ptr)
-{
- if (!ptr)
- return;
-
- Managed *m = static_cast<Managed *>(ptr);
- m->_data = 0;
- m->markBit = 0;
- m->~Managed();
-}
-
-void Managed::operator delete(void *ptr, MemoryManager *mm)
-{
- Q_UNUSED(mm);
-
- operator delete(ptr);
-}
-
ExecutionEngine *Managed::engine() const
{
- return internalClass ? internalClass->engine : 0;
+ return internalClass()->engine;
}
QString Managed::className() const
{
const char *s = 0;
- switch (Type(internalClass->vtable->type)) {
+ switch (Type(internalClass()->vtable->type)) {
case Type_Invalid:
case Type_String:
return QString();
@@ -124,7 +108,7 @@ QString Managed::className() const
s = "RegExp";
break;
case Type_ErrorObject:
- switch (ErrorObject::ErrorType(subtype)) {
+ switch (ErrorObject::ErrorType(subtype())) {
case ErrorObject::Error:
s = "Error";
break;
@@ -177,10 +161,17 @@ QString Managed::className() const
void Managed::setVTable(const ManagedVTable *vt)
{
+ Q_ASSERT(internalClass());
+ d()->internalClass = internalClass()->changeVTable(vt);
+}
+
+void Managed::Data::setVTable(const ManagedVTable *vt)
+{
Q_ASSERT(internalClass);
internalClass = internalClass->changeVTable(vt);
}
+
bool Managed::isEqualTo(Managed *, Managed *)
{
return false;
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 06d3e4884b..cc58983dfc 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -62,26 +62,44 @@ inline int qYouForgotTheQ_MANAGED_Macro(T, T) { return 0; }
template <typename T1, typename T2>
inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
-#define V4_MANAGED \
+#ifdef Q_COMPILER_STATIC_ASSERT
+#define V4_MANAGED_SIZE_TEST void __dataTest() { Q_STATIC_ASSERT(sizeof(*this) == sizeof(Managed)); }
+#else
+#define V4_MANAGED_SIZE_TEST
+#endif
+
+#define V4_MANAGED(superClass) \
public: \
Q_MANAGED_CHECK \
+ typedef superClass SuperClass; \
static const QV4::ManagedVTable static_vtbl; \
static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \
template <typename T> \
QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \
+ V4_MANAGED_SIZE_TEST \
+ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \
+ Data *d() { return &static_cast<Data &>(Managed::data); }
-#define V4_OBJECT \
+#define V4_OBJECT(superClass) \
public: \
Q_MANAGED_CHECK \
+ typedef superClass SuperClass; \
static const QV4::ObjectVTable static_vtbl; \
static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \
template <typename T> \
QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \
+ V4_MANAGED_SIZE_TEST \
+ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \
+ Data *d() { return &static_cast<Data &>(Managed::data); }
#define Q_MANAGED_TYPE(type) \
public: \
enum { MyType = Type_##type };
+#define Q_VTABLE_FUNCTION(classname, func) \
+ (classname::func == QV4::Managed::func ? 0 : classname::func)
+
+
struct GCDeletable
{
GCDeletable() : next(0), lastCall(false) {}
@@ -92,6 +110,7 @@ struct GCDeletable
struct ManagedVTable
{
+ const ManagedVTable * const parent;
uint isExecutionContext : 1;
uint isString : 1;
uint isObject : 1;
@@ -111,22 +130,23 @@ struct ObjectVTable
ManagedVTable managedVTable;
ReturnedValue (*call)(Managed *, CallData *data);
ReturnedValue (*construct)(Managed *, CallData *data);
- ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty);
+ ReturnedValue (*get)(Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty);
- void (*put)(Managed *, const StringRef name, const ValueRef value);
+ void (*put)(Managed *, String *name, const ValueRef value);
void (*putIndexed)(Managed *, uint index, const ValueRef value);
- PropertyAttributes (*query)(const Managed *, StringRef name);
+ PropertyAttributes (*query)(const Managed *, String *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
- bool (*deleteProperty)(Managed *m, const StringRef name);
+ bool (*deleteProperty)(Managed *m, String *name);
bool (*deleteIndexedProperty)(Managed *m, uint index);
ReturnedValue (*getLookup)(Managed *m, Lookup *l);
void (*setLookup)(Managed *m, Lookup *l, const ValueRef v);
uint (*getLength)(const Managed *m);
- void (*advanceIterator)(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes);
+ void (*advanceIterator)(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes);
};
-#define DEFINE_MANAGED_VTABLE_INT(classname) \
+#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
{ \
+ parentVTable, \
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
@@ -135,21 +155,20 @@ struct ObjectVTable
classname::IsArrayData, \
0, \
classname::MyType, \
- #classname, \
- destroy, \
+ #classname, \
+ Q_VTABLE_FUNCTION(classname, destroy), \
markObjects, \
isEqualTo \
}
-
#define DEFINE_MANAGED_VTABLE(classname) \
-const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname)
+const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0)
#define DEFINE_OBJECT_VTABLE(classname) \
const QV4::ObjectVTable classname::static_vtbl = \
{ \
- DEFINE_MANAGED_VTABLE_INT(classname), \
+ DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.managedVTable), \
call, \
construct, \
get, \
@@ -166,30 +185,44 @@ const QV4::ObjectVTable classname::static_vtbl = \
advanceIterator \
}
-#define DEFINE_MANAGED_VTABLE_WITH_NAME(classname, name) \
-const QV4::ObjectVTable classname::static_vtbl = \
-{ \
- DEFINE_MANAGED_VTABLE_INT(name), \
- call, \
- construct, \
- get, \
- getIndexed, \
- put, \
- putIndexed, \
- query, \
- queryIndexed, \
- deleteProperty, \
- deleteIndexedProperty, \
- getLookup, \
- setLookup, \
- getLength, \
- advanceIterator \
-}
-
-
struct Q_QML_PRIVATE_EXPORT Managed
{
- V4_MANAGED
+ struct Q_QML_PRIVATE_EXPORT Data : HeapObject {
+ Data() {}
+ Data(InternalClass *internal)
+ : internalClass(internal)
+ , markBit(0)
+ , inUse(1)
+ , extensible(1)
+ {
+ // ####
+// Q_ASSERT(internal && internal->vtable);
+ }
+ InternalClass *internalClass;
+ struct {
+ uchar markBit : 1;
+ uchar inUse : 1;
+ uchar extensible : 1; // used by Object
+ uchar _unused : 1;
+ uchar needsActivation : 1; // used by FunctionObject
+ uchar strictMode : 1; // used by FunctionObject
+ uchar bindingKeyFlag : 1;
+ uchar hasAccessorProperty : 1;
+ uchar _type;
+ mutable uchar subtype;
+ uchar _flags;
+ };
+
+ void setVTable(const ManagedVTable *vt);
+ ReturnedValue asReturnedValue() const {
+ return reinterpret_cast<Managed *>(const_cast<Data *>(this))->asReturnedValue();
+ }
+
+ void *operator new(size_t, Managed *m) { return m; }
+ void *operator new(size_t, Managed::Data *m) { return m; }
+ };
+ Data data;
+ V4_MANAGED(Managed)
enum {
IsExecutionContext = false,
IsString = false,
@@ -205,17 +238,13 @@ private:
protected:
Managed(InternalClass *internal)
- : internalClass(internal), _data(0)
+ : data(internal)
{
- Q_ASSERT(internalClass && internalClass->vtable);
- inUse = 1; extensible = 1;
}
public:
void *operator new(size_t size, MemoryManager *mm);
void *operator new(size_t, Managed *m) { return m; }
- void operator delete(void *ptr);
- void operator delete(void *ptr, MemoryManager *mm);
inline void mark(QV4::ExecutionEngine *engine);
@@ -248,12 +277,18 @@ public:
template <typename T>
T *as() {
// ### FIXME:
- if (!this || !internalClass)
+ if (!this || !internalClass())
return 0;
#if !defined(QT_NO_QOBJECT_CHECK)
static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this));
#endif
- return internalClass->vtable == T::staticVTable() ? static_cast<T *>(this) : 0;
+ const ManagedVTable *vt = internalClass()->vtable;
+ while (vt) {
+ if (vt == T::staticVTable())
+ return static_cast<T *>(this);
+ vt = vt->parent;
+ }
+ return 0;
}
template <typename T>
const T *as() const {
@@ -263,24 +298,30 @@ public:
#if !defined(QT_NO_QOBJECT_CHECK)
static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this)));
#endif
- return internalClass->vtable == T::staticVTable() ? static_cast<const T *>(this) : 0;
+ const ManagedVTable *vt = internalClass()->vtable;
+ while (vt) {
+ if (vt == T::staticVTable())
+ return static_cast<T *>(this);
+ vt = vt->parent;
+ }
+ return 0;
}
- String *asString() { return internalClass->vtable->isString ? reinterpret_cast<String *>(this) : 0; }
- Object *asObject() { return internalClass->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; }
- ArrayObject *asArrayObject() { return internalClass->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; }
- FunctionObject *asFunctionObject() { return internalClass->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; }
- BooleanObject *asBooleanObject() { return internalClass->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; }
- NumberObject *asNumberObject() { return internalClass->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; }
- StringObject *asStringObject() { return internalClass->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; }
- DateObject *asDateObject() { return internalClass->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; }
- ErrorObject *asErrorObject() { return internalClass->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; }
- ArgumentsObject *asArgumentsObject() { return internalClass->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; }
+ String *asString() { return internalClass()->vtable->isString ? reinterpret_cast<String *>(this) : 0; }
+ Object *asObject() { return internalClass()->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; }
+ ArrayObject *asArrayObject() { return internalClass()->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; }
+ FunctionObject *asFunctionObject() { return internalClass()->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; }
+ BooleanObject *asBooleanObject() { return internalClass()->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; }
+ NumberObject *asNumberObject() { return internalClass()->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; }
+ StringObject *asStringObject() { return internalClass()->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; }
+ DateObject *asDateObject() { return internalClass()->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; }
+ ErrorObject *asErrorObject() { return internalClass()->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; }
+ ArgumentsObject *asArgumentsObject() { return internalClass()->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; }
- bool isListType() const { return internalClass->vtable->type == Type_QmlSequence; }
+ bool isListType() const { return internalClass()->vtable->type == Type_QmlSequence; }
- bool isArrayObject() const { return internalClass->vtable->type == Type_ArrayObject; }
- bool isStringObject() const { return internalClass->vtable->type == Type_StringObject; }
+ bool isArrayObject() const { return internalClass()->vtable->type == Type_ArrayObject; }
+ bool isStringObject() const { return internalClass()->vtable->type == Type_StringObject; }
QString className() const;
@@ -297,33 +338,22 @@ public:
void setVTable(const ManagedVTable *vt);
bool isEqualTo(Managed *other)
- { return internalClass->vtable->isEqualTo(this, other); }
+ { return internalClass()->vtable->isEqualTo(this, other); }
- static void destroy(Managed *that) { that->_data = 0; }
static bool isEqualTo(Managed *m, Managed *other);
ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); }
+ InternalClass *internalClass() const { return d()->internalClass; }
+ void setInternalClass(InternalClass *ic) { d()->internalClass = ic; }
- InternalClass *internalClass;
+ uchar subtype() const { return d()->subtype; }
+ void setSubtype(uchar subtype) const { d()->subtype = subtype; }
- union {
- uint _data;
- struct {
- uchar markBit : 1;
- uchar inUse : 1;
- uchar extensible : 1; // used by Object
- uchar _unused : 1;
- uchar needsActivation : 1; // used by FunctionObject
- uchar strictMode : 1; // used by FunctionObject
- uchar bindingKeyFlag : 1;
- uchar hasAccessorProperty : 1;
- uchar _type;
- mutable uchar subtype;
- uchar _flags;
- };
- };
+ bool inUse() const { return d()->inUse; }
+ bool markBit() const { return d()->markBit; }
+ static void destroy(Managed *) {}
private:
friend class MemoryManager;
friend struct Identifiers;
@@ -358,69 +388,6 @@ inline FunctionObject *managed_cast(Managed *m)
return m->asFunctionObject();
}
-
-Value *extractValuePointer(const ScopedValue &);
-template<typename T>
-Value *extractValuePointer(const Scoped<T> &);
-
-#define DEFINE_REF_METHODS(Class, Base) \
- Class##Ref(const QV4::ScopedValue &v) \
- { QV4::Value *val = extractValuePointer(v); ptr = QV4::value_cast<Class>(*val) ? val : 0; } \
- Class##Ref(const QV4::Scoped<Class> &v) { ptr = extractValuePointer(v); } \
- Class##Ref(QV4::TypedValue<Class> &v) { ptr = &v; } \
- Class##Ref(QV4::Value &v) { ptr = QV4::value_cast<Class>(v) ? &v : 0; } \
- Class##Ref &operator=(Class *t) { \
- if (sizeof(void *) == 4) \
- ptr->tag = QV4::Value::Managed_Type; \
- ptr->m = t; \
- return *this; \
- } \
- Class##Ref &operator=(QV4::Returned<Class> *t) { \
- if (sizeof(void *) == 4) \
- ptr->tag = QV4::Value::Managed_Type; \
- ptr->m = t->getPointer(); \
- return *this; \
- } \
- operator const Class *() const { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \
- const Class *operator->() const { return static_cast<Class*>(ptr->managed()); } \
- operator Class *() { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \
- Class *operator->() { return static_cast<Class*>(ptr->managed()); } \
- Class *getPointer() const { return static_cast<Class *>(ptr->managed()); } \
- operator QV4::Returned<Class> *() const { return ptr ? QV4::Returned<Class>::create(getPointer()) : 0; } \
- static Class##Ref null() { Class##Ref c; c.ptr = 0; return c; } \
-protected: \
- Class##Ref() {} \
-public: \
-
-#define DEFINE_REF(Class, Base) \
-struct Class##Ref : public Base##Ref \
-{ DEFINE_REF_METHODS(Class, Base) } \
-
-
-struct ManagedRef {
- // Important: Do NOT add a copy constructor to this class or any derived class
- // adding a copy constructor actually changes the calling convention, ie.
- // is not even binary compatible. Adding it would break assumptions made
- // in the jit'ed code.
- DEFINE_REF_METHODS(Managed, Managed);
-
- bool operator==(const ManagedRef &other) {
- if (ptr == other.ptr)
- return true;
- return ptr && other.ptr && ptr->m == other.ptr->m;
- }
- bool operator!=(const ManagedRef &other) {
- return !operator==(other);
- }
- bool operator!() const { return !ptr || !ptr->managed(); }
-
- bool isNull() const { return !ptr; }
- ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Primitive::undefinedValue().asReturnedValue(); }
-
-public:
- Value *ptr;
-};
-
}
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 16d76e6914..3b8100c3fb 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -55,39 +55,39 @@ DEFINE_OBJECT_VTABLE(MathObject);
static const double qt_PI = 2.0 * ::asin(1.0);
-MathObject::MathObject(InternalClass *ic)
- : Object(ic)
+MathObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
Scope scope(ic->engine);
- ScopedObject protectThis(scope, this);
-
- defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0)));
- defineReadonlyProperty(QStringLiteral("LN2"), Primitive::fromDouble(::log(2.0)));
- defineReadonlyProperty(QStringLiteral("LN10"), Primitive::fromDouble(::log(10.0)));
- defineReadonlyProperty(QStringLiteral("LOG2E"), Primitive::fromDouble(1.0/::log(2.0)));
- defineReadonlyProperty(QStringLiteral("LOG10E"), Primitive::fromDouble(1.0/::log(10.0)));
- defineReadonlyProperty(QStringLiteral("PI"), Primitive::fromDouble(qt_PI));
- defineReadonlyProperty(QStringLiteral("SQRT1_2"), Primitive::fromDouble(::sqrt(0.5)));
- defineReadonlyProperty(QStringLiteral("SQRT2"), Primitive::fromDouble(::sqrt(2.0)));
-
- defineDefaultProperty(QStringLiteral("abs"), method_abs, 1);
- defineDefaultProperty(QStringLiteral("acos"), method_acos, 1);
- defineDefaultProperty(QStringLiteral("asin"), method_asin, 0);
- defineDefaultProperty(QStringLiteral("atan"), method_atan, 1);
- defineDefaultProperty(QStringLiteral("atan2"), method_atan2, 2);
- defineDefaultProperty(QStringLiteral("ceil"), method_ceil, 1);
- defineDefaultProperty(QStringLiteral("cos"), method_cos, 1);
- defineDefaultProperty(QStringLiteral("exp"), method_exp, 1);
- defineDefaultProperty(QStringLiteral("floor"), method_floor, 1);
- defineDefaultProperty(QStringLiteral("log"), method_log, 1);
- defineDefaultProperty(QStringLiteral("max"), method_max, 2);
- defineDefaultProperty(QStringLiteral("min"), method_min, 2);
- defineDefaultProperty(QStringLiteral("pow"), method_pow, 2);
- defineDefaultProperty(QStringLiteral("random"), method_random, 0);
- defineDefaultProperty(QStringLiteral("round"), method_round, 1);
- defineDefaultProperty(QStringLiteral("sin"), method_sin, 1);
- defineDefaultProperty(QStringLiteral("sqrt"), method_sqrt, 1);
- defineDefaultProperty(QStringLiteral("tan"), method_tan, 1);
+ ScopedObject m(scope, this);
+
+ m->defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0)));
+ m->defineReadonlyProperty(QStringLiteral("LN2"), Primitive::fromDouble(::log(2.0)));
+ m->defineReadonlyProperty(QStringLiteral("LN10"), Primitive::fromDouble(::log(10.0)));
+ m->defineReadonlyProperty(QStringLiteral("LOG2E"), Primitive::fromDouble(1.0/::log(2.0)));
+ m->defineReadonlyProperty(QStringLiteral("LOG10E"), Primitive::fromDouble(1.0/::log(10.0)));
+ m->defineReadonlyProperty(QStringLiteral("PI"), Primitive::fromDouble(qt_PI));
+ m->defineReadonlyProperty(QStringLiteral("SQRT1_2"), Primitive::fromDouble(::sqrt(0.5)));
+ m->defineReadonlyProperty(QStringLiteral("SQRT2"), Primitive::fromDouble(::sqrt(2.0)));
+
+ m->defineDefaultProperty(QStringLiteral("abs"), method_abs, 1);
+ m->defineDefaultProperty(QStringLiteral("acos"), method_acos, 1);
+ m->defineDefaultProperty(QStringLiteral("asin"), method_asin, 0);
+ m->defineDefaultProperty(QStringLiteral("atan"), method_atan, 1);
+ m->defineDefaultProperty(QStringLiteral("atan2"), method_atan2, 2);
+ m->defineDefaultProperty(QStringLiteral("ceil"), method_ceil, 1);
+ m->defineDefaultProperty(QStringLiteral("cos"), method_cos, 1);
+ m->defineDefaultProperty(QStringLiteral("exp"), method_exp, 1);
+ m->defineDefaultProperty(QStringLiteral("floor"), method_floor, 1);
+ m->defineDefaultProperty(QStringLiteral("log"), method_log, 1);
+ m->defineDefaultProperty(QStringLiteral("max"), method_max, 2);
+ m->defineDefaultProperty(QStringLiteral("min"), method_min, 2);
+ m->defineDefaultProperty(QStringLiteral("pow"), method_pow, 2);
+ m->defineDefaultProperty(QStringLiteral("random"), method_random, 0);
+ m->defineDefaultProperty(QStringLiteral("round"), method_round, 1);
+ m->defineDefaultProperty(QStringLiteral("sin"), method_sin, 1);
+ m->defineDefaultProperty(QStringLiteral("sqrt"), method_sqrt, 1);
+ m->defineDefaultProperty(QStringLiteral("tan"), method_tan, 1);
}
/* copies the sign from y to x and returns the result */
@@ -104,15 +104,15 @@ static double copySign(double x, double y)
ReturnedValue MathObject::method_abs(CallContext *context)
{
- if (!context->callData->argc)
+ if (!context->d()->callData->argc)
return Encode(qSNaN());
- if (context->callData->args[0].isInteger()) {
- int i = context->callData->args[0].integerValue();
+ if (context->d()->callData->args[0].isInteger()) {
+ int i = context->d()->callData->args[0].integerValue();
return Encode(i < 0 ? - i : i);
}
- double v = context->callData->args[0].toNumber();
+ double v = context->d()->callData->args[0].toNumber();
if (v == 0) // 0 | -0
return Encode(0);
@@ -121,7 +121,7 @@ ReturnedValue MathObject::method_abs(CallContext *context)
ReturnedValue MathObject::method_acos(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : 2;
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : 2;
if (v > 1)
return Encode(qSNaN());
@@ -130,7 +130,7 @@ ReturnedValue MathObject::method_acos(CallContext *context)
ReturnedValue MathObject::method_asin(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : 2;
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : 2;
if (v > 1)
return Encode(qSNaN());
else
@@ -139,7 +139,7 @@ ReturnedValue MathObject::method_asin(CallContext *context)
ReturnedValue MathObject::method_atan(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
if (v == 0.0)
return Encode(v);
else
@@ -148,8 +148,8 @@ ReturnedValue MathObject::method_atan(CallContext *context)
ReturnedValue MathObject::method_atan2(CallContext *context)
{
- double v1 = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
- double v2 = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN();
+ double v1 = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
+ double v2 = context->d()->callData->argc > 1 ? context->d()->callData->args[1].toNumber() : qSNaN();
if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0))
return Encode(copySign(0, -1.0));
@@ -166,7 +166,7 @@ ReturnedValue MathObject::method_atan2(CallContext *context)
ReturnedValue MathObject::method_ceil(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
if (v < 0.0 && v > -1.0)
return Encode(copySign(0, -1.0));
else
@@ -175,13 +175,13 @@ ReturnedValue MathObject::method_ceil(CallContext *context)
ReturnedValue MathObject::method_cos(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
return Encode(::cos(v));
}
ReturnedValue MathObject::method_exp(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
if (qIsInf(v)) {
if (copySign(1.0, v) == -1.0)
return Encode(0);
@@ -194,13 +194,13 @@ ReturnedValue MathObject::method_exp(CallContext *context)
ReturnedValue MathObject::method_floor(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
return Encode(::floor(v));
}
ReturnedValue MathObject::method_log(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
if (v < 0)
return Encode(qSNaN());
else
@@ -210,8 +210,8 @@ ReturnedValue MathObject::method_log(CallContext *context)
ReturnedValue MathObject::method_max(CallContext *context)
{
double mx = -qInf();
- for (int i = 0; i < context->callData->argc; ++i) {
- double x = context->callData->args[i].toNumber();
+ for (int i = 0; i < context->d()->callData->argc; ++i) {
+ double x = context->d()->callData->args[i].toNumber();
if (x > mx || std::isnan(x))
mx = x;
}
@@ -221,8 +221,8 @@ ReturnedValue MathObject::method_max(CallContext *context)
ReturnedValue MathObject::method_min(CallContext *context)
{
double mx = qInf();
- for (int i = 0; i < context->callData->argc; ++i) {
- double x = context->callData->args[i].toNumber();
+ for (int i = 0; i < context->d()->callData->argc; ++i) {
+ double x = context->d()->callData->args[i].toNumber();
if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
|| (x < mx) || std::isnan(x)) {
mx = x;
@@ -233,8 +233,8 @@ ReturnedValue MathObject::method_min(CallContext *context)
ReturnedValue MathObject::method_pow(CallContext *context)
{
- double x = context->callData->argc > 0 ? context->callData->args[0].toNumber() : qSNaN();
- double y = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN();
+ double x = context->d()->callData->argc > 0 ? context->d()->callData->args[0].toNumber() : qSNaN();
+ double y = context->d()->callData->argc > 1 ? context->d()->callData->args[1].toNumber() : qSNaN();
if (std::isnan(y))
return Encode(qSNaN());
@@ -294,26 +294,26 @@ ReturnedValue MathObject::method_random(CallContext *context)
ReturnedValue MathObject::method_round(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
v = copySign(::floor(v + 0.5), v);
return Encode(v);
}
ReturnedValue MathObject::method_sin(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
return Encode(::sin(v));
}
ReturnedValue MathObject::method_sqrt(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
return Encode(::sqrt(v));
}
ReturnedValue MathObject::method_tan(CallContext *context)
{
- double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN();
+ double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN();
if (v == 0.0)
return Encode(v);
else
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index 18a80c2ba0..65366aab86 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -49,9 +49,12 @@ namespace QV4 {
struct MathObject: Object
{
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(InternalClass *ic);
+ };
+
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(MathObject)
- MathObject(InternalClass *ic);
static ReturnedValue method_abs(CallContext *context);
static ReturnedValue method_acos(CallContext *context);
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index aeb4c38a8e..7eca47c3ce 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -44,29 +44,13 @@
using namespace QV4;
-const ManagedVTable MemberData::static_vtbl =
-{
- MemberData::IsExecutionContext,
- MemberData::IsString,
- MemberData::IsObject,
- MemberData::IsFunctionObject,
- MemberData::IsErrorObject,
- MemberData::IsArrayData,
- 0,
- MemberData::MyType,
- "MemberData",
- destroy,
- markObjects,
- isEqualTo
-};
-
-
+DEFINE_MANAGED_VTABLE(MemberData);
void MemberData::markObjects(Managed *that, ExecutionEngine *e)
{
MemberData *m = static_cast<MemberData *>(that);
- for (uint i = 0; i < m->size; ++i)
- m->data[i].mark(e);
+ for (uint i = 0; i < m->d()->size; ++i)
+ m->d()->data[i].mark(e);
}
void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx)
@@ -74,13 +58,13 @@ void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx)
uint s = size();
if (idx >= s) {
int newAlloc = qMax((uint)4, 2*idx);
- uint alloc = sizeof(MemberData) + (newAlloc)*sizeof(Value);
- MemberData *newMemberData = reinterpret_cast<MemberData *>(e->memoryManager->allocManaged(alloc));
+ uint alloc = sizeof(MemberData::Data) + (newAlloc)*sizeof(Value);
+ MemberData *newMemberData = static_cast<MemberData *>(e->memoryManager->allocManaged(alloc));
if (d())
- memcpy(newMemberData, d(), sizeof(MemberData) + s*sizeof(Value));
+ memcpy(newMemberData, d(), sizeof(MemberData::Data) + s*sizeof(Value));
else
new (newMemberData) MemberData(e->memberDataClass);
- newMemberData->size = newAlloc;
+ newMemberData->d()->size = newAlloc;
m = newMemberData;
}
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index 03aa75a365..cd8667adb7 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -50,23 +50,29 @@ namespace QV4 {
struct MemberData : Managed
{
- V4_MANAGED
- uint size;
- Value data[1];
+ struct Data : Managed::Data {
+ union {
+ uint size;
+ double _dummy;
+ };
+ Value data[1];
+ };
+ V4_MANAGED(Managed)
MemberData(QV4::InternalClass *ic) : Managed(ic) {}
- Value &operator[] (uint idx) { return data[idx]; }
+ Value &operator[] (uint idx) { return d()->data[idx]; }
static void markObjects(Managed *that, ExecutionEngine *e);
};
struct Members : Value
{
+ void reset() { m = 0; }
void ensureIndex(QV4::ExecutionEngine *e, uint idx);
- Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->data[idx]; }
- inline uint size() const { return d() ? d()->size : 0; }
+ Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->d()->data[idx]; }
+ inline uint size() const { return d() ? d()->d()->size : 0; }
inline MemberData *d() const { return static_cast<MemberData *>(managed()); }
- Value *data() const { return static_cast<MemberData *>(managed())->data; }
+ Value *data() const { return static_cast<MemberData *>(managed())->d()->data; }
void mark(ExecutionEngine *e) const {
MemberData *m = d();
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index ca2ccd33f7..3e7ac17078 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -57,6 +57,7 @@
#include <cstdlib>
#include <algorithm>
#include "qv4alloca_p.h"
+#include "qv4profiling_p.h"
#ifdef V4_USE_VALGRIND
#include <valgrind/valgrind.h>
@@ -102,6 +103,7 @@ struct MemoryManager::Data
struct LargeItem {
LargeItem *next;
+ size_t size;
void *data;
Managed *managed() {
@@ -149,8 +151,10 @@ struct MemoryManager::Data
~Data()
{
- for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i)
+ for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
+ Q_V4_PROFILE_DEALLOC(engine, 0, i->memory.size(), Profiling::HeapPage);
i->memory.deallocate();
+ }
}
};
@@ -174,7 +178,7 @@ MemoryManager::MemoryManager()
#endif
}
-Managed *MemoryManager::alloc(std::size_t size)
+Managed *MemoryManager::allocData(std::size_t size)
{
if (m_d->aggressiveGC)
runGC();
@@ -190,9 +194,12 @@ Managed *MemoryManager::alloc(std::size_t size)
// doesn't fit into a small bucket
if (size >= MemoryManager::Data::MaxItemSize) {
// we use malloc for this
- MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem)));
+ MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(
+ malloc(Q_V4_PROFILE_ALLOC(m_d->engine, size + sizeof(MemoryManager::Data::LargeItem),
+ Profiling::LargeItem)));
memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem));
item->next = m_d->largeItems;
+ item->size = size;
m_d->largeItems = item;
return item->managed();
}
@@ -218,7 +225,9 @@ Managed *MemoryManager::alloc(std::size_t size)
std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
Data::Chunk allocation;
- allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
+ allocation.memory = PageAllocation::allocate(
+ Q_V4_PROFILE_ALLOC(m_d->engine, allocSize, Profiling::HeapPage),
+ OSAllocator::JSGCHeapPages);
allocation.chunkSize = int(size);
m_d->heapChunks.append(allocation);
std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end());
@@ -228,7 +237,6 @@ Managed *MemoryManager::alloc(std::size_t size)
Managed **last = &m_d->smallItems[pos];
while (chunk <= end) {
Managed *o = reinterpret_cast<Managed *>(chunk);
- o->_data = 0;
*last = o;
last = o->nextFreeRef();
chunk += size;
@@ -247,6 +255,7 @@ Managed *MemoryManager::alloc(std::size_t size)
#ifdef V4_USE_VALGRIND
VALGRIND_MEMPOOL_ALLOC(this, m, size);
#endif
+ Q_V4_PROFILE_ALLOC(m_d->engine, size, Profiling::SmallItem);
++m_d->allocCount[pos];
++m_d->totalAlloc;
@@ -308,8 +317,8 @@ void MemoryManager::mark()
// now that we marked all roots, start marking recursively and popping from the mark stack
while (m_d->engine->jsStackTop > markBase) {
Managed *m = m_d->engine->popForGC();
- Q_ASSERT (m->internalClass->vtable->markObjects);
- m->internalClass->vtable->markObjects(m, m_d->engine);
+ Q_ASSERT (m->internalClass()->vtable->markObjects);
+ m->internalClass()->vtable->markObjects(m, m_d->engine);
}
}
@@ -325,7 +334,7 @@ void MemoryManager::sweep(bool lastSweep)
continue;
}
if (Managed *m = weak->value.asManaged()) {
- if (!m->markBit) {
+ if (!m->markBit()) {
weak->value = Primitive::undefinedValue();
PersistentValuePrivate *n = weak->next;
weak->removeFromList();
@@ -338,7 +347,7 @@ void MemoryManager::sweep(bool lastSweep)
if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) {
for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
- if (!it.value()->markBit)
+ if (!it.value()->markBit())
it = multiplyWrappedQObjects->erase(it);
else
++it;
@@ -352,18 +361,19 @@ void MemoryManager::sweep(bool lastSweep)
Data::LargeItem **last = &m_d->largeItems;
while (i) {
Managed *m = i->managed();
- Q_ASSERT(m->inUse);
- if (m->markBit) {
- m->markBit = 0;
+ Q_ASSERT(m->inUse());
+ if (m->markBit()) {
+ m->d()->markBit = 0;
last = &i->next;
i = i->next;
continue;
}
- if (m->internalClass->vtable->destroy)
- m->internalClass->vtable->destroy(m);
+ if (m->internalClass()->vtable->destroy)
+ m->internalClass()->vtable->destroy(m);
*last = i->next;
- free(i);
+ free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem),
+ Profiling::LargeItem));
i = *last;
}
@@ -392,16 +402,16 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size)
Q_ASSERT((qintptr) chunk % 16 == 0);
- if (m->inUse) {
- if (m->markBit) {
- m->markBit = 0;
+ if (m->inUse()) {
+ if (m->markBit()) {
+ m->d()->markBit = 0;
} else {
// qDebug() << "-- collecting it." << m << *f << m->nextFree();
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
- if (m->internalClass->vtable->destroy)
- m->internalClass->vtable->destroy(m);
+ if (m->internalClass()->vtable->destroy)
+ m->internalClass()->vtable->destroy(m);
memset(m, 0, size);
m->setNextFree(*f);
@@ -409,6 +419,7 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size)
VALGRIND_DISABLE_ERROR_REPORTING;
VALGRIND_MEMPOOL_FREE(this, m);
#endif
+ Q_V4_PROFILE_DEALLOC(m_d->engine, m, size, Profiling::SmallItem);
*f = m;
}
}
@@ -439,9 +450,7 @@ void MemoryManager::runGC()
mark();
sweep();
} else {
- int totalMem = 0;
- for (int i = 0; i < m_d->heapChunks.size(); ++i)
- totalMem += m_d->heapChunks.at(i).memory.size();
+ int totalMem = getAllocatedMem();
QTime t;
t.start();
@@ -467,22 +476,38 @@ void MemoryManager::runGC()
m_d->totalAlloc = 0;
}
-uint MemoryManager::getUsedMem()
+size_t MemoryManager::getUsedMem() const
{
- uint usedMem = 0;
- for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) {
+ size_t usedMem = 0;
+ for (QVector<Data::Chunk>::const_iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) {
char *chunkStart = reinterpret_cast<char *>(i->memory.base());
char *chunkEnd = chunkStart + i->memory.size() - i->chunkSize;
for (char *chunk = chunkStart; chunk <= chunkEnd; chunk += i->chunkSize) {
Managed *m = reinterpret_cast<Managed *>(chunk);
Q_ASSERT((qintptr) chunk % 16 == 0);
- if (m->inUse)
+ if (m->inUse())
usedMem += i->chunkSize;
}
}
return usedMem;
}
+size_t MemoryManager::getAllocatedMem() const
+{
+ size_t total = 0;
+ for (int i = 0; i < m_d->heapChunks.size(); ++i)
+ total += m_d->heapChunks.at(i).memory.size();
+ return total;
+}
+
+size_t MemoryManager::getLargeItemsMem() const
+{
+ size_t total = 0;
+ for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next)
+ total += i->size;
+ return total;
+}
+
MemoryManager::~MemoryManager()
{
PersistentValuePrivate *persistent = m_persistentValues;
@@ -526,11 +551,6 @@ void MemoryManager::registerDeletable(GCDeletable *d)
m_d->deletable = d;
}
-ExecutionEngine *MemoryManager::engine() const
-{
- return m_d->engine;
-}
-
#ifdef DETAILED_MM_STATS
void MemoryManager::willAllocate(std::size_t size)
{
@@ -545,11 +565,11 @@ void MemoryManager::willAllocate(std::size_t size)
void MemoryManager::collectFromJSStack() const
{
- Value *v = engine()->jsStackBase;
- Value *top = engine()->jsStackTop;
+ Value *v = m_d->engine->jsStackBase;
+ Value *top = m_d->engine->jsStackTop;
while (v < top) {
Managed *m = v->asManaged();
- if (m && m->inUse)
+ if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
m->mark(m_d->engine);
++v;
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index 47020c12f0..f0025dc70e 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -99,10 +99,58 @@ public:
inline Managed *allocManaged(std::size_t size)
{
size = align(size);
- Managed *o = alloc(size);
+ Managed *o = allocData(size);
return o;
}
+ template <typename ManagedType>
+ ManagedType *alloc()
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data();
+ return t;
+ }
+
+ template <typename ManagedType, typename Arg1>
+ ManagedType *alloc(Arg1 arg1)
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data(arg1);
+ return t;
+ }
+
+ template <typename ManagedType, typename Arg1, typename Arg2>
+ ManagedType *alloc(Arg1 arg1, Arg2 arg2)
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data(arg1, arg2);
+ return t;
+ }
+
+ template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3>
+ ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3);
+ return t;
+ }
+
+ template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4);
+ return t;
+ }
+
+ template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+ ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ {
+ ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)));
+ (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5);
+ return t;
+ }
+
bool isGCBlocked() const;
void setGCBlocked(bool blockGC);
void runGC();
@@ -113,12 +161,14 @@ public:
void registerDeletable(GCDeletable *d);
+ size_t getUsedMem() const;
+ size_t getAllocatedMem() const;
+ size_t getLargeItemsMem() const;
+
protected:
/// expects size to be aligned
// TODO: try to inline
- Managed *alloc(std::size_t size);
-
- ExecutionEngine *engine() const;
+ Managed *allocData(std::size_t size);
#ifdef DETAILED_MM_STATS
void willAllocate(std::size_t size);
@@ -129,7 +179,6 @@ private:
void mark();
void sweep(bool lastSweep = false);
void sweep(char *chunkStart, std::size_t chunkSize, size_t size);
- uint getUsedMem();
protected:
QScopedPointer<Data> m_d;
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index c97e86f2cd..f1bac1109a 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -51,8 +51,8 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(NumberCtor);
DEFINE_OBJECT_VTABLE(NumberObject);
-NumberCtor::NumberCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Number"))
+NumberCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Number"))
{
setVTable(staticVTable());
}
@@ -71,7 +71,7 @@ ReturnedValue NumberCtor::call(Managed *, CallData *callData)
return Encode(dbl);
}
-void NumberPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -103,40 +103,40 @@ void NumberPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
inline ReturnedValue thisNumberValue(ExecutionContext *ctx)
{
- if (ctx->callData->thisObject.isNumber())
- return ctx->callData->thisObject.asReturnedValue();
- NumberObject *n = ctx->callData->thisObject.asNumberObject();
+ if (ctx->d()->callData->thisObject.isNumber())
+ return ctx->d()->callData->thisObject.asReturnedValue();
+ NumberObject *n = ctx->d()->callData->thisObject.asNumberObject();
if (!n)
return ctx->throwTypeError();
- return n->value.asReturnedValue();
+ return n->value().asReturnedValue();
}
inline double thisNumber(ExecutionContext *ctx)
{
- if (ctx->callData->thisObject.isNumber())
- return ctx->callData->thisObject.asDouble();
- NumberObject *n = ctx->callData->thisObject.asNumberObject();
+ if (ctx->d()->callData->thisObject.isNumber())
+ return ctx->d()->callData->thisObject.asDouble();
+ NumberObject *n = ctx->d()->callData->thisObject.asNumberObject();
if (!n)
return ctx->throwTypeError();
- return n->value.asDouble();
+ return n->value().asDouble();
}
ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
{
double num = thisNumber(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
- if (ctx->callData->argc && !ctx->callData->args[0].isUndefined()) {
- int radix = ctx->callData->args[0].toInt32();
+ if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) {
+ int radix = ctx->d()->callData->args[0].toInt32();
if (radix < 2 || radix > 36)
return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
.arg(radix));
if (std::isnan(num)) {
- return ctx->engine->newString(QStringLiteral("NaN"))->asReturnedValue();
+ return ctx->d()->engine->newString(QStringLiteral("NaN"))->asReturnedValue();
} else if (qIsInf(num)) {
- return ctx->engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue();
+ return ctx->d()->engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue();
}
if (radix != 10) {
@@ -166,7 +166,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
}
if (negative)
str.prepend(QLatin1Char('-'));
- return ctx->engine->newString(str)->asReturnedValue();
+ return ctx->d()->engine->newString(str)->asReturnedValue();
}
}
@@ -178,7 +178,7 @@ ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx)
Scope scope(ctx);
ScopedValue v(scope, thisNumberValue(ctx));
ScopedString str(scope, v->toString(ctx));
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
return str.asReturnedValue();
}
@@ -191,19 +191,19 @@ ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx)
ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
{
double v = thisNumber(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
double fdigits = 0;
- if (ctx->callData->argc > 0)
- fdigits = ctx->callData->args[0].toInteger();
+ if (ctx->d()->callData->argc > 0)
+ fdigits = ctx->d()->callData->args[0].toInteger();
if (std::isnan(fdigits))
fdigits = 0;
if (fdigits < 0 || fdigits > 20)
- return ctx->throwRangeError(ctx->callData->thisObject);
+ return ctx->throwRangeError(ctx->d()->callData->thisObject);
QString str;
if (std::isnan(v))
@@ -214,22 +214,22 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
str = QString::number(v, 'f', int (fdigits));
else
return RuntimeHelpers::stringFromNumber(ctx, v)->asReturnedValue();
- return ctx->engine->newString(str)->asReturnedValue();
+ return ctx->d()->engine->newString(str)->asReturnedValue();
}
ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx)
{
Scope scope(ctx);
double d = thisNumber(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
int fdigits = -1;
- if (ctx->callData->argc && !ctx->callData->args[0].isUndefined()) {
- fdigits = ctx->callData->args[0].toInt32();
+ if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) {
+ fdigits = ctx->d()->callData->args[0].toInt32();
if (fdigits < 0 || fdigits > 20) {
- ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
+ ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
return ctx->throwRangeError(error);
}
}
@@ -239,22 +239,22 @@ ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx)
double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToExponential(d, fdigits, &builder);
QString result = QString::fromLatin1(builder.Finalize());
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
{
Scope scope(ctx);
ScopedValue v(scope, thisNumberValue(ctx));
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
- if (!ctx->callData->argc || ctx->callData->args[0].isUndefined())
+ if (!ctx->d()->callData->argc || ctx->d()->callData->args[0].isUndefined())
return RuntimeHelpers::toString(ctx, v);
- double precision = ctx->callData->args[0].toInt32();
+ double precision = ctx->d()->callData->args[0].toInt32();
if (precision < 1 || precision > 21) {
- ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
+ ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
return ctx->throwRangeError(error);
}
@@ -263,5 +263,5 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(v->asDouble(), precision, &builder);
QString result = QString::fromLatin1(builder.Finalize());
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index ccabcf6727..3e776f0f2f 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -51,8 +51,10 @@ namespace QV4 {
struct NumberCtor: FunctionObject
{
- V4_OBJECT
- NumberCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *that, CallData *callData);
static ReturnedValue call(Managed *, CallData *callData);
@@ -60,8 +62,7 @@ struct NumberCtor: FunctionObject
struct NumberPrototype: NumberObject
{
- NumberPrototype(InternalClass *ic): NumberObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_toString(CallContext *ctx);
static ReturnedValue method_toLocaleString(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index c8d360d511..e0f05a65f8 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -70,29 +70,16 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(Object);
-Object::Object(ExecutionEngine *engine)
- : Managed(engine->objectClass)
+Object::Data::Data(InternalClass *internalClass)
+ : Managed::Data(internalClass)
{
-}
-
-Object::Object(InternalClass *ic)
- : Managed(ic)
-{
- Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
-
- Q_ASSERT(!memberData.d());
if (internalClass->size) {
- Scope scope(engine());
- ScopedObject protectThis(scope, this);
- memberData.ensureIndex(engine(), internalClass->size);
+ Scope scope(internalClass->engine);
+ ScopedObject o(scope, this);
+ o->memberData().ensureIndex(internalClass->engine, internalClass->size);
}
}
-Object::~Object()
-{
- _data = 0;
-}
-
bool Object::setPrototype(Object *proto)
{
Object *pp = proto;
@@ -101,20 +88,15 @@ bool Object::setPrototype(Object *proto)
return false;
pp = pp->prototype();
}
- internalClass = internalClass->changePrototype(proto);
+ setInternalClass(internalClass()->changePrototype(proto));
return true;
}
-void Object::destroy(Managed *that)
-{
- static_cast<Object *>(that)->~Object();
-}
-
void Object::put(ExecutionContext *ctx, const QString &name, const ValueRef value)
{
Scope scope(ctx);
- ScopedString n(scope, ctx->engine->newString(name));
- put(n, value);
+ ScopedString n(scope, ctx->d()->engine->newString(name));
+ put(n.getPointer(), value);
}
ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, PropertyAttributes attrs)
@@ -133,7 +115,7 @@ ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, Pro
void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef value)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return;
if (attrs.isAccessor()) {
@@ -155,7 +137,7 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val
return;
reject:
- if (engine()->currentContext()->strictMode)
+ if (engine()->currentContext()->d()->strictMode)
engine()->currentContext()->throwTypeError();
}
@@ -164,7 +146,7 @@ void Object::defineDefaultProperty(const QString &name, ValueRef value)
ExecutionEngine *e = engine();
Scope scope(e);
ScopedString s(scope, e->newIdentifier(name));
- defineDefaultProperty(s, value);
+ defineDefaultProperty(s.getPointer(), value);
}
void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount)
@@ -172,16 +154,16 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca
ExecutionEngine *e = engine();
Scope scope(e);
ScopedString s(scope, e->newIdentifier(name));
- Scoped<FunctionObject> function(scope, e->newBuiltinFunction(e->rootContext, s, code));
+ Scoped<FunctionObject> function(scope, BuiltinFunction::create(e->rootContext, s.getPointer(), code));
function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount));
- defineDefaultProperty(s, function);
+ defineDefaultProperty(s.getPointer(), function);
}
-void Object::defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount)
+void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount)
{
ExecutionEngine *e = engine();
Scope scope(e);
- Scoped<FunctionObject> function(scope, e->newBuiltinFunction(e->rootContext, name, code));
+ Scoped<FunctionObject> function(scope, BuiltinFunction::create(e->rootContext, name, code));
function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -191,16 +173,16 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)
ExecutionEngine *e = engine();
Scope scope(e);
Scoped<String> s(scope, e->newIdentifier(name));
- defineAccessorProperty(s, getter, setter);
+ defineAccessorProperty(s.getPointer(), getter, setter);
}
-void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
+void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
ScopedProperty p(scope);
- p->setGetter(getter ? v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer() : 0);
- p->setSetter(setter ? v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer() : 0);
+ p->setGetter(getter ? ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, name, getter)).getPointer() : 0);
+ p->setSetter(setter ? ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, name, setter)).getPointer() : 0);
insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
@@ -209,10 +191,10 @@ void Object::defineReadonlyProperty(const QString &name, ValueRef value)
QV4::ExecutionEngine *e = engine();
Scope scope(e);
ScopedString s(scope, e->newIdentifier(name));
- defineReadonlyProperty(s, value);
+ defineReadonlyProperty(s.getPointer(), value);
}
-void Object::defineReadonlyProperty(const StringRef name, ValueRef value)
+void Object::defineReadonlyProperty(String *name, ValueRef value)
{
insertMember(name, value, Attr_ReadOnly);
}
@@ -221,45 +203,45 @@ void Object::markObjects(Managed *that, ExecutionEngine *e)
{
Object *o = static_cast<Object *>(that);
- o->memberData.mark(e);
- if (o->arrayData)
- o->arrayData->mark(e);
+ o->memberData().mark(e);
+ if (o->arrayData())
+ o->arrayData()->mark(e);
}
void Object::ensureMemberIndex(uint idx)
{
- memberData.ensureIndex(engine(), idx);
+ memberData().ensureIndex(engine(), idx);
}
-void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes)
+void Object::insertMember(String *s, const Property &p, PropertyAttributes attributes)
{
uint idx;
- InternalClass::addMember(this, s.getPointer(), attributes, &idx);
+ InternalClass::addMember(this, s, attributes, &idx);
- ensureMemberIndex(internalClass->size);
+ ensureMemberIndex(internalClass()->size);
if (attributes.isAccessor()) {
- hasAccessorProperty = 1;
+ setHasAccessorProperty();
Property *pp = propertyAt(idx);
pp->value = p.value;
pp->set = p.set;
} else {
- memberData[idx] = p.value;
+ memberData()[idx] = p.value;
}
}
// Section 8.12.1
-Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *attrs)
+Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return __getOwnProperty__(idx, attrs);
- uint member = internalClass->find(name);
+ uint member = internalClass()->find(name);
if (member < UINT_MAX) {
if (attrs)
- *attrs = internalClass->propertyData[member];
+ *attrs = internalClass()->propertyData[member];
return propertyAt(member);
}
@@ -270,10 +252,10 @@ Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *a
Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
{
- Property *p = arrayData->getProperty(index);
+ Property *p = arrayData()->getProperty(index);
if (p) {
if (attrs)
- *attrs = arrayData->attributes(index);
+ *attrs = arrayData()->attributes(index);
return p;
}
if (isStringObject()) {
@@ -288,7 +270,7 @@ Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
}
// Section 8.12.2
-Property *Object::__getPropertyDescriptor__(const StringRef name, PropertyAttributes *attrs) const
+Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -297,10 +279,10 @@ Property *Object::__getPropertyDescriptor__(const StringRef name, PropertyAttrib
const Object *o = this;
while (o) {
- uint idx = o->internalClass->find(name.getPointer());
+ uint idx = o->internalClass()->find(name);
if (idx < UINT_MAX) {
if (attrs)
- *attrs = o->internalClass->propertyData[idx];
+ *attrs = o->internalClass()->propertyData[idx];
return o->propertyAt(idx);
}
@@ -315,10 +297,10 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
{
const Object *o = this;
while (o) {
- Property *p = o->arrayData->getProperty(index);
+ Property *p = o->arrayData()->getProperty(index);
if (p) {
if (attrs)
- *attrs = o->arrayData->attributes(index);
+ *attrs = o->arrayData()->attributes(index);
return p;
}
if (o->isStringObject()) {
@@ -336,7 +318,7 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr
return 0;
}
-bool Object::hasProperty(const StringRef name) const
+bool Object::hasProperty(String *name) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -366,13 +348,13 @@ bool Object::hasProperty(uint index) const
return false;
}
-bool Object::hasOwnProperty(const StringRef name) const
+bool Object::hasOwnProperty(String *name) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return hasOwnProperty(idx);
- if (internalClass->find(name) < UINT_MAX)
+ if (internalClass()->find(name) < UINT_MAX)
return true;
if (!query(name).isEmpty())
return true;
@@ -381,11 +363,11 @@ bool Object::hasOwnProperty(const StringRef name) const
bool Object::hasOwnProperty(uint index) const
{
- if (!arrayData->isEmpty(index))
+ if (!arrayData()->isEmpty(index))
return true;
if (isStringObject()) {
- String *s = static_cast<const StringObject *>(this)->value.asString();
- if (index < (uint)s->length())
+ String *s = static_cast<const StringObject *>(this)->d()->value.asString();
+ if (index < (uint)s->d()->length())
return true;
}
if (!queryIndexed(index).isEmpty())
@@ -403,7 +385,7 @@ ReturnedValue Object::call(Managed *m, CallData *)
return m->engine()->currentContext()->throwTypeError();
}
-ReturnedValue Object::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty)
{
return static_cast<Object *>(m)->internalGet(name, hasProperty);
}
@@ -413,7 +395,7 @@ ReturnedValue Object::getIndexed(Managed *m, uint index, bool *hasProperty)
return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty);
}
-void Object::put(Managed *m, const StringRef name, const ValueRef value)
+void Object::put(Managed *m, String *name, const ValueRef value)
{
static_cast<Object *>(m)->internalPut(name, value);
}
@@ -423,16 +405,16 @@ void Object::putIndexed(Managed *m, uint index, const ValueRef value)
static_cast<Object *>(m)->internalPutIndexed(index, value);
}
-PropertyAttributes Object::query(const Managed *m, StringRef name)
+PropertyAttributes Object::query(const Managed *m, String *name)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return queryIndexed(m, idx);
const Object *o = static_cast<const Object *>(m);
- idx = o->internalClass->find(name.getPointer());
+ idx = o->internalClass()->find(name);
if (idx < UINT_MAX)
- return o->internalClass->propertyData[idx];
+ return o->internalClass()->propertyData[idx];
return Attr_Invalid;
}
@@ -440,18 +422,18 @@ PropertyAttributes Object::query(const Managed *m, StringRef name)
PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
{
const Object *o = static_cast<const Object *>(m);
- if (o->arrayData->get(index) != Primitive::emptyValue().asReturnedValue())
- return o->arrayData->attributes(index);
+ if (o->arrayData()->get(index) != Primitive::emptyValue().asReturnedValue())
+ return o->arrayData()->attributes(index);
if (o->isStringObject()) {
- String *s = static_cast<const StringObject *>(o)->value.asString();
- if (index < (uint)s->length())
+ String *s = static_cast<const StringObject *>(o)->d()->value.asString();
+ if (index < (uint)s->d()->length())
return (Attr_NotWritable|Attr_NotConfigurable);
}
return Attr_Invalid;
}
-bool Object::deleteProperty(Managed *m, const StringRef name)
+bool Object::deleteProperty(Managed *m, String *name)
{
return static_cast<Object *>(m)->internalDeleteProperty(name);
}
@@ -497,46 +479,46 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value)
Scope scope(m->engine());
ScopedObject o(scope, static_cast<Object *>(m));
- InternalClass *c = o->internalClass;
+ InternalClass *c = o->internalClass();
uint idx = c->find(l->name);
if (!o->isArrayObject() || idx != ArrayObject::LengthPropertyIndex) {
- if (idx != UINT_MAX && o->internalClass->propertyData[idx].isData() && o->internalClass->propertyData[idx].isWritable()) {
- l->classList[0] = o->internalClass;
+ if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) {
+ l->classList[0] = o->internalClass();
l->index = idx;
l->setter = Lookup::setter0;
- o->memberData[idx] = *value;
+ o->memberData()[idx] = *value;
return;
}
if (idx != UINT_MAX) {
- o->putValue(o->propertyAt(idx), o->internalClass->propertyData[idx], value);
+ o->putValue(o->propertyAt(idx), o->internalClass()->propertyData[idx], value);
return;
}
}
ScopedString s(scope, l->name);
- o->put(s, value);
+ o->put(s.getPointer(), value);
- if (o->internalClass == c)
+ if (o->internalClass() == c)
return;
- idx = o->internalClass->find(l->name);
+ idx = o->internalClass()->find(l->name);
if (idx == UINT_MAX)
return;
l->classList[0] = c;
- l->classList[3] = o->internalClass;
+ l->classList[3] = o->internalClass();
l->index = idx;
if (!o->prototype()) {
l->setter = Lookup::setterInsert0;
return;
}
o = o->prototype();
- l->classList[1] = o->internalClass;
+ l->classList[1] = o->internalClass();
if (!o->prototype()) {
l->setter = Lookup::setterInsert1;
return;
}
o = o->prototype();
- l->classList[2] = o->internalClass;
+ l->classList[2] = o->internalClass();
if (!o->prototype()) {
l->setter = Lookup::setterInsert2;
return;
@@ -544,13 +526,13 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value)
l->setter = Lookup::setterGeneric;
}
-void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *pd, PropertyAttributes *attrs)
+void Object::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *pd, PropertyAttributes *attrs)
{
Object *o = static_cast<Object *>(m);
name = (String *)0;
*index = UINT_MAX;
- if (o->arrayData) {
+ if (o->arrayData()) {
if (!it->arrayIndex)
it->arrayNode = o->sparseBegin();
@@ -559,9 +541,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
while (it->arrayNode != o->sparseEnd()) {
int k = it->arrayNode->key();
uint pidx = it->arrayNode->value;
- Property *p = reinterpret_cast<Property *>(o->arrayData->data + pidx);
+ Property *p = reinterpret_cast<Property *>(o->arrayData()->arrayData() + pidx);
it->arrayNode = it->arrayNode->nextNode();
- PropertyAttributes a = o->arrayData->attributes(k);
+ PropertyAttributes a = o->arrayData()->attributes(k);
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
it->arrayIndex = k + 1;
*index = k;
@@ -574,9 +556,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
it->arrayIndex = UINT_MAX;
}
// dense arrays
- while (it->arrayIndex < o->arrayData->length()) {
- Value *val = o->arrayData->data + it->arrayIndex;
- PropertyAttributes a = o->arrayData->attributes(it->arrayIndex);
+ while (it->arrayIndex < o->arrayData()->length()) {
+ Value *val = o->arrayData()->arrayData() + it->arrayIndex;
+ PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
++it->arrayIndex;
if (!val->isEmpty()
&& (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
@@ -588,8 +570,8 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
}
}
- while (it->memberIndex < o->internalClass->size) {
- String *n = o->internalClass->nameMap.at(it->memberIndex);
+ while (it->memberIndex < o->internalClass()->size) {
+ String *n = o->internalClass()->nameMap.at(it->memberIndex);
if (!n) {
// accessor properties have a dummy entry with n == 0
++it->memberIndex;
@@ -597,7 +579,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
}
Property *p = o->propertyAt(it->memberIndex);
- PropertyAttributes a = o->internalClass->propertyData[it->memberIndex];
+ PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex];
++it->memberIndex;
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
name = n;
@@ -611,7 +593,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin
}
// Section 8.12.3
-ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty)
+ReturnedValue Object::internalGet(String *name, bool *hasProperty)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -621,11 +603,11 @@ ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty)
Object *o = this;
while (o) {
- uint idx = o->internalClass->find(name.getPointer());
+ uint idx = o->internalClass()->find(name);
if (idx < UINT_MAX) {
if (hasProperty)
*hasProperty = true;
- return getValue(o->propertyAt(idx), o->internalClass->propertyData.at(idx));
+ return getValue(o->propertyAt(idx), o->internalClass()->propertyData.at(idx));
}
o = o->prototype();
@@ -642,10 +624,10 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
PropertyAttributes attrs;
Object *o = this;
while (o) {
- Property *p = o->arrayData->getProperty(index);
+ Property *p = o->arrayData()->getProperty(index);
if (p) {
pd = p;
- attrs = o->arrayData->attributes(index);
+ attrs = o->arrayData()->attributes(index);
break;
}
if (o->isStringObject()) {
@@ -671,9 +653,9 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty)
// Section 8.12.5
-void Object::internalPut(const StringRef name, const ValueRef value)
+void Object::internalPut(String *name, const ValueRef value)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return;
uint idx = name->asArrayIndex();
@@ -682,12 +664,12 @@ void Object::internalPut(const StringRef name, const ValueRef value)
name->makeIdentifier();
- uint member = internalClass->find(name.getPointer());
+ uint member = internalClass()->find(name);
Property *pd = 0;
PropertyAttributes attrs;
if (member < UINT_MAX) {
pd = propertyAt(member);
- attrs = internalClass->propertyData[member];
+ attrs = internalClass()->propertyData[member];
}
// clause 1
@@ -713,7 +695,7 @@ void Object::internalPut(const StringRef name, const ValueRef value)
}
return;
} else if (!prototype()) {
- if (!extensible)
+ if (!isExtensible())
goto reject;
} else {
// clause 4
@@ -721,10 +703,10 @@ void Object::internalPut(const StringRef name, const ValueRef value)
if (attrs.isAccessor()) {
if (!pd->setter())
goto reject;
- } else if (!extensible || !attrs.isWritable()) {
+ } else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
}
- } else if (!extensible) {
+ } else if (!isExtensible()) {
goto reject;
}
}
@@ -747,7 +729,7 @@ void Object::internalPut(const StringRef name, const ValueRef value)
return;
reject:
- if (engine()->currentContext()->strictMode) {
+ if (engine()->currentContext()->d()->strictMode) {
QString message = QStringLiteral("Cannot assign to read-only property \"");
message += name->toQString();
message += QLatin1Char('\"');
@@ -757,14 +739,14 @@ void Object::internalPut(const StringRef name, const ValueRef value)
void Object::internalPutIndexed(uint index, const ValueRef value)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return;
PropertyAttributes attrs;
- Property *pd = arrayData->getProperty(index);
+ Property *pd = arrayData()->getProperty(index);
if (pd)
- attrs = arrayData->attributes(index);
+ attrs = arrayData()->attributes(index);
if (!pd && isStringObject()) {
pd = static_cast<StringObject *>(this)->getIndex(index);
@@ -785,7 +767,7 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
pd->value = *value;
return;
} else if (!prototype()) {
- if (!extensible)
+ if (!isExtensible())
goto reject;
} else {
// clause 4
@@ -793,10 +775,10 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
if (attrs.isAccessor()) {
if (!pd->setter())
goto reject;
- } else if (!extensible || !attrs.isWritable()) {
+ } else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
}
- } else if (!extensible) {
+ } else if (!isExtensible()) {
goto reject;
}
}
@@ -819,14 +801,14 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
return;
reject:
- if (engine()->currentContext()->strictMode)
+ if (engine()->currentContext()->d()->strictMode)
engine()->currentContext()->throwTypeError();
}
// Section 8.12.7
-bool Object::internalDeleteProperty(const StringRef name)
+bool Object::internalDeleteProperty(String *name)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return false;
uint idx = name->asArrayIndex();
@@ -835,13 +817,13 @@ bool Object::internalDeleteProperty(const StringRef name)
name->makeIdentifier();
- uint memberIdx = internalClass->find(name);
+ uint memberIdx = internalClass()->find(name);
if (memberIdx != UINT_MAX) {
- if (internalClass->propertyData[memberIdx].isConfigurable()) {
- InternalClass::removeMember(this, name->identifier);
+ if (internalClass()->propertyData[memberIdx].isConfigurable()) {
+ InternalClass::removeMember(this, name->identifier());
return true;
}
- if (engine()->currentContext()->strictMode)
+ if (engine()->currentContext()->d()->strictMode)
engine()->currentContext()->throwTypeError();
return false;
}
@@ -851,19 +833,19 @@ bool Object::internalDeleteProperty(const StringRef name)
bool Object::internalDeleteIndexedProperty(uint index)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return false;
- if (!arrayData || arrayData->vtable()->del(this, index))
+ if (!arrayData() || arrayData()->vtable()->del(this, index))
return true;
- if (engine()->currentContext()->strictMode)
+ if (engine()->currentContext()->d()->strictMode)
engine()->currentContext()->throwTypeError();
return false;
}
// Section 8.12.9
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -876,10 +858,10 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
PropertyAttributes *cattrs;
uint memberIndex;
- if (isArrayObject() && name->equals(ctx->engine->id_length)) {
- assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length));
+ if (isArrayObject() && name->equals(ctx->d()->engine->id_length)) {
+ assert(ArrayObject::LengthPropertyIndex == internalClass()->find(ctx->d()->engine->id_length));
Property *lp = propertyAt(ArrayObject::LengthPropertyIndex);
- cattrs = internalClass->propertyData.constData() + ArrayObject::LengthPropertyIndex;
+ cattrs = internalClass()->propertyData.constData() + ArrayObject::LengthPropertyIndex;
if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs))
return true;
if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
@@ -900,18 +882,18 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
if (!succeeded)
goto reject;
if (attrs.isAccessor())
- hasAccessorProperty = 1;
+ setHasAccessorProperty();
return true;
}
// Clause 1
- memberIndex = internalClass->find(name.getPointer());
+ memberIndex = internalClass()->find(name);
current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0;
- cattrs = internalClass->propertyData.constData() + memberIndex;
+ cattrs = internalClass()->propertyData.constData() + memberIndex;
if (!current) {
// clause 3
- if (!extensible)
+ if (!isExtensible())
goto reject;
// clause 4
Property pd;
@@ -923,7 +905,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name,
return __defineOwnProperty__(ctx, memberIndex, name, p, attrs);
reject:
- if (ctx->strictMode)
+ if (ctx->d()->strictMode)
ctx->throwTypeError();
return false;
}
@@ -931,7 +913,7 @@ reject:
bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
{
// 15.4.5.1, 4b
- if (isArrayObject() && index >= getLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ if (isArrayObject() && index >= getLength() && !internalClass()->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
goto reject;
if (ArgumentsObject::isNonStrictArgumentsObject(this))
@@ -939,7 +921,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop
return defineOwnProperty2(ctx, index, p, attrs);
reject:
- if (ctx->strictMode)
+ if (ctx->d()->strictMode)
ctx->throwTypeError();
return false;
}
@@ -950,14 +932,14 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert
// Clause 1
{
- current = arrayData->getProperty(index);
+ current = arrayData()->getProperty(index);
if (!current && isStringObject())
current = static_cast<StringObject *>(this)->getIndex(index);
}
if (!current) {
// clause 3
- if (!extensible)
+ if (!isExtensible())
goto reject;
// clause 4
Property pp;
@@ -973,14 +955,14 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert
return true;
}
- return __defineOwnProperty__(ctx, index, StringRef::null(), p, attrs);
+ return __defineOwnProperty__(ctx, index, 0, p, attrs);
reject:
- if (ctx->strictMode)
+ if (ctx->d()->strictMode)
ctx->throwTypeError();
return false;
}
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const StringRef member, const Property &p, PropertyAttributes attrs)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *member, const Property &p, PropertyAttributes attrs)
{
// clause 5
if (attrs.isEmpty())
@@ -988,12 +970,12 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri
Property *current;
PropertyAttributes cattrs;
- if (!member.isNull()) {
+ if (member) {
current = propertyAt(index);
- cattrs = internalClass->propertyData[index];
+ cattrs = internalClass()->propertyData[index];
} else {
- current = arrayData->getProperty(index);
- cattrs = arrayData->attributes(index);
+ current = arrayData()->getProperty(index);
+ cattrs = arrayData()->attributes(index);
}
// clause 6
@@ -1021,11 +1003,11 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri
// 9b
cattrs.setType(PropertyAttributes::Accessor);
cattrs.clearWritable();
- if (member.isNull()) {
+ if (!member) {
// need to convert the array and the slot
initSparseArray();
setArrayAttributes(index, cattrs);
- current = arrayData->getProperty(index);
+ current = arrayData()->getProperty(index);
}
current->setGetter(0);
current->setSetter(0);
@@ -1033,10 +1015,10 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri
// 9c
cattrs.setType(PropertyAttributes::Data);
cattrs.setWritable(false);
- if (member.isNull()) {
+ if (!member) {
// need to convert the array and the slot
setArrayAttributes(index, cattrs);
- current = arrayData->getProperty(index);
+ current = arrayData()->getProperty(index);
}
current->value = Primitive::undefinedValue();
}
@@ -1058,16 +1040,16 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri
accept:
current->merge(cattrs, p, attrs);
- if (!member.isNull()) {
- InternalClass::changeMember(this, member.getPointer(), cattrs);
+ if (member) {
+ InternalClass::changeMember(this, member, cattrs);
} else {
setArrayAttributes(index, cattrs);
}
if (cattrs.isAccessor())
- hasAccessorProperty = 1;
+ setHasAccessorProperty();
return true;
reject:
- if (ctx->strictMode)
+ if (ctx->d()->strictMode)
ctx->throwTypeError();
return false;
}
@@ -1076,8 +1058,8 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri
bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs)
{
Scope scope(ctx);
- ScopedString s(scope, ctx->engine->newString(name));
- return __defineOwnProperty__(ctx, s, p, attrs);
+ ScopedString s(scope, ctx->d()->engine->newString(name));
+ return __defineOwnProperty__(ctx, s.getPointer(), p, attrs);
}
@@ -1086,7 +1068,7 @@ void Object::copyArrayData(Object *other)
Q_ASSERT(isArrayObject());
Scope scope(engine());
- if (other->protoHasArray() || other->hasAccessorProperty) {
+ if (other->protoHasArray() || other->hasAccessorProperty()) {
uint len = other->getLength();
Q_ASSERT(len);
@@ -1094,30 +1076,30 @@ void Object::copyArrayData(Object *other)
for (uint i = 0; i < len; ++i) {
arraySet(i, (v = other->getIndexed(i)));
}
- } else if (!other->arrayData) {
+ } else if (!other->arrayData()) {
;
- } else if (other->hasAccessorProperty && other->arrayData->attrs && other->arrayData->isSparse()){
+ } else if (other->hasAccessorProperty() && other->arrayData()->attrs() && other->arrayData()->isSparse()){
// do it the slow way
ScopedValue v(scope);
- for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other->arrayData)->sparse->begin();
- it != static_cast<const SparseArrayData *>(other->arrayData)->sparse->end(); it = it->nextNode()) {
- v = other->getValue(reinterpret_cast<Property *>(other->arrayData->data + it->value), other->arrayData->attrs[it->value]);
+ for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other->arrayData())->sparse()->begin();
+ it != static_cast<const SparseArrayData *>(other->arrayData())->sparse()->end(); it = it->nextNode()) {
+ v = other->getValue(reinterpret_cast<Property *>(other->arrayData()->arrayData() + it->value), other->arrayData()->attrs()[it->value]);
arraySet(it->key(), v);
}
} else {
- Q_ASSERT(!arrayData && other->arrayData);
- ArrayData::realloc(this, other->arrayData->type, 0, other->arrayData->alloc, other->arrayData->attrs);
+ Q_ASSERT(!arrayData() && other->arrayData());
+ ArrayData::realloc(this, other->arrayData()->type(), 0, other->arrayData()->alloc(), other->arrayData()->attrs());
if (other->arrayType() == ArrayData::Sparse) {
- SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData);
- SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData);
- dd->sparse = new SparseArray(*od->sparse);
- dd->freeList = od->freeList;
+ SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData());
+ SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData());
+ dd->setSparse(new SparseArray(*od->sparse()));
+ dd->freeList() = od->freeList();
} else {
- SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData);
- d->len = static_cast<SimpleArrayData *>(other->arrayData)->len;
- d->offset = 0;
+ SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData());
+ d->len() = static_cast<SimpleArrayData *>(other->arrayData())->len();
+ d->offset() = 0;
}
- memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(Value));
+ memcpy(arrayData()->arrayData(), other->arrayData()->arrayData(), arrayData()->alloc()*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
@@ -1132,15 +1114,15 @@ uint Object::getLength(const Managed *m)
bool Object::setArrayLength(uint newLen)
{
Q_ASSERT(isArrayObject());
- if (!internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ if (!internalClass()->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
return false;
uint oldLen = getLength();
bool ok = true;
if (newLen < oldLen) {
- if (!arrayData) {
+ if (!arrayData()) {
Q_ASSERT(!newLen);
} else {
- uint l = arrayData->vtable()->truncate(this, newLen);
+ uint l = arrayData()->vtable()->truncate(this, newLen);
if (l != newLen)
ok = false;
newLen = l;
@@ -1164,30 +1146,23 @@ void Object::initSparseArray()
DEFINE_OBJECT_VTABLE(ArrayObject);
-ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
- : Object(engine->arrayClass)
+ArrayObject::Data::Data(ExecutionEngine *engine, const QStringList &list)
+ : Object::Data(engine->arrayClass)
{
- init(engine);
+ init();
Scope scope(engine);
- ScopedValue protectThis(scope, this);
+ ScopedObject a(scope, this);
// Converts a QStringList to JS.
// The result is a new Array object with length equal to the length
// of the QStringList, and the elements being the QStringList's
// elements converted to JS Strings.
int len = list.count();
- arrayReserve(len);
+ a->arrayReserve(len);
ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii)
- arrayPut(ii, (v = engine->newString(list.at(ii))));
- setArrayLengthUnchecked(len);
-}
-
-void ArrayObject::init(ExecutionEngine *engine)
-{
- Q_UNUSED(engine);
-
- memberData[LengthPropertyIndex] = Primitive::fromInt32(0);
+ a->arrayPut(ii, (v = engine->newString(list.at(ii))));
+ a->setArrayLengthUnchecked(len);
}
ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l)
@@ -1196,7 +1171,7 @@ ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l)
// special case, as the property is on the object itself
l->getter = Lookup::arrayLengthGetter;
ArrayObject *a = static_cast<ArrayObject *>(m);
- return a->memberData[ArrayObject::LengthPropertyIndex].asReturnedValue();
+ return a->memberData()[ArrayObject::LengthPropertyIndex].asReturnedValue();
}
return Object::getLookup(m, l);
}
@@ -1204,16 +1179,16 @@ ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l)
uint ArrayObject::getLength(const Managed *m)
{
const ArrayObject *a = static_cast<const ArrayObject *>(m);
- if (a->memberData[ArrayObject::LengthPropertyIndex].isInteger())
- return a->memberData[ArrayObject::LengthPropertyIndex].integerValue();
- return Primitive::toUInt32(a->memberData[ArrayObject::LengthPropertyIndex].doubleValue());
+ if (a->memberData()[ArrayObject::LengthPropertyIndex].isInteger())
+ return a->memberData()[ArrayObject::LengthPropertyIndex].integerValue();
+ return Primitive::toUInt32(a->memberData()[ArrayObject::LengthPropertyIndex].doubleValue());
}
QStringList ArrayObject::toQStringList() const
{
QStringList result;
- QV4::ExecutionEngine *engine = internalClass->engine;
+ QV4::ExecutionEngine *engine = internalClass()->engine;
Scope scope(engine);
ScopedValue v(scope);
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 40f38ee347..67459d5e77 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -103,39 +103,49 @@ struct URIErrorPrototype;
struct Q_QML_EXPORT Object: Managed {
- V4_OBJECT
+ struct Data : Managed::Data {
+ Data(ExecutionEngine *engine)
+ : Managed::Data(engine->objectClass)
+ {
+ }
+ Data(InternalClass *internal = 0);
+
+ Members memberData;
+ ArrayData *arrayData;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(Object)
+
enum {
IsObject = true
};
- Members memberData;
- ArrayData *arrayData;
+ Members &memberData() { return d()->memberData; }
+ const Members &memberData() const { return d()->memberData; }
+ const ArrayData *arrayData() const { return d()->arrayData; }
+ ArrayData *arrayData() { return d()->arrayData; }
+ void setArrayData(ArrayData *a) { d()->arrayData = a; }
- Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData.data() + index); }
+ Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData().data() + index); }
- Object(ExecutionEngine *engine);
- Object(InternalClass *internalClass);
- ~Object();
-
- const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(internalClass->vtable); }
- Object *prototype() const { return internalClass->prototype; }
+ const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(internalClass()->vtable); }
+ Object *prototype() const { return internalClass()->prototype; }
bool setPrototype(Object *proto);
- Property *__getOwnProperty__(const StringRef name, PropertyAttributes *attrs = 0);
+ Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0);
Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0);
- Property *__getPropertyDescriptor__(const StringRef name, PropertyAttributes *attrs = 0) const;
+ Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const;
Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const;
- bool hasProperty(const StringRef name) const;
+ bool hasProperty(String *name) const;
bool hasProperty(uint index) const;
- bool hasOwnProperty(const StringRef name) const;
+ bool hasOwnProperty(String *name) const;
bool hasOwnProperty(uint index) const;
- bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const StringRef member, const Property &p, PropertyAttributes attrs);
- bool __defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, uint index, String *member, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs);
bool defineOwnProperty2(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
@@ -155,24 +165,31 @@ struct Q_QML_EXPORT Object: Managed {
void putValue(Property *pd, PropertyAttributes attrs, const ValueRef value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
- void defineDefaultProperty(const StringRef name, ValueRef value) {
+ void defineDefaultProperty(String *name, ValueRef value) {
insertMember(name, value, Attr_Data|Attr_NotEnumerable);
}
void defineDefaultProperty(const QString &name, ValueRef value);
void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
- void defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
+ void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
- void defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
+ void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, ValueRef value);
- void defineReadonlyProperty(const StringRef name, ValueRef value);
+ void defineReadonlyProperty(String *name, ValueRef value);
- void insertMember(const StringRef s, const ValueRef v, PropertyAttributes attributes = Attr_Data) {
- insertMember(s, Property(*v), attributes);
+ void insertMember(String *s, const ValueRef v, PropertyAttributes attributes = Attr_Data) {
+ Property p(*v);
+ insertMember(s, p, attributes);
}
- void insertMember(const StringRef s, const Property &p, PropertyAttributes attributes);
+ void insertMember(String *s, const Property &p, PropertyAttributes attributes);
+
+ inline ExecutionEngine *engine() const { return internalClass()->engine; }
- inline ExecutionEngine *engine() const { return internalClass->engine; }
+ inline bool hasAccessorProperty() const { return d()->hasAccessorProperty; }
+ inline void setHasAccessorProperty() { d()->hasAccessorProperty = true; }
+
+ bool isExtensible() const { return d()->extensible; }
+ void setExtensible(bool b) { d()->extensible = b; }
// Array handling
@@ -186,30 +203,30 @@ public:
void arraySet(uint index, ValueRef value);
bool arrayPut(uint index, ValueRef value) {
- return arrayData->vtable()->put(this, index, value);
+ return arrayData()->vtable()->put(this, index, value);
}
bool arrayPut(uint index, Value *values, uint n) {
- return arrayData->vtable()->putArray(this, index, values, n);
+ return arrayData()->vtable()->putArray(this, index, values, n);
}
void setArrayAttributes(uint i, PropertyAttributes a) {
- Q_ASSERT(arrayData);
- if (arrayData->attrs || a != Attr_Data) {
+ Q_ASSERT(arrayData());
+ if (arrayData()->attrs() || a != Attr_Data) {
ArrayData::ensureAttributes(this);
a.resolve();
- arrayData->vtable()->setAttribute(this, i, a);
+ arrayData()->vtable()->setAttribute(this, i, a);
}
}
void push_back(const ValueRef v);
ArrayData::Type arrayType() const {
- return arrayData ? arrayData->type : ArrayData::Simple;
+ return arrayData() ? arrayData()->type() : ArrayData::Simple;
}
// ### remove me
void setArrayType(ArrayData::Type t) {
Q_ASSERT(t != ArrayData::Simple && t != ArrayData::Sparse);
arrayCreate();
- arrayData->type = t;
+ arrayData()->setType(t);
}
inline void arrayReserve(uint n) {
@@ -217,7 +234,7 @@ public:
}
void arrayCreate() {
- if (!arrayData)
+ if (!arrayData())
ArrayData::realloc(this, ArrayData::Simple, 0, 0, false);
#ifdef CHECK_SPARSE_ARRAYS
initSparseArray();
@@ -225,34 +242,34 @@ public:
}
void initSparseArray();
- SparseArrayNode *sparseBegin() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->begin() : 0; }
- SparseArrayNode *sparseEnd() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->end() : 0; }
+ SparseArrayNode *sparseBegin() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData())->sparse()->begin() : 0; }
+ SparseArrayNode *sparseEnd() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData())->sparse()->end() : 0; }
inline bool protoHasArray() {
Scope scope(engine());
Scoped<Object> p(scope, this);
while ((p = p->prototype()))
- if (p->arrayData)
+ if (p->arrayData())
return true;
return false;
}
void ensureMemberIndex(uint idx);
- inline ReturnedValue get(const StringRef name, bool *hasProperty = 0)
+ inline ReturnedValue get(String *name, bool *hasProperty = 0)
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0)
{ return vtable()->getIndexed(this, idx, hasProperty); }
- inline void put(const StringRef name, const ValueRef v)
+ inline void put(String *name, const ValueRef v)
{ vtable()->put(this, name, v); }
inline void putIndexed(uint idx, const ValueRef v)
{ vtable()->putIndexed(this, idx, v); }
- PropertyAttributes query(StringRef name) const
+ PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
{ return vtable()->queryIndexed(this, index); }
- bool deleteProperty(const StringRef name)
+ bool deleteProperty(String *name)
{ return vtable()->deleteProperty(this, name); }
bool deleteIndexedProperty(uint index)
{ return vtable()->deleteIndexedProperty(this, index); }
@@ -260,7 +277,7 @@ public:
{ return vtable()->getLookup(this, l); }
void setLookup(Lookup *l, const ValueRef v)
{ vtable()->setLookup(this, l, v); }
- void advanceIterator(ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes)
+ void advanceIterator(ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
@@ -269,29 +286,28 @@ public:
inline ReturnedValue call(CallData *d)
{ return vtable()->call(this, d); }
protected:
- static void destroy(Managed *that);
static void markObjects(Managed *that, ExecutionEngine *e);
static ReturnedValue construct(Managed *m, CallData *);
static ReturnedValue call(Managed *m, CallData *);
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
+ static void put(Managed *m, String *name, const ValueRef value);
static void putIndexed(Managed *m, uint index, const ValueRef value);
- static PropertyAttributes query(const Managed *m, StringRef name);
+ static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static bool deleteProperty(Managed *m, const StringRef name);
+ static bool deleteProperty(Managed *m, String *name);
static bool deleteIndexedProperty(Managed *m, uint index);
static ReturnedValue getLookup(Managed *m, Lookup *l);
static void setLookup(Managed *m, Lookup *l, const ValueRef v);
- static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes);
+ static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
private:
- ReturnedValue internalGet(const StringRef name, bool *hasProperty);
+ ReturnedValue internalGet(String *name, bool *hasProperty);
ReturnedValue internalGetIndexed(uint index, bool *hasProperty);
- void internalPut(const StringRef name, const ValueRef value);
+ void internalPut(String *name, const ValueRef value);
void internalPutIndexed(uint index, const ValueRef value);
- bool internalDeleteProperty(const StringRef name);
+ bool internalDeleteProperty(String *name);
bool internalDeleteIndexedProperty(uint index);
friend struct ObjectIterator;
@@ -299,48 +315,62 @@ private:
};
struct BooleanObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, const ValueRef val)
+ : Object::Data(engine->booleanClass)
+ {
+ value = val;
+ }
+ Data(InternalClass *ic)
+ : Object::Data(ic)
+ {
+ Q_ASSERT(internalClass->vtable == staticVTable());
+ value = Encode(false);
+ }
+ Value value;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(BooleanObject)
- Value value;
- BooleanObject(ExecutionEngine *engine, const ValueRef val)
- : Object(engine->booleanClass) {
- value = val;
- }
-protected:
- BooleanObject(InternalClass *ic)
- : Object(ic) {
- Q_ASSERT(internalClass->vtable == staticVTable());
- value = Encode(false);
- }
+
+ Value value() const { return d()->value; }
+
};
struct NumberObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, const ValueRef val)
+ : Object::Data(engine->numberClass) {
+ value = val;
+ }
+ Data(InternalClass *ic)
+ : Object::Data(ic) {
+ Q_ASSERT(internalClass->vtable == staticVTable());
+ value = Encode((int)0);
+ }
+ Value value;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(NumberObject)
- Value value;
- NumberObject(ExecutionEngine *engine, const ValueRef val)
- : Object(engine->numberClass) {
- value = val;
- }
-protected:
- NumberObject(InternalClass *ic)
- : Object(ic) {
- Q_ASSERT(internalClass->vtable == staticVTable());
- value = Encode((int)0);
- }
+
+ Value value() const { return d()->value; }
+
};
struct ArrayObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine) : Object::Data(engine->arrayClass) { init(); }
+ Data(ExecutionEngine *engine, const QStringList &list);
+ Data(InternalClass *ic) : Object::Data(ic) { init(); }
+ void init()
+ { memberData[LengthPropertyIndex] = Primitive::fromInt32(0); }
+ };
+
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(ArrayObject)
enum {
LengthPropertyIndex = 0
};
- ArrayObject(ExecutionEngine *engine) : Object(engine->arrayClass) { init(engine); }
- ArrayObject(ExecutionEngine *engine, const QStringList &list);
- ArrayObject(InternalClass *ic) : Object(ic) { init(ic->engine); }
-
void init(ExecutionEngine *engine);
static ReturnedValue getLookup(Managed *m, Lookup *l);
@@ -353,7 +383,7 @@ struct ArrayObject: Object {
inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject())
- memberData[ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l);
+ memberData()[ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l);
}
inline void Object::push_back(const ValueRef v)
@@ -371,12 +401,12 @@ inline void Object::arraySet(uint index, const Property &p, PropertyAttributes a
// ### Clean up
arrayCreate();
if (attributes.isAccessor()) {
- hasAccessorProperty = 1;
+ setHasAccessorProperty();
initSparseArray();
- } else if (index > 0x1000 && index > 2*arrayData->alloc) {
+ } else if (index > 0x1000 && index > 2*arrayData()->alloc()) {
initSparseArray();
} else {
- arrayData->vtable()->reallocate(this, index + 1, false);
+ arrayData()->vtable()->reallocate(this, index + 1, false);
}
setArrayAttributes(index, attributes);
Property *pd = ArrayData::insert(this, index, attributes.isAccessor());
@@ -391,7 +421,7 @@ inline void Object::arraySet(uint index, const Property &p, PropertyAttributes a
inline void Object::arraySet(uint index, ValueRef value)
{
arrayCreate();
- if (index > 0x1000 && index > 2*arrayData->alloc) {
+ if (index > 0x1000 && index > 2*arrayData()->alloc()) {
initSparseArray();
}
Property *pd = ArrayData::insert(this, index);
@@ -418,23 +448,6 @@ inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
}
#endif
-struct ObjectRef : public ManagedRef
-{
- DEFINE_REF_METHODS(Object, Managed)
-
- static ObjectRef fromValuePointer(Value *s) {
- ObjectRef r;
- r.ptr = s;
- if (sizeof(void *) == 8)
- r.ptr->val = 0;
- else
- *r.ptr = Value::fromManaged(0);
- return r;
- }
-};
-
-DEFINE_REF(ArrayObject, Object);
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index e5f693c323..216700fe69 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -46,63 +46,71 @@
using namespace QV4;
-ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags)
- : object(ObjectRef::fromValuePointer(scratch1))
- , current(ObjectRef::fromValuePointer(scratch2))
+ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint flags)
+ : object(scratch1)
+ , current(scratch2)
, arrayNode(0)
, arrayIndex(0)
, memberIndex(0)
, flags(flags)
{
- object = o.getPointer();
- current = o.getPointer();
-
- if (!!object && object->asArgumentsObject()) {
+ object->o = o;
+ current->o = o;
+#if QT_POINTER_SIZE == 4
+ object->tag = QV4::Value::Managed_Type;
+ current->tag = QV4::Value::Managed_Type;
+#endif
+
+ if (object->as<ArgumentsObject>()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
}
-ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
- : object(ObjectRef::fromValuePointer(scope.alloc(1)))
- , current(ObjectRef::fromValuePointer(scope.alloc(1)))
+ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags)
+ : object(scope.alloc(1))
+ , current(scope.alloc(1))
, arrayNode(0)
, arrayIndex(0)
, memberIndex(0)
, flags(flags)
{
- object = o;
- current = o;
-
- if (!!object && object->asArgumentsObject()) {
+ object->o = o;
+ current->o = o;
+#if QT_POINTER_SIZE == 4
+ object->tag = QV4::Value::Managed_Type;
+ current->tag = QV4::Value::Managed_Type;
+#endif
+
+ if (object->as<ArgumentsObject>()) {
Scope scope(object->engine());
Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
}
}
-void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAttributes *attrs)
+void ObjectIterator::next(String *&name, uint *index, Property *pd, PropertyAttributes *attrs)
{
name = (String *)0;
*index = UINT_MAX;
- if (!object) {
+ if (!object->asObject()) {
*attrs = PropertyAttributes();
return;
}
while (1) {
- if (!current)
+ if (!current->asObject())
break;
while (1) {
- current->advanceIterator(this, name, index, pd, attrs);
+ current->asObject()->advanceIterator(this, name, index, pd, attrs);
if (attrs->isEmpty())
break;
// check the property is not already defined earlier in the proto chain
- if (current != object) {
- Object *o = object;
+ if (current->asObject() != object->asObject()) {
+ Object *o = object->asObject();
bool shadowed = false;
- while (o != current) {
+ while (o != current->asObject()) {
if ((!!name && o->hasOwnProperty(name)) ||
(*index != UINT_MAX && o->hasOwnProperty(*index))) {
shadowed = true;
@@ -117,9 +125,9 @@ void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAtt
}
if (flags & WithProtoChain)
- current = current->prototype();
+ current->o = current->objectValue()->prototype();
else
- current = (Object *)0;
+ current->o = (Object *)0;
arrayIndex = 0;
memberIndex = 0;
@@ -129,7 +137,7 @@ void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAtt
ReturnedValue ObjectIterator::nextPropertyName(ValueRef value)
{
- if (!object)
+ if (!object->asObject())
return Encode::null();
PropertyAttributes attrs;
@@ -137,11 +145,13 @@ ReturnedValue ObjectIterator::nextPropertyName(ValueRef value)
uint index;
Scope scope(object->engine());
ScopedString name(scope);
- next(name, &index, &p, &attrs);
+ String *n;
+ next(n, &index, &p, &attrs);
+ name = n;
if (attrs.isEmpty())
return Encode::null();
- value = object->getValue(&p, attrs);
+ value = object->objectValue()->getValue(&p, attrs);
if (!!name)
return name->asReturnedValue();
@@ -151,7 +161,7 @@ ReturnedValue ObjectIterator::nextPropertyName(ValueRef value)
ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value)
{
- if (!object)
+ if (!object->asObject())
return Encode::null();
PropertyAttributes attrs;
@@ -159,11 +169,13 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value)
uint index;
Scope scope(object->engine());
ScopedString name(scope);
- next(name, &index, &p, &attrs);
+ String *n;
+ next(n, &index, &p, &attrs);
+ name = n;
if (attrs.isEmpty())
return Encode::null();
- value = object->getValue(&p, attrs);
+ value = object->objectValue()->getValue(&p, attrs);
if (!!name)
return name->asReturnedValue();
@@ -173,7 +185,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value)
ReturnedValue ObjectIterator::nextPropertyNameAsString()
{
- if (!object)
+ if (!object->asObject())
return Encode::null();
PropertyAttributes attrs;
@@ -181,7 +193,9 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
uint index;
Scope scope(object->engine());
ScopedString name(scope);
- next(name, &index, &p, &attrs);
+ String *n;
+ next(n, &index, &p, &attrs);
+ name = n;
if (attrs.isEmpty())
return Encode::null();
@@ -197,7 +211,7 @@ DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
void ForEachIteratorObject::markObjects(Managed *that, ExecutionEngine *e)
{
ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that);
- o->workArea[0].mark(e);
- o->workArea[1].mark(e);
+ o->d()->workArea[0].mark(e);
+ o->d()->workArea[1].mark(e);
Object::markObjects(that, e);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index c87f284288..f20ad17b4a 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -67,37 +67,38 @@ struct Q_QML_EXPORT ObjectIterator
WithProtoChain = 0x2,
};
- ObjectRef object;
- ObjectRef current;
+ Value *object;
+ Value *current;
SparseArrayNode *arrayNode;
uint arrayIndex;
uint memberIndex;
uint flags;
- ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags);
- ObjectIterator(Scope &scope, const ObjectRef o, uint flags);
- void next(StringRef name, uint *index, Property *pd, PropertyAttributes *attributes = 0);
+ ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint flags);
+ ObjectIterator(Scope &scope, Object *o, uint flags);
+ void next(String *&name, uint *index, Property *pd, PropertyAttributes *attributes = 0);
ReturnedValue nextPropertyName(ValueRef value);
ReturnedValue nextPropertyNameAsString(ValueRef value);
ReturnedValue nextPropertyNameAsString();
};
struct ForEachIteratorObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionContext *ctx, Object *o)
+ : Object::Data(ctx->engine())
+ , it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
+ setVTable(staticVTable());
+ }
+ ObjectIterator it;
+ Value workArea[2];
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(ForeachIteratorObject)
- ObjectIterator it;
- ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
- : Object(ctx->engine), it(workArea, workArea + 1,
- o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
- setVTable(staticVTable());
- }
- ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); }
+ ReturnedValue nextPropertyName() { return d()->it.nextPropertyNameAsString(); }
protected:
static void markObjects(Managed *that, ExecutionEngine *e);
-
- Value workArea[2];
};
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 5c824bdfbd..6b8a19c7e6 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -74,8 +74,8 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ObjectCtor);
-ObjectCtor::ObjectCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("Object"))
+ObjectCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("Object"))
{
setVTable(staticVTable());
}
@@ -102,7 +102,7 @@ ReturnedValue ObjectCtor::call(Managed *m, CallData *callData)
return RuntimeHelpers::toObject(m->engine()->currentContext(), ValueRef(&callData->args[0]));
}
-void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
+void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
{
Scope scope(v4);
ScopedObject o(scope, this);
@@ -133,10 +133,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2);
defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2);
- Scoped<String> id_proto(scope, v4->id___proto__);
- Property p(v4->newBuiltinFunction(v4->rootContext, id_proto, method_get_proto)->getPointer(),
- v4->newBuiltinFunction(v4->rootContext, id_proto, method_set_proto)->getPointer());
- insertMember(StringRef(v4->id___proto__), p, Attr_Accessor|Attr_NotEnumerable);
+ Property p(ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, v4->id___proto__, method_get_proto)).getPointer(),
+ ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, v4->id___proto__, method_set_proto)).getPointer());
+ insertMember(v4->id___proto__, p, Attr_Accessor|Attr_NotEnumerable);
}
ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx)
@@ -165,7 +164,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
if (scope.hasException())
return Encode::undefined();
PropertyAttributes attrs;
- Property *desc = O->__getOwnProperty__(name, &attrs);
+ Property *desc = O->__getOwnProperty__(name.getPointer(), &attrs);
return fromPropertyDescriptor(ctx, desc, attrs);
}
@@ -176,7 +175,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context)
if (!O)
return context->throwTypeError();
- ScopedArrayObject array(scope, getOwnPropertyNames(context->engine, context->callData->args[0]));
+ ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->d()->callData->args[0]));
return array.asReturnedValue();
}
@@ -187,11 +186,11 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx)
if (!O->isObject() && !O->isNull())
return ctx->throwTypeError();
- Scoped<Object> newObject(scope, ctx->engine->newObject());
+ Scoped<Object> newObject(scope, ctx->d()->engine->newObject());
newObject->setPrototype(O->asObject());
- if (ctx->callData->argc > 1 && !ctx->callData->args[1].isUndefined()) {
- ctx->callData->args[0] = newObject.asReturnedValue();
+ if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isUndefined()) {
+ ctx->d()->callData->args[0] = newObject.asReturnedValue();
return method_defineProperties(ctx);
}
@@ -216,7 +215,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx)
if (scope.engine->hasException)
return Encode::undefined();
- if (!O->__defineOwnProperty__(ctx, name, pd, attrs))
+ if (!O->__defineOwnProperty__(ctx, name.getPointer(), pd, attrs))
return ctx->throwTypeError();
return O.asReturnedValue();
@@ -240,7 +239,9 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
uint index;
PropertyAttributes attrs;
Property pd;
- it.next(name, &index, &pd, &attrs);
+ String *nm;
+ it.next(nm, &index, &pd, &attrs);
+ name = nm;
if (attrs.isEmpty())
break;
Property n;
@@ -251,7 +252,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
return Encode::undefined();
bool ok;
if (name)
- ok = O->__defineOwnProperty__(ctx, name, n, nattrs);
+ ok = O->__defineOwnProperty__(ctx, name.getPointer(), n, nattrs);
else
ok = O->__defineOwnProperty__(ctx, index, n, nattrs);
if (!ok)
@@ -268,15 +269,15 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- o->extensible = false;
+ o->setExtensible(false);
- o->internalClass = o->internalClass->sealed();
+ o->setInternalClass(o->internalClass()->sealed());
- if (o->arrayData) {
+ if (o->arrayData()) {
ArrayData::ensureAttributes(o.getPointer());
- for (uint i = 0; i < o->arrayData->alloc; ++i) {
- if (!o->arrayData->isEmpty(i))
- o->arrayData->attrs[i].setConfigurable(false);
+ for (uint i = 0; i < o->arrayData()->alloc(); ++i) {
+ if (!o->arrayData()->isEmpty(i))
+ o->arrayData()->attrs()[i].setConfigurable(false);
}
}
@@ -293,17 +294,17 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
if (ArgumentsObject::isNonStrictArgumentsObject(o.getPointer()))
Scoped<ArgumentsObject>(scope, o)->fullyCreate();
- o->extensible = false;
+ o->setExtensible(false);
- o->internalClass = o->internalClass->frozen();
+ o->setInternalClass(o->internalClass()->frozen());
- if (o->arrayData) {
+ if (o->arrayData()) {
ArrayData::ensureAttributes(o.getPointer());
- for (uint i = 0; i < o->arrayData->alloc; ++i) {
- if (!o->arrayData->isEmpty(i))
- o->arrayData->attrs[i].setConfigurable(false);
- if (o->arrayData->attrs[i].isData())
- o->arrayData->attrs[i].setWritable(false);
+ for (uint i = 0; i < o->arrayData()->alloc(); ++i) {
+ if (!o->arrayData()->isEmpty(i))
+ o->arrayData()->attrs()[i].setConfigurable(false);
+ if (o->arrayData()->attrs()[i].isData())
+ o->arrayData()->attrs()[i].setWritable(false);
}
}
return o.asReturnedValue();
@@ -316,7 +317,7 @@ ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- o->extensible = false;
+ o->setExtensible(false);
return o.asReturnedValue();
}
@@ -327,22 +328,22 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- if (o->extensible)
+ if (o->isExtensible())
return Encode(false);
- if (o->internalClass != o->internalClass->sealed())
+ if (o->internalClass() != o->internalClass()->sealed())
return Encode(false);
- if (!o->arrayData || !o->arrayData->length())
+ if (!o->arrayData() || !o->arrayData()->length())
return Encode(true);
- if (o->arrayData->length() && !o->arrayData->attrs)
+ if (o->arrayData()->length() && !o->arrayData()->attrs())
return Encode(false);
- for (uint i = 0; i < o->arrayData->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->alloc(); ++i) {
// ### Fix for sparse arrays
- if (!o->arrayData->isEmpty(i))
- if (o->arrayData->attributes(i).isConfigurable())
+ if (!o->arrayData()->isEmpty(i))
+ if (o->arrayData()->attributes(i).isConfigurable())
return Encode(false);
}
@@ -356,22 +357,22 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- if (o->extensible)
+ if (o->isExtensible())
return Encode(false);
- if (o->internalClass != o->internalClass->frozen())
+ if (o->internalClass() != o->internalClass()->frozen())
return Encode(false);
- if (!o->arrayData->length())
+ if (!o->arrayData()->length())
return Encode(true);
- if (o->arrayData->length() && !o->arrayData->attrs)
+ if (o->arrayData()->length() && !o->arrayData()->attrs())
return Encode(false);
- for (uint i = 0; i < o->arrayData->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->alloc(); ++i) {
// ### Fix for sparse arrays
- if (!o->arrayData->isEmpty(i))
- if (o->arrayData->attributes(i).isConfigurable() || o->arrayData->attributes(i).isWritable())
+ if (!o->arrayData()->isEmpty(i))
+ if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
return Encode(false);
}
@@ -385,7 +386,7 @@ ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- return Encode((bool)o->extensible);
+ return Encode((bool)o->isExtensible());
}
ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
@@ -395,7 +396,7 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
- Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject());
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
ScopedValue name(scope);
@@ -412,24 +413,24 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
ReturnedValue ObjectPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
- if (ctx->callData->thisObject.isUndefined()) {
- return ctx->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue();
- } else if (ctx->callData->thisObject.isNull()) {
- return ctx->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue();
+ if (ctx->d()->callData->thisObject.isUndefined()) {
+ return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue();
+ } else if (ctx->d()->callData->thisObject.isNull()) {
+ return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue();
} else {
- ScopedObject obj(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->callData->thisObject)));
+ ScopedObject obj(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->d()->callData->thisObject)));
QString className = obj->className();
- return ctx->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue();
+ return ctx->d()->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue();
}
}
ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx));
+ ScopedObject o(scope, ctx->d()->callData->thisObject.toObject(ctx));
if (!o)
return Encode::undefined();
- Scoped<FunctionObject> f(scope, o->get(ctx->engine->id_toString));
+ Scoped<FunctionObject> f(scope, o->get(ctx->d()->engine->id_toString));
if (!f)
return ctx->throwTypeError();
ScopedCallData callData(scope, 0);
@@ -440,8 +441,8 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
{
Scope scope(ctx);
- ScopedValue v(scope, ctx->callData->thisObject.toObject(ctx));
- if (ctx->engine->hasException)
+ ScopedValue v(scope, ctx->d()->callData->thisObject.toObject(ctx));
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
return v.asReturnedValue();
}
@@ -452,12 +453,12 @@ ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx)
Scoped<String> P(scope, ctx->argument(0), Scoped<String>::Convert);
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ Scoped<Object> O(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert);
if (scope.engine->hasException)
return Encode::undefined();
- bool r = O->hasOwnProperty(P);
+ bool r = O->hasOwnProperty(P.getPointer());
if (!r)
- r = !O->query(P).isEmpty();
+ r = !O->query(P.getPointer()).isEmpty();
return Encode(r);
}
@@ -468,7 +469,7 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx)
if (!V)
return Encode(false);
- Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ Scoped<Object> O(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert);
if (scope.engine->hasException)
return Encode::undefined();
Scoped<Object> proto(scope, V->prototype());
@@ -487,17 +488,17 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx)
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<Object> o(scope, ctx->callData->thisObject, Scoped<Object>::Convert);
+ Scoped<Object> o(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert);
if (scope.engine->hasException)
return Encode::undefined();
PropertyAttributes attrs;
- o->__getOwnProperty__(p, &attrs);
+ o->__getOwnProperty__(p.getPointer(), &attrs);
return Encode(attrs.isEnumerable());
}
ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx)
{
- if (ctx->callData->argc < 2)
+ if (ctx->d()->callData->argc < 2)
return ctx->throwTypeError();
Scope scope(ctx);
@@ -509,23 +510,23 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx)
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<Object> o(scope, ctx->callData->thisObject);
+ Scoped<Object> o(scope, ctx->d()->callData->thisObject);
if (!o) {
- if (!ctx->callData->thisObject.isUndefined())
+ if (!ctx->d()->callData->thisObject.isUndefined())
return Encode::undefined();
- o = ctx->engine->globalObject;
+ o = ctx->d()->engine->globalObject;
}
Property pd;
pd.value = f;
pd.set = Primitive::emptyValue();
- o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
+ o->__defineOwnProperty__(ctx, prop.getPointer(), pd, Attr_Accessor);
return Encode::undefined();
}
ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx)
{
- if (ctx->callData->argc < 2)
+ if (ctx->d()->callData->argc < 2)
return ctx->throwTypeError();
Scope scope(ctx);
@@ -537,24 +538,24 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx)
if (scope.engine->hasException)
return Encode::undefined();
- Scoped<Object> o(scope, ctx->callData->thisObject);
+ Scoped<Object> o(scope, ctx->d()->callData->thisObject);
if (!o) {
- if (!ctx->callData->thisObject.isUndefined())
+ if (!ctx->d()->callData->thisObject.isUndefined())
return Encode::undefined();
- o = ctx->engine->globalObject;
+ o = ctx->d()->engine->globalObject;
}
Property pd;
pd.value = Primitive::emptyValue();
pd.set = f;
- o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
+ o->__defineOwnProperty__(ctx, prop.getPointer(), pd, Attr_Accessor);
return Encode::undefined();
}
ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx)
{
Scope scope(ctx);
- ScopedObject o(scope, ctx->callData->thisObject.asObject());
+ ScopedObject o(scope, ctx->d()->callData->thisObject.asObject());
if (!o)
return ctx->throwTypeError();
@@ -564,21 +565,21 @@ ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx)
ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Object> o(scope, ctx->callData->thisObject);
- if (!o || !ctx->callData->argc)
+ Scoped<Object> o(scope, ctx->d()->callData->thisObject);
+ if (!o || !ctx->d()->callData->argc)
return ctx->throwTypeError();
- if (ctx->callData->args[0].isNull()) {
+ if (ctx->d()->callData->args[0].isNull()) {
o->setPrototype(0);
return Encode::undefined();
}
- Scoped<Object> p(scope, ctx->callData->args[0]);
+ Scoped<Object> p(scope, ctx->d()->callData->args[0]);
bool ok = false;
if (!!p) {
if (o->prototype() == p.getPointer()) {
ok = true;
- } else if (o->extensible) {
+ } else if (o->isExtensible()) {
ok = o->setPrototype(p.getPointer());
}
}
@@ -601,14 +602,14 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
desc->set = Primitive::emptyValue();
ScopedValue tmp(scope);
- if (o->hasProperty(ctx->engine->id_enumerable))
- attrs->setEnumerable((tmp = o->get(ctx->engine->id_enumerable))->toBoolean());
+ if (o->hasProperty(ctx->d()->engine->id_enumerable))
+ attrs->setEnumerable((tmp = o->get(ctx->d()->engine->id_enumerable))->toBoolean());
- if (o->hasProperty(ctx->engine->id_configurable))
- attrs->setConfigurable((tmp = o->get(ctx->engine->id_configurable))->toBoolean());
+ if (o->hasProperty(ctx->d()->engine->id_configurable))
+ attrs->setConfigurable((tmp = o->get(ctx->d()->engine->id_configurable))->toBoolean());
- if (o->hasProperty(ctx->engine->id_get)) {
- ScopedValue get(scope, o->get(ctx->engine->id_get));
+ if (o->hasProperty(ctx->d()->engine->id_get)) {
+ ScopedValue get(scope, o->get(ctx->d()->engine->id_get));
FunctionObject *f = get->asFunctionObject();
if (f || get->isUndefined()) {
desc->value = get;
@@ -619,8 +620,8 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
attrs->setType(PropertyAttributes::Accessor);
}
- if (o->hasProperty(ctx->engine->id_set)) {
- ScopedValue set(scope, o->get(ctx->engine->id_set));
+ if (o->hasProperty(ctx->d()->engine->id_set)) {
+ ScopedValue set(scope, o->get(ctx->d()->engine->id_set));
FunctionObject *f = set->asFunctionObject();
if (f || set->isUndefined()) {
desc->set = set;
@@ -631,22 +632,22 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef
attrs->setType(PropertyAttributes::Accessor);
}
- if (o->hasProperty(ctx->engine->id_writable)) {
+ if (o->hasProperty(ctx->d()->engine->id_writable)) {
if (attrs->isAccessor()) {
ctx->throwTypeError();
return;
}
- attrs->setWritable((tmp = o->get(ctx->engine->id_writable))->toBoolean());
+ attrs->setWritable((tmp = o->get(ctx->d()->engine->id_writable))->toBoolean());
// writable forces it to be a data descriptor
desc->value = Primitive::undefinedValue();
}
- if (o->hasProperty(ctx->engine->id_value)) {
+ if (o->hasProperty(ctx->d()->engine->id_value)) {
if (attrs->isAccessor()) {
ctx->throwTypeError();
return;
}
- desc->value = o->get(ctx->engine->id_value);
+ desc->value = o->get(ctx->d()->engine->id_value);
attrs->setType(PropertyAttributes::Data);
}
@@ -660,7 +661,7 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, con
if (!desc)
return Encode::undefined();
- ExecutionEngine *engine = ctx->engine;
+ ExecutionEngine *engine = ctx->d()->engine;
Scope scope(engine);
// Let obj be the result of creating a new object as if by the expression new Object() where Object
// is the standard built-in constructor with that name.
@@ -671,24 +672,24 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, con
if (attrs.isData()) {
pd.value = desc->value;
s = engine->newString(QStringLiteral("value"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
pd.value = Primitive::fromBoolean(attrs.isWritable());
s = engine->newString(QStringLiteral("writable"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
} else {
pd.value = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
s = engine->newString(QStringLiteral("get"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
pd.value = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
s = engine->newString(QStringLiteral("set"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
}
pd.value = Primitive::fromBoolean(attrs.isEnumerable());
s = engine->newString(QStringLiteral("enumerable"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
pd.value = Primitive::fromBoolean(attrs.isConfigurable());
s = engine->newString(QStringLiteral("configurable"));
- o->__defineOwnProperty__(ctx, s, pd, Attr_Data);
+ o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data);
return o.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 2b9974be06..c34b367223 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -51,8 +51,10 @@ namespace QV4 {
struct ObjectCtor: FunctionObject
{
- V4_OBJECT
- ObjectCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *that, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -60,9 +62,7 @@ struct ObjectCtor: FunctionObject
struct ObjectPrototype: Object
{
- ObjectPrototype(InternalClass *ic) : Object(ic) {}
-
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_getPrototypeOf(CallContext *ctx);
static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index 21f37f3d96..7b0f80e06a 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -84,13 +84,11 @@ public:
PersistentValue(ReturnedValue val);
template<typename T>
PersistentValue(Returned<T> *obj);
- PersistentValue(const ManagedRef obj);
PersistentValue &operator=(const ValueRef other);
PersistentValue &operator=(const ScopedValue &other);
PersistentValue &operator =(ReturnedValue other);
template<typename T>
PersistentValue &operator=(Returned<T> *obj);
- PersistentValue &operator=(const ManagedRef obj);
~PersistentValue();
ReturnedValue value() const {
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 8a0cc56448..b70e9de1a0 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qv4profiling_p.h"
+#include "qv4mm_p.h"
QT_BEGIN_NAMESPACE
@@ -60,10 +61,12 @@ FunctionCallProperties FunctionCall::resolve() const
}
-Profiler::Profiler() : enabled(false)
+Profiler::Profiler(QV4::ExecutionEngine *engine) : enabled(false), m_engine(engine)
{
static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >();
+ static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >();
Q_UNUSED(metatype);
+ Q_UNUSED(metatype2);
m_timer.start();
}
@@ -87,13 +90,29 @@ void Profiler::reportData()
FunctionCallProperties props = call.resolve();
resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props);
}
- emit dataReady(resolved);
+ emit dataReady(resolved, m_memory_data);
}
void Profiler::startProfiling()
{
if (!enabled) {
m_data.clear();
+ m_memory_data.clear();
+
+ qint64 timestamp = m_timer.nsecsElapsed();
+ MemoryAllocationProperties heap = {timestamp,
+ (qint64)m_engine->memoryManager->getAllocatedMem(),
+ HeapPage};
+ m_memory_data.append(heap);
+ MemoryAllocationProperties small = {timestamp,
+ (qint64)m_engine->memoryManager->getUsedMem(),
+ SmallItem};
+ m_memory_data.append(small);
+ MemoryAllocationProperties large = {timestamp,
+ (qint64)m_engine->memoryManager->getLargeItemsMem(),
+ LargeItem};
+ m_memory_data.append(large);
+
enabled = true;
}
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 6869b3134d..b9ddac0309 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -54,6 +54,12 @@ namespace QV4 {
namespace Profiling {
+enum MemoryType {
+ HeapPage,
+ LargeItem,
+ SmallItem
+};
+
struct FunctionCallProperties {
qint64 start;
qint64 end;
@@ -63,6 +69,12 @@ struct FunctionCallProperties {
int column;
};
+struct MemoryAllocationProperties {
+ qint64 timestamp;
+ qint64 size;
+ MemoryType type;
+};
+
class FunctionCall {
public:
@@ -101,6 +113,14 @@ private:
qint64 m_end;
};
+#define Q_V4_PROFILE_ALLOC(engine, size, type)\
+ (engine->profiler && engine->profiler->enabled ?\
+ engine->profiler->trackAlloc(size, type) : size)
+
+#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \
+ (engine->profiler && engine->profiler->enabled ?\
+ engine->profiler->trackDealloc(pointer, size, type) : pointer)
+
#define Q_V4_PROFILE(engine, ctx, function)\
((engine->profiler && engine->profiler->enabled) ?\
Profiling::FunctionCallProfiler::profileCall(engine->profiler, ctx, function) :\
@@ -110,7 +130,21 @@ class Q_QML_EXPORT Profiler : public QObject {
Q_OBJECT
Q_DISABLE_COPY(Profiler)
public:
- Profiler();
+ Profiler(QV4::ExecutionEngine *engine);
+
+ size_t trackAlloc(size_t size, MemoryType type)
+ {
+ MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type};
+ m_memory_data.append(allocation);
+ return size;
+ }
+
+ void *trackDealloc(void *pointer, size_t size, MemoryType type)
+ {
+ MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type};
+ m_memory_data.append(allocation);
+ return pointer;
+ }
bool enabled;
@@ -121,11 +155,14 @@ public slots:
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
- void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &);
+ void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &,
+ const QList<QV4::Profiling::MemoryAllocationProperties> &);
private:
+ QV4::ExecutionEngine *m_engine;
QElapsedTimer m_timer;
QVector<FunctionCall> m_data;
+ QList<MemoryAllocationProperties> m_memory_data;
friend class FunctionCallProfiler;
};
@@ -160,10 +197,12 @@ public:
} // namespace Profiling
} // namespace QV4
+Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QList<QV4::Profiling::FunctionCallProperties>)
+Q_DECLARE_METATYPE(QList<QV4::Profiling::MemoryAllocationProperties>)
#endif // QV4PROFILING_H
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index d64f821a38..e12b8f1756 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -87,7 +87,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-static QPair<QObject *, int> extractQtMethod(QV4::FunctionObjectRef function)
+static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function)
{
QV4::ExecutionEngine *v4 = function->engine();
if (v4) {
@@ -239,14 +239,11 @@ static QV4::ReturnedValue LoadProperty(QV8Engine *engine, QObject *object,
}
}
-QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
- : Object(engine)
- , m_object(object)
+QObjectWrapper::Data::Data(ExecutionEngine *engine, QObject *object)
+ : Object::Data(engine)
+ , object(object)
{
setVTable(staticVTable());
-
- Scope scope(engine);
- ScopedObject protectThis(scope, this);
}
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
@@ -259,21 +256,21 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont
{
Q_UNUSED(revisionMode);
- QQmlData *ddata = QQmlData::get(m_object, false);
+ QQmlData *ddata = QQmlData::get(d()->object, false);
if (!ddata)
return 0;
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name, m_object, qmlContext);
+ result = ddata->propertyCache->property(name, d()->object, qmlContext);
else
- result = QQmlPropertyCache::property(engine->v8Engine->engine(), m_object, name, qmlContext, *local);
+ result = QQmlPropertyCache::property(engine->v8Engine->engine(), d()->object, name, qmlContext, *local);
return result;
}
ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports)
{
- if (QQmlData::wasDeleted(m_object)) {
+ if (QQmlData::wasDeleted(d()->object)) {
if (hasProperty)
*hasProperty = false;
return QV4::Encode::undefined();
@@ -284,14 +281,14 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (name->equals(scope.engine->id_destroy) || name->equals(scope.engine->id_toString)) {
int index = name->equals(scope.engine->id_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
- QV4::ScopedValue method(scope, QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, index));
+ QV4::ScopedValue method(scope, QV4::QObjectMethod::create(ctx->d()->engine->rootContext, d()->object, index));
if (hasProperty)
*hasProperty = true;
return method.asReturnedValue();
}
QQmlPropertyData local;
- QQmlPropertyData *result = findProperty(ctx->engine, qmlContext, name.getPointer(), revisionMode, &local);
+ QQmlPropertyData *result = findProperty(ctx->d()->engine, qmlContext, name.getPointer(), revisionMode, &local);
if (!result) {
if (includeImports && name->startsWithUpper()) {
@@ -306,18 +303,18 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (r.scriptIndex != -1) {
return QV4::Encode::undefined();
} else if (r.type) {
- return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, r.type, QmlTypeWrapper::ExcludeEnums);
+ return QmlTypeWrapper::create(ctx->d()->engine->v8Engine, d()->object, r.type, QmlTypeWrapper::ExcludeEnums);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, qmlContext->imports, r.importNamespace, QmlTypeWrapper::ExcludeEnums);
+ return QmlTypeWrapper::create(ctx->d()->engine->v8Engine, d()->object, qmlContext->imports, r.importNamespace, QmlTypeWrapper::ExcludeEnums);
}
Q_ASSERT(!"Unreachable");
}
}
}
- return QV4::Object::get(this, name, hasProperty);
+ return QV4::Object::get(this, name.getPointer(), hasProperty);
}
- QQmlData *ddata = QQmlData::get(m_object, false);
+ QQmlData *ddata = QQmlData::get(d()->object, false);
if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
@@ -330,7 +327,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (hasProperty)
*hasProperty = true;
- return getProperty(m_object, ctx, result);
+ return getProperty(d()->object, ctx, result);
}
ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
@@ -345,23 +342,23 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex);
} else if (property->isV4Function()) {
- QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex, qmlcontextobject);
+ QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->d()->engine->qmlContextObject());
+ return QV4::QObjectMethod::create(ctx->d()->engine->rootContext, object, property->coreIndex, qmlcontextobject);
} else if (property->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, object, property->coreIndex));
+ QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(ctx->d()->engine, object, property->coreIndex));
- QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect")));
- QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect")));
- handler->put(connect, QV4::ScopedValue(scope, ctx->engine->functionClass->prototype->get(connect)));
- handler->put(disconnect, QV4::ScopedValue(scope, ctx->engine->functionClass->prototype->get(disconnect)));
+ QV4::ScopedString connect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("connect")));
+ QV4::ScopedString disconnect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("disconnect")));
+ handler->put(connect.getPointer(), QV4::ScopedValue(scope, ctx->d()->engine->functionClass->prototype->get(connect.getPointer())));
+ handler->put(disconnect.getPointer(), QV4::ScopedValue(scope, ctx->d()->engine->functionClass->prototype->get(disconnect.getPointer())));
return handler.asReturnedValue();
} else {
- return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex);
+ return QV4::QObjectMethod::create(ctx->d()->engine->rootContext, object, property->coreIndex);
}
}
- QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0;
+ QQmlEnginePrivate *ep = ctx->d()->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->d()->engine->v8Engine->engine()) : 0;
if (property->hasAccessors()) {
QQmlNotifier *n = 0;
@@ -370,7 +367,7 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx
if (ep && ep->propertyCapture && property->accessors->notifier)
nptr = &n;
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, object, *property, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->d()->engine->v8Engine, object, *property, nptr));
if (captureRequired) {
if (property->accessors->notifier) {
@@ -392,9 +389,9 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx
Q_ASSERT(vmemo);
return vmemo->vmeProperty(property->coreIndex);
} else if (property->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, object, *property, 0);
+ return LoadProperty<ReadAccessor::Direct>(ctx->d()->engine->v8Engine, object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, object, *property, 0);
+ return LoadProperty<ReadAccessor::Indirect>(ctx->d()->engine->v8Engine, object, *property, 0);
}
}
@@ -413,7 +410,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
return QV4::Encode::null();
}
- QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(ctx->engine, object));
+ QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(ctx->d()->engine, object));
if (!wrapper) {
if (hasProperty)
*hasProperty = false;
@@ -431,7 +428,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC
QQmlPropertyData local;
QQmlPropertyData *result = 0;
{
- result = QQmlPropertyCache::property(ctx->engine->v8Engine->engine(), object, name, qmlContext, local);
+ result = QQmlPropertyCache::property(ctx->d()->engine->v8Engine->engine(), object, name, qmlContext, local);
}
if (!result)
@@ -460,7 +457,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro
QV4::Scope scope(ctx);
QV4::ScopedFunctionObject f(scope, value);
if (f) {
- if (!f->bindingKeyFlag) {
+ if (!f->bindingKeyFlag()) {
if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) {
// assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ");
@@ -473,7 +470,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro
}
} else {
// binding assignment.
- QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
+ QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine);
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, f);
bindingFunction->initBindingLocation();
@@ -513,7 +510,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro
} else if (value->isUndefined() && property->propType == QMetaType::QJsonValue) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
} else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) {
- PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value));
+ PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->d()->engine, value));
} else if (value->isUndefined()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
if (!QMetaType::typeName(property->propType))
@@ -541,11 +538,11 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro
} else {
QVariant v;
if (property->isQList())
- v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ v = ctx->d()->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
else
- v = ctx->engine->v8Engine->toVariant(value, property->propType);
+ v = ctx->d()->engine->v8Engine->toVariant(value, property->propType);
- QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
+ QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine);
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
const char *valueType = 0;
if (v.userType() == QVariant::Invalid) valueType = "null";
@@ -634,9 +631,9 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx
void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value)
{
- if (QQmlData::wasDeleted(m_object))
+ if (QQmlData::wasDeleted(d()->object))
return;
- QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ QQmlData *ddata = QQmlData::get(d()->object, /*create*/false);
if (!ddata)
return;
@@ -644,7 +641,7 @@ void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const
Q_ASSERT(cache);
QQmlPropertyData *property = cache->property(propertyIndex);
Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return setProperty(m_object, ctx, property, value);
+ return setProperty(d()->object, ctx, property, value);
}
bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
@@ -661,28 +658,28 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
QQmlEngine *qmlEngine = engine->v8Engine->engine();
if (qmlEngine)
QQmlData::ensurePropertyCache(qmlEngine, object);
- return (new (engine->memoryManager) QV4::QObjectWrapper(engine, object))->asReturnedValue();
+ return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue();
}
-QV4::ReturnedValue QObjectWrapper::get(Managed *m, const StringRef name, bool *hasProperty)
+QV4::ReturnedValue QObjectWrapper::get(Managed *m, String *name, bool *hasProperty)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = m->engine();
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return that->getQmlProperty(v4->currentContext(), qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true);
+ return that->getQmlProperty(v4->currentContext(), qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
+void QObjectWrapper::put(Managed *m, String *name, const ValueRef value)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = m->engine();
- if (v4->hasException || QQmlData::wasDeleted(that->m_object))
+ if (v4->hasException || QQmlData::wasDeleted(that->d()->object))
return;
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
- QQmlData *ddata = QQmlData::get(that->m_object);
+ if (!setQmlProperty(v4->currentContext(), qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) {
+ QQmlData *ddata = QQmlData::get(that->d()->object);
// Types created by QML are not extensible at run-time, but for other QObjects we can store them
// as regular JavaScript properties, like on JavaScript objects.
if (ddata && ddata->context) {
@@ -695,7 +692,7 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
}
}
-PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name)
+PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
{
const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
ExecutionEngine *engine = that->engine();
@@ -708,27 +705,36 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name)
return QV4::Object::query(m, name);
}
-void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes)
+void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes)
{
+ // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
+ static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+ static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
+ static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+
name = (String *)0;
*index = UINT_MAX;
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
- if (that->m_object) {
- const QMetaObject *mo = that->m_object->metaObject();
+ if (that->d()->object) {
+ const QMetaObject *mo = that->d()->object->metaObject();
const int propertyCount = mo->propertyCount();
if (it->arrayIndex < static_cast<uint>(propertyCount)) {
- name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()));
+ name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))->getPointer();
++it->arrayIndex;
*attributes = QV4::Attr_Data;
p->value = that->get(name);
return;
}
const int methodCount = mo->methodCount();
- if (it->arrayIndex < static_cast<uint>(propertyCount + methodCount)) {
- name = that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name()));
+ while (it->arrayIndex < static_cast<uint>(propertyCount + methodCount)) {
+ const int index = it->arrayIndex - propertyCount;
+ const QMetaMethod method = mo->method(index);
++it->arrayIndex;
+ if (method.access() == QMetaMethod::Private || index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2)
+ continue;
+ name = that->engine()->newString(QString::fromUtf8(method.name()))->getPointer();
*attributes = QV4::Attr_Data;
p->value = that->get(name);
return;
@@ -857,10 +863,10 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
{
- if (ctx->callData->argc == 0)
+ if (ctx->d()->callData->argc == 0)
V4THROW_ERROR("Function.prototype.connect: no arguments given");
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject);
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->d()->callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second; // in method range, not signal range!
@@ -877,11 +883,11 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
QV4::ScopedFunctionObject f(scope);
QV4::ScopedValue thisObject (scope, QV4::Encode::undefined());
- if (ctx->callData->argc == 1) {
- f = ctx->callData->args[0];
- } else if (ctx->callData->argc >= 2) {
- thisObject = ctx->callData->args[0];
- f = ctx->callData->args[1];
+ if (ctx->d()->callData->argc == 1) {
+ f = ctx->d()->callData->args[0];
+ } else if (ctx->d()->callData->argc >= 2) {
+ thisObject = ctx->d()->callData->args[0];
+ f = ctx->d()->callData->args[1];
}
if (!f)
@@ -908,12 +914,12 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
{
- if (ctx->callData->argc == 0)
+ if (ctx->d()->callData->argc == 0)
V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
QV4::Scope scope(ctx);
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject);
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->d()->callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second;
@@ -929,11 +935,11 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
QV4::ScopedFunctionObject functionValue(scope);
QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined());
- if (ctx->callData->argc == 1) {
- functionValue = ctx->callData->args[0];
- } else if (ctx->callData->argc >= 2) {
- functionThisValue = ctx->callData->args[0];
- functionValue = ctx->callData->args[1];
+ if (ctx->d()->callData->argc == 1) {
+ functionValue = ctx->d()->callData->args[0];
+ } else if (ctx->d()->callData->argc >= 2) {
+ functionThisValue = ctx->d()->callData->args[0];
+ functionValue = ctx->d()->callData->args[1];
}
if (!functionValue)
@@ -945,7 +951,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
QPair<QObject *, int> functionData = extractQtMethod(functionValue);
void *a[] = {
- ctx->engine,
+ ctx->d()->engine,
functionValue.ptr,
functionThisValue.ptr,
functionData.first,
@@ -975,7 +981,7 @@ void QObjectWrapper::markObjects(Managed *that, QV4::ExecutionEngine *e)
{
QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
- if (QObject *o = This->m_object.data()) {
+ if (QObject *o = This->d()->object.data()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
vme->mark(e);
@@ -1017,9 +1023,9 @@ namespace {
void QObjectWrapper::destroy(Managed *that)
{
QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
- QPointer<QObject> object = This->m_object;
+ QPointer<QObject> object = This->d()->object;
ExecutionEngine *engine = This->engine();
- This->~QObjectWrapper();
+ This->d()->~Data();
This = 0;
if (!object)
return;
@@ -1728,7 +1734,7 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
} else if (type == -1 || type == qMetaTypeId<QVariant>()) {
QVariant value = *qvariantPtr;
QV4::ScopedValue rv(scope, engine->fromVariant(value));
- QV4::QObjectWrapperRef qobjectWrapper = rv;
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, rv);
if (!!qobjectWrapper) {
if (QObject *object = qobjectWrapper->object())
QQmlData::get(object, true)->setImplicitDestructible();
@@ -1741,28 +1747,28 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal)
{
- return (new (scope->engine->memoryManager) QObjectMethod(scope, object, index, qmlGlobal))->asReturnedValue();
+ return (scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope, object, index, qmlGlobal))->asReturnedValue();
}
-QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal)
- : FunctionObject(scope)
- , m_object(object)
- , m_index(index)
+QObjectMethod::Data::Data(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal)
+ : FunctionObject::Data(scope)
+ , object(object)
+ , index(index)
+ , qmlGlobal(qmlGlobal)
{
setVTable(staticVTable());
subtype = WrappedQtMethod;
- m_qmlGlobal = qmlGlobal;
}
QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx)
{
QString result;
- if (m_object) {
- QString objectName = m_object->objectName();
+ if (d()->object) {
+ QString objectName = d()->object->objectName();
- result += QString::fromUtf8(m_object->metaObject()->className());
+ result += QString::fromUtf8(d()->object->metaObject()->className());
result += QLatin1String("(0x");
- result += QString::number((quintptr)m_object.data(),16);
+ result += QString::number((quintptr)d()->object.data(),16);
if (!objectName.isEmpty()) {
result += QLatin1String(", \"");
@@ -1775,14 +1781,14 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx)
result = QLatin1String("null");
}
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const ValueRef args, int argc)
{
- if (!m_object)
+ if (!d()->object)
return Encode::undefined();
- if (QQmlData::keepAliveDuringGarbageCollection(m_object))
+ if (QQmlData::keepAliveDuringGarbageCollection(d()->object))
return ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
int delay = 0;
@@ -1790,9 +1796,9 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con
delay = args[0].toUInt32();
if (delay > 0)
- QTimer::singleShot(delay, m_object, SLOT(deleteLater()));
+ QTimer::singleShot(delay, d()->object, SLOT(deleteLater()));
else
- m_object->deleteLater();
+ d()->object->deleteLater();
return Encode::undefined();
}
@@ -1806,12 +1812,12 @@ ReturnedValue QObjectMethod::call(Managed *m, CallData *callData)
ReturnedValue QObjectMethod::callInternal(CallData *callData)
{
ExecutionContext *context = engine()->currentContext();
- if (m_index == DestroyMethod)
+ if (d()->index == DestroyMethod)
return method_destroy(context, callData->args, callData->argc);
- else if (m_index == ToStringMethod)
+ else if (d()->index == ToStringMethod)
return method_toString(context);
- QObject *object = m_object.data();
+ QObject *object = d()->object.data();
if (!object)
return Encode::undefined();
@@ -1819,7 +1825,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
if (!ddata)
return Encode::undefined();
- QV8Engine *v8Engine = context->engine->v8Engine;
+ QV8Engine *v8Engine = context->d()->engine->v8Engine;
QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8Engine);
QV4::Scope scope(v4);
@@ -1827,16 +1833,16 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) {
if (ddata->propertyCache) {
- QQmlPropertyData *d = ddata->propertyCache->method(m_index);
- if (!d)
+ QQmlPropertyData *data = ddata->propertyCache->method(d()->index);
+ if (!data)
return QV4::Encode::undefined();
- method = *d;
+ method = *data;
}
}
if (method.coreIndex == -1) {
const QMetaObject *mo = object->metaObject();
- const QMetaMethod moMethod = mo->method(m_index);
+ const QMetaMethod moMethod = mo->method(d()->index);
method.load(moMethod);
if (method.coreIndex == -1)
@@ -1845,7 +1851,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
// Look for overloaded methods
QByteArray methodName = moMethod.name();
const int methodOffset = mo->methodOffset();
- for (int ii = m_index - 1; ii >= methodOffset; --ii) {
+ for (int ii = d()->index - 1; ii >= methodOffset; --ii) {
if (methodName == mo->method(ii).name()) {
method.setFlags(method.getFlags() | QQmlPropertyData::IsOverload);
method.overrideIndexIsProperty = 0;
@@ -1858,7 +1864,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
if (method.isV4Function()) {
QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue());
- QV4::ScopedValue qmlGlobal(scope, m_qmlGlobal.value());
+ QV4::ScopedValue qmlGlobal(scope, d()->qmlGlobal.value());
QQmlV4Function func(callData, rv, qmlGlobal,
QmlContextWrapper::getContext(qmlGlobal),
v8Engine);
@@ -1879,10 +1885,10 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
DEFINE_OBJECT_VTABLE(QObjectMethod);
-QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex)
- : Object(engine)
- , m_object(object)
- , m_signalIndex(signalIndex)
+QmlSignalHandler::Data::Data(ExecutionEngine *engine, QObject *object, int signalIndex)
+ : Object::Data(engine)
+ , object(object)
+ , signalIndex(signalIndex)
{
setVTable(staticVTable());
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 0af01c5614..f60640c9fa 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -77,13 +77,17 @@ struct QObjectSlotDispatcher;
struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
{
- V4_OBJECT
+ struct Data : QV4::Object::Data {
+ Data(ExecutionEngine *engine, QObject *object);
+ QPointer<QObject> object;
+ };
+ V4_OBJECT(QV4::Object)
enum RevisionMode { IgnoreRevision, CheckRevision };
static void initializeBindings(ExecutionEngine *engine);
- QObject *object() const { return m_object.data(); }
+ QObject *object() const { return d()->object.data(); }
ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false);
static ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0);
@@ -106,16 +110,12 @@ private:
static ReturnedValue create(ExecutionEngine *engine, QObject *object);
- QObjectWrapper(ExecutionEngine *engine, QObject *object);
-
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
- QPointer<QObject> m_object;
-
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
- static PropertyAttributes query(const Managed *, StringRef name);
- static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const ValueRef value);
+ static PropertyAttributes query(const Managed *, String *name);
+ static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Managed *that, QV4::ExecutionEngine *e);
static void destroy(Managed *that);
@@ -123,53 +123,54 @@ private:
static ReturnedValue method_disconnect(CallContext *ctx);
};
-struct QObjectMethod : public QV4::FunctionObject
+struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
{
- V4_OBJECT
+ struct Data : QV4::FunctionObject::Data {
+ Data(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal);
+ QPointer<QObject> object;
+ int index;
+ QV4::PersistentValue qmlGlobal;
+ };
+ V4_OBJECT(QV4::FunctionObject)
enum { DestroyMethod = -1, ToStringMethod = -2 };
static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal = Primitive::undefinedValue());
- int methodIndex() const { return m_index; }
- QObject *object() const { return m_object.data(); }
-
-private:
- QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal);
+ int methodIndex() const { return d()->index; }
+ QObject *object() const { return d()->object.data(); }
QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx);
QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const ValueRef args, int argc);
- QPointer<QObject> m_object;
- int m_index;
- QV4::PersistentValue m_qmlGlobal;
-
static ReturnedValue call(Managed *, CallData *callData);
ReturnedValue callInternal(CallData *callData);
static void destroy(Managed *that)
{
- static_cast<QObjectMethod *>(that)->~QObjectMethod();
+ static_cast<QObjectMethod *>(that)->d()->~Data();
}
};
struct QmlSignalHandler : public QV4::Object
{
- V4_OBJECT
+ struct Data : QV4::Object::Data {
+ Data(ExecutionEngine *engine, QObject *object, int signalIndex);
+ QPointer<QObject> object;
+ int signalIndex;
+ };
+ V4_OBJECT(QV4::Object)
- QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex);
- int signalIndex() const { return m_signalIndex; }
- QObject *object() const { return m_object.data(); }
+ int signalIndex() const { return d()->signalIndex; }
+ QObject *object() const { return d()->object.data(); }
private:
- QPointer<QObject> m_object;
- int m_signalIndex;
static void destroy(Managed *that)
{
- static_cast<QmlSignalHandler *>(that)->~QmlSignalHandler();
+ static_cast<QmlSignalHandler *>(that)->d()->~Data();
}
};
@@ -195,8 +196,6 @@ private Q_SLOTS:
void removeDestroyedObject(QObject*);
};
-DEFINE_REF(QObjectWrapper, Object);
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index e5490cffd1..e2de584e31 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -42,6 +42,7 @@
#include "qv4regexp_p.h"
#include "qv4engine_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4mm_p.h"
using namespace QV4;
@@ -49,7 +50,7 @@ RegExpCache::~RegExpCache()
{
for (RegExpCache::Iterator it = begin(), e = end();
it != e; ++it)
- it.value()->m_cache = 0;
+ it.value()->d()->cache = 0;
clear();
}
@@ -63,11 +64,11 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
WTF::String s(string);
#if ENABLE(YARR_JIT)
- if (!m_jitCode.isFallBack() && m_jitCode.has16BitCode())
- return m_jitCode.execute(s.characters16(), start, s.length(), (int*)matchOffsets).start;
+ if (!jitCode().isFallBack() && jitCode().has16BitCode())
+ return jitCode().execute(s.characters16(), start, s.length(), (int*)matchOffsets).start;
#endif
- return JSC::Yarr::interpret(m_byteCode.get(), s.characters16(), string.length(), start, matchOffsets);
+ return JSC::Yarr::interpret(byteCode().get(), s.characters16(), string.length(), start, matchOffsets);
}
RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline)
@@ -80,53 +81,49 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign
return result;
}
- RegExp *result = new (engine->memoryManager) RegExp(engine, pattern, ignoreCase, multiline);
+ RegExp *result = engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline);
if (!cache)
cache = engine->regExpCache = new RegExpCache;
- result->m_cache = cache;
+ result->d()->cache = cache;
cache->insert(key, result);
return result;
}
-RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
- : Managed(engine->regExpValueClass)
- , m_pattern(pattern)
- , m_cache(0)
- , m_subPatternCount(0)
- , m_ignoreCase(ignoreCase)
- , m_multiLine(multiline)
+RegExp::Data::Data(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
+ : Managed::Data(engine->regExpValueClass)
+ , pattern(pattern)
+ , ignoreCase(ignoreCase)
+ , multiLine(multiline)
{
- if (!engine)
- return;
+ setVTable(staticVTable());
const char* error = 0;
JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error);
if (error)
return;
- m_subPatternCount = yarrPattern.m_numSubpatterns;
- m_byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator);
+ subPatternCount = yarrPattern.m_numSubpatterns;
+ byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator);
#if ENABLE(YARR_JIT)
if (!yarrPattern.m_containsBackreferences && engine->iselFactory->jitCompileRegexps()) {
JSC::JSGlobalData dummy(engine->regExpAllocator);
- JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, m_jitCode);
+ JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, jitCode);
}
#endif
}
-RegExp::~RegExp()
+RegExp::Data::~Data()
{
- if (m_cache) {
+ if (cache) {
RegExpCacheKey key(this);
- m_cache->remove(key);
+ cache->remove(key);
}
- _data = 0;
}
void RegExp::destroy(Managed *that)
{
- static_cast<RegExp*>(that)->~RegExp();
+ static_cast<RegExp*>(that)->d()->~Data();
}
void RegExp::markObjects(Managed *that, ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 1bcc2c6f5a..e1d3a9ef90 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -62,6 +62,50 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct ExecutionEngine;
+struct RegExpCacheKey;
+
+struct RegExp : public Managed
+{
+ struct Data : Managed::Data {
+ Data(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline);
+ ~Data();
+ QString pattern;
+ OwnPtr<JSC::Yarr::BytecodePattern> byteCode;
+#if ENABLE(YARR_JIT)
+ JSC::Yarr::YarrCodeBlock jitCode;
+#endif
+ RegExpCache *cache;
+ int subPatternCount;
+ bool ignoreCase;
+ bool multiLine;
+ };
+ V4_MANAGED(Managed)
+ Q_MANAGED_TYPE(RegExp)
+
+
+ QString pattern() const { return d()->pattern; }
+ OwnPtr<JSC::Yarr::BytecodePattern> &byteCode() { return d()->byteCode; }
+#if ENABLE(YARR_JIT)
+ JSC::Yarr::YarrCodeBlock jitCode() const { return d()->jitCode; }
+#endif
+ RegExpCache *cache() const { return d()->cache; }
+ int subPatternCount() const { return d()->subPatternCount; }
+ bool ignoreCase() const { return d()->ignoreCase; }
+ bool multiLine() const { return d()->multiLine; }
+
+ static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false);
+
+ bool isValid() const { return d()->byteCode.get(); }
+
+ uint match(const QString& string, int start, uint *matchOffsets);
+
+ int captureCount() const { return subPatternCount() + 1; }
+
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that, QV4::ExecutionEngine *e);
+
+ friend class RegExpCache;
+};
struct RegExpCacheKey
{
@@ -70,7 +114,7 @@ struct RegExpCacheKey
, ignoreCase(ignoreCase)
, multiLine(multiLine)
{ }
- explicit inline RegExpCacheKey(const RegExp *re);
+ explicit inline RegExpCacheKey(const RegExp::Data *re);
bool operator==(const RegExpCacheKey &other) const
{ return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine; }
@@ -82,6 +126,12 @@ struct RegExpCacheKey
uint multiLine : 1;
};
+inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re)
+ : pattern(re->pattern)
+ , ignoreCase(re->ignoreCase)
+ , multiLine(re->multiLine)
+{}
+
inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW
{ return qHash(key.pattern, seed); }
@@ -91,49 +141,6 @@ public:
~RegExpCache();
};
-class RegExp : public Managed
-{
- V4_MANAGED
- Q_MANAGED_TYPE(RegExp)
-public:
- static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false);
- ~RegExp();
-
- QString pattern() const { return m_pattern; }
-
- bool isValid() const { return m_byteCode.get(); }
-
- uint match(const QString& string, int start, uint *matchOffsets);
-
- bool ignoreCase() const { return m_ignoreCase; }
- bool multiLine() const { return m_multiLine; }
- int captureCount() const { return m_subPatternCount + 1; }
-
-protected:
- static void destroy(Managed *that);
- static void markObjects(Managed *that, QV4::ExecutionEngine *e);
-
-private:
- friend class RegExpCache;
- Q_DISABLE_COPY(RegExp);
- RegExp(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline);
-
- const QString m_pattern;
- OwnPtr<JSC::Yarr::BytecodePattern> m_byteCode;
-#if ENABLE(YARR_JIT)
- JSC::Yarr::YarrCodeBlock m_jitCode;
-#endif
- RegExpCache *m_cache;
- int m_subPatternCount;
- const bool m_ignoreCase;
- const bool m_multiLine;
-};
-
-inline RegExpCacheKey::RegExpCacheKey(const RegExp *re)
- : pattern(re->pattern())
- , ignoreCase(re->ignoreCase())
- , multiLine(re->multiLine())
-{}
}
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 956d1c594e..6a592ee792 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -70,32 +70,43 @@ Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyn
using namespace QV4;
DEFINE_OBJECT_VTABLE(RegExpObject);
+DEFINE_OBJECT_VTABLE(RegExpPrototype);
-RegExpObject::RegExpObject(InternalClass *ic)
- : Object(ic)
- , value(RegExp::create(ic->engine, QString(), false, false))
- , global(false)
+RegExpObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
- Q_ASSERT(internalClass->vtable == staticVTable());
- init(ic->engine);
+ setVTable(staticVTable());
+
+ Scope scope(ic->engine);
+ Scoped<RegExpObject> o(scope, this);
+ o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(ic->engine, QString(), false, false));
+ o->d()->global = false;
+ o->init(ic->engine);
}
-RegExpObject::RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global)
- : Object(engine->regExpClass)
+RegExpObject::Data::Data(ExecutionEngine *engine, RegExp *value, bool global)
+ : Object::Data(engine->regExpClass)
, value(value)
, global(global)
{
- init(engine);
+ setVTable(staticVTable());
+
+ Scope scope(engine);
+ Scoped<RegExpObject> o(scope, this);
+ o->init(engine);
}
// Converts a QRegExp to a JS RegExp.
// The conversion is not 100% exact since ECMA regexp and QRegExp
// have different semantics/flags, but we try to do our best.
-RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
- : Object(engine->regExpClass)
- , value(0)
- , global(false)
+RegExpObject::Data::Data(ExecutionEngine *engine, const QRegExp &re)
+ : Object::Data(engine->regExpClass)
{
+ setVTable(staticVTable());
+
+ value = 0;
+ global = false;
+
// Convert the pattern to a ECMAScript pattern.
QString pattern = QT_PREPEND_NAMESPACE(qt_regexp_toCanonical)(re.pattern(), re.patternSyntax());
if (re.isMinimal()) {
@@ -134,27 +145,25 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
}
Scope scope(engine);
- ScopedObject protectThis(scope, this);
+ Scoped<RegExpObject> o(scope, this);
- value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
+ o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false));
- init(engine);
+ o->init(engine);
}
void RegExpObject::init(ExecutionEngine *engine)
{
- setVTable(staticVTable());
-
Scope scope(engine);
ScopedObject protectThis(scope, this);
ScopedString lastIndex(scope, engine->newIdentifier(QStringLiteral("lastIndex")));
ScopedValue v(scope, Primitive::fromInt32(0));
- insertMember(lastIndex, v, Attr_NotEnumerable|Attr_NotConfigurable);
- if (!this->value)
+ insertMember(lastIndex.getPointer(), v, Attr_NotEnumerable|Attr_NotConfigurable);
+ if (!this->value())
return;
- QString p = this->value->pattern();
+ QString p = this->value()->pattern();
if (p.isEmpty()) {
p = QStringLiteral("(?:)");
} else {
@@ -163,29 +172,24 @@ void RegExpObject::init(ExecutionEngine *engine)
}
defineReadonlyProperty(QStringLiteral("source"), (v = engine->newString(p)));
- defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global));
- defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value->ignoreCase()));
- defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value->multiLine()));
+ defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global()));
+ defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value()->ignoreCase()));
+ defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value()->multiLine()));
}
-void RegExpObject::destroy(Managed *that)
-{
- static_cast<RegExpObject *>(that)->~RegExpObject();
-}
-
void RegExpObject::markObjects(Managed *that, ExecutionEngine *e)
{
RegExpObject *re = static_cast<RegExpObject*>(that);
- if (re->value)
- re->value->mark(e);
+ if (re->value())
+ re->value()->mark(e);
Object::markObjects(that, e);
}
Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
{
Q_UNUSED(ctx);
- Q_ASSERT(0 == internalClass->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex"))));
+ Q_ASSERT(0 == internalClass()->find(ctx->d()->engine->newIdentifier(QStringLiteral("lastIndex"))));
return propertyAt(0);
}
@@ -194,19 +198,19 @@ Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
// have different semantics/flags, but we try to do our best.
QRegExp RegExpObject::toQRegExp() const
{
- Qt::CaseSensitivity caseSensitivity = value->ignoreCase() ? Qt::CaseInsensitive : Qt::CaseSensitive;
- return QRegExp(value->pattern(), caseSensitivity, QRegExp::RegExp2);
+ Qt::CaseSensitivity caseSensitivity = value()->ignoreCase() ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ return QRegExp(value()->pattern(), caseSensitivity, QRegExp::RegExp2);
}
QString RegExpObject::toString() const
{
QString result = QLatin1Char('/') + source();
result += QLatin1Char('/');
- if (global)
+ if (global())
result += QLatin1Char('g');
- if (value->ignoreCase())
+ if (value()->ignoreCase())
result += QLatin1Char('i');
- if (value->multiLine())
+ if (value()->multiLine())
result += QLatin1Char('m');
return result;
}
@@ -215,35 +219,35 @@ QString RegExpObject::source() const
{
Scope scope(engine());
ScopedString source(scope, scope.engine->newIdentifier(QStringLiteral("source")));
- ScopedValue s(scope, const_cast<RegExpObject *>(this)->get(source));
+ ScopedValue s(scope, const_cast<RegExpObject *>(this)->get(source.getPointer()));
return s->toQString();
}
uint RegExpObject::flags() const
{
uint f = 0;
- if (global)
+ if (global())
f |= QV4::RegExpObject::RegExp_Global;
- if (value->ignoreCase())
+ if (value()->ignoreCase())
f |= QV4::RegExpObject::RegExp_IgnoreCase;
- if (value->multiLine())
+ if (value()->multiLine())
f |= QV4::RegExpObject::RegExp_Multiline;
return f;
}
DEFINE_OBJECT_VTABLE(RegExpCtor);
-RegExpCtor::RegExpCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("RegExp"))
+RegExpCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("RegExp"))
{
setVTable(staticVTable());
clearLastMatch();
}
-void RegExpCtor::clearLastMatch()
+void RegExpCtor::Data::clearLastMatch()
{
lastMatch = Primitive::nullValue();
- lastInput = engine()->id_empty;
+ lastInput = internalClass->engine->id_empty;
lastMatchStart = 0;
lastMatchEnd = 0;
}
@@ -260,8 +264,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
if (!f->isUndefined())
return ctx->throwTypeError();
- Scoped<RegExp> newRe(scope, re->value);
- return Encode(ctx->engine->newRegExpObject(newRe, re->global));
+ return Encode(ctx->d()->engine->newRegExpObject(re->value(), re->global()));
}
QString pattern;
@@ -291,11 +294,11 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
}
}
- Scoped<RegExp> regexp(scope, RegExp::create(ctx->engine, pattern, ignoreCase, multiLine));
+ RegExp *regexp = reinterpret_cast<RegExp *>(RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine));
if (!regexp->isValid())
return ctx->throwSyntaxError(QStringLiteral("Invalid regular expression"));
- return Encode(ctx->engine->newRegExpObject(regexp, global));
+ return Encode(ctx->d()->engine->newRegExpObject(regexp, global));
}
ReturnedValue RegExpCtor::call(Managed *that, CallData *callData)
@@ -311,15 +314,16 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData)
void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e)
{
RegExpCtor *This = static_cast<RegExpCtor*>(that);
- This->lastMatch.mark(e);
- This->lastInput.mark(e);
+ This->lastMatch().mark(e);
+ This->lastInput().mark(e);
FunctionObject::markObjects(that, e);
}
-void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
{
Scope scope(engine);
ScopedObject o(scope);
+ ScopedObject ctor(scope, constructor);
ctor->defineReadonlyProperty(engine->id_prototype, (o = this));
ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2));
@@ -355,7 +359,7 @@ void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>());
if (!r)
return ctx->throwTypeError();
@@ -365,17 +369,17 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
return Encode::undefined();
QString s = arg->stringValue()->toQString();
- int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0;
+ int offset = r->global() ? r->lastIndexProperty(ctx)->value.toInt32() : 0;
if (offset < 0 || offset > s.length()) {
r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0);
return Encode::null();
}
- uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint));
- const int result = r->value->match(s, offset, matchOffsets);
+ uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint));
+ const int result = r->value()->match(s, offset, matchOffsets);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor);
- regExpCtor->clearLastMatch();
+ Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor);
+ regExpCtor->d()->clearLastMatch();
if (result == -1) {
r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0);
@@ -383,26 +387,27 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
}
// fill in result data
- Scoped<ArrayObject> array(scope, ctx->engine->newArrayObject(ctx->engine->regExpExecArrayClass));
- int len = r->value->captureCount();
+ Scoped<ArrayObject> array(scope, ctx->d()->engine->newArrayObject(ctx->d()->engine->regExpExecArrayClass));
+ int len = r->value()->captureCount();
array->arrayReserve(len);
ScopedValue v(scope);
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
- v = (start != -1 && end != -1) ? ctx->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ v = (start != -1 && end != -1) ? ctx->d()->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
- array->memberData[Index_ArrayIndex] = Primitive::fromInt32(result);
- array->memberData[Index_ArrayInput] = arg.asReturnedValue();
+ array->memberData()[Index_ArrayIndex] = Primitive::fromInt32(result);
+ array->memberData()[Index_ArrayInput] = arg.asReturnedValue();
- regExpCtor->lastMatch = array;
- regExpCtor->lastInput = arg->stringValue();
- regExpCtor->lastMatchStart = matchOffsets[0];
- regExpCtor->lastMatchEnd = matchOffsets[1];
+ RegExpCtor::Data *dd = regExpCtor->d();
+ dd->lastMatch = array;
+ dd->lastInput = arg->stringValue();
+ dd->lastMatchStart = matchOffsets[0];
+ dd->lastMatchEnd = matchOffsets[1];
- if (r->global)
+ if (r->global())
r->lastIndexProperty(ctx)->value = Primitive::fromInt32(matchOffsets[1]);
return array.asReturnedValue();
@@ -418,27 +423,27 @@ ReturnedValue RegExpPrototype::method_test(CallContext *ctx)
ReturnedValue RegExpPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>());
if (!r)
return ctx->throwTypeError();
- return ctx->engine->newString(r->toString())->asReturnedValue();
+ return ctx->d()->engine->newString(r->toString())->asReturnedValue();
}
ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>());
if (!r)
return ctx->throwTypeError();
- ScopedCallData callData(scope, ctx->callData->argc);
- memcpy(callData->args, ctx->callData->args, ctx->callData->argc*sizeof(Value));
+ ScopedCallData callData(scope, ctx->d()->callData->argc);
+ memcpy(callData->args, ctx->d()->callData->args, ctx->d()->callData->argc*sizeof(Value));
- Scoped<RegExpObject> re(scope, ctx->engine->regExpCtor.asFunctionObject()->construct(callData));
+ Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData));
- r->value = re->value;
- r->global = re->global;
+ r->d()->value = re->value();
+ r->d()->global = re->global();
return Encode::undefined();
}
@@ -446,42 +451,42 @@ template <int index>
ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx)
{
Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch);
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch());
ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined());
if (result->isUndefined())
- return ctx->engine->newString(QString())->asReturnedValue();
+ return ctx->d()->engine->newString(QString())->asReturnedValue();
return result.asReturnedValue();
}
ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx)
{
Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch);
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch());
ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined());
if (result->isUndefined())
- return ctx->engine->newString(QString())->asReturnedValue();
+ return ctx->d()->engine->newString(QString())->asReturnedValue();
return result.asReturnedValue();
}
ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx)
{
- return static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastInput.asReturnedValue();
+ return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastInput().asReturnedValue();
}
ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor);
- QString lastInput = regExpCtor->lastInput->toQString();
- return ctx->engine->newString(lastInput.left(regExpCtor->lastMatchStart))->asReturnedValue();
+ Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor);
+ QString lastInput = regExpCtor->lastInput()->toQString();
+ return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue();
}
ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor);
- QString lastInput = regExpCtor->lastInput->toQString();
- return ctx->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd))->asReturnedValue();
+ Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor);
+ QString lastInput = regExpCtor->lastInput()->toQString();
+ return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 1b408749d3..ac07707b2f 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -63,11 +63,18 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-class RegExp;
-
struct RegExpObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, RegExp *value, bool global);
+ Data(ExecutionEngine *engine, const QRegExp &re);
+ Data(InternalClass *ic);
+
+ RegExp *value;
+ bool global;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(RegExpObject)
+
// needs to be compatible with the flags in qv4jsir_p.h
enum Flags {
RegExp_Global = 0x01,
@@ -80,39 +87,37 @@ struct RegExpObject: Object {
Index_ArrayInput = Index_ArrayIndex + 1
};
- RegExp* value;
- Property *lastIndexProperty(ExecutionContext *ctx);
- bool global;
-
- RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global);
- RegExpObject(ExecutionEngine *engine, const QRegExp &re);
- ~RegExpObject() {}
+ RegExp *value() const { return d()->value; }
+ bool global() const { return d()->global; }
void init(ExecutionEngine *engine);
+ Property *lastIndexProperty(ExecutionContext *ctx);
QRegExp toQRegExp() const;
QString toString() const;
QString source() const;
uint flags() const;
protected:
- RegExpObject(InternalClass *ic);
- static void destroy(Managed *that);
static void markObjects(Managed *that, ExecutionEngine *e);
};
-DEFINE_REF(RegExp, Object);
-
struct RegExpCtor: FunctionObject
{
- V4_OBJECT
- RegExpCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ Value lastMatch;
+ StringValue lastInput;
+ int lastMatchStart;
+ int lastMatchEnd;
+ void clearLastMatch();
+ };
+ V4_OBJECT(FunctionObject)
- Value lastMatch;
- StringValue lastInput;
- int lastMatchStart;
- int lastMatchEnd;
- void clearLastMatch();
+ Value lastMatch() { return d()->lastMatch; }
+ StringValue lastInput() { return d()->lastInput; }
+ int lastMatchStart() { return d()->lastMatchStart; }
+ int lastMatchEnd() { return d()->lastMatchEnd; }
static ReturnedValue construct(Managed *m, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -121,8 +126,16 @@ struct RegExpCtor: FunctionObject
struct RegExpPrototype: RegExpObject
{
- RegExpPrototype(InternalClass *ic): RegExpObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ struct Data : RegExpObject::Data
+ {
+ Data(InternalClass *ic): RegExpObject::Data(ic)
+ {
+ setVTable(staticVTable());
+ }
+ };
+ V4_OBJECT(RegExpObject)
+
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_exec(CallContext *ctx);
static ReturnedValue method_test(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index e44d1a07a6..05a2027f9b 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -53,6 +53,7 @@
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmltypewrapper_p.h>
#include "qv4qobjectwrapper_p.h"
#include <private/qv8engine_p.h>
#endif
@@ -265,10 +266,9 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
ReturnedValue Runtime::closure(ExecutionContext *ctx, int functionId)
{
- QV4::Function *clos = ctx->compilationUnit->runtimeFunctions[functionId];
+ QV4::Function *clos = ctx->d()->compilationUnit->runtimeFunctions[functionId];
Q_ASSERT(clos);
- FunctionObject *f = FunctionObject::createScriptFunction(ctx, clos);
- return f->asReturnedValue();
+ return FunctionObject::createScriptFunction(ctx, clos)->asReturnedValue();
}
ReturnedValue Runtime::deleteElement(ExecutionContext *ctx, const ValueRef base, const ValueRef index)
@@ -283,10 +283,10 @@ ReturnedValue Runtime::deleteElement(ExecutionContext *ctx, const ValueRef base,
}
ScopedString name(scope, index->toString(ctx));
- return Runtime::deleteMember(ctx, base, name);
+ return Runtime::deleteMember(ctx, base, name.getPointer());
}
-ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base, const StringRef name)
+ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base, String *name)
{
Scope scope(ctx);
ScopedObject obj(scope, base->toObject(ctx));
@@ -295,7 +295,7 @@ ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base,
return Encode(obj->deleteProperty(name));
}
-ReturnedValue Runtime::deleteName(ExecutionContext *ctx, const StringRef name)
+ReturnedValue Runtime::deleteName(ExecutionContext *ctx, String *name)
{
Scope scope(ctx);
return Encode(ctx->deleteProperty(name));
@@ -310,8 +310,8 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef
if (!f)
return ctx->throwTypeError();
- if (f->subtype == FunctionObject::BoundFunction)
- f = static_cast<BoundFunction *>(f)->target;
+ if (f->subtype() == FunctionObject::BoundFunction)
+ f = static_cast<BoundFunction *>(f)->target();
Object *v = left->asObject();
if (!v)
@@ -341,7 +341,7 @@ QV4::ReturnedValue Runtime::in(ExecutionContext *ctx, const ValueRef left, const
ScopedString s(scope, left->toString(ctx));
if (scope.hasException())
return Encode::undefined();
- bool r = right->objectValue()->hasProperty(s);
+ bool r = right->objectValue()->hasProperty(s.getPointer());
return Encode(r);
}
@@ -370,7 +370,7 @@ Returned<String> *RuntimeHelpers::stringFromNumber(ExecutionContext *ctx, double
{
QString qstr;
RuntimeHelpers::numberToString(&qstr, number, 10);
- return ctx->engine->newString(qstr);
+ return ctx->engine()->newString(qstr);
}
ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint)
@@ -382,7 +382,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint)
typeHint = NUMBER_HINT;
}
- ExecutionEngine *engine = object->internalClass->engine;
+ ExecutionEngine *engine = object->internalClass()->engine;
if (engine->hasException)
return Encode::undefined();
@@ -428,13 +428,13 @@ Returned<Object> *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const V
ctx->throwTypeError();
return 0;
case Value::Boolean_Type:
- return ctx->engine->newBooleanObject(value);
+ return ctx->engine()->newBooleanObject(value);
case Value::Managed_Type:
Q_ASSERT(value->isString());
- return ctx->engine->newStringObject(value);
+ return ctx->engine()->newStringObject(value);
case Value::Integer_Type:
default: // double
- return ctx->engine->newNumberObject(value);
+ return ctx->engine()->newNumberObject(value);
}
}
@@ -444,14 +444,14 @@ Returned<String> *RuntimeHelpers::convertToString(ExecutionContext *ctx, const V
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
case Value::Undefined_Type:
- return ctx->engine->id_undefined.ret();
+ return ctx->engine()->id_undefined.ret();
case Value::Null_Type:
- return ctx->engine->id_null.ret();
+ return ctx->engine()->id_null.ret();
case Value::Boolean_Type:
if (value->booleanValue())
- return ctx->engine->id_true.ret();
+ return ctx->engine()->id_true.ret();
else
- return ctx->engine->id_false.ret();
+ return ctx->engine()->id_false.ret();
case Value::Managed_Type:
if (value->isString())
return value->stringValue()->asReturned<String>();
@@ -475,14 +475,14 @@ static Returned<String> *convert_to_string_add(ExecutionContext *ctx, const Valu
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
case Value::Undefined_Type:
- return ctx->engine->id_undefined.ret();
+ return ctx->engine()->id_undefined.ret();
case Value::Null_Type:
- return ctx->engine->id_null.ret();
+ return ctx->engine()->id_null.ret();
case Value::Boolean_Type:
if (value->booleanValue())
- return ctx->engine->id_true.ret();
+ return ctx->engine()->id_true.ret();
else
- return ctx->engine->id_false.ret();
+ return ctx->engine()->id_false.ret();
case Value::Managed_Type:
if (value->isString())
return value->stringValue()->asReturned<String>();
@@ -511,11 +511,11 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionContext *ctx, const ValueR
pright = convert_to_string_add(ctx, pright);
if (scope.engine->hasException)
return Encode::undefined();
- if (!pleft->stringValue()->length())
+ if (!pleft->stringValue()->d()->length())
return pright->asReturnedValue();
- if (!pright->stringValue()->length())
+ if (!pright->stringValue()->d()->length())
return pleft->asReturnedValue();
- return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
+ return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
}
double x = RuntimeHelpers::toNumber(pleft);
double y = RuntimeHelpers::toNumber(pright);
@@ -527,11 +527,11 @@ QV4::ReturnedValue Runtime::addString(QV4::ExecutionContext *ctx, const QV4::Val
Q_ASSERT(left->isString() || right->isString());
if (left->isString() && right->isString()) {
- if (!left->stringValue()->length())
+ if (!left->stringValue()->d()->length())
return right->asReturnedValue();
- if (!right->stringValue()->length())
+ if (!right->stringValue()->d()->length())
return left->asReturnedValue();
- return (new (ctx->engine->memoryManager) String(ctx->engine, left->stringValue(), right->stringValue()))->asReturnedValue();
+ return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, left->stringValue(), right->stringValue()))->asReturnedValue();
}
Scope scope(ctx);
@@ -544,14 +544,14 @@ QV4::ReturnedValue Runtime::addString(QV4::ExecutionContext *ctx, const QV4::Val
pright = convert_to_string_add(ctx, right);
if (scope.engine->hasException)
return Encode::undefined();
- if (!pleft->stringValue()->length())
+ if (!pleft->stringValue()->d()->length())
return pright->asReturnedValue();
- if (!pright->stringValue()->length())
+ if (!pright->stringValue()->d()->length())
return pleft->asReturnedValue();
- return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
+ return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue();
}
-void Runtime::setProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value)
+void Runtime::setProperty(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef value)
{
Scope scope(ctx);
ScopedObject o(scope, object->toObject(ctx));
@@ -588,8 +588,8 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object,
}
if (idx < UINT_MAX) {
- if (!o->arrayData->hasAttributes()) {
- ScopedValue v(scope, o->arrayData->get(idx));
+ if (!o->arrayData()->hasAttributes()) {
+ ScopedValue v(scope, o->arrayData()->get(idx));
if (!v->isEmpty())
return v->asReturnedValue();
}
@@ -600,7 +600,7 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object,
ScopedString name(scope, index->toString(ctx));
if (scope.hasException())
return Encode::undefined();
- return o->get(name);
+ return o->get(name.getPointer());
}
void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index, const ValueRef value)
@@ -613,9 +613,9 @@ void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const Val
uint idx = index->asArrayIndex();
if (idx < UINT_MAX) {
if (o->arrayType() == ArrayData::Simple) {
- SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData);
- if (s && idx < s->len && !s->data[idx].isEmpty()) {
- s->data[idx] = value;
+ SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData());
+ if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) {
+ s->arrayData()[idx] = value;
return;
}
}
@@ -624,7 +624,7 @@ void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const Val
}
ScopedString name(scope, index->toString(ctx));
- o->put(name, value);
+ o->put(name.getPointer(), value);
}
ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in)
@@ -633,7 +633,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in)
Scoped<Object> o(scope, (Object *)0);
if (!in->isNullOrUndefined())
o = in->toObject(ctx);
- Scoped<Object> it(scope, ctx->engine->newForEachIteratorObject(ctx, o));
+ Scoped<Object> it(scope, ctx->engine()->newForEachIteratorObject(ctx, o));
return it.asReturnedValue();
}
@@ -648,12 +648,12 @@ ReturnedValue Runtime::foreachNextPropertyName(const ValueRef foreach_iterator)
}
-void Runtime::setActivationProperty(ExecutionContext *ctx, const StringRef name, const ValueRef value)
+void Runtime::setActivationProperty(ExecutionContext *ctx, String *name, const ValueRef value)
{
ctx->setProperty(name, value);
}
-ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name)
+ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, String *name)
{
Scope scope(ctx);
@@ -672,7 +672,7 @@ ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object,
return o->get(name);
}
-ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, const StringRef name)
+ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, String *name)
{
return ctx->getProperty(name);
}
@@ -866,31 +866,31 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r
}
#ifndef V4_BOOTSTRAP
-ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData)
+ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallData *callData)
{
Scope scope(context);
Q_ASSERT(callData->thisObject.isUndefined());
- Lookup *l = context->lookups + index;
+ Lookup *l = context->d()->lookups + index;
Scoped<FunctionObject> o(scope, l->globalGetter(l, context));
if (!o)
return context->throwTypeError();
- if (o.getPointer() == context->engine->evalFunction && l->name->equals(context->engine->id_eval))
+ if (o.getPointer() == scope.engine->evalFunction && l->name->equals(scope.engine->id_eval))
return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true);
return o->call(callData);
}
-ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, const StringRef name, CallDataRef callData)
+ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String *name, CallData *callData)
{
Q_ASSERT(callData->thisObject.isUndefined());
Scope scope(context);
ScopedObject base(scope);
- ScopedValue func(scope, context->getPropertyAndBase(name, base));
- if (context->engine->hasException)
+ ScopedValue func(scope, context->getPropertyAndBase(name, base.ptr->o));
+ if (scope.engine->hasException)
return Encode::undefined();
if (base)
@@ -905,14 +905,14 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, const S
return context->throwTypeError(msg);
}
- if (o == context->engine->evalFunction && name->equals(context->engine->id_eval)) {
+ if (o == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) {
return static_cast<EvalFunction *>(o)->evalCall(callData, true);
}
return o->call(callData);
}
-ReturnedValue Runtime::callProperty(ExecutionContext *context, const StringRef name, CallDataRef callData)
+ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, CallData *callData)
{
Scope scope(context);
Scoped<Object> baseObject(scope, callData->thisObject);
@@ -938,9 +938,9 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, const StringRef n
return o->call(callData);
}
-ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData)
+ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, CallData *callData)
{
- Lookup *l = context->lookups + index;
+ Lookup *l = context->d()->lookups + index;
Value v;
v = l->getter(l, callData->thisObject);
if (!v.isObject())
@@ -949,7 +949,7 @@ ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index,
return v.objectValue()->call(callData);
}
-ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef index, CallDataRef callData)
+ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef index, CallData *callData)
{
Scope scope(context);
ScopedObject baseObject(scope, callData->thisObject.toObject(context));
@@ -959,14 +959,14 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind
return Encode::undefined();
callData->thisObject = baseObject;
- ScopedObject o(scope, baseObject->get(s));
+ ScopedObject o(scope, baseObject->get(s.getPointer()));
if (!o)
return context->throwTypeError();
return o->call(callData);
}
-ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallDataRef callData)
+ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallData *callData)
{
if (!func->isObject())
return context->throwTypeError();
@@ -975,12 +975,12 @@ ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func,
}
-ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData)
+ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint index, CallData *callData)
{
Scope scope(context);
Q_ASSERT(callData->thisObject.isUndefined());
- Lookup *l = context->lookups + index;
+ Lookup *l = context->d()->lookups + index;
Scoped<Object> f(scope, l->globalGetter(l, context));
if (!f)
return context->throwTypeError();
@@ -989,11 +989,11 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint ind
}
-ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, const StringRef name, CallDataRef callData)
+ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, String *name, CallData *callData)
{
Scope scope(context);
ScopedValue func(scope, context->getProperty(name));
- if (context->engine->hasException)
+ if (scope.engine->hasException)
return Encode::undefined();
Object *f = func->asObject();
@@ -1003,7 +1003,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, co
return f->construct(callData);
}
-ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef func, CallDataRef callData)
+ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef func, CallData *callData)
{
Object *f = func->asObject();
if (!f)
@@ -1012,7 +1012,7 @@ ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef
return f->construct(callData);
}
-ReturnedValue Runtime::constructProperty(ExecutionContext *context, const StringRef name, CallDataRef callData)
+ReturnedValue Runtime::constructProperty(ExecutionContext *context, String *name, CallData *callData)
{
Scope scope(context);
ScopedObject thisObject(scope, callData->thisObject.toObject(context));
@@ -1026,9 +1026,9 @@ ReturnedValue Runtime::constructProperty(ExecutionContext *context, const String
return f->construct(callData);
}
-ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData)
+ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint index, CallData *callData)
{
- Lookup *l = context->lookups + index;
+ Lookup *l = context->d()->lookups + index;
Value v;
v = l->getter(l, callData->thisObject);
if (!v.isObject())
@@ -1050,39 +1050,39 @@ ReturnedValue Runtime::typeofValue(ExecutionContext *ctx, const ValueRef value)
ScopedString res(scope);
switch (value->type()) {
case Value::Undefined_Type:
- res = ctx->engine->id_undefined;
+ res = ctx->engine()->id_undefined;
break;
case Value::Null_Type:
- res = ctx->engine->id_object;
+ res = ctx->engine()->id_object;
break;
case Value::Boolean_Type:
- res = ctx->engine->id_boolean;
+ res = ctx->engine()->id_boolean;
break;
case Value::Managed_Type:
if (value->isString())
- res = ctx->engine->id_string;
+ res = ctx->engine()->id_string;
else if (value->objectValue()->asFunctionObject())
- res = ctx->engine->id_function;
+ res = ctx->engine()->id_function;
else
- res = ctx->engine->id_object; // ### implementation-defined
+ res = ctx->engine()->id_object; // ### implementation-defined
break;
default:
- res = ctx->engine->id_number;
+ res = ctx->engine()->id_number;
break;
}
return res.asReturnedValue();
}
-QV4::ReturnedValue Runtime::typeofName(ExecutionContext *context, const StringRef name)
+QV4::ReturnedValue Runtime::typeofName(ExecutionContext *context, String *name)
{
Scope scope(context);
ScopedValue prop(scope, context->getProperty(name));
// typeof doesn't throw. clear any possible exception
- context->engine->hasException = false;
+ scope.engine->hasException = false;
return Runtime::typeofValue(context, prop);
}
-QV4::ReturnedValue Runtime::typeofMember(ExecutionContext *context, const ValueRef base, const StringRef name)
+QV4::ReturnedValue Runtime::typeofMember(ExecutionContext *context, const ValueRef base, String *name)
{
Scope scope(context);
ScopedObject obj(scope, base->toObject(context));
@@ -1099,7 +1099,7 @@ QV4::ReturnedValue Runtime::typeofElement(ExecutionContext *context, const Value
ScopedObject obj(scope, base->toObject(context));
if (scope.engine->hasException)
return Encode::undefined();
- ScopedValue prop(scope, obj->get(name));
+ ScopedValue prop(scope, obj->get(name.getPointer()));
return Runtime::typeofValue(context, prop);
}
@@ -1107,29 +1107,29 @@ ExecutionContext *Runtime::pushWithScope(const ValueRef o, ExecutionContext *ctx
{
Scope scope(ctx);
ScopedObject obj(scope, o->toObject(ctx));
- return ctx->newWithContext(obj);
+ return reinterpret_cast<ExecutionContext *>(ctx->newWithContext(obj));
}
ReturnedValue Runtime::unwindException(ExecutionContext *ctx)
{
- if (!ctx->engine->hasException)
+ if (!ctx->engine()->hasException)
return Primitive::emptyValue().asReturnedValue();
- return ctx->engine->catchException(ctx, 0);
+ return ctx->engine()->catchException(ctx, 0);
}
-ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, const StringRef exceptionVarName)
+ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, String *exceptionVarName)
{
Scope scope(ctx);
- ScopedValue v(scope, ctx->engine->catchException(ctx, 0));
- return ctx->newCatchContext(exceptionVarName, v);
+ ScopedValue v(scope, ctx->engine()->catchException(ctx, 0));
+ return reinterpret_cast<ExecutionContext *>(ctx->newCatchContext(exceptionVarName, v));
}
ExecutionContext *Runtime::popScope(ExecutionContext *ctx)
{
- return ctx->engine->popContext();
+ return ctx->engine()->popContext();
}
-void Runtime::declareVar(ExecutionContext *ctx, bool deletable, const StringRef name)
+void Runtime::declareVar(ExecutionContext *ctx, bool deletable, String *name)
{
ctx->createMutableBinding(name, deletable);
}
@@ -1137,7 +1137,7 @@ void Runtime::declareVar(ExecutionContext *ctx, bool deletable, const StringRef
ReturnedValue Runtime::arrayLiteral(ExecutionContext *ctx, Value *values, uint length)
{
Scope scope(ctx);
- Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject());
+ Scoped<ArrayObject> a(scope, ctx->engine()->newArrayObject());
if (length) {
a->arrayReserve(length);
@@ -1150,8 +1150,8 @@ ReturnedValue Runtime::arrayLiteral(ExecutionContext *ctx, Value *values, uint l
ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
{
Scope scope(ctx);
- QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId];
- Scoped<Object> o(scope, ctx->engine->newObject(klass));
+ QV4::InternalClass *klass = ctx->d()->compilationUnit->runtimeClasses[classId];
+ Scoped<Object> o(scope, ctx->engine()->newObject(klass));
{
bool needSparseArray = arrayGetterSetterCountAndFlags >> 30;
@@ -1160,26 +1160,30 @@ ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Valu
}
for (uint i = 0; i < klass->size; ++i)
- o->memberData[i] = *args++;
-
- ScopedValue entry(scope);
- for (int i = 0; i < arrayValueCount; ++i) {
- uint idx = args->toUInt32();
- ++args;
- entry = *args++;
- o->arraySet(idx, entry);
+ o->memberData()[i] = *args++;
+
+ if (arrayValueCount > 0) {
+ ScopedValue entry(scope);
+ for (int i = 0; i < arrayValueCount; ++i) {
+ uint idx = args->toUInt32();
+ ++args;
+ entry = *args++;
+ o->arraySet(idx, entry);
+ }
}
- ScopedProperty pd(scope);
uint arrayGetterSetterCount = arrayGetterSetterCountAndFlags & ((1 << 30) - 1);
- for (uint i = 0; i < arrayGetterSetterCount; ++i) {
- uint idx = args->toUInt32();
- ++args;
- pd->value = *args;
- ++args;
- pd->set = *args;
- ++args;
- o->arraySet(idx, pd, Attr_Accessor);
+ if (arrayGetterSetterCount > 0) {
+ ScopedProperty pd(scope);
+ for (uint i = 0; i < arrayGetterSetterCount; ++i) {
+ uint idx = args->toUInt32();
+ ++args;
+ pd->value = *args;
+ ++args;
+ pd->set = *args;
+ ++args;
+ o->arraySet(idx, pd, Attr_Accessor);
+ }
}
return o.asReturnedValue();
@@ -1187,9 +1191,9 @@ ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Valu
QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionContext *ctx)
{
- assert(ctx->type >= ExecutionContext::Type_CallContext);
+ Q_ASSERT(ctx->d()->type >= ExecutionContext::Type_CallContext);
CallContext *c = static_cast<CallContext *>(ctx);
- return (new (c->engine->memoryManager) ArgumentsObject(c))->asReturnedValue();
+ return (c->engine()->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue();
}
#endif // V4_BOOTSTRAP
@@ -1275,27 +1279,27 @@ unsigned Runtime::doubleToUInt(const double &d)
ReturnedValue Runtime::regexpLiteral(ExecutionContext *ctx, int id)
{
- return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
+ return ctx->d()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
ReturnedValue Runtime::getQmlIdArray(NoThrowContext *ctx)
{
- return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray();
+ return ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray();
}
ReturnedValue Runtime::getQmlContextObject(NoThrowContext *ctx)
{
- QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine());
if (!context)
return Encode::undefined();
- return QObjectWrapper::wrap(ctx->engine, context->contextObject);
+ return QObjectWrapper::wrap(ctx->d()->engine, context->contextObject);
}
ReturnedValue Runtime::getQmlScopeObject(NoThrowContext *ctx)
{
Scope scope(ctx);
- QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
- return QObjectWrapper::wrap(ctx->engine, c->getScopeObject());
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ return QObjectWrapper::wrap(ctx->d()->engine, c->getScopeObject());
}
ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired)
@@ -1312,15 +1316,26 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueR
QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex)
{
Scope scope(ctx);
- QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
QObject *scopeObject = c->getScopeObject();
QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject);
- QQmlEngine *qmlEngine = ctx->engine->v8Engine->engine();
+ QQmlEngine *qmlEngine = ctx->engine()->v8Engine->engine();
QQmlData::ensurePropertyCache(qmlEngine, attachedObject);
return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true);
}
+ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QmlTypeWrapper> wrapper(scope, object);
+ if (!wrapper) {
+ ctx->throwTypeError(QStringLiteral("Cannot read property of null"));
+ return Encode::undefined();
+ }
+ return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired);
+}
+
void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value)
{
Scope scope(ctx);
@@ -1334,24 +1349,24 @@ void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object
ReturnedValue Runtime::getQmlImportedScripts(NoThrowContext *ctx)
{
- QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
+ QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine());
if (!context)
return Encode::undefined();
return context->importedScripts.value();
}
-QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowContext *ctx, const QV4::StringRef name)
+QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowContext *ctx, String *name)
{
- return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(ctx->engine->v8Engine, name);
+ return ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(ctx->engine()->v8Engine, name);
}
void Runtime::convertThisToObject(ExecutionContext *ctx)
{
- Value *t = &ctx->callData->thisObject;
+ Value *t = &ctx->d()->callData->thisObject;
if (t->isObject())
return;
if (t->isNullOrUndefined()) {
- *t = ctx->engine->globalObject->asReturnedValue();
+ *t = ctx->engine()->globalObject->asReturnedValue();
} else {
*t = t->toObject(ctx)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 0979105680..d216f58db0 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -105,51 +105,51 @@ struct NoThrowContext : public ExecutionContext
struct Q_QML_PRIVATE_EXPORT Runtime {
// call
- static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData);
- static ReturnedValue callActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData);
- static ReturnedValue callProperty(ExecutionContext *context, const StringRef name, CallDataRef callData);
- static ReturnedValue callPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData);
- static ReturnedValue callElement(ExecutionContext *context, const ValueRef index, CallDataRef callData);
- static ReturnedValue callValue(ExecutionContext *context, const ValueRef func, CallDataRef callData);
+ static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallData *callData);
+ static ReturnedValue callActivationProperty(ExecutionContext *, String *name, CallData *callData);
+ static ReturnedValue callProperty(ExecutionContext *context, String *name, CallData *callData);
+ static ReturnedValue callPropertyLookup(ExecutionContext *context, uint index, CallData *callData);
+ static ReturnedValue callElement(ExecutionContext *context, const ValueRef index, CallData *callData);
+ static ReturnedValue callValue(ExecutionContext *context, const ValueRef func, CallData *callData);
// construct
- static ReturnedValue constructGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData);
- static ReturnedValue constructActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData);
- static ReturnedValue constructProperty(ExecutionContext *context, const StringRef name, CallDataRef callData);
- static ReturnedValue constructPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData);
- static ReturnedValue constructValue(ExecutionContext *context, const ValueRef func, CallDataRef callData);
+ static ReturnedValue constructGlobalLookup(ExecutionContext *context, uint index, CallData *callData);
+ static ReturnedValue constructActivationProperty(ExecutionContext *, String *name, CallData *callData);
+ static ReturnedValue constructProperty(ExecutionContext *context, String *name, CallData *callData);
+ static ReturnedValue constructPropertyLookup(ExecutionContext *context, uint index, CallData *callData);
+ static ReturnedValue constructValue(ExecutionContext *context, const ValueRef func, CallData *callData);
// set & get
- static void setActivationProperty(ExecutionContext *ctx, const StringRef name, const ValueRef value);
- static void setProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value);
+ static void setActivationProperty(ExecutionContext *ctx, String *name, const ValueRef value);
+ static void setProperty(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef value);
static void setElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index, const ValueRef value);
- static ReturnedValue getProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name);
- static ReturnedValue getActivationProperty(ExecutionContext *ctx, const StringRef name);
+ static ReturnedValue getProperty(ExecutionContext *ctx, const ValueRef object, String *name);
+ static ReturnedValue getActivationProperty(ExecutionContext *ctx, String *name);
static ReturnedValue getElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index);
// typeof
static ReturnedValue typeofValue(ExecutionContext *ctx, const ValueRef val);
- static ReturnedValue typeofName(ExecutionContext *context, const StringRef name);
- static ReturnedValue typeofMember(ExecutionContext* context, const ValueRef base, const StringRef name);
+ static ReturnedValue typeofName(ExecutionContext *context, String *name);
+ static ReturnedValue typeofMember(ExecutionContext* context, const ValueRef base, String *name);
static ReturnedValue typeofElement(ExecutionContext* context, const ValueRef base, const ValueRef index);
// delete
static ReturnedValue deleteElement(ExecutionContext *ctx, const ValueRef base, const ValueRef index);
- static ReturnedValue deleteMember(ExecutionContext *ctx, const ValueRef base, const StringRef name);
- static ReturnedValue deleteName(ExecutionContext *ctx, const StringRef name);
+ static ReturnedValue deleteMember(ExecutionContext *ctx, const ValueRef base, String *name);
+ static ReturnedValue deleteName(ExecutionContext *ctx, String *name);
// exceptions & scopes
static void throwException(ExecutionContext*, const ValueRef value);
static ReturnedValue unwindException(ExecutionContext *ctx);
static ExecutionContext *pushWithScope(const ValueRef o, ExecutionContext *ctx);
- static ExecutionContext *pushCatchScope(ExecutionContext *ctx, const StringRef exceptionVarName);
+ static ExecutionContext *pushCatchScope(ExecutionContext *ctx, String *exceptionVarName);
static ExecutionContext *popScope(ExecutionContext *ctx);
// closures
static ReturnedValue closure(ExecutionContext *ctx, int functionId);
// function header
- static void declareVar(ExecutionContext *ctx, bool deletable, const StringRef name);
+ static void declareVar(ExecutionContext *ctx, bool deletable, String *name);
static ReturnedValue setupArgumentsObject(ExecutionContext *ctx);
static void convertThisToObject(ExecutionContext *ctx);
@@ -226,9 +226,10 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static ReturnedValue getQmlImportedScripts(NoThrowContext *ctx);
static ReturnedValue getQmlContextObject(NoThrowContext *ctx);
static ReturnedValue getQmlScopeObject(NoThrowContext *ctx);
- static ReturnedValue getQmlSingleton(NoThrowContext *ctx, const StringRef name);
+ static ReturnedValue getQmlSingleton(NoThrowContext *ctx, String *name);
static ReturnedValue getQmlAttachedProperty(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex);
static ReturnedValue getQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired);
+ static ReturnedValue getQmlSingletonQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired);
static void setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value);
};
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 5d471ab4fb..563d097440 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -117,6 +117,18 @@ struct ScopedValue
#endif
}
+ ScopedValue(const Scope &scope, HeapObject *o)
+ {
+ ptr = scope.engine->jsStackTop++;
+ ptr->m = reinterpret_cast<Managed *>(o);
+#if QT_POINTER_SIZE == 4
+ ptr->tag = QV4::Value::Managed_Type;
+#endif
+#ifndef QT_NO_DEBUG
+ ++scope.size;
+#endif
+ }
+
ScopedValue(const Scope &scope, Managed *m)
{
ptr = scope.engine->jsStackTop++;
@@ -150,6 +162,14 @@ struct ScopedValue
return *this;
}
+ ScopedValue &operator=(HeapObject *o) {
+ ptr->m = reinterpret_cast<Managed *>(o);
+#if QT_POINTER_SIZE == 4
+ ptr->tag = QV4::Value::Managed_Type;
+#endif
+ return *this;
+ }
+
ScopedValue &operator=(Managed *m) {
ptr->val = m->asReturnedValue();
return *this;
@@ -215,6 +235,19 @@ struct Scoped
++scope.size;
#endif
}
+ Scoped(const Scope &scope, HeapObject *o)
+ {
+ Value v;
+ v.m = reinterpret_cast<Managed *>(o);
+#if QT_POINTER_SIZE == 4
+ v.tag = QV4::Value::Managed_Type;
+#endif
+ ptr = scope.engine->jsStackTop++;
+ setPointer(value_cast<T>(v));
+#ifndef QT_NO_DEBUG
+ ++scope.size;
+#endif
+ }
Scoped(const Scope &scope, const ScopedValue &v)
{
ptr = scope.engine->jsStackTop++;
@@ -280,6 +313,15 @@ struct Scoped
#endif
}
+ Scoped<T> &operator=(HeapObject *o) {
+ Value v;
+ v.m = reinterpret_cast<Managed *>(o);
+#if QT_POINTER_SIZE == 4
+ v.tag = QV4::Value::Managed_Type;
+#endif
+ setPointer(value_cast<T>(v));
+ return *this;
+ }
Scoped<T> &operator=(const Value &v) {
setPointer(value_cast<T>(v));
return *this;
@@ -308,6 +350,9 @@ struct Scoped
return *this;
}
+ operator T *() {
+ return static_cast<T *>(ptr->managed());
+ }
T *operator->() {
return static_cast<T *>(ptr->managed());
@@ -379,10 +424,6 @@ struct ScopedCallData {
};
-struct StringRef;
-struct ObjectRef;
-struct FunctionObjectRef;
-
template<typename T>
inline Scoped<T>::Scoped(const Scope &scope, const ValueRef &v)
{
@@ -400,38 +441,6 @@ inline Scoped<T> &Scoped<T>::operator=(const ValueRef &v)
return *this;
}
-struct CallDataRef {
- CallDataRef(const ScopedCallData &c)
- : ptr(c.ptr) {}
- CallDataRef(CallData *v) { ptr = v; }
- // Important: Do NOT add a copy constructor to this class
- // adding a copy constructor actually changes the calling convention, ie.
- // is not even binary compatible. Adding it would break assumptions made
- // in the jit'ed code.
- CallDataRef &operator=(const ScopedCallData &c)
- { *ptr = *c.ptr; return *this; }
- CallDataRef &operator=(const CallDataRef &o)
- { *ptr = *o.ptr; return *this; }
-
- operator const CallData *() const {
- return ptr;
- }
- const CallData *operator->() const {
- return ptr;
- }
-
- operator CallData *() {
- return ptr;
- }
- CallData *operator->() {
- return ptr;
- }
-
-private:
- CallData *ptr;
-};
-
-
template <typename T>
inline Value &Value::operator=(Returned<T> *t)
{
@@ -467,14 +476,20 @@ inline Returned<T> *Value::as()
template<typename T>
inline TypedValue<T> &TypedValue<T>::operator =(T *t)
{
- val = t->asReturnedValue();
+ m = t;
+#if QT_POINTER_SIZE == 4
+ tag = Managed_Type;
+#endif
return *this;
}
template<typename T>
inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v)
{
- val = v.ptr->val;
+ m = v.ptr->managed();
+#if QT_POINTER_SIZE == 4
+ tag = Managed_Type;
+#endif
return *this;
}
@@ -517,22 +532,12 @@ PersistentValue::PersistentValue(Returned<T> *obj)
{
}
-inline PersistentValue::PersistentValue(const ManagedRef obj)
- : d(new PersistentValuePrivate(obj.asReturnedValue()))
-{
-}
-
template<typename T>
inline PersistentValue &PersistentValue::operator=(Returned<T> *obj)
{
return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue());
}
-inline PersistentValue &PersistentValue::operator=(const ManagedRef obj)
-{
- return operator=(obj.asReturnedValue());
-}
-
inline PersistentValue &PersistentValue::operator=(const ScopedValue &other)
{
return operator=(other.asReturnedValue());
@@ -573,18 +578,6 @@ inline ValueRef &ValueRef::operator=(const ScopedValue &o)
return *this;
}
-
-inline Value *extractValuePointer(const ScopedValue &v)
-{
- return v.ptr;
-}
-
-template<typename T>
-Value *extractValuePointer(const Scoped<T> &v)
-{
- return v.ptr;
-}
-
struct ScopedProperty
{
ScopedProperty(Scope &scope)
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 36f61a1df5..27bb7c8d2f 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -61,12 +61,11 @@
using namespace QV4;
-QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
- : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
+QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml)
+ : FunctionObject::Data(scope, scope->d()->engine->id_eval, /*createProto = */ false)
, qml(qml)
- , qmlContext(0)
{
- Q_ASSERT(scope->inUse);
+ Q_ASSERT(scope->inUse());
setVTable(staticVTable());
function = f;
@@ -75,32 +74,30 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec
needsActivation = function ? function->needsActivation() : false;
Scope s(scope);
- ScopedValue protectThis(s, this);
+ Scoped<QmlBindingWrapper> o(s, this);
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
+ o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
- scope->engine->popContext();
+ o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml));
+ s.engine->popContext();
}
-QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
- : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false)
+QmlBindingWrapper::Data::Data(ExecutionContext *scope, Object *qml)
+ : FunctionObject::Data(scope, scope->d()->engine->id_eval, /*createProto = */ false)
, qml(qml)
- , qmlContext(0)
{
- Q_ASSERT(scope->inUse);
+ Q_ASSERT(scope->inUse());
setVTable(staticVTable());
- function = 0;
needsActivation = false;
Scope s(scope);
- ScopedValue protectThis(s, this);
+ Scoped<QmlBindingWrapper> o(s, this);
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
+ o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
- scope->engine->popContext();
+ o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml));
+ s.engine->popContext();
}
ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
@@ -110,13 +107,13 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
Scope scope(engine);
QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
- if (!This->function)
+ if (!This->function())
return QV4::Encode::undefined();
- CallContext *ctx = This->qmlContext;
- std::fill(ctx->locals, ctx->locals + ctx->function->varCount(), Primitive::undefinedValue());
+ CallContext *ctx = This->d()->qmlContext;
+ std::fill(ctx->d()->locals, ctx->d()->locals + ctx->d()->function->varCount(), Primitive::undefinedValue());
engine->pushContext(ctx);
- ScopedValue result(scope, This->function->code(ctx, This->function->codeData));
+ ScopedValue result(scope, This->function()->code(ctx, This->function()->codeData));
engine->popContext();
return result.asReturnedValue();
@@ -125,16 +122,16 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *)
void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
{
QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
- if (wrapper->qml)
- wrapper->qml->mark(e);
+ if (wrapper->d()->qml)
+ wrapper->d()->qml->mark(e);
FunctionObject::markObjects(m, e);
- if (wrapper->qmlContext)
- wrapper->qmlContext->mark(e);
+ if (wrapper->d()->qmlContext)
+ wrapper->d()->qmlContext->mark(e);
}
static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex)
{
- QV4::CallContext *signalEmittingContext = ctx->parent->asCallContext();
+ QV4::CallContext *signalEmittingContext = ctx->d()->parent->asCallContext();
Q_ASSERT(signalEmittingContext);
return signalEmittingContext->argument(parameterIndex);
}
@@ -144,7 +141,7 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo
ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine);
QV4::Scope valueScope(engine);
QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine->v8Engine, qmlContext, scopeObject));
- QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (engine->memoryManager) QV4::QmlBindingWrapper(engine->rootContext, qmlScopeObject));
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(engine->rootContext, qmlScopeObject));
if (!signalParameters.isEmpty()) {
if (error)
@@ -153,10 +150,11 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo
QV4::ScopedString s(valueScope);
int index = 0;
foreach (const QByteArray &param, signalParameters) {
- p->setGetter(new (engine->memoryManager) QV4::IndexedBuiltinFunction(wrapper->context(), index++, signalParameterGetter));
+ QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapper->context(), index++, signalParameterGetter));
+ p->setGetter(g);
p->setSetter(0);
s = engine->newString(QString::fromUtf8(param));
- qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
+ qmlScopeObject->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
}
}
@@ -166,35 +164,37 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo
DEFINE_OBJECT_VTABLE(QmlBindingWrapper);
-struct CompilationUnitHolder : public QV4::Object
+struct CompilationUnitHolder : public Object
{
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, CompiledData::CompilationUnit *unit)
+ : Object::Data(engine)
+ , unit(unit)
+ {
+ unit->ref();
+ setVTable(staticVTable());
+ }
+ ~Data()
+ {
+ unit->deref();
+ }
+ QV4::CompiledData::CompilationUnit *unit;
+ };
+ V4_OBJECT(Object)
- CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit)
- : Object(engine)
- , unit(unit)
- {
- unit->ref();
- setVTable(staticVTable());
- }
- ~CompilationUnitHolder()
- {
- unit->deref();
- }
static void destroy(Managed *that)
{
- static_cast<CompilationUnitHolder*>(that)->~CompilationUnitHolder();
+ static_cast<CompilationUnitHolder*>(that)->d()->~Data();
}
- QV4::CompiledData::CompilationUnit *unit;
};
DEFINE_OBJECT_VTABLE(CompilationUnitHolder);
-Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit)
+Script::Script(ExecutionEngine *v4, Object *qml, CompiledData::CompilationUnit *compilationUnit)
: line(0), column(0), scope(v4->rootContext), strictMode(false), inheritContext(true), parsed(false)
- , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true)
+ , qml(qml->asReturnedValue()), vmFunction(0), parseAsBinding(true)
{
parsed = true;
@@ -202,7 +202,7 @@ Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit
vmFunction = compilationUnit->linkToEngine(v4);
Q_ASSERT(vmFunction);
Scope valueScope(v4);
- ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
+ ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit));
compilationUnitHolder = holder.asReturnedValue();
} else
vmFunction = 0;
@@ -221,7 +221,7 @@ void Script::parse()
parsed = true;
- ExecutionEngine *v4 = scope->engine;
+ ExecutionEngine *v4 = scope->d()->engine;
Scope valueScope(v4);
MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
@@ -274,7 +274,7 @@ void Script::parse()
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
vmFunction = compilationUnit->linkToEngine(v4);
- ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
+ ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit));
compilationUnitHolder = holder.asReturnedValue();
}
@@ -287,33 +287,12 @@ void Script::parse()
ReturnedValue Script::run()
{
- struct ContextStateSaver {
- ExecutionContext *savedContext;
- bool strictMode;
- Lookup *lookups;
- CompiledData::CompilationUnit *compilationUnit;
-
- ContextStateSaver(ExecutionContext *context)
- : savedContext(context)
- , strictMode(context->strictMode)
- , lookups(context->lookups)
- , compilationUnit(context->compilationUnit)
- {}
-
- ~ContextStateSaver()
- {
- savedContext->strictMode = strictMode;
- savedContext->lookups = lookups;
- savedContext->compilationUnit = compilationUnit;
- }
- };
-
if (!parsed)
parse();
if (!vmFunction)
return Encode::undefined();
- QV4::ExecutionEngine *engine = scope->engine;
+ QV4::ExecutionEngine *engine = scope->d()->engine;
QV4::Scope valueScope(engine);
if (qml.isUndefined()) {
@@ -321,14 +300,14 @@ ReturnedValue Script::run()
ExecutionContextSaver ctxSaver(scope);
ContextStateSaver stateSaver(scope);
- scope->strictMode = vmFunction->isStrict();
- scope->lookups = vmFunction->compilationUnit->runtimeLookups;
- scope->compilationUnit = vmFunction->compilationUnit;
+ scope->d()->strictMode = vmFunction->isStrict();
+ scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups;
+ scope->d()->compilationUnit = vmFunction->compilationUnit;
return vmFunction->code(scope, vmFunction->codeData);
} else {
ScopedObject qmlObj(valueScope, qml.value());
- FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj);
+ ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj));
ScopedCallData callData(valueScope, 0);
callData->thisObject = Primitive::undefinedValue();
return f->call(callData);
@@ -401,14 +380,14 @@ ReturnedValue Script::qmlBinding()
{
if (!parsed)
parse();
- ExecutionEngine *v4 = scope->engine;
+ ExecutionEngine *v4 = scope->d()->engine;
Scope valueScope(v4);
ScopedObject qmlObj(valueScope, qml.value());
- ScopedObject v(valueScope, new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj));
+ ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj));
return v.asReturnedValue();
}
-QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject)
+QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject)
{
QV4::Scope scope(engine);
QV4::Script qmlScript(engine, scopeObject, script, QString());
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index de582f9674..6f947cd430 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -55,23 +55,49 @@ namespace QV4 {
struct ExecutionContext;
-struct QmlBindingWrapper : FunctionObject {
- V4_OBJECT
+struct ContextStateSaver {
+ ExecutionContext *savedContext;
+ bool strictMode;
+ Lookup *lookups;
+ CompiledData::CompilationUnit *compilationUnit;
+ int lineNumber;
+
+ ContextStateSaver(ExecutionContext *context)
+ : savedContext(context)
+ , strictMode(context->d()->strictMode)
+ , lookups(context->d()->lookups)
+ , compilationUnit(context->d()->compilationUnit)
+ , lineNumber(context->d()->lineNumber)
+ {}
+
+ ~ContextStateSaver()
+ {
+ savedContext->d()->strictMode = strictMode;
+ savedContext->d()->lookups = lookups;
+ savedContext->d()->compilationUnit = compilationUnit;
+ savedContext->d()->lineNumber = lineNumber;
+ }
+};
- QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml);
- // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable!
- QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml);
+struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject {
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope, Function *f, Object *qml);
+ // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable!
+ Data(ExecutionContext *scope, Object *qml);
+ Object *qml;
+ CallContext *qmlContext;
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue call(Managed *that, CallData *);
static void markObjects(Managed *m, ExecutionEngine *e);
- CallContext *context() const { return qmlContext; }
+ CallContext *context() const { return d()->qmlContext; }
- static Returned<FunctionObject> *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0);
+ static Returned<FunctionObject> *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction,
+ const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0);
private:
- Object *qml;
- CallContext *qmlContext;
};
struct Q_QML_EXPORT Script {
@@ -79,11 +105,11 @@ struct Q_QML_EXPORT Script {
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, scope(scope), strictMode(false), inheritContext(false), parsed(false)
, vmFunction(0), parseAsBinding(false) {}
- Script(ExecutionEngine *engine, ObjectRef qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
+ Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, scope(engine->rootContext), strictMode(false), inheritContext(true), parsed(false)
- , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true) {}
- Script(ExecutionEngine *engine, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit);
+ , qml(qml->asReturnedValue()), vmFunction(0), parseAsBinding(true) {}
+ Script(ExecutionEngine *engine, Object *qml, CompiledData::CompilationUnit *compilationUnit);
~Script();
QString sourceFile;
int line;
@@ -106,7 +132,7 @@ struct Q_QML_EXPORT Script {
static QV4::CompiledData::CompilationUnit *precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0);
- static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject);
+ static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject);
};
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 89231cfe5f..b55cd2daad 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -58,13 +58,13 @@ using namespace QV4;
// helper function to generate valid warnings if errors occur during sequence operations.
static void generateWarning(QV4::ExecutionContext *ctx, const QString& description)
{
- QQmlEngine *engine = ctx->engine->v8Engine->engine();
+ QQmlEngine *engine = ctx->d()->engine->v8Engine->engine();
if (!engine)
return;
QQmlError retn;
retn.setDescription(description);
- QV4::StackFrame frame = ctx->engine->currentStackFrame();
+ QV4::StackFrame frame = ctx->d()->engine->currentStackFrame();
retn.setLine(frame.line);
retn.setUrl(QUrl(frame.source));
@@ -163,38 +163,41 @@ template <> bool convertValueToElement(const ValueRef value)
}
template <typename Container>
-class QQmlSequence : public QV4::Object
+struct QQmlSequence : public QV4::Object
{
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *engine, const Container &container)
+ : Object::Data(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject()))
+ , container(container)
+ , propertyIndex(-1)
+ , isReference(false)
+ {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QQmlSequence<Container> > o(scope, this);
+ o->setArrayType(ArrayData::Custom);
+ o->init();
+ }
+
+ Data(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex)
+ : Object::Data(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject()))
+ , object(object)
+ , propertyIndex(propertyIndex)
+ , isReference(true)
+ {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QQmlSequence<Container> > o(scope, this);
+ o->setArrayType(ArrayData::Custom);
+ o->loadReference();
+ o->init();
+ }
+ mutable Container container;
+ QPointer<QObject> object;
+ int propertyIndex;
+ bool isReference;
+ };
+ V4_OBJECT(QV4::Object)
Q_MANAGED_TYPE(QmlSequence)
public:
- QQmlSequence(QV4::ExecutionEngine *engine, const Container &container)
- : QV4::Object(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject()))
- , m_container(container)
- , m_object(0)
- , m_propertyIndex(-1)
- , m_isReference(false)
- {
- QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
- Q_UNUSED(protectThis);
- setArrayType(ArrayData::Custom);
- init();
- }
-
- QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex)
- : QV4::Object(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject()))
- , m_object(object)
- , m_propertyIndex(propertyIndex)
- , m_isReference(true)
- {
- QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
- Q_UNUSED(protectThis);
- setArrayType(ArrayData::Custom);
- loadReference();
- init();
- }
void init()
{
@@ -210,8 +213,8 @@ public:
*hasProperty = false;
return Encode::undefined();
}
- if (m_isReference) {
- if (!m_object) {
+ if (d()->isReference) {
+ if (!d()->object) {
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
@@ -219,10 +222,10 @@ public:
loadReference();
}
qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx < m_container.count()) {
+ if (signedIdx < d()->container.count()) {
if (hasProperty)
*hasProperty = true;
- return convertElementToValue(engine(), m_container.at(signedIdx));
+ return convertElementToValue(engine(), d()->container.at(signedIdx));
}
if (hasProperty)
*hasProperty = false;
@@ -231,7 +234,7 @@ public:
void containerPutIndexed(uint index, const QV4::ValueRef value)
{
- if (internalClass->engine->hasException)
+ if (internalClass()->engine->hasException)
return;
/* Qt containers have int (rather than uint) allowable indexes. */
@@ -240,33 +243,33 @@ public:
return;
}
- if (m_isReference) {
- if (!m_object)
+ if (d()->isReference) {
+ if (!d()->object)
return;
loadReference();
}
qint32 signedIdx = static_cast<qint32>(index);
- int count = m_container.count();
+ int count = d()->container.count();
typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
if (signedIdx == count) {
- m_container.append(element);
+ d()->container.append(element);
} else if (signedIdx < count) {
- m_container[signedIdx] = element;
+ d()->container[signedIdx] = element;
} else {
/* according to ECMA262r3 we need to insert */
/* the value at the given index, increasing length to index+1. */
- m_container.reserve(signedIdx + 1);
+ d()->container.reserve(signedIdx + 1);
while (signedIdx > count++) {
- m_container.append(typename Container::value_type());
+ d()->container.append(typename Container::value_type());
}
- m_container.append(element);
+ d()->container.append(element);
}
- if (m_isReference)
+ if (d()->isReference)
storeReference();
}
@@ -277,33 +280,33 @@ public:
generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed query"));
return QV4::Attr_Invalid;
}
- if (m_isReference) {
- if (!m_object)
+ if (d()->isReference) {
+ if (!d()->object)
return QV4::Attr_Invalid;
loadReference();
}
qint32 signedIdx = static_cast<qint32>(index);
- return (signedIdx < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ return (signedIdx < d()->container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
}
- void containerAdvanceIterator(ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs)
+ void containerAdvanceIterator(ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs)
{
name = (String *)0;
*index = UINT_MAX;
- if (m_isReference) {
- if (!m_object) {
+ if (d()->isReference) {
+ if (!d()->object) {
QV4::Object::advanceIterator(this, it, name, index, p, attrs);
return;
}
loadReference();
}
- if (it->arrayIndex < static_cast<uint>(m_container.count())) {
+ if (it->arrayIndex < static_cast<uint>(d()->container.count())) {
*index = it->arrayIndex;
++it->arrayIndex;
*attrs = QV4::Attr_Data;
- p->value = convertElementToValue(engine(), m_container.at(*index));
+ p->value = convertElementToValue(engine(), d()->container.at(*index));
return;
}
QV4::Object::advanceIterator(this, it, name, index, p, attrs);
@@ -314,21 +317,21 @@ public:
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX)
return false;
- if (m_isReference) {
- if (!m_object)
+ if (d()->isReference) {
+ if (!d()->object)
return false;
loadReference();
}
qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx >= m_container.count())
+ if (signedIdx >= d()->container.count())
return false;
/* according to ECMA262r3 it should be Undefined, */
/* but we cannot, so we insert a default-value instead. */
- m_container.replace(signedIdx, typename Container::value_type());
+ d()->container.replace(signedIdx, typename Container::value_type());
- if (m_isReference)
+ if (d()->isReference)
storeReference();
return true;
@@ -339,9 +342,9 @@ public:
QQmlSequence<Container> *otherSequence = other->as<QQmlSequence<Container> >();
if (!otherSequence)
return false;
- if (m_isReference && otherSequence->m_isReference) {
- return m_object == otherSequence->m_object && m_propertyIndex == otherSequence->m_propertyIndex;
- } else if (!m_isReference && !otherSequence->m_isReference) {
+ if (d()->isReference && otherSequence->d()->isReference) {
+ return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex;
+ } else if (!d()->isReference && !otherSequence->d()->isReference) {
return this == otherSequence;
}
return false;
@@ -366,9 +369,9 @@ public:
QV4::Scope scope(m_ctx);
ScopedObject compare(scope, m_compareFn);
ScopedCallData callData(scope, 2);
- callData->args[0] = convertElementToValue(this->m_ctx->engine, lhs);
- callData->args[1] = convertElementToValue(this->m_ctx->engine, rhs);
- callData->thisObject = this->m_ctx->engine->globalObject;
+ callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs);
+ callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs);
+ callData->thisObject = this->m_ctx->d()->engine->globalObject;
QV4::ScopedValue result(scope, compare->call(callData));
return result->toNumber() < 0;
}
@@ -380,82 +383,82 @@ public:
void sort(QV4::CallContext *ctx)
{
- if (m_isReference) {
- if (!m_object)
+ if (d()->isReference) {
+ if (!d()->object)
return;
loadReference();
}
QV4::Scope scope(ctx);
- if (ctx->callData->argc == 1 && ctx->callData->args[0].asFunctionObject()) {
- CompareFunctor cf(ctx, ctx->callData->args[0]);
- std::sort(m_container.begin(), m_container.end(), cf);
+ if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].asFunctionObject()) {
+ CompareFunctor cf(ctx, ctx->d()->callData->args[0]);
+ std::sort(d()->container.begin(), d()->container.end(), cf);
} else {
DefaultCompareFunctor cf;
- std::sort(m_container.begin(), m_container.end(), cf);
+ std::sort(d()->container.begin(), d()->container.end(), cf);
}
- if (m_isReference)
+ if (d()->isReference)
storeReference();
}
static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
return ctx->throwTypeError();
- if (This->m_isReference) {
- if (!This->m_object)
+ if (This->d()->isReference) {
+ if (!This->d()->object)
return QV4::Encode(0);
This->loadReference();
}
- return QV4::Encode(This->m_container.count());
+ return QV4::Encode(This->d()->container.count());
}
static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
return ctx->throwTypeError();
- quint32 newLength = ctx->callData->args[0].toUInt32();
+ quint32 newLength = ctx->d()->callData->args[0].toUInt32();
/* Qt containers have int (rather than uint) allowable indexes. */
if (newLength > INT_MAX) {
generateWarning(ctx, QLatin1String("Index out of range during length set"));
return QV4::Encode::undefined();
}
/* Read the sequence from the QObject property if we're a reference */
- if (This->m_isReference) {
- if (!This->m_object)
+ if (This->d()->isReference) {
+ if (!This->d()->object)
return QV4::Encode::undefined();
This->loadReference();
}
/* Determine whether we need to modify the sequence */
qint32 newCount = static_cast<qint32>(newLength);
- qint32 count = This->m_container.count();
+ qint32 count = This->d()->container.count();
if (newCount == count) {
return QV4::Encode::undefined();
} else if (newCount > count) {
/* according to ECMA262r3 we need to insert */
/* undefined values increasing length to newLength. */
/* We cannot, so we insert default-values instead. */
- This->m_container.reserve(newCount);
+ This->d()->container.reserve(newCount);
while (newCount > count++) {
- This->m_container.append(typename Container::value_type());
+ This->d()->container.append(typename Container::value_type());
}
} else {
/* according to ECMA262r3 we need to remove */
/* elements until the sequence is the required length. */
while (newCount < count) {
count--;
- This->m_container.removeAt(count);
+ This->d()->container.removeAt(count);
}
}
/* write back if required. */
- if (This->m_isReference) {
+ if (This->d()->isReference) {
/* write back. already checked that object is non-null, so skip that check here. */
This->storeReference();
}
@@ -463,9 +466,9 @@ public:
}
QVariant toVariant() const
- { return QVariant::fromValue<Container>(m_container); }
+ { return QVariant::fromValue<Container>(d()->container); }
- static QVariant toVariant(QV4::ArrayObjectRef array)
+ static QVariant toVariant(QV4::ArrayObject *array)
{
QV4::Scope scope(array->engine());
Container result;
@@ -479,27 +482,22 @@ public:
private:
void loadReference() const
{
- Q_ASSERT(m_object);
- Q_ASSERT(m_isReference);
- void *a[] = { &m_container, 0 };
- QMetaObject::metacall(m_object, QMetaObject::ReadProperty, m_propertyIndex, a);
+ Q_ASSERT(d()->object);
+ Q_ASSERT(d()->isReference);
+ void *a[] = { &d()->container, 0 };
+ QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a);
}
void storeReference()
{
- Q_ASSERT(m_object);
- Q_ASSERT(m_isReference);
+ Q_ASSERT(d()->object);
+ Q_ASSERT(d()->isReference);
int status = -1;
QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding;
- void *a[] = { &m_container, 0, &status, &flags };
- QMetaObject::metacall(m_object, QMetaObject::WriteProperty, m_propertyIndex, a);
+ void *a[] = { &d()->container, 0, &status, &flags };
+ QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
}
- mutable Container m_container;
- QPointer<QObject> m_object;
- int m_propertyIndex;
- bool m_isReference;
-
static QV4::ReturnedValue getIndexed(QV4::Managed *that, uint index, bool *hasProperty)
{ return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
static void putIndexed(Managed *that, uint index, const QV4::ValueRef value)
@@ -510,7 +508,7 @@ private:
{ return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index); }
static bool isEqualTo(Managed *that, Managed *other)
{ return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); }
- static void advanceIterator(Managed *that, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs)
+ static void advanceIterator(Managed *that, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs)
{ return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, p, attrs); }
static void destroy(Managed *that)
@@ -539,27 +537,22 @@ template<>
DEFINE_OBJECT_VTABLE(QQmlRealList);
#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>(#SequenceType);
-SequencePrototype::SequencePrototype(InternalClass *ic)
- : QV4::Object(ic)
-{
- FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
-}
-#undef REGISTER_QML_SEQUENCE_METATYPE
-
void SequencePrototype::init()
{
+ FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0);
}
+#undef REGISTER_QML_SEQUENCE_METATYPE
QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::ScopedObject o(scope, ctx->callData->thisObject);
+ QV4::ScopedObject o(scope, ctx->d()->callData->thisObject);
if (!o || !o->isListType())
return ctx->throwTypeError();
- if (ctx->callData->argc >= 2)
+ if (ctx->d()->callData->argc >= 2)
return o.asReturnedValue();
#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
@@ -587,7 +580,7 @@ bool SequencePrototype::isSequenceType(int sequenceTypeId)
#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::Scoped<QV4::Object> obj(scope, new (engine->memoryManager) QQml##ElementTypeName##List(engine, object, propertyIndex)); \
+ QV4::Scoped<QV4::Object> obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, object, propertyIndex)); \
return obj.asReturnedValue(); \
} else
@@ -605,7 +598,7 @@ ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int s
#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::Scoped<QV4::Object> obj(scope, new (engine->memoryManager) QQml##ElementTypeName##List(engine, v.value<SequenceType >())); \
+ QV4::Scoped<QV4::Object> obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, v.value<SequenceType >())); \
return obj.asReturnedValue(); \
} else
@@ -627,7 +620,7 @@ ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const
return list->toVariant(); \
else
-QVariant SequencePrototype::toVariant(ObjectRef object)
+QVariant SequencePrototype::toVariant(Object *object)
{
Q_ASSERT(object->isListType());
FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ return QVariant(); }
@@ -660,7 +653,7 @@ QVariant SequencePrototype::toVariant(const QV4::ValueRef array, int typeHint, b
return qMetaTypeId<SequenceType>(); \
} else
-int SequencePrototype::metaTypeForSequence(QV4::ObjectRef object)
+int SequencePrototype::metaTypeForSequence(QV4::Object *object)
{
FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE)
/*else*/ {
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 4a5e82b688..727f312930 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -65,13 +65,11 @@ namespace QV4 {
struct SequencePrototype : public QV4::Object
{
- SequencePrototype(QV4::InternalClass *ic);
-
void init();
static ReturnedValue method_valueOf(QV4::CallContext *ctx)
{
- return ctx->callData->thisObject.toString(ctx)->asReturnedValue();
+ return ctx->d()->callData->thisObject.toString(ctx)->asReturnedValue();
}
static ReturnedValue method_sort(QV4::CallContext *ctx);
@@ -79,8 +77,8 @@ struct SequencePrototype : public QV4::Object
static bool isSequenceType(int sequenceTypeId);
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded);
- static int metaTypeForSequence(ObjectRef object);
- static QVariant toVariant(QV4::ObjectRef object);
+ static int metaTypeForSequence(Object *object);
+ static QVariant toVariant(Object *object);
static QVariant toVariant(const ValueRef array, int typeHint, bool *succeeded);
};
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 3d754389a2..4e88a331a4 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -208,7 +208,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
} else if (QV4::DateObject *d = v->asDateObject()) {
reserve(data, sizeof(quint32) + sizeof(double));
push(data, valueheader(WorkerDate));
- push(data, d->value.asDouble());
+ push(data, d->date().asDouble());
} else if (v->as<RegExpObject>()) {
Scoped<RegExpObject> re(scope, v);
quint32 flags = re->flags();
@@ -281,7 +281,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
QV4::ExecutionContext *ctx = v4->currentContext();
str = s;
- val = o->get(str);
+ val = o->get(str.getPointer());
if (scope.hasException())
ctx->catchException();
@@ -342,7 +342,7 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine)
name = deserialize(data, engine);
value = deserialize(data, engine);
n = name.asReturnedValue();
- o->put(n, value);
+ o->put(n.getPointer(), value);
}
return o.asReturnedValue();
}
@@ -372,7 +372,7 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine)
QVariant var = qVariantFromValue(ref);
QV4::ScopedValue v(scope, engine->fromVariant((var)));
QV4::ScopedString s(scope, v4->newString(QStringLiteral("__qml:hidden:ref")));
- rv->asObject()->defineReadonlyProperty(s, v);
+ rv->asObject()->defineReadonlyProperty(s.getPointer(), v);
agent->release();
agent->setV8Engine(engine);
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index d9aa881f21..86995e48f9 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -108,7 +108,7 @@ static uint toArrayIndex(const char *ch, const char *end, bool *ok)
const ObjectVTable String::static_vtbl =
{
- DEFINE_MANAGED_VTABLE_INT(String),
+ DEFINE_MANAGED_VTABLE_INT(String, 0),
0,
0,
get,
@@ -133,13 +133,13 @@ void String::destroy(Managed *that)
void String::markObjects(Managed *that, ExecutionEngine *e)
{
String *s = static_cast<String *>(that);
- if (s->largestSubLength) {
- s->left->mark(e);
- s->right->mark(e);
+ if (s->d()->largestSubLength) {
+ s->d()->left->mark(e);
+ s->d()->right->mark(e);
}
}
-ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue String::get(Managed *m, String *name, bool *hasProperty)
{
ExecutionEngine *v4 = m->engine();
Scope scope(v4);
@@ -148,7 +148,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
if (name->equals(v4->id_length)) {
if (hasProperty)
*hasProperty = true;
- return Primitive::fromInt32(that->_text->size).asReturnedValue();
+ return Primitive::fromInt32(that->d()->text->size).asReturnedValue();
}
PropertyAttributes attrs;
Property *pd = v4->stringObjectClass->prototype->__getPropertyDescriptor__(name, &attrs);
@@ -168,7 +168,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
Scope scope(engine);
ScopedString that(scope, static_cast<String *>(m));
- if (index < static_cast<uint>(that->_text->size)) {
+ if (index < static_cast<uint>(that->d()->text->size)) {
if (hasProperty)
*hasProperty = true;
return Encode(engine->newString(that->toQString().mid(index, 1)));
@@ -185,7 +185,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
return engine->stringObjectClass->prototype->getValue(that, pd, attrs);
}
-void String::put(Managed *m, const StringRef name, const ValueRef value)
+void String::put(Managed *m, String *name, const ValueRef value)
{
Scope scope(m->engine());
if (scope.hasException())
@@ -206,7 +206,7 @@ void String::putIndexed(Managed *m, uint index, const ValueRef value)
o->putIndexed(index, value);
}
-PropertyAttributes String::query(const Managed *m, StringRef name)
+PropertyAttributes String::query(const Managed *m, String *name)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -217,10 +217,10 @@ PropertyAttributes String::query(const Managed *m, StringRef name)
PropertyAttributes String::queryIndexed(const Managed *m, uint index)
{
const String *that = static_cast<const String *>(m);
- return (index < static_cast<uint>(that->_text->size)) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
+ return (index < static_cast<uint>(that->d()->text->size)) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
}
-bool String::deleteProperty(Managed *, const StringRef)
+bool String::deleteProperty(Managed *, String *)
{
return false;
}
@@ -235,44 +235,50 @@ bool String::isEqualTo(Managed *t, Managed *o)
if (t == o)
return true;
- if (!o->internalClass->vtable->isString)
+ if (!o->internalClass()->vtable->isString)
return false;
String *that = static_cast<String *>(t);
String *other = static_cast<String *>(o);
if (that->hashValue() != other->hashValue())
return false;
- if (that->identifier && that->identifier == other->identifier)
+ if (that->identifier() && that->identifier() == other->identifier())
return true;
- if (that->subtype >= StringType_UInt && that->subtype == other->subtype)
+ if (that->subtype() >= StringType_UInt && that->subtype() == other->subtype())
return true;
return that->toQString() == other->toQString();
}
-String::String(ExecutionEngine *engine, const QString &text)
- : Managed(engine->stringClass), _text(const_cast<QString &>(text).data_ptr())
- , identifier(0), stringHash(UINT_MAX)
- , largestSubLength(0)
+String::Data::Data(ExecutionEngine *engine, const QString &t)
+ : Managed::Data(engine->stringClass)
{
- _text->ref.ref();
- len = _text->size;
subtype = StringType_Unknown;
+
+ text = const_cast<QString &>(t).data_ptr();
+ text->ref.ref();
+ identifier = 0;
+ stringHash = UINT_MAX;
+ largestSubLength = 0;
+ len = text->size;
}
-String::String(ExecutionEngine *engine, String *l, String *r)
- : Managed(engine->stringClass)
- , left(l), right(r)
- , stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength))
- , len(l->len + r->len)
+String::Data::Data(ExecutionEngine *engine, String *l, String *r)
+ : Managed::Data(engine->stringClass)
{
subtype = StringType_Unknown;
- if (!l->largestSubLength && l->len > largestSubLength)
- largestSubLength = l->len;
- if (!r->largestSubLength && r->len > largestSubLength)
- largestSubLength = r->len;
+ left = l;
+ right = r;
+ stringHash = UINT_MAX;
+ largestSubLength = qMax(l->d()->largestSubLength, r->d()->largestSubLength);
+ len = l->d()->len + r->d()->len;
+
+ if (!l->d()->largestSubLength && l->d()->len > largestSubLength)
+ largestSubLength = l->d()->len;
+ if (!r->d()->largestSubLength && r->d()->len > largestSubLength)
+ largestSubLength = r->d()->len;
// make sure we don't get excessive depth in our strings
if (len > 256 && len >= 2*largestSubLength)
@@ -283,10 +289,10 @@ uint String::toUInt(bool *ok) const
{
*ok = true;
- if (subtype == StringType_Unknown)
+ if (subtype() == StringType_Unknown)
createHashValue();
- if (subtype >= StringType_UInt)
- return stringHash;
+ if (subtype() >= StringType_UInt)
+ return d()->stringHash;
// ### this conversion shouldn't be required
double d = RuntimeHelpers::stringToNumber(toQString());
@@ -297,15 +303,15 @@ uint String::toUInt(bool *ok) const
return UINT_MAX;
}
-bool String::equals(const StringRef other) const
+bool String::equals(String *other) const
{
- if (this == other.getPointer())
+ if (this == other)
return true;
if (hashValue() != other->hashValue())
return false;
- if (identifier && identifier == other->identifier)
+ if (identifier() && identifier() == other->identifier())
return true;
- if (subtype >= StringType_UInt && subtype == other->subtype)
+ if (subtype() >= StringType_UInt && subtype() == other->subtype())
return true;
return toQString() == other->toQString();
@@ -313,52 +319,60 @@ bool String::equals(const StringRef other) const
void String::makeIdentifierImpl() const
{
- if (largestSubLength)
- simplifyString();
- Q_ASSERT(!largestSubLength);
+ if (d()->largestSubLength)
+ d()->simplifyString();
+ Q_ASSERT(!d()->largestSubLength);
engine()->identifierTable->identifier(this);
}
-void String::simplifyString() const
+void String::Data::simplifyString() const
{
Q_ASSERT(largestSubLength);
int l = length();
QString result(l, Qt::Uninitialized);
QChar *ch = const_cast<QChar *>(result.constData());
- recursiveAppend(ch);
- _text = result.data_ptr();
- _text->ref.ref();
+ append(this, ch);
+ text = result.data_ptr();
+ text->ref.ref();
identifier = 0;
largestSubLength = 0;
}
-QChar *String::recursiveAppend(QChar *ch) const
+void String::Data::append(const String::Data *data, QChar *ch)
{
- if (largestSubLength) {
- ch = left->recursiveAppend(ch);
- ch = right->recursiveAppend(ch);
- } else {
- memcpy(ch, _text->data(), _text->size*sizeof(QChar));
- ch += _text->size;
+ std::vector<const String::Data *> worklist;
+ worklist.reserve(32);
+ worklist.push_back(data);
+
+ while (!worklist.empty()) {
+ const String::Data *item = worklist.back();
+ worklist.pop_back();
+
+ if (item->largestSubLength) {
+ worklist.push_back(item->right->d());
+ worklist.push_back(item->left->d());
+ } else {
+ memcpy(ch, item->text->data(), item->text->size * sizeof(QChar));
+ ch += item->text->size;
+ }
}
- return ch;
}
void String::createHashValue() const
{
- if (largestSubLength)
- simplifyString();
- Q_ASSERT(!largestSubLength);
- const QChar *ch = reinterpret_cast<const QChar *>(_text->data());
- const QChar *end = ch + _text->size;
+ if (d()->largestSubLength)
+ d()->simplifyString();
+ Q_ASSERT(!d()->largestSubLength);
+ const QChar *ch = reinterpret_cast<const QChar *>(d()->text->data());
+ const QChar *end = ch + d()->text->size;
// array indices get their number as hash value
bool ok;
- stringHash = ::toArrayIndex(ch, end, &ok);
+ d()->stringHash = ::toArrayIndex(ch, end, &ok);
if (ok) {
- subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex;
+ setSubtype((d()->stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex);
return;
}
@@ -368,8 +382,8 @@ void String::createHashValue() const
++ch;
}
- stringHash = h;
- subtype = StringType_Regular;
+ d()->stringHash = h;
+ setSubtype(StringType_Regular);
}
uint String::createHashValue(const QChar *ch, int length)
@@ -414,7 +428,7 @@ uint String::createHashValue(const char *ch, int length)
uint String::getLength(const Managed *m)
{
- return static_cast<const String *>(m)->length();
+ return static_cast<const String *>(m)->d()->length();
}
#endif // V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index ed2a4e3646..082f296f48 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -53,8 +53,36 @@ struct Identifier;
struct Q_QML_PRIVATE_EXPORT String : public Managed {
#ifndef V4_BOOTSTRAP
+ struct Q_QML_PRIVATE_EXPORT Data : Managed::Data {
+ Data(ExecutionEngine *engine, const QString &text);
+ Data(ExecutionEngine *engine, String *l, String *n);
+ ~Data() {
+ if (!largestSubLength && !text->ref.deref())
+ QStringData::deallocate(text);
+ }
+ void simplifyString() const;
+ int length() const {
+ Q_ASSERT((largestSubLength &&
+ (len == left->d()->len + right->d()->len)) ||
+ len == (uint)text->size);
+ return len;
+ }
+ union {
+ mutable QStringData *text;
+ mutable String *left;
+ };
+ union {
+ mutable Identifier *identifier;
+ mutable String *right;
+ };
+ mutable uint stringHash;
+ mutable uint largestSubLength;
+ uint len;
+ private:
+ static void append(const Data *data, QChar *ch);
+ };
// ### FIXME: Should this be a V4_OBJECT
- V4_OBJECT
+ V4_OBJECT(QV4::Managed)
Q_MANAGED_TYPE(String)
enum {
IsString = true
@@ -67,24 +95,16 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
StringType_ArrayIndex
};
- String(ExecutionEngine *engine, const QString &text);
- String(ExecutionEngine *engine, String *l, String *n);
- ~String() {
- if (!largestSubLength && !_text->ref.deref())
- QStringData::deallocate(_text);
- _data = 0;
- }
-
- bool equals(const StringRef other) const;
+ bool equals(String *other) const;
inline bool isEqualTo(const String *other) const {
if (this == other)
return true;
if (hashValue() != other->hashValue())
return false;
- Q_ASSERT(!largestSubLength);
- if (identifier && identifier == other->identifier)
+ Q_ASSERT(!d()->largestSubLength);
+ if (d()->identifier && d()->identifier == other->d()->identifier)
return true;
- if (subtype >= StringType_UInt && subtype == other->subtype)
+ if (subtype() >= StringType_UInt && subtype() == other->subtype())
return true;
return toQString() == other->toQString();
@@ -95,34 +115,32 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
}
inline QString toQString() const {
- if (largestSubLength)
- simplifyString();
- QStringDataPtr ptr = { _text };
- _text->ref.ref();
+ if (d()->largestSubLength)
+ d()->simplifyString();
+ QStringDataPtr ptr = { d()->text };
+ d()->text->ref.ref();
return QString(ptr);
}
- void simplifyString() const;
-
inline unsigned hashValue() const {
- if (subtype == StringType_Unknown)
+ if (subtype() == StringType_Unknown)
createHashValue();
- Q_ASSERT(!largestSubLength);
+ Q_ASSERT(!d()->largestSubLength);
- return stringHash;
+ return d()->stringHash;
}
uint asArrayIndex() const {
- if (subtype == StringType_Unknown)
+ if (subtype() == StringType_Unknown)
createHashValue();
- Q_ASSERT(!largestSubLength);
- if (subtype == StringType_ArrayIndex)
- return stringHash;
+ Q_ASSERT(!d()->largestSubLength);
+ if (subtype() == StringType_ArrayIndex)
+ return d()->stringHash;
return UINT_MAX;
}
uint toUInt(bool *ok) const;
void makeIdentifier() const {
- if (identifier)
+ if (d()->identifier)
return;
makeIdentifierImpl();
}
@@ -135,44 +153,26 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
bool startsWithUpper() const {
const String *l = this;
- while (l->largestSubLength)
- l = l->left;
- return l->_text->size && QChar::isUpper(l->_text->data()[0]);
- }
- int length() const {
- Q_ASSERT((largestSubLength && (len == left->len + right->len)) || len == (uint)_text->size);
- return len;
+ while (l->d()->largestSubLength)
+ l = l->d()->left;
+ return l->d()->text->size && QChar::isUpper(l->d()->text->data()[0]);
}
- union {
- mutable QStringData *_text;
- mutable String *left;
- };
- union {
- mutable Identifier *identifier;
- mutable String *right;
- };
- mutable uint stringHash;
- mutable uint largestSubLength;
- uint len;
-
+ Identifier *identifier() const { return d()->identifier; }
protected:
static void destroy(Managed *);
static void markObjects(Managed *that, ExecutionEngine *e);
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
+ static void put(Managed *m, String *name, const ValueRef value);
static void putIndexed(Managed *m, uint index, const ValueRef value);
- static PropertyAttributes query(const Managed *m, StringRef name);
+ static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static bool deleteProperty(Managed *, const StringRef);
+ static bool deleteProperty(Managed *, String *);
static bool deleteIndexedProperty(Managed *m, uint index);
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
-
-private:
- QChar *recursiveAppend(QChar *ch) const;
#endif
public:
@@ -191,7 +191,6 @@ inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
return v.toString(e)->asReturnedValue();
}
-DEFINE_REF(String, Managed);
#endif
}
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index f1e51703a8..3f683495cd 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -77,44 +77,38 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(StringObject);
-StringObject::StringObject(InternalClass *ic)
- : Object(ic)
+StringObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
Q_ASSERT(internalClass->vtable == staticVTable());
-
- Scope scope(engine());
- ScopedObject protectThis(scope, this);
-
value = ic->engine->newString(QStringLiteral(""))->asReturnedValue();
-
tmpProperty.value = Primitive::undefinedValue();
- defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0));
+ Scope scope(ic->engine);
+ ScopedObject s(scope, this);
+ s->defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0));
}
-StringObject::StringObject(ExecutionEngine *engine, const ValueRef val)
- : Object(engine->stringObjectClass)
+StringObject::Data::Data(ExecutionEngine *engine, const ValueRef val)
+ : Object::Data(engine->stringObjectClass)
{
+ value = val;
+ Q_ASSERT(value.isString());
+ tmpProperty.value = Primitive::undefinedValue();
setVTable(staticVTable());
Scope scope(engine);
- ScopedObject protectThis(scope, this);
-
- value = *val;
-
- tmpProperty.value = Primitive::undefinedValue();
-
- assert(value.isString());
- defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length()));
+ ScopedObject s(scope, this);
+ s->defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length()));
}
Property *StringObject::getIndex(uint index) const
{
- QString str = value.stringValue()->toQString();
+ QString str = d()->value.stringValue()->toQString();
if (index >= (uint)str.length())
return 0;
- tmpProperty.value = Encode(internalClass->engine->newString(str.mid(index, 1)));
- return &tmpProperty;
+ d()->tmpProperty.value = Encode(internalClass()->engine->newString(str.mid(index, 1)));
+ return &d()->tmpProperty;
}
bool StringObject::deleteIndexedProperty(Managed *m, uint index)
@@ -127,19 +121,19 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index)
return false;
}
- if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) {
- if (v4->currentContext()->strictMode)
+ if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) {
+ if (v4->currentContext()->d()->strictMode)
v4->currentContext()->throwTypeError();
return false;
}
return true;
}
-void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs)
+void StringObject::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs)
{
name = (String *)0;
StringObject *s = static_cast<StringObject *>(m);
- uint slen = s->value.stringValue()->toQString().length();
+ uint slen = s->d()->value.stringValue()->toQString().length();
if (it->arrayIndex <= slen) {
while (it->arrayIndex < slen) {
*index = it->arrayIndex;
@@ -152,7 +146,7 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef nam
return;
}
}
- if (s->arrayData) {
+ if (s->arrayData()) {
it->arrayNode = s->sparseBegin();
// iterate until we're past the end of the string
while (it->arrayNode && it->arrayNode->key() < slen)
@@ -166,15 +160,15 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef nam
void StringObject::markObjects(Managed *that, ExecutionEngine *e)
{
StringObject *o = static_cast<StringObject *>(that);
- o->value.stringValue()->mark(e);
- o->tmpProperty.value.mark(e);
+ o->d()->value.stringValue()->mark(e);
+ o->d()->tmpProperty.value.mark(e);
Object::markObjects(that, e);
}
DEFINE_OBJECT_VTABLE(StringCtor);
-StringCtor::StringCtor(ExecutionContext *scope)
- : FunctionObject(scope, QStringLiteral("String"))
+StringCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("String"))
{
setVTable(staticVTable());
}
@@ -203,7 +197,7 @@ ReturnedValue StringCtor::call(Managed *m, CallData *callData)
return value.asReturnedValue();
}
-void StringPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
+void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
@@ -238,11 +232,11 @@ void StringPrototype::init(ExecutionEngine *engine, ObjectRef ctor)
static QString getThisString(ExecutionContext *ctx)
{
Scope scope(ctx);
- ScopedValue t(scope, ctx->callData->thisObject);
+ ScopedValue t(scope, ctx->d()->callData->thisObject);
if (t->isString())
return t->stringValue()->toQString();
if (StringObject *thisString = t->asStringObject())
- return thisString->value.stringValue()->toQString();
+ return thisString->d()->value.stringValue()->toQString();
if (t->isUndefined() || t->isNull()) {
ctx->throwTypeError();
return QString();
@@ -252,41 +246,41 @@ static QString getThisString(ExecutionContext *ctx)
ReturnedValue StringPrototype::method_toString(CallContext *context)
{
- if (context->callData->thisObject.isString())
- return context->callData->thisObject.asReturnedValue();
+ if (context->d()->callData->thisObject.isString())
+ return context->d()->callData->thisObject.asReturnedValue();
- StringObject *o = context->callData->thisObject.asStringObject();
+ StringObject *o = context->d()->callData->thisObject.asStringObject();
if (!o)
return context->throwTypeError();
- return o->value.asReturnedValue();
+ return o->d()->value.asReturnedValue();
}
ReturnedValue StringPrototype::method_charAt(CallContext *context)
{
const QString str = getThisString(context);
- if (context->engine->hasException)
+ if (context->d()->engine->hasException)
return Encode::undefined();
int pos = 0;
- if (context->callData->argc > 0)
- pos = (int) context->callData->args[0].toInteger();
+ if (context->d()->callData->argc > 0)
+ pos = (int) context->d()->callData->args[0].toInteger();
QString result;
if (pos >= 0 && pos < str.length())
result += str.at(pos);
- return context->engine->newString(result)->asReturnedValue();
+ return context->d()->engine->newString(result)->asReturnedValue();
}
ReturnedValue StringPrototype::method_charCodeAt(CallContext *context)
{
const QString str = getThisString(context);
- if (context->engine->hasException)
+ if (context->d()->engine->hasException)
return Encode::undefined();
int pos = 0;
- if (context->callData->argc > 0)
- pos = (int) context->callData->args[0].toInteger();
+ if (context->d()->callData->argc > 0)
+ pos = (int) context->d()->callData->args[0].toInteger();
if (pos >= 0 && pos < str.length())
@@ -304,30 +298,30 @@ ReturnedValue StringPrototype::method_concat(CallContext *context)
return Encode::undefined();
ScopedValue v(scope);
- for (int i = 0; i < context->callData->argc; ++i) {
- v = RuntimeHelpers::toString(context, ValueRef(&context->callData->args[i]));
+ for (int i = 0; i < context->d()->callData->argc; ++i) {
+ v = RuntimeHelpers::toString(context, ValueRef(&context->d()->callData->args[i]));
if (scope.hasException())
return Encode::undefined();
Q_ASSERT(v->isString());
value += v->stringValue()->toQString();
}
- return context->engine->newString(value)->asReturnedValue();
+ return context->d()->engine->newString(value)->asReturnedValue();
}
ReturnedValue StringPrototype::method_indexOf(CallContext *context)
{
QString value = getThisString(context);
- if (context->engine->hasException)
+ if (context->d()->engine->hasException)
return Encode::undefined();
QString searchString;
- if (context->callData->argc)
- searchString = context->callData->args[0].toString(context)->toQString();
+ if (context->d()->callData->argc)
+ searchString = context->d()->callData->args[0].toString(context)->toQString();
int pos = 0;
- if (context->callData->argc > 1)
- pos = (int) context->callData->args[1].toInteger();
+ if (context->d()->callData->argc > 1)
+ pos = (int) context->d()->callData->args[1].toInteger();
int index = -1;
if (! value.isEmpty())
@@ -345,8 +339,8 @@ ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
return Encode::undefined();
QString searchString;
- if (context->callData->argc)
- searchString = context->callData->args[0].toQString();
+ if (context->d()->callData->argc)
+ searchString = context->d()->callData->args[0].toQString();
ScopedValue posArg(scope, context->argument(1));
double position = RuntimeHelpers::toNumber(posArg);
@@ -371,36 +365,36 @@ ReturnedValue StringPrototype::method_localeCompare(CallContext *context)
if (scope.engine->hasException)
return Encode::undefined();
- ScopedValue v(scope, context->callData->argument(0));
+ ScopedValue v(scope, context->d()->callData->argument(0));
const QString that = v->toQString();
return Encode(QString::localeAwareCompare(value, that));
}
ReturnedValue StringPrototype::method_match(CallContext *context)
{
- if (context->callData->thisObject.isUndefined() || context->callData->thisObject.isNull())
+ if (context->d()->callData->thisObject.isUndefined() || context->d()->callData->thisObject.isNull())
return context->throwTypeError();
Scope scope(context);
- ScopedString s(scope, context->callData->thisObject.toString(context));
+ ScopedString s(scope, context->d()->callData->thisObject.toString(context));
- ScopedValue regexp(scope, context->callData->argument(0));
+ ScopedValue regexp(scope, context->d()->callData->argument(0));
Scoped<RegExpObject> rx(scope, regexp);
if (!rx) {
ScopedCallData callData(scope, 1);
callData->args[0] = regexp;
- rx = context->engine->regExpCtor.asFunctionObject()->construct(callData);
+ rx = context->d()->engine->regExpCtor.asFunctionObject()->construct(callData);
}
if (!rx)
// ### CHECK
return context->throwTypeError();
- bool global = rx->global;
+ bool global = rx->global();
// ### use the standard builtin function, not the one that might be redefined in the proto
- ScopedString execString(scope, context->engine->newString(QStringLiteral("exec")));
- Scoped<FunctionObject> exec(scope, context->engine->regExpClass->prototype->get(execString));
+ ScopedString execString(scope, context->d()->engine->newString(QStringLiteral("exec")));
+ Scoped<FunctionObject> exec(scope, context->d()->engine->regExpClass->prototype->get(execString.getPointer()));
ScopedCallData callData(scope, 1);
callData->thisObject = rx;
@@ -408,9 +402,9 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
if (!global)
return exec->call(callData);
- ScopedString lastIndex(scope, context->engine->newString(QStringLiteral("lastIndex")));
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
- Scoped<ArrayObject> a(scope, context->engine->newArrayObject());
+ ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex")));
+ rx->put(lastIndex.getPointer(), ScopedValue(scope, Primitive::fromInt32(0)));
+ Scoped<ArrayObject> a(scope, context->d()->engine->newArrayObject());
double previousLastIndex = 0;
uint n = 0;
@@ -422,11 +416,11 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
if (result->isNull())
break;
assert(result->isObject());
- index = rx->get(lastIndex, 0);
+ index = rx->get(lastIndex.getPointer(), 0);
double thisIndex = index->toInteger();
if (previousLastIndex == thisIndex) {
previousLastIndex = thisIndex + 1;
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromDouble(previousLastIndex)));
+ rx->put(lastIndex.getPointer(), ScopedValue(scope, Primitive::fromDouble(previousLastIndex)));
} else {
previousLastIndex = thisIndex;
}
@@ -491,10 +485,10 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
{
Scope scope(ctx);
QString string;
- if (StringObject *thisString = ctx->callData->thisObject.asStringObject())
- string = thisString->value.stringValue()->toQString();
+ if (StringObject *thisString = ctx->d()->callData->thisObject.asStringObject())
+ string = thisString->d()->value.stringValue()->toQString();
else
- string = ctx->callData->thisObject.toString(ctx)->toQString();
+ string = ctx->d()->callData->thisObject.toString(ctx)->toQString();
int numCaptures = 0;
int numStringMatches = 0;
@@ -510,7 +504,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint offset = 0;
// We extract the pointer here to work around a compiler bug on Android.
- Scoped<RegExp> re(scope, regExp->value);
+ Scoped<RegExp> re(scope, regExp->value());
while (true) {
int oldSize = nMatchOffsets;
if (allocatedMatchOffsets < nMatchOffsets + re->captureCount() * 2) {
@@ -526,14 +520,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
break;
}
nMatchOffsets += re->captureCount() * 2;
- if (!regExp->global)
+ if (!regExp->d()->global)
break;
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
- if (regExp->global)
+ if (regExp->global())
regExp->lastIndexProperty(ctx)->value = Primitive::fromUInt32(0);
- numStringMatches = nMatchOffsets / (regExp->value->captureCount() * 2);
- numCaptures = regExp->value->captureCount();
+ numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2);
+ numCaptures = regExp->value()->captureCount();
} else {
numCaptures = 1;
QString searchString = searchValue->toString(ctx)->toQString();
@@ -563,14 +557,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint end = matchOffsets[idx + 1];
entry = Primitive::undefinedValue();
if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch)
- entry = ctx->engine->newString(string.mid(start, end - start));
+ entry = ctx->d()->engine->newString(string.mid(start, end - start));
callData->args[k] = entry;
}
uint matchStart = matchOffsets[i * numCaptures * 2];
Q_ASSERT(matchStart >= static_cast<uint>(lastEnd));
uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
- callData->args[numCaptures + 1] = ctx->engine->newString(string);
+ callData->args[numCaptures + 1] = ctx->d()->engine->newString(string);
replacement = searchCallback->call(callData);
result += string.midRef(lastEnd, matchStart - lastEnd);
@@ -600,7 +594,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
if (matchOffsets != _matchOffsets)
free(matchOffsets);
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
ReturnedValue StringPrototype::method_search(CallContext *ctx)
@@ -614,14 +608,14 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
if (!regExp) {
ScopedCallData callData(scope, 1);
callData->args[0] = regExpValue;
- regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(callData);
+ regExpValue = ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData);
if (scope.engine->hasException)
return Encode::undefined();
regExp = regExpValue->as<RegExpObject>();
Q_ASSERT(regExp);
}
- uint* matchOffsets = (uint*)alloca(regExp->value->captureCount() * 2 * sizeof(uint));
- uint result = regExp->value->match(string, /*offset*/0, matchOffsets);
+ uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint));
+ uint result = regExp->value()->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
return Encode(-1);
return Encode(result);
@@ -630,14 +624,14 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
ReturnedValue StringPrototype::method_slice(CallContext *ctx)
{
const QString text = getThisString(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
const double length = text.length();
- double start = ctx->callData->argc ? ctx->callData->args[0].toInteger() : 0;
- double end = (ctx->callData->argc < 2 || ctx->callData->args[1].isUndefined())
- ? length : ctx->callData->args[1].toInteger();
+ double start = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toInteger() : 0;
+ double end = (ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined())
+ ? length : ctx->d()->callData->args[1].toInteger();
if (start < 0)
start = qMax(length + start, 0.);
@@ -653,7 +647,7 @@ ReturnedValue StringPrototype::method_slice(CallContext *ctx)
const int intEnd = int(end);
int count = qMax(0, intEnd - intStart);
- return ctx->engine->newString(text.mid(intStart, count))->asReturnedValue();
+ return ctx->d()->engine->newString(text.mid(intStart, count))->asReturnedValue();
}
ReturnedValue StringPrototype::method_split(CallContext *ctx)
@@ -666,15 +660,15 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
ScopedValue separatorValue(scope, ctx->argument(0));
ScopedValue limitValue(scope, ctx->argument(1));
- ScopedArrayObject array(scope, ctx->engine->newArrayObject());
+ ScopedArrayObject array(scope, ctx->d()->engine->newArrayObject());
if (separatorValue->isUndefined()) {
if (limitValue->isUndefined()) {
- ScopedString s(scope, ctx->engine->newString(text));
+ ScopedString s(scope, ctx->d()->engine->newString(text));
array->push_back(s);
return array.asReturnedValue();
}
- return ctx->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue();
+ return ctx->d()->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue();
}
uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32();
@@ -684,55 +678,55 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
Scoped<RegExpObject> re(scope, separatorValue);
if (re) {
- if (re->value->pattern().isEmpty()) {
+ if (re->value()->pattern().isEmpty()) {
re = (RegExpObject *)0;
- separatorValue = ctx->engine->newString(QString());
+ separatorValue = ctx->d()->engine->newString(QString());
}
}
ScopedString s(scope);
if (re) {
uint offset = 0;
- uint* matchOffsets = (uint*)alloca(re->value->captureCount() * 2 * sizeof(uint));
+ uint* matchOffsets = (uint*)alloca(re->value()->captureCount() * 2 * sizeof(uint));
while (true) {
- uint result = re->value->match(text, offset, matchOffsets);
+ uint result = re->value()->match(text, offset, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
break;
- array->push_back((s = ctx->engine->newString(text.mid(offset, matchOffsets[0] - offset))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(offset, matchOffsets[0] - offset))));
offset = qMax(offset + 1, matchOffsets[1]);
if (array->getLength() >= limit)
break;
- for (int i = 1; i < re->value->captureCount(); ++i) {
+ for (int i = 1; i < re->value()->captureCount(); ++i) {
uint start = matchOffsets[i * 2];
uint end = matchOffsets[i * 2 + 1];
- array->push_back((s = ctx->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
if (array->getLength() >= limit)
break;
}
}
if (array->getLength() < limit)
- array->push_back((s = ctx->engine->newString(text.mid(offset))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(offset))));
} else {
QString separator = separatorValue->toString(ctx)->toQString();
if (separator.isEmpty()) {
for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
- array->push_back((s = ctx->engine->newString(text.mid(i, 1))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1))));
return array.asReturnedValue();
}
int start = 0;
int end;
while ((end = text.indexOf(separator, start)) != -1) {
- array->push_back((s = ctx->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
start = end + separator.size();
if (array->getLength() >= limit)
break;
}
if (array->getLength() < limit && start != -1)
- array->push_back((s = ctx->engine->newString(text.mid(start))));
+ array->push_back((s = ctx->d()->engine->newString(text.mid(start))));
}
return array.asReturnedValue();
}
@@ -740,16 +734,16 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
ReturnedValue StringPrototype::method_substr(CallContext *context)
{
const QString value = getThisString(context);
- if (context->engine->hasException)
+ if (context->d()->engine->hasException)
return Encode::undefined();
double start = 0;
- if (context->callData->argc > 0)
- start = context->callData->args[0].toInteger();
+ if (context->d()->callData->argc > 0)
+ start = context->d()->callData->args[0].toInteger();
double length = +qInf();
- if (context->callData->argc > 1)
- length = context->callData->args[1].toInteger();
+ if (context->d()->callData->argc > 1)
+ length = context->d()->callData->args[1].toInteger();
double count = value.length();
if (start < 0)
@@ -759,21 +753,21 @@ ReturnedValue StringPrototype::method_substr(CallContext *context)
qint32 x = Primitive::toInt32(start);
qint32 y = Primitive::toInt32(length);
- return context->engine->newString(value.mid(x, y))->asReturnedValue();
+ return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
}
ReturnedValue StringPrototype::method_substring(CallContext *context)
{
QString value = getThisString(context);
- if (context->engine->hasException)
+ if (context->d()->engine->hasException)
return Encode::undefined();
int length = value.length();
double start = 0;
double end = length;
- if (context->callData->argc > 0)
- start = context->callData->args[0].toInteger();
+ if (context->d()->callData->argc > 0)
+ start = context->d()->callData->args[0].toInteger();
Scope scope(context);
ScopedValue endValue(scope, context->argument(1));
@@ -800,15 +794,15 @@ ReturnedValue StringPrototype::method_substring(CallContext *context)
qint32 x = (int)start;
qint32 y = (int)(end - start);
- return context->engine->newString(value.mid(x, y))->asReturnedValue();
+ return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
}
ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx)
{
QString value = getThisString(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
- return ctx->engine->newString(value.toLower())->asReturnedValue();
+ return ctx->d()->engine->newString(value.toLower())->asReturnedValue();
}
ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx)
@@ -819,9 +813,9 @@ ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx)
ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx)
{
QString value = getThisString(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
- return ctx->engine->newString(value.toUpper())->asReturnedValue();
+ return ctx->d()->engine->newString(value.toUpper())->asReturnedValue();
}
ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx)
@@ -831,19 +825,19 @@ ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx)
ReturnedValue StringPrototype::method_fromCharCode(CallContext *context)
{
- QString str(context->callData->argc, Qt::Uninitialized);
+ QString str(context->d()->callData->argc, Qt::Uninitialized);
QChar *ch = str.data();
- for (int i = 0; i < context->callData->argc; ++i) {
- *ch = QChar(context->callData->args[i].toUInt16());
+ for (int i = 0; i < context->d()->callData->argc; ++i) {
+ *ch = QChar(context->d()->callData->args[i].toUInt16());
++ch;
}
- return context->engine->newString(str)->asReturnedValue();
+ return context->d()->engine->newString(str)->asReturnedValue();
}
ReturnedValue StringPrototype::method_trim(CallContext *ctx)
{
QString s = getThisString(ctx);
- if (ctx->engine->hasException)
+ if (ctx->d()->engine->hasException)
return Encode::undefined();
const QChar *chars = s.constData();
@@ -857,5 +851,5 @@ ReturnedValue StringPrototype::method_trim(CallContext *ctx)
break;
}
- return ctx->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue();
+ return ctx->d()->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index c38fd5b75f..0fc556f849 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -50,27 +50,32 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct StringObject: Object {
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, const ValueRef value);
+ Data(InternalClass *ic);
+ Value value;
+ // ### get rid of tmpProperty
+ mutable Property tmpProperty;
+ };
+ V4_OBJECT(Object)
Q_MANAGED_TYPE(StringObject)
- Value value;
- mutable Property tmpProperty;
- StringObject(ExecutionEngine *engine, const ValueRef value);
Property *getIndex(uint index) const;
static bool deleteIndexedProperty(Managed *m, uint index);
protected:
- StringObject(InternalClass *ic);
- static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs);
+ static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs);
static void markObjects(Managed *that, ExecutionEngine *e);
};
struct StringCtor: FunctionObject
{
- V4_OBJECT
- StringCtor(ExecutionContext *scope);
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+ V4_OBJECT(FunctionObject)
static ReturnedValue construct(Managed *m, CallData *callData);
static ReturnedValue call(Managed *that, CallData *callData);
@@ -78,8 +83,7 @@ struct StringCtor: FunctionObject
struct StringPrototype: StringObject
{
- StringPrototype(InternalClass *ic): StringObject(ic) {}
- void init(ExecutionEngine *engine, ObjectRef ctor);
+ void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_toString(CallContext *context);
static ReturnedValue method_charAt(CallContext *context);
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index e9246f7a14..e122b18892 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -95,7 +95,7 @@ double Value::toNumberImpl() const
if (isString())
return RuntimeHelpers::stringToNumber(stringValue()->toQString());
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
+ ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), NUMBER_HINT));
return prim->toNumber();
@@ -129,7 +129,7 @@ QString Value::toQStringNoThrow() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
+ ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext();
Scope scope(ctx);
ScopedValue ex(scope);
bool caughtException = false;
@@ -182,7 +182,7 @@ QString Value::toQString() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
+ ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), STRING_HINT));
return prim->toQString();
diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h
index 1fe9e1c165..84a8e1adf2 100644
--- a/src/qml/jsruntime/qv4value_inl_p.h
+++ b/src/qml/jsruntime/qv4value_inl_p.h
@@ -64,13 +64,13 @@ inline bool Value::isString() const
{
if (!isManaged())
return false;
- return managed() && managed()->internalClass->vtable->isString;
+ return managed() && managed()->internalClass()->vtable->isString;
}
inline bool Value::isObject() const
{
if (!isManaged())
return false;
- return managed() && managed()->internalClass->vtable->isObject;
+ return managed() && managed()->internalClass()->vtable->isObject;
}
inline bool Value::isPrimitive() const
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 29cb8b42ed..7b49db74d9 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -64,6 +64,8 @@ struct Returned : private T
using T::asReturnedValue;
};
+struct HeapObject {};
+
struct Q_QML_PRIVATE_EXPORT Value
{
/*
@@ -347,6 +349,10 @@ struct Q_QML_PRIVATE_EXPORT Value
val = Value::fromManaged(t).val;
return *this;
}
+ Value &operator=(HeapObject *o) {
+ m = reinterpret_cast<Managed *>(o);
+ return *this;
+ }
template<typename T>
Value &operator=(const Scoped<T> &t);
@@ -430,7 +436,10 @@ struct TypedValue : public Value
{
template<typename X>
TypedValue &operator =(X *x) {
- val = Value::fromManaged(x).val;
+ m = x;
+#if QT_POINTER_SIZE == 4
+ tag = Managed_Type;
+#endif
}
TypedValue &operator =(T *t);
TypedValue &operator =(const Scoped<T> &v);
@@ -441,6 +450,7 @@ struct TypedValue : public Value
bool operator!() const { return !managed(); }
+ operator T *() { return static_cast<T *>(managed()); }
T *operator->() { return static_cast<T *>(managed()); }
const T *operator->() const { return static_cast<T *>(managed()); }
T *getPointer() const { return static_cast<T *>(managed()); }
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 92cc19d8b9..a5b22a2de8 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -51,18 +51,15 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(VariantObject);
-VariantObject::VariantObject(InternalClass *ic)
- : Object(ic)
- , ExecutionEngine::ScarceResourceData(QVariant())
- , m_vmePropertyReferenceCount(0)
+VariantObject::Data::Data(InternalClass *ic)
+ : Object::Data(ic)
{
}
-VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
- : Object(engine->variantClass)
- , ExecutionEngine::ScarceResourceData(value)
- , m_vmePropertyReferenceCount(0)
+VariantObject::Data::Data(ExecutionEngine *engine, const QVariant &value)
+ : Object::Data(engine->variantClass)
{
+ data = value;
if (isScarce())
engine->scarceResources.insert(this);
}
@@ -89,7 +86,7 @@ QVariant VariantObject::toVariant(const QV4::ValueRef v)
return QVariant();
}
-bool VariantObject::isScarce() const
+bool VariantObject::Data::isScarce() const
{
QVariant::Type t = data.type();
return t == QVariant::Pixmap || t == QVariant::Image;
@@ -98,9 +95,7 @@ bool VariantObject::isScarce() const
void VariantObject::destroy(Managed *that)
{
VariantObject *v = static_cast<VariantObject *>(that);
- if (v->isScarce())
- v->node.remove();
- v->~VariantObject();
+ v->d()->~Data();
}
bool VariantObject::isEqualTo(Managed *m, Managed *other)
@@ -109,40 +104,35 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other)
assert(lv);
if (QV4::VariantObject *rv = other->as<QV4::VariantObject>())
- return lv->data == rv->data;
+ return lv->d()->data == rv->d()->data;
if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>())
- return v->isEqual(lv->data);
+ return v->isEqual(lv->d()->data);
return false;
}
void VariantObject::addVmePropertyReference()
{
- if (isScarce() && ++m_vmePropertyReferenceCount == 1) {
+ if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
// remove from the ep->scarceResources list
// since it is now no longer eligible to be
// released automatically by the engine.
- node.remove();
+ d()->node.remove();
}
}
void VariantObject::removeVmePropertyReference()
{
- if (isScarce() && --m_vmePropertyReferenceCount == 0) {
+ if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
// and add to the ep->scarceResources list
// since it is now eligible to be released
// automatically by the engine.
- internalClass->engine->scarceResources.insert(this);
+ internalClass()->engine->scarceResources.insert(d());
}
}
-VariantPrototype::VariantPrototype(InternalClass *ic)
- : VariantObject(ic)
-{
-}
-
void VariantPrototype::init()
{
defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0);
@@ -154,20 +144,20 @@ void VariantPrototype::init()
QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
- if (o && o->isScarce())
- o->node.remove();
+ Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>());
+ if (o && o->d()->isScarce())
+ o->d()->node.remove();
return Encode::undefined();
}
QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>());
if (o) {
- if (o->isScarce())
- o->node.remove();
- o->data = QVariant();
+ if (o->d()->isScarce())
+ o->d()->node.remove();
+ o->d()->data = QVariant();
}
return Encode::undefined();
}
@@ -175,26 +165,26 @@ QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx)
QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>());
if (!o)
return Encode::undefined();
- QString result = o->data.toString();
- if (result.isEmpty() && !o->data.canConvert(QVariant::String))
- result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->data.typeName()));
- return Encode(ctx->engine->newString(result));
+ QString result = o->d()->data.toString();
+ if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String))
+ result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName()));
+ return Encode(ctx->d()->engine->newString(result));
}
QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>());
if (o) {
- QVariant v = o->data;
+ QVariant v = o->d()->data;
switch (v.type()) {
case QVariant::Invalid:
return Encode::undefined();
case QVariant::String:
- return Encode(ctx->engine->newString(v.toString()));
+ return Encode(ctx->d()->engine->newString(v.toString()));
case QVariant::Int:
return Encode(v.toInt());
case QVariant::Double:
@@ -206,7 +196,7 @@ QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx)
break;
}
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 656608d49b..18e93f6ca7 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -64,31 +64,33 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct VariantObject : Object, public ExecutionEngine::ScarceResourceData
+struct VariantObject : Object
{
- V4_OBJECT
-public:
- VariantObject(InternalClass *ic);
- VariantObject(ExecutionEngine *engine, const QVariant &value);
+ struct Data : Object::Data, public ExecutionEngine::ScarceResourceData
+ {
+ Data(InternalClass *ic);
+ Data(ExecutionEngine *engine, const QVariant &value);
+ ~Data() {
+ if (isScarce())
+ node.remove();
+ }
+ bool isScarce() const;
+ int vmePropertyReferenceCount;
+ };
+ V4_OBJECT(Object)
static QVariant toVariant(const ValueRef v);
void addVmePropertyReference();
void removeVmePropertyReference();
- bool isScarce() const;
- int m_vmePropertyReferenceCount;
static void destroy(Managed *that);
static bool isEqualTo(Managed *m, Managed *other);
};
-DEFINE_REF(VariantObject, Object);
-
struct VariantPrototype : VariantObject
{
public:
- VariantPrototype(InternalClass *ic);
-
void init();
static ReturnedValue method_preserve(CallContext *ctx);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 8e52ed5a96..2df4bdd076 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -185,14 +185,14 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
const uchar *exceptionHandler = 0;
- context->lineNumber = -1;
- QV4::ExecutionEngine *engine = context->engine;
+ context->d()->lineNumber = -1;
+ QV4::ExecutionEngine *engine = context->d()->engine;
#ifdef DO_TRACE_INSTR
qDebug("Starting VME with context=%p and code=%p", context, code);
#endif // DO_TRACE_INSTR
- QV4::StringValue * const runtimeStrings = context->compilationUnit->runtimeStrings;
+ QV4::StringValue * const runtimeStrings = context->d()->compilationUnit->runtimeStrings;
// setup lookup scopes
int scopeDepth = 0;
@@ -200,28 +200,28 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
QV4::ExecutionContext *scope = context;
while (scope) {
++scopeDepth;
- scope = scope->outer;
+ scope = scope->d()->outer;
}
}
QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth)));
{
- scopes[0] = const_cast<QV4::Value *>(context->compilationUnit->data->constants());
+ scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->data->constants());
// stack gets setup in push instruction
scopes[1] = 0;
QV4::ExecutionContext *scope = context;
int i = 0;
while (scope) {
- if (scope->type >= QV4::ExecutionContext::Type_SimpleCallContext) {
+ if (scope->d()->type >= QV4::ExecutionContext::Type_SimpleCallContext) {
QV4::CallContext *cc = static_cast<QV4::CallContext *>(scope);
- scopes[2*i + 2] = cc->callData->args;
- scopes[2*i + 3] = cc->locals;
+ scopes[2*i + 2] = cc->d()->callData->args;
+ scopes[2*i + 3] = cc->d()->locals;
} else {
scopes[2*i + 2] = 0;
scopes[2*i + 3] = 0;
}
++i;
- scope = scope->outer;
+ scope = scope->d()->outer;
}
}
@@ -253,7 +253,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_BEGIN_INSTR(LoadRegExp)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = context->compilationUnit->runtimeRegularExpressions[instr.regExpId];
+ VALUE(instr.result) = context->d()->compilationUnit->runtimeRegularExpressions[instr.regExpId];
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
@@ -267,7 +267,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_BEGIN_INSTR(GetGlobalLookup)
TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- QV4::Lookup *l = context->lookups + instr.index;
+ QV4::Lookup *l = context->d()->lookups + instr.index;
STOREVALUE(instr.result, l->globalGetter(l, context));
MOTH_END_INSTR(GetGlobalLookup)
@@ -282,7 +282,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(LoadElementLookup)
- QV4::Lookup *l = context->lookups + instr.lookup;
+ QV4::Lookup *l = context->d()->lookups + instr.lookup;
STOREVALUE(instr.result, l->indexedGetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
@@ -292,7 +292,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(StoreElementLookup)
- QV4::Lookup *l = context->lookups + instr.lookup;
+ QV4::Lookup *l = context->d()->lookups + instr.lookup;
l->indexedSetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
@@ -302,7 +302,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- QV4::Lookup *l = context->lookups + instr.index;
+ QV4::Lookup *l = context->d()->lookups + instr.index;
STOREVALUE(instr.result, l->getter(l, VALUEPTR(instr.base)));
MOTH_END_INSTR(GetLookup)
@@ -312,7 +312,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(SetLookup)
- QV4::Lookup *l = context->lookups + instr.index;
+ QV4::Lookup *l = context->d()->lookups + instr.index;
l->setter(l, VALUEPTR(instr.base), VALUEPTR(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(SetLookup)
@@ -330,10 +330,14 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
STOREVALUE(instr.result, Runtime::getQmlAttachedProperty(context, instr.attachedPropertiesId, instr.propertyIndex));
MOTH_END_INSTR(LoadAttachedQObjectProperty)
+ MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty)
+ STOREVALUE(instr.result, Runtime::getQmlSingletonQObjectProperty(context, VALUEPTR(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 = context->engine->stackPush(stackSize);
+ stack = context->engine()->stackPush(stackSize);
#ifndef QT_NO_DEBUG
memset(stack, 0, stackSize * sizeof(QV4::Value));
#endif
@@ -342,7 +346,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_BEGIN_INSTR(CallValue)
#if 0 //def DO_TRACE_INSTR
- if (Debugging::Debugger *debugger = context->engine->debugger) {
+ if (Debugging::Debugger *debugger = context->engine()->debugger) {
if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) {
if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) {
QString n = debugger->name(o);
@@ -655,24 +659,24 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
MOTH_END_INSTR(BinopContext)
MOTH_BEGIN_INSTR(Ret)
- context->engine->stackPop(stackSize);
+ context->engine()->stackPop(stackSize);
// TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData());
return VALUE(instr.result).asReturnedValue();
MOTH_END_INSTR(Ret)
MOTH_BEGIN_INSTR(Debug)
- context->lineNumber = instr.lineNumber;
- QV4::Debugging::Debugger *debugger = context->engine->debugger;
+ context->d()->lineNumber = instr.lineNumber;
+ QV4::Debugging::Debugger *debugger = context->engine()->debugger;
if (debugger && debugger->pauseAtNextOpportunity())
debugger->maybeBreakAtInstruction();
MOTH_END_INSTR(Debug)
MOTH_BEGIN_INSTR(Line)
- context->lineNumber = instr.lineNumber;
+ context->d()->lineNumber = instr.lineNumber;
MOTH_END_INSTR(Debug)
MOTH_BEGIN_INSTR(LoadThis)
- VALUE(instr.result) = context->callData->thisObject;
+ VALUE(instr.result) = context->d()->callData->thisObject;
MOTH_END_INSTR(LoadThis)
MOTH_BEGIN_INSTR(LoadQmlIdArray)
@@ -706,9 +710,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code
Q_ASSERT(false);
catchException:
- Q_ASSERT(context->engine->hasException);
+ Q_ASSERT(context->engine()->hasException);
if (!exceptionHandler) {
- context->engine->stackPop(stackSize);
+ context->engine()->stackPop(stackSize);
return QV4::Encode::undefined();
}
code = exceptionHandler;
@@ -732,7 +736,7 @@ void **VME::instructionJumpTable()
QV4::ReturnedValue VME::exec(QV4::ExecutionContext *ctxt, const uchar *code)
{
VME vme;
- QV4::Debugging::Debugger *debugger = ctxt->engine->debugger;
+ QV4::Debugging::Debugger *debugger = ctxt->engine()->debugger;
if (debugger)
debugger->enteringFunction();
QV4::ReturnedValue retVal = vme.run(ctxt, code);
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 17d35f8c54..6e06fb42ef 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -19,9 +19,11 @@ exists("qqml_enable_gcov") {
QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
# 2415: variable "xx" of static storage duration was declared but never referenced
-# unused variable 'xx' [-Werror,-Wunused-const-variable]
intel_icc: WERROR += -ww2415
-clang:if(greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)): \
+# unused variable 'xx' [-Werror,-Wunused-const-variable]
+greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \
+ greaterThan(QT_APPLE_CLANG_MAJOR_VERSION, 5)| \
+ if(equals(QT_APPLE_CLANG_MAJOR_VERSION, 5):greaterThan(QT_APPLE_CLANG_MINOR_VERSION, 0)): \
WERROR += -Wno-error=unused-const-variable
load(qt_module)
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 61a492013d..57217a6bf8 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -245,7 +245,7 @@ public:
}
inline bool equals(const QV4::String *string) const {
- if (length != string->length() || hash != string->hashValue())
+ if (length != string->d()->length() || hash != string->hashValue())
return false;
if (isQString()) {
QStringDataPtr dd;
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 721f2cc5a8..86cb395c3d 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -198,6 +198,44 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T, typename E>
+int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+{
+ QML_GETTYPENAMES
+
+ QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
+ const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
+ if (!attached) {
+ attached = QQmlPrivate::attachedPropertiesFunc<T>();
+ attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>();
+ }
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ 0, 0,
+ reason,
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ attached,
+ attachedMetaObject,
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ QQmlPrivate::createParent<E>, &E::staticMetaObject,
+
+ 0,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
@@ -414,6 +452,45 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+template<typename T, typename E>
+int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, QQmlCustomParser *parser)
+{
+ QML_GETTYPENAMES
+
+ QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
+ const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
+ if (!attached) {
+ attached = QQmlPrivate::attachedPropertiesFunc<T>();
+ attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>();
+ }
+
+ QQmlPrivate::RegisterType type = {
+ 0,
+
+ qRegisterNormalizedMetaType<T *>(pointerName.constData()),
+ qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ sizeof(T), QQmlPrivate::createInto<T>,
+ QString(),
+
+ uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+
+ attached,
+ attachedMetaObject,
+
+ QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
+
+ QQmlPrivate::createParent<E>, &E::staticMetaObject,
+
+ parser,
+ 0
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
class QQmlContext;
class QQmlEngine;
class QJSValue;
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 571d78312e..1ba7a8091d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -71,34 +71,6 @@ QQmlAbstractBinding::VTable QQmlBinding_vtable = {
QQmlBinding::Identifier QQmlBinding::Invalid = -1;
-QQmlBinding *
-QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt)
-{
- if (id < 0)
- return 0;
-
- QQmlBinding *rv = 0;
-
- QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
- if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
- QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
- Q_ASSERT(typeData);
-
- if (QQmlCompiledData *cdata = typeData->compiledData()) {
- QV4::ExecutionEngine *v4 = engine->v4engine();
- QV4::Scope valueScope(v4);
- QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
- QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction));
- rv = new QQmlBinding(function, obj, ctxtdata);
- }
-
- typeData->release();
- }
-
- return rv;
-}
-
static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = {
QQmlBinding::expressionIdentifier,
QQmlBinding::expressionChanged
@@ -134,7 +106,7 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- url = cdata->name;
+ url = cdata->fileName();
if (scriptPrivate->bindingId != QQmlBinding::Invalid)
runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
}
@@ -213,13 +185,13 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
QV4::Scope scope(ep->v4engine());
QV4::ScopedFunctionObject f(scope, v4function.value());
Q_ASSERT(f);
- if (f->bindingKeyFlag) {
- QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->bindingLocation;
+ if (f->bindingKeyFlag()) {
+ QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->d()->bindingLocation;
url = loc.sourceFile;
lineNumber = loc.line;
columnNumber = loc.column;
} else {
- QV4::Function *function = f->asFunctionObject()->function;
+ QV4::Function *function = f->asFunctionObject()->function();
Q_ASSERT(function);
url = function->sourceFile();
@@ -312,7 +284,7 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine);
QV4::Scope scope(ep->v4engine());
QV4::ScopedValue f(scope, This->v4function.value());
- QV4::Function *function = f->asFunctionObject()->function;
+ QV4::Function *function = f->asFunctionObject()->function();
QString url = function->sourceFile();
quint16 lineNumber = function->compiledFunction->location.line;
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 3c2c832e0c..879129fe85 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -112,8 +112,6 @@ public:
typedef int Identifier;
static Identifier Invalid;
- static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *);
-
QVariant evaluate();
static QString expressionIdentifier(QQmlJavaScriptExpression *);
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 876f367097..cec5c31898 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -190,7 +190,7 @@ QV4::Function *QQmlBoundSignalExpression::function() const
Q_ASSERT (context() && engine());
QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine());
QV4::Scoped<QV4::FunctionObject> v(scope, m_v8function.value());
- return v ? v->function : 0;
+ return v ? v->function() : 0;
}
return 0;
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index f3b6f621ce..129d312ad1 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -91,8 +91,8 @@ public:
QQmlEngine *engine;
- QString name;
- QUrl url;
+ QString fileName() const { return compilationUnit->fileName(); }
+ QUrl url() const { return QUrl(fileName()); }
QQmlTypeNameCache *importCache;
int metaTypeId;
@@ -136,13 +136,8 @@ public:
// index in first hash is component index, hash inside maps from object index in that scope to integer id
QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, int> objectIndexToIdForRoot;
- // hash key is object index
- struct CustomParserData {
- QByteArray compilationArtifact; // produced by custom parser
- QBitArray bindings; // bindings covered by the custom parser
- };
- QHash<int, CustomParserData> customParserData;
- QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
+ // hash key is object index, value is indicies of bindings covered by custom parser
+ QHash<int, QBitArray> customParserBindings;
QHash<int, QBitArray> deferredBindingsPerObject; // index is object index
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
@@ -154,9 +149,6 @@ public:
bool isInitialized() const { return hasEngine(); }
void initialize(QQmlEngine *);
- QV4::Function *functionForBindingId(int bindingId) const
- { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; }
-
protected:
virtual void destroy(); // From QQmlRefCount
virtual void clear(); // From QQmlCleanup
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 89ab353cdf..84ceefccba 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -591,7 +591,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start
d->cc = cc;
cc->addref();
d->start = start;
- d->url = cc->url;
+ d->url = cc->url();
d->progress = 1.0;
}
@@ -1078,11 +1078,18 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
class QQmlComponentIncubator;
-class QmlIncubatorObject : public QV4::Object
+struct QmlIncubatorObject : public QV4::Object
{
- V4_OBJECT
-public:
- QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
+ struct Data : QV4::Object::Data {
+ Data(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
+ QScopedPointer<QQmlComponentIncubator> incubator;
+ QV8Engine *v8;
+ QPointer<QObject> parent;
+ QV4::Value valuemap;
+ QV4::Value qmlGlobal;
+ QV4::Value statusChanged;
+ };
+ V4_OBJECT(QV4::Object)
static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx);
static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx);
@@ -1093,13 +1100,6 @@ public:
static void destroy(Managed *that);
static void markObjects(Managed *that, QV4::ExecutionEngine *e);
- QScopedPointer<QQmlComponentIncubator> incubator;
- QV8Engine *v8;
- QPointer<QObject> parent;
- QV4::Value valuemap;
- QV4::Value qmlGlobal;
- QV4::Value m_statusChanged;
-
void statusChanged(QQmlIncubator::Status);
void setInitialState(QObject *);
};
@@ -1109,20 +1109,24 @@ DEFINE_OBJECT_VTABLE(QmlIncubatorObject);
class QQmlComponentIncubator : public QQmlIncubator
{
public:
- QQmlComponentIncubator(QmlIncubatorObject *inc, IncubationMode mode)
+ QQmlComponentIncubator(QmlIncubatorObject::Data *inc, IncubationMode mode)
: QQmlIncubator(mode)
, incubatorObject(inc)
{}
virtual void statusChanged(Status s) {
- incubatorObject->statusChanged(s);
+ QV4::Scope scope(incubatorObject->internalClass->engine);
+ QV4::Scoped<QmlIncubatorObject> i(scope, incubatorObject);
+ i->statusChanged(s);
}
virtual void setInitialState(QObject *o) {
- incubatorObject->setInitialState(o);
+ QV4::Scope scope(incubatorObject->internalClass->engine);
+ QV4::Scoped<QmlIncubatorObject> i(scope, incubatorObject);
+ i->setInitialState(o);
}
- QmlIncubatorObject *incubatorObject;
+ QmlIncubatorObject::Data *incubatorObject;
};
@@ -1358,17 +1362,17 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
QQmlComponentExtension *e = componentExtension(args->engine());
- QV4::Scoped<QmlIncubatorObject> r(scope, new (v4->memoryManager) QmlIncubatorObject(args->engine(), mode));
+ QV4::Scoped<QmlIncubatorObject> r(scope, v4->memoryManager->alloc<QmlIncubatorObject>(args->engine(), mode));
QV4::ScopedObject p(scope, e->incubationProto.value());
r->setPrototype(p.getPointer());
if (!valuemap->isUndefined()) {
- r->valuemap = valuemap;
- r->qmlGlobal = args->qmlGlobal();
+ r->d()->valuemap = valuemap;
+ r->d()->qmlGlobal = args->qmlGlobal();
}
- r->parent = parent;
+ r->d()->parent = parent;
- QQmlIncubator *incubator = r.getPointer()->incubator.data();
+ QQmlIncubator *incubator = r.getPointer()->d()->incubator.data();
create(*incubator, creationContext());
if (incubator->status() == QQmlIncubator::Null) {
@@ -1418,21 +1422,21 @@ QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
return ctx->throwTypeError();
- return QV4::QObjectWrapper::wrap(ctx->engine, o->incubator->object());
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object());
}
QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
return ctx->throwTypeError();
- o->incubator->forceCompletion();
+ o->d()->incubator->forceCompletion();
return QV4::Encode::undefined();
}
@@ -1440,32 +1444,32 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext *
QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
return ctx->throwTypeError();
- return QV4::Encode(o->incubator->status());
+ return QV4::Encode(o->d()->incubator->status());
}
QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>());
if (!o)
return ctx->throwTypeError();
- return o->m_statusChanged.asReturnedValue();
+ return o->d()->statusChanged.asReturnedValue();
}
QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>());
- if (!o || ctx->callData->argc < 1)
+ QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>());
+ if (!o || ctx->d()->callData->argc < 1)
return ctx->throwTypeError();
- o->m_statusChanged = ctx->callData->args[0];
+ o->d()->statusChanged = ctx->d()->callData->args[0];
return QV4::Encode::undefined();
}
@@ -1473,65 +1477,63 @@ QQmlComponentExtension::~QQmlComponentExtension()
{
}
-QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode m)
- : Object(QV8Engine::getV4(engine))
+QmlIncubatorObject::Data::Data(QV8Engine *engine, QQmlIncubator::IncubationMode m)
+ : Object::Data(QV8Engine::getV4(engine))
+ , v8(engine)
+ , valuemap(QV4::Primitive::undefinedValue())
+ , qmlGlobal(QV4::Primitive::undefinedValue())
+ , statusChanged(QV4::Primitive::undefinedValue())
{
- incubator.reset(new QQmlComponentIncubator(this, m));
- v8 = engine;
setVTable(staticVTable());
- valuemap = QV4::Primitive::undefinedValue();
- qmlGlobal = QV4::Primitive::undefinedValue();
- m_statusChanged = QV4::Primitive::undefinedValue();
+ incubator.reset(new QQmlComponentIncubator(this, m));
}
void QmlIncubatorObject::setInitialState(QObject *o)
{
- QQmlComponent_setQmlParent(o, parent);
+ QQmlComponent_setQmlParent(o, d()->parent);
- if (!valuemap.isUndefined()) {
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8);
+ if (!d()->valuemap.isUndefined()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(d()->v8);
QV4::Scope scope(v4);
- QV4::Scoped<QV4::FunctionObject> f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal));
+ QV4::Scoped<QV4::FunctionObject> f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.asObject()));
QV4::ScopedCallData callData(scope, 2);
callData->thisObject = v4->globalObject;
callData->args[0] = QV4::QObjectWrapper::wrap(v4, o);
- callData->args[1] = valuemap;
+ callData->args[1] = d()->valuemap;
f->call(callData);
}
}
void QmlIncubatorObject::destroy(Managed *that)
{
- QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
- Q_ASSERT(o);
- o->~QmlIncubatorObject();
+ that->as<QmlIncubatorObject>()->d()->~Data();
}
void QmlIncubatorObject::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e)
{
QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
Q_ASSERT(o);
- o->valuemap.mark(e);
- o->qmlGlobal.mark(e);
- o->m_statusChanged.mark(e);
+ o->d()->valuemap.mark(e);
+ o->d()->qmlGlobal.mark(e);
+ o->d()->statusChanged.mark(e);
Object::markObjects(that, e);
}
void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
- QV4::Scope scope(QV8Engine::getV4(v8));
+ QV4::Scope scope(QV8Engine::getV4(d()->v8));
// hold the incubated object in a scoped value to prevent it's destruction before this method returns
- QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, incubator->object()));
+ QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, d()->incubator->object()));
if (s == QQmlIncubator::Ready) {
- Q_ASSERT(QQmlData::get(incubator->object()));
- QQmlData::get(incubator->object())->explicitIndestructibleSet = false;
- QQmlData::get(incubator->object())->indestructible = false;
+ Q_ASSERT(QQmlData::get(d()->incubator->object()));
+ QQmlData::get(d()->incubator->object())->explicitIndestructibleSet = false;
+ QQmlData::get(d()->incubator->object())->indestructible = false;
}
- QV4::ScopedFunctionObject f(scope, m_statusChanged);
+ QV4::ScopedFunctionObject f(scope, d()->statusChanged);
if (f) {
QV4::ExecutionContext *ctx = scope.engine->currentContext();
QV4::ScopedCallData callData(scope, 1);
@@ -1540,7 +1542,7 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
f->call(callData);
if (scope.hasException()) {
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(d()->v8->engine()), error);
}
}
}
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index a5574b706a..83ef8c6230 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -61,15 +61,18 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlContextWrapper);
-QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
- : Object(QV8Engine::getV4(engine)),
- readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
- context(context), scopeObject(scopeObject), idObjectsWrapper(0)
+QmlContextWrapper::Data::Data(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
+ : Object::Data(QV8Engine::getV4(engine))
+ , readOnly(true)
+ , ownsContext(ownsContext)
+ , isNullWrapper(false)
+ , context(context)
+ , scopeObject(scopeObject)
{
setVTable(staticVTable());
}
-QmlContextWrapper::~QmlContextWrapper()
+QmlContextWrapper::Data::~Data()
{
if (context && ownsContext)
context->destroy();
@@ -80,7 +83,7 @@ ReturnedValue QmlContextWrapper::qmlScope(QV8Engine *v8, QQmlContextData *ctxt,
ExecutionEngine *v4 = QV8Engine::getV4(v8);
Scope valueScope(v4);
- Scoped<QmlContextWrapper> w(valueScope, new (v4->memoryManager) QmlContextWrapper(v8, ctxt, scope));
+ Scoped<QmlContextWrapper> w(valueScope, v4->memoryManager->alloc<QmlContextWrapper>(v8, ctxt, scope));
return w.asReturnedValue();
}
@@ -94,8 +97,8 @@ ReturnedValue QmlContextWrapper::urlScope(QV8Engine *v8, const QUrl &url)
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0, true));
- w->isNullWrapper = true;
+ Scoped<QmlContextWrapper> w(scope, v4->memoryManager->alloc<QmlContextWrapper>(v8, context, (QObject*)0, true));
+ w->d()->isNullWrapper = true;
return w.asReturnedValue();
}
@@ -127,11 +130,11 @@ void QmlContextWrapper::takeContextOwnership(const ValueRef qmlglobal)
Scope scope(v4);
QV4::Scoped<QmlContextWrapper> c(scope, qmlglobal);
Q_ASSERT(c);
- c->ownsContext = true;
+ c->d()->ownsContext = true;
}
-ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty)
{
QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
@@ -149,10 +152,10 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
return result.asReturnedValue();
}
- if (resource->isNullWrapper)
+ if (resource->d()->isNullWrapper)
return Object::get(m, name, hasProperty);
- if (QV4::QmlContextWrapper::callingContext(v4) != resource->context)
+ if (QV4::QmlContextWrapper::callingContext(v4) != resource->d()->context)
return Object::get(m, name, hasProperty);
result = Object::get(m, name, &hasProp);
@@ -211,7 +214,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
while (context) {
// Search context properties
if (context->propertyNames.count()) {
- int propertyIdx = context->propertyNames.value(name.getPointer());
+ int propertyIdx = context->propertyNames.value(name);
if (propertyIdx != -1) {
@@ -247,7 +250,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
if (scopeObject) {
bool hasProp = false;
QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, scopeObject,
- name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp));
+ name, QV4::QObjectWrapper::CheckRevision, &hasProp));
if (hasProp) {
if (hasProperty)
*hasProperty = true;
@@ -260,7 +263,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
// Search context object
if (context->contextObject) {
bool hasProp = false;
- result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp);
+ result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp);
if (hasProp) {
if (hasProperty)
*hasProperty = true;
@@ -276,7 +279,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
return Primitive::undefinedValue().asReturnedValue();
}
-void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef value)
+void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value)
{
ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
@@ -295,11 +298,11 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
return;
}
- if (wrapper->isNullWrapper) {
- if (wrapper && wrapper->readOnly) {
+ if (wrapper->d()->isNullWrapper) {
+ if (wrapper && wrapper->d()->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
- Scoped<String> e(scope, v4->currentContext()->engine->newString(error));
+ Scoped<String> e(scope, v4->currentContext()->d()->engine->newString(error));
v4->currentContext()->throwError(e);
return;
}
@@ -322,18 +325,18 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
while (context) {
// Search context properties
- if (context->propertyNames.count() && -1 != context->propertyNames.value(name.getPointer()))
+ if (context->propertyNames.count() && -1 != context->propertyNames.value(name))
return;
// Search scope object
if (scopeObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
return;
scopeObject = 0;
// Search context object
if (context->contextObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
return;
context = context->parent;
@@ -341,7 +344,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
expressionContext->unresolvedNames = true;
- if (wrapper->readOnly) {
+ if (wrapper->d()->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->currentContext()->throwError(error);
@@ -353,14 +356,14 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
void QmlContextWrapper::destroy(Managed *that)
{
- static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
+ static_cast<QmlContextWrapper *>(that)->d()->~Data();
}
void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine)
{
QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m);
- if (This->idObjectsWrapper)
- This->idObjectsWrapper->mark(engine);
+ if (This->d()->idObjectsWrapper)
+ This->d()->idObjectsWrapper->mark(engine);
Object::markObjects(m, engine);
}
@@ -409,19 +412,21 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C
ReturnedValue QmlContextWrapper::idObjectsArray()
{
- if (!idObjectsWrapper) {
+ if (!d()->idObjectsWrapper) {
ExecutionEngine *v4 = engine();
- idObjectsWrapper = new (v4->memoryManager) QQmlIdObjectsArray(v4, this);
+ Scope scope(v4);
+ Scoped<QQmlIdObjectsArray> a(scope, v4->memoryManager->alloc<QQmlIdObjectsArray>(v4, this));
+ d()->idObjectsWrapper = a.getPointer();
}
- return idObjectsWrapper->asReturnedValue();
+ return d()->idObjectsWrapper->asReturnedValue();
}
-ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, const StringRef &name)
+ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, String *name)
{
- if (!context->imports)
+ if (!d()->context->imports)
return Encode::undefined();
// Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports->query(name);
+ QQmlTypeNameCache::Result r = d()->context->imports->query(name);
Q_ASSERT(r.isValid());
Q_ASSERT(r.type);
@@ -439,8 +444,8 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, const String
DEFINE_OBJECT_VTABLE(QQmlIdObjectsArray);
-QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper)
- : Object(engine)
+QQmlIdObjectsArray::Data::Data(ExecutionEngine *engine, QmlContextWrapper *contextWrapper)
+ : Object::Data(engine)
, contextWrapper(contextWrapper)
{
setVTable(staticVTable());
@@ -449,7 +454,7 @@ QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrappe
ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty)
{
QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(m);
- QQmlContextData *context = This->contextWrapper->getContext();
+ QQmlContextData *context = This->d()->contextWrapper->getContext();
if (!context) {
if (hasProperty)
*hasProperty = false;
@@ -475,7 +480,7 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr
void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine)
{
QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that);
- This->contextWrapper->mark(engine);
+ This->d()->contextWrapper->mark(engine);
Object::markObjects(that, engine);
}
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index 3facf71aa0..d6f25ac79a 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -73,9 +73,18 @@ struct QQmlIdObjectsArray;
struct Q_QML_EXPORT QmlContextWrapper : Object
{
- V4_OBJECT
- QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
- ~QmlContextWrapper();
+ struct Data : Object::Data {
+ Data(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
+ ~Data();
+ bool readOnly;
+ bool ownsContext;
+ bool isNullWrapper;
+
+ QQmlGuardedContextData context;
+ QPointer<QObject> scopeObject;
+ QQmlIdObjectsArray *idObjectsWrapper;
+ };
+ V4_OBJECT(Object)
static ReturnedValue qmlScope(QV8Engine *e, QQmlContextData *ctxt, QObject *scope);
static ReturnedValue urlScope(QV8Engine *e, const QUrl &);
@@ -83,41 +92,35 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
static QQmlContextData *callingContext(ExecutionEngine *v4);
static void takeContextOwnership(const ValueRef qmlglobal);
- inline QObject *getScopeObject() const { return scopeObject; }
- inline QQmlContextData *getContext() const { return context; }
+ inline QObject *getScopeObject() const { return d()->scopeObject; }
+ inline QQmlContextData *getContext() const { return d()->context; }
static QQmlContextData *getContext(const ValueRef value);
- void setReadOnly(bool b) { readOnly = b; }
+ void setReadOnly(bool b) { d()->readOnly = b; }
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const ValueRef value);
static void destroy(Managed *that);
static void markObjects(Managed *m, ExecutionEngine *engine);
static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
ReturnedValue idObjectsArray();
- ReturnedValue qmlSingletonWrapper(QV8Engine *e, const StringRef &name);
+ ReturnedValue qmlSingletonWrapper(QV8Engine *e, String *name);
- bool readOnly;
- bool ownsContext;
- bool isNullWrapper;
-
- QQmlGuardedContextData context;
- QPointer<QObject> scopeObject;
-private:
- QQmlIdObjectsArray *idObjectsWrapper;
};
struct QQmlIdObjectsArray : public Object
{
- V4_OBJECT
- QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper);
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, QmlContextWrapper *contextWrapper);
+ QmlContextWrapper *contextWrapper;
+ };
+ V4_OBJECT(Object)
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
static void markObjects(Managed *that, ExecutionEngine *engine);
- QmlContextWrapper *contextWrapper;
};
}
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 75acbdb778..312c4a8a10 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -109,6 +109,12 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const
exceptions << error;
}
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
+
/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
@@ -125,7 +131,34 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
if (dot == -1)
return -1;
- return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1), ok);
+
+ QString scope = QString::fromUtf8(script.left(dot));
+ QByteArray enumValue = script.mid(dot+1);
+
+ if (scope != QLatin1String("Qt")) {
+ if (imports.isNull())
+ return -1;
+ QQmlType *type = 0;
+
+ if (imports.isT1()) {
+ imports.asT1()->resolveType(scope, &type, 0, 0, 0);
+ } else {
+ QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
+ if (result.isValid())
+ type = result.type;
+ }
+
+ return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ }
+
+ const QMetaObject *mo = StaticQtMetaObject::get();
+ int i = mo->enumeratorCount();
+ while (i--) {
+ int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ if (*ok)
+ return v;
+ }
+ return -1;
}
/*!
@@ -137,17 +170,6 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
return compiler->resolveType(name);
}
-QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding)
-{
- return compiler->bindingIdentifier(binding, this);
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 2ce6375870..9e3f810738 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -71,8 +71,6 @@ struct QQmlCustomParserCompilerBackend
int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const;
const QMetaObject *resolveType(const QString& name) const;
-
- virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
@@ -92,8 +90,8 @@ public:
void clearErrors();
Flags flags() const { return m_flags; }
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0;
- virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0;
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0;
QList<QQmlError> errors() const { return exceptions; }
@@ -108,13 +106,13 @@ protected:
const QMetaObject *resolveType(const QString&) const;
- QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
-
private:
QList<QQmlError> exceptions;
QQmlCustomParserCompilerBackend *compiler;
Flags m_flags;
+ QBiPointer<const QQmlImports, QQmlTypeNameCache> imports;
friend class QQmlPropertyValidator;
+ friend class QQmlObjectCreator;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 9bf983ab85..9ba6e67079 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -585,9 +585,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
if (incubationController) incubationController->d = 0;
incubationController = 0;
- delete rootContext;
- rootContext = 0;
-
for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter)
(*iter)->release();
for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter)
@@ -907,6 +904,8 @@ QQmlEngine::~QQmlEngine()
if (d->isDebugging)
QQmlDebugServer::instance()->removeEngine(this);
+ d->typeLoader.invalidate();
+
// Emit onDestruction signals for the root context before
// we destroy the contexts, engine, Singleton Types etc. that
// may be required to handle the destruction signal.
@@ -919,6 +918,9 @@ QQmlEngine::~QQmlEngine()
QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes();
foreach (QQmlType *currType, singletonTypes)
currType->singletonInstanceInfo()->destroy(this);
+
+ delete d->rootContext;
+ d->rootContext = 0;
}
/*! \fn void QQmlEngine::quit()
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index c583156c43..6d72bfcffa 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -249,16 +249,17 @@ QString QQmlError::toString() const
QUrl u(url());
int l(line());
- if (u.isEmpty()) {
+ if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty()))
rv = QLatin1String("<Unknown File>");
- } else if (l != -1) {
- rv = u.toString() + QLatin1Char(':') + QString::number(l);
+ else
+ rv = u.toString();
+
+ if (l != -1) {
+ rv += QLatin1Char(':') + QString::number(l);
int c(column());
if (c != -1)
rv += QLatin1Char(':') + QString::number(c);
- } else {
- rv = u.toString();
}
rv += QLatin1String(": ") + description();
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 4dc3704bbb..e993ed98eb 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -161,7 +161,7 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- d->url = cdata->name;
+ d->url = cdata->fileName();
d->line = scriptPrivate->lineNumber;
d->column = scriptPrivate->columnNumber;
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 187c3656c6..8498a4d67d 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -106,8 +106,8 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
{
Q_D(QQmlFileSelector);
d->engine = engine;
- interceptorInstances()->insert(d->myInstance, this);
- d->engine->setUrlInterceptor(d->myInstance);
+ interceptorInstances()->insert(d->myInstance.data(), this);
+ d->engine->setUrlInterceptor(d->myInstance.data());
}
QQmlFileSelector::~QQmlFileSelector()
@@ -117,7 +117,7 @@ QQmlFileSelector::~QQmlFileSelector()
d->engine->setUrlInterceptor(0);
d->engine = 0;
}
- interceptorInstances()->remove(d->myInstance);
+ interceptorInstances()->remove(d->myInstance.data());
}
QQmlFileSelectorPrivate::QQmlFileSelectorPrivate()
@@ -125,7 +125,7 @@ QQmlFileSelectorPrivate::QQmlFileSelectorPrivate()
Q_Q(QQmlFileSelector);
ownSelector = true;
selector = new QFileSelector(q);
- myInstance = new QQmlFileSelectorInterceptor(this);
+ myInstance.reset(new QQmlFileSelectorInterceptor(this));
}
/*!
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index 501f563ade..73a98788ee 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -71,7 +71,7 @@ public:
QFileSelector* selector;
QPointer<QQmlEngine> engine;
bool ownSelector;
- QQmlFileSelectorInterceptor* myInstance;
+ QScopedPointer<QQmlFileSelectorInterceptor> myInstance;
};
class Q_QML_PRIVATE_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 098a664ded..c342d8b080 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -283,7 +283,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!compiledData)
return;
- QML_MEMORY_SCOPE_URL(compiledData->url);
+ QML_MEMORY_SCOPE_URL(compiledData->url());
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
@@ -294,7 +294,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!vmeGuard.isOK()) {
QQmlError error;
- error.setUrl(compiledData->url);
+ error.setUrl(compiledData->url());
error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
errors << error;
progress = QQmlIncubatorPrivate::Completed;
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index 63ce2d419c..2f013863ca 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -147,7 +147,7 @@ QQmlInfo::~QQmlInfo()
d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": "));
QQmlData *ddata = QQmlData::get(object, false);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ if (ddata && ddata->outerContext) {
error.setUrl(ddata->outerContext->url);
error.setLine(ddata->lineNumber);
error.setColumn(ddata->columnNumber);
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 560a4c8afd..8fea5e66d3 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -158,7 +158,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
QV4::ExecutionContext *ctx = v4->currentContext();
callData->thisObject = v4->globalObject;
if (scopeObject()) {
- QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()));
+ QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->d()->engine, scopeObject()));
if (value->isObject())
callData->thisObject = value;
}
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index fd50e2dbbc..b84752501f 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -52,18 +52,18 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlListWrapper);
-QmlListWrapper::QmlListWrapper(QV8Engine *engine)
- : Object(QV8Engine::getV4(engine)),
- v8(engine)
+QmlListWrapper::Data::Data(QV8Engine *engine)
+ : Object::Data(QV8Engine::getV4(engine))
+ , v8(engine)
{
setVTable(staticVTable());
+
QV4::Scope scope(QV8Engine::getV4(engine));
- QV4::ScopedObject protectThis(scope, this);
- Q_UNUSED(protectThis);
- setArrayType(ArrayData::Custom);
+ QV4::ScopedObject o(scope, this);
+ o->setArrayType(ArrayData::Custom);
}
-QmlListWrapper::~QmlListWrapper()
+QmlListWrapper::Data::~Data()
{
}
@@ -75,10 +75,10 @@ ReturnedValue QmlListWrapper::create(QV8Engine *v8, QObject *object, int propId,
ExecutionEngine *v4 = QV8Engine::getV4(v8);
Scope scope(v4);
- Scoped<QmlListWrapper> r(scope, new (v4->memoryManager) QmlListWrapper(v8));
- r->object = object;
- r->propertyType = propType;
- void *args[] = { &r->property, 0 };
+ Scoped<QmlListWrapper> r(scope, v4->memoryManager->alloc<QmlListWrapper>(v8));
+ r->d()->object = object;
+ r->d()->propertyType = propType;
+ void *args[] = { &r->d()->property, 0 };
QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
return r.asReturnedValue();
}
@@ -88,31 +88,31 @@ ReturnedValue QmlListWrapper::create(QV8Engine *v8, const QQmlListProperty<QObje
ExecutionEngine *v4 = QV8Engine::getV4(v8);
Scope scope(v4);
- Scoped<QmlListWrapper> r(scope, new (v4->memoryManager) QmlListWrapper(v8));
- r->object = prop.object;
- r->property = prop;
- r->propertyType = propType;
+ Scoped<QmlListWrapper> r(scope, v4->memoryManager->alloc<QmlListWrapper>(v8));
+ r->d()->object = prop.object;
+ r->d()->property = prop;
+ r->d()->propertyType = propType;
return r.asReturnedValue();
}
QVariant QmlListWrapper::toVariant() const
{
- if (!object)
+ if (!d()->object)
return QVariant();
- return QVariant::fromValue(QQmlListReferencePrivate::init(property, propertyType, v8->engine()));
+ return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property, d()->propertyType, d()->v8->engine()));
}
-ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty)
{
QV4::ExecutionEngine *v4 = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
return v4->currentContext()->throwTypeError();
- if (name->equals(v4->id_length) && !w->object.isNull()) {
- quint32 count = w->property.count ? w->property.count(&w->property) : 0;
+ if (name->equals(v4->id_length) && !w->d()->object.isNull()) {
+ quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0;
return Primitive::fromUInt32(count).asReturnedValue();
}
@@ -135,11 +135,11 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper
return e->currentContext()->throwTypeError();
}
- quint32 count = w->property.count ? w->property.count(&w->property) : 0;
- if (index < count && w->property.at) {
+ quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0;
+ if (index < count && w->d()->property.at) {
if (hasProperty)
*hasProperty = true;
- return QV4::QObjectWrapper::wrap(e, w->property.at(&w->property, index));
+ return QV4::QObjectWrapper::wrap(e, w->d()->property.at(&w->d()->property, index));
}
if (hasProperty)
@@ -147,7 +147,7 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper
return Primitive::undefinedValue().asReturnedValue();
}
-void QmlListWrapper::put(Managed *m, const StringRef name, const ValueRef value)
+void QmlListWrapper::put(Managed *m, String *name, const ValueRef value)
{
// doesn't do anything. Should we throw?
Q_UNUSED(m);
@@ -158,20 +158,20 @@ void QmlListWrapper::put(Managed *m, const StringRef name, const ValueRef value)
void QmlListWrapper::destroy(Managed *that)
{
QmlListWrapper *w = that->as<QmlListWrapper>();
- w->~QmlListWrapper();
+ w->d()->~Data();
}
-void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs)
+void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs)
{
name = (String *)0;
*index = UINT_MAX;
QmlListWrapper *w = m->as<QmlListWrapper>();
- quint32 count = w->property.count ? w->property.count(&w->property) : 0;
+ quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0;
if (it->arrayIndex < count) {
*index = it->arrayIndex;
++it->arrayIndex;
*attrs = QV4::Attr_Data;
- p->value = QV4::QObjectWrapper::wrap(w->engine(), w->property.at(&w->property, *index));
+ p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property.at(&w->d()->property, *index));
return;
}
return QV4::Object::advanceIterator(m, it, name, index, p, attrs);
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index a7ce8b30bf..f6aee04487 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -69,30 +69,26 @@ namespace QV4 {
struct Q_QML_EXPORT QmlListWrapper : Object
{
- V4_OBJECT
-protected:
- QmlListWrapper(QV8Engine *engine);
- ~QmlListWrapper();
-
-public:
+ struct Data : Object::Data {
+ Data(QV8Engine *engine);
+ ~Data();
+ QV8Engine *v8;
+ QPointer<QObject> object;
+ QQmlListProperty<QObject> property;
+ int propertyType;
+ };
+ V4_OBJECT(Object)
static ReturnedValue create(QV8Engine *v8, QObject *object, int propId, int propType);
static ReturnedValue create(QV8Engine *v8, const QQmlListProperty<QObject> &prop, int propType);
QVariant toVariant() const;
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
- static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes);
+ static void put(Managed *m, String *name, const ValueRef value);
+ static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes);
static void destroy(Managed *that);
-
-private:
- QV8Engine *v8;
- QPointer<QObject> object;
- QQmlListProperty<QObject> property;
- int propertyType;
-
};
}
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 178280b27c..b1ce0da8e0 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -82,171 +82,171 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine)
QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleString(ctx);
QV4::Scope scope(ctx);
- QV4::DateObject *date = ctx->callData->thisObject.asDateObject();
+ QV4::DateObject *date = ctx->d()->callData->thisObject.asDateObject();
if (!date)
return QV4::DatePrototype::method_toLocaleString(ctx);
QDateTime dt = date->toQDateTime();
- if (ctx->callData->argc == 0) {
+ if (ctx->d()->callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->engine->newString(locale.toString(dt))->asReturnedValue();
+ return ctx->d()->engine->newString(locale.toString(dt))->asReturnedValue();
}
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString()
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDt;
- if (ctx->callData->argc == 2) {
- if (ctx->callData->args[1].isString()) {
- QString format = ctx->callData->args[1].stringValue()->toQString();
- formattedDt = r->locale.toString(dt, format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2) {
+ if (ctx->d()->callData->args[1].isString()) {
+ QString format = ctx->d()->callData->args[1].stringValue()->toQString();
+ formattedDt = r->d()->locale.toString(dt, format);
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDt = r->locale.toString(dt, format);
+ formattedDt = r->d()->locale.toString(dt, format);
} else {
V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
- formattedDt = r->locale.toString(dt, enumFormat);
+ formattedDt = r->d()->locale.toString(dt, enumFormat);
}
- return ctx->engine->newString(formattedDt)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
}
QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleTimeString(ctx);
QV4::Scope scope(ctx);
- QV4::DateObject *date = ctx->callData->thisObject.asDateObject();
+ QV4::DateObject *date = ctx->d()->callData->thisObject.asDateObject();
if (!date)
return QV4::DatePrototype::method_toLocaleTimeString(ctx);
QDateTime dt = date->toQDateTime();
QTime time = dt.time();
- if (ctx->callData->argc == 0) {
+ if (ctx->d()->callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->engine->newString(locale.toString(time))->asReturnedValue();
+ return ctx->d()->engine->newString(locale.toString(time))->asReturnedValue();
}
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString()
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedTime;
- if (ctx->callData->argc == 2) {
- if (ctx->callData->args[1].isString()) {
- QString format = ctx->callData->args[1].stringValue()->toQString();
- formattedTime = r->locale.toString(time, format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2) {
+ if (ctx->d()->callData->args[1].isString()) {
+ QString format = ctx->d()->callData->args[1].stringValue()->toQString();
+ formattedTime = r->d()->locale.toString(time, format);
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedTime = r->locale.toString(time, format);
+ formattedTime = r->d()->locale.toString(time, format);
} else {
V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
- formattedTime = r->locale.toString(time, enumFormat);
+ formattedTime = r->d()->locale.toString(time, enumFormat);
}
- return ctx->engine->newString(formattedTime)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
}
QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc > 2)
return QV4::DatePrototype::method_toLocaleDateString(ctx);
QV4::Scope scope(ctx);
- QV4::DateObject *dateObj = ctx->callData->thisObject.asDateObject();
+ QV4::DateObject *dateObj = ctx->d()->callData->thisObject.asDateObject();
if (!dateObj)
return QV4::DatePrototype::method_toLocaleDateString(ctx);
QDateTime dt = dateObj->toQDateTime();
QDate date = dt.date();
- if (ctx->callData->argc == 0) {
+ if (ctx->d()->callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->engine->newString(locale.toString(date))->asReturnedValue();
+ return ctx->d()->engine->newString(locale.toString(date))->asReturnedValue();
}
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString()
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDate;
- if (ctx->callData->argc == 2) {
- if (ctx->callData->args[1].isString()) {
- QString format = ctx->callData->args[1].stringValue()->toQString();
- formattedDate = r->locale.toString(date, format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2) {
+ if (ctx->d()->callData->args[1].isString()) {
+ QString format = ctx->d()->callData->args[1].stringValue()->toQString();
+ formattedDate = r->d()->locale.toString(date, format);
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDate = r->locale.toString(date, format);
+ formattedDate = r->d()->locale.toString(date, format);
} else {
V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
- formattedDate = r->locale.toString(date, enumFormat);
+ formattedDate = r->d()->locale.toString(date, enumFormat);
}
- return ctx->engine->newString(formattedDate)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
}
QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine * const engine = ctx->engine;
- if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) {
+ QV4::ExecutionEngine * const engine = ctx->d()->engine;
+ if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) {
QLocale locale;
- QString dateString = ctx->callData->args[0].stringValue()->toQString();
+ QString dateString = ctx->d()->callData->args[0].stringValue()->toQString();
QDateTime dt = locale.toDateTime(dateString);
return QV4::Encode(engine->newDateObject(dt));
}
QV4::Scope scope(ctx);
- if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0]))
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0]))
V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDateTime dt;
- QString dateString = ctx->callData->args[1].toQStringNoThrow();
- if (ctx->callData->argc == 3) {
- if (ctx->callData->args[2].isString()) {
- QString format = ctx->callData->args[2].stringValue()->toQString();
- dt = r->locale.toDateTime(dateString, format);
- } else if (ctx->callData->args[2].isNumber()) {
- quint32 intFormat = ctx->callData->args[2].toNumber();
+ QString dateString = ctx->d()->callData->args[1].toQStringNoThrow();
+ if (ctx->d()->callData->argc == 3) {
+ if (ctx->d()->callData->args[2].isString()) {
+ QString format = ctx->d()->callData->args[2].stringValue()->toQString();
+ dt = r->d()->locale.toDateTime(dateString, format);
+ } else if (ctx->d()->callData->args[2].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->locale.toDateTime(dateString, format);
+ dt = r->d()->locale.toDateTime(dateString, format);
} else {
V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
- dt = r->locale.toDateTime(dateString, enumFormat);
+ dt = r->d()->locale.toDateTime(dateString, enumFormat);
}
return QV4::Encode(engine->newDateObject(dt));
@@ -254,40 +254,40 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *
QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine * const engine = ctx->engine;
+ QV4::ExecutionEngine * const engine = ctx->d()->engine;
- if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) {
+ if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) {
QLocale locale;
- QString timeString = ctx->callData->args[0].stringValue()->toQString();
+ QString timeString = ctx->d()->callData->args[0].stringValue()->toQString();
QTime time = locale.toTime(timeString);
QDateTime dt = QDateTime::currentDateTime();
dt.setTime(time);
return QV4::Encode(engine->newDateObject(dt));
}
- if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0]))
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0]))
V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
QV4::Scope scope(ctx);
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QTime tm;
- QString dateString = ctx->callData->args[1].toQStringNoThrow();
- if (ctx->callData->argc == 3) {
- if (ctx->callData->args[2].isString()) {
- QString format = ctx->callData->args[2].stringValue()->toQString();
- tm = r->locale.toTime(dateString, format);
- } else if (ctx->callData->args[2].isNumber()) {
- quint32 intFormat = ctx->callData->args[2].toNumber();
+ QString dateString = ctx->d()->callData->args[1].toQStringNoThrow();
+ if (ctx->d()->callData->argc == 3) {
+ if (ctx->d()->callData->args[2].isString()) {
+ QString format = ctx->d()->callData->args[2].stringValue()->toQString();
+ tm = r->d()->locale.toTime(dateString, format);
+ } else if (ctx->d()->callData->args[2].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- tm = r->locale.toTime(dateString, format);
+ tm = r->d()->locale.toTime(dateString, format);
} else {
V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
- tm = r->locale.toTime(dateString, enumFormat);
+ tm = r->d()->locale.toTime(dateString, enumFormat);
}
QDateTime dt;
@@ -301,38 +301,38 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte
QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine * const engine = ctx->engine;
+ QV4::ExecutionEngine * const engine = ctx->d()->engine;
- if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) {
+ if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) {
QLocale locale;
- QString dateString = ctx->callData->args[0].stringValue()->toQString();
+ QString dateString = ctx->d()->callData->args[0].stringValue()->toQString();
QDate date = locale.toDate(dateString);
return QV4::Encode(engine->newDateObject(QDateTime(date)));
}
- if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0]))
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0]))
V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
QV4::Scope scope(ctx);
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDate dt;
- QString dateString = ctx->callData->args[1].toQStringNoThrow();
- if (ctx->callData->argc == 3) {
- if (ctx->callData->args[2].isString()) {
- QString format = ctx->callData->args[2].stringValue()->toQString();
- dt = r->locale.toDate(dateString, format);
- } else if (ctx->callData->args[2].isNumber()) {
- quint32 intFormat = ctx->callData->args[2].toNumber();
+ QString dateString = ctx->d()->callData->args[1].toQStringNoThrow();
+ if (ctx->d()->callData->argc == 3) {
+ if (ctx->d()->callData->args[2].isString()) {
+ QString format = ctx->d()->callData->args[2].stringValue()->toQString();
+ dt = r->d()->locale.toDate(dateString, format);
+ } else if (ctx->d()->callData->args[2].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->locale.toDate(dateString, format);
+ dt = r->d()->locale.toDate(dateString, format);
} else {
V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
- dt = r->locale.toDate(dateString, enumFormat);
+ dt = r->d()->locale.toDate(dateString, enumFormat);
}
return QV4::Encode(engine->newDateObject(QDateTime(dt)));
@@ -340,7 +340,7 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte
QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 0)
+ if (ctx->d()->callData->argc != 0)
V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
QV4::DatePrototype::timezoneUpdated();
@@ -360,75 +360,75 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine)
QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc > 3)
+ if (ctx->d()->callData->argc > 3)
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- double number = ctx->callData->thisObject.toNumber();
+ double number = ctx->d()->callData->thisObject.toNumber();
- if (ctx->callData->argc == 0) {
+ if (ctx->d()->callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->engine->newString(locale.toString(number))->asReturnedValue();
+ return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
}
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString()
QV4::Scope scope(ctx);
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
quint16 format = 'f';
- if (ctx->callData->argc > 1) {
- if (!ctx->callData->args[1].isString())
+ if (ctx->d()->callData->argc > 1) {
+ if (!ctx->d()->callData->args[1].isString())
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- QV4::String *fs = ctx->callData->args[1].toString(ctx);
- if (fs->length())
+ QV4::String *fs = ctx->d()->callData->args[1].toString(ctx);
+ if (fs->d()->length())
format = fs->toQString().at(0).unicode();
}
int prec = 2;
- if (ctx->callData->argc > 2) {
- if (!ctx->callData->args[2].isNumber())
+ if (ctx->d()->callData->argc > 2) {
+ if (!ctx->d()->callData->args[2].isNumber())
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- prec = ctx->callData->args[2].toInt32();
+ prec = ctx->d()->callData->args[2].toInt32();
}
- return ctx->engine->newString(r->locale.toString(number, (char)format, prec))->asReturnedValue();
+ return ctx->d()->engine->newString(r->d()->locale.toString(number, (char)format, prec))->asReturnedValue();
}
QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc > 2)
V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- double number = ctx->callData->thisObject.toNumber();
+ double number = ctx->d()->callData->thisObject.toNumber();
- if (ctx->callData->argc == 0) {
+ if (ctx->d()->callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->engine->newString(locale.toString(number))->asReturnedValue();
+ return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
}
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
QV4::Scope scope(ctx);
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
QString symbol;
- if (ctx->callData->argc > 1) {
- if (!ctx->callData->args[1].isString())
+ if (ctx->d()->callData->argc > 1) {
+ if (!ctx->d()->callData->args[1].isString())
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- symbol = ctx->callData->args[1].toQStringNoThrow();
+ symbol = ctx->d()->callData->args[1].toQStringNoThrow();
}
- return ctx->engine->newString(r->locale.toCurrencyString(number, symbol))->asReturnedValue();
+ return ctx->d()->engine->newString(r->d()->locale.toCurrencyString(number, symbol))->asReturnedValue();
}
QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx)
{
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2)
V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
int numberIdx = 0;
@@ -436,18 +436,18 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext
QV4::Scope scope(ctx);
- if (ctx->callData->argc == 2) {
- if (!isLocaleObject(ctx->callData->args[0]))
+ if (ctx->d()->callData->argc == 2) {
+ if (!isLocaleObject(ctx->d()->callData->args[0]))
V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]);
- locale = r->locale;
+ GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]);
+ locale = r->d()->locale;
numberIdx = 1;
}
- QV4::String *ns = ctx->callData->args[numberIdx].toString(ctx);
- if (!ns->length())
+ QV4::String *ns = ctx->d()->callData->args[numberIdx].toString(ctx);
+ if (!ns->d()->length())
return QV4::Encode(Q_QNAN);
bool ok = false;
@@ -499,7 +499,7 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
QList<Qt::DayOfWeek> days = locale->weekdays();
- QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
+ QV4::Scoped<QV4::ArrayObject> result(scope, ctx->d()->engine->newArrayObject());
result->arrayReserve(days.size());
for (int i = 0; i < days.size(); ++i) {
int day = days.at(i);
@@ -520,11 +520,11 @@ QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
return QV4::Encode::undefined();
QStringList langs = locale->uiLanguages();
- QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject());
+ QV4::Scoped<QV4::ArrayObject> result(scope, ctx->d()->engine->newArrayObject());
result->arrayReserve(langs.size());
QV4::ScopedValue v(scope);
for (int i = 0; i < langs.size(); ++i)
- result->arrayPut(i, (v = ctx->engine->newString(langs.at(i))));
+ result->arrayPut(i, (v = ctx->d()->engine->newString(langs.at(i))));
result->setArrayLengthUnchecked(langs.size());
@@ -537,16 +537,16 @@ QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx)
if (!locale)
return QV4::Encode::undefined();
- if (ctx->callData->argc > 1)
+ if (ctx->d()->callData->argc > 1)
V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (ctx->callData->argc == 1) {
- quint32 intFormat = ctx->callData->args[0].toNumber();
+ if (ctx->d()->callData->argc == 1) {
+ quint32 intFormat = ctx->d()->callData->args[0].toNumber();
format = QLocale::CurrencySymbolFormat(intFormat);
}
- return ctx->engine->newString(locale->currencySymbol(format))->asReturnedValue();
+ return ctx->d()->engine->newString(locale->currencySymbol(format))->asReturnedValue();
}
#define LOCALE_FORMAT(FUNC) \
@@ -554,14 +554,14 @@ QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \
QLocale *locale = getThisLocale(ctx); \
if (!locale) \
return QV4::Encode::undefined(); \
- if (ctx->callData->argc > 1) \
+ if (ctx->d()->callData->argc > 1) \
V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
QLocale::FormatType format = QLocale::LongFormat;\
- if (ctx->callData->argc == 1) { \
- quint32 intFormat = ctx->callData->args[0].toUInt32(); \
+ if (ctx->d()->callData->argc == 1) { \
+ quint32 intFormat = ctx->d()->callData->args[0].toUInt32(); \
format = QLocale::FormatType(intFormat); \
} \
- return ctx->engine->newString(locale-> FUNC (format))->asReturnedValue(); \
+ return ctx->engine()->newString(locale-> FUNC (format))->asReturnedValue(); \
}
LOCALE_FORMAT(dateTimeFormat)
@@ -574,16 +574,16 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {
QLocale *locale = getThisLocale(ctx); \
if (!locale) \
return QV4::Encode::undefined(); \
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) \
V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->callData->args[0].toInt32() + 1; \
+ int idx = ctx->d()->callData->args[0].toInt32() + 1; \
if (idx < 1 || idx > 12) \
V4THROW_ERROR("Locale: Invalid month"); \
QString name; \
- if (ctx->callData->argc == 2) { \
- if (ctx->callData->args[1].isNumber()) { \
- quint32 intFormat = ctx->callData->args[1].toUInt32(); \
+ if (ctx->d()->callData->argc == 2) { \
+ if (ctx->d()->callData->args[1].isNumber()) { \
+ quint32 intFormat = ctx->d()->callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
@@ -592,7 +592,7 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine->newString(name)->asReturnedValue(); \
+ return ctx->engine()->newString(name)->asReturnedValue(); \
}
// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
@@ -601,17 +601,17 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {
QLocale *locale = getThisLocale(ctx); \
if (!locale) \
return QV4::Encode::undefined(); \
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) \
V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->callData->args[0].toInt32(); \
+ int idx = ctx->d()->callData->args[0].toInt32(); \
if (idx < 0 || idx > 7) \
V4THROW_ERROR("Locale: Invalid day"); \
if (idx == 0) idx = 7; \
QString name; \
- if (ctx->callData->argc == 2) { \
- if (ctx->callData->args[1].isNumber()) { \
- quint32 intFormat = ctx->callData->args[1].toUInt32(); \
+ if (ctx->d()->callData->argc == 2) { \
+ if (ctx->d()->callData->args[1].isNumber()) { \
+ quint32 intFormat = ctx->d()->callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
@@ -620,7 +620,7 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine->newString(name)->asReturnedValue(); \
+ return ctx->engine()->newString(name)->asReturnedValue(); \
}
LOCALE_FORMATTED_MONTHNAME(monthName)
@@ -633,7 +633,7 @@ LOCALE_FORMATTED_DAYNAME(standaloneDayName)
QLocale *locale = getThisLocale(ctx); \
if (!locale) \
return QV4::Encode::undefined(); \
- return ctx->engine->newString(locale-> VARIABLE())->asReturnedValue();\
+ return ctx->engine()->newString(locale-> VARIABLE())->asReturnedValue();\
}
LOCALE_STRING_PROPERTY(name)
@@ -814,8 +814,8 @@ QV4::ReturnedValue QQmlLocale::wrap(QV8Engine *engine, const QLocale &locale)
QV8LocaleDataDeletable *d = localeV8Data(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
- QV4::Scoped<QQmlLocaleData> wrapper(scope, new (v4->memoryManager) QQmlLocaleData(v4));
- wrapper->locale = locale;
+ QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->alloc<QQmlLocaleData>(v4));
+ wrapper->d()->locale = locale;
QV4::ScopedObject p(scope, d->prototype.value());
wrapper->setPrototype(p.getPointer());
return wrapper.asReturnedValue();
@@ -828,14 +828,14 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 1 || (!ctx->callData->args[0].isString() && !ctx->callData->args[0].asStringObject()))
+ if (ctx->d()->callData->argc != 1 || (!ctx->d()->callData->args[0].isString() && !ctx->d()->callData->args[0].asStringObject()))
return QV4::StringPrototype::method_localeCompare(ctx);
- if (!ctx->callData->thisObject.isString() && !ctx->callData->thisObject.asStringObject())
+ if (!ctx->d()->callData->thisObject.isString() && !ctx->d()->callData->thisObject.asStringObject())
return QV4::StringPrototype::method_localeCompare(ctx);
- QString thisString = ctx->callData->thisObject.toQStringNoThrow();
- QString thatString = ctx->callData->args[0].toQStringNoThrow();
+ QString thisString = ctx->d()->callData->thisObject.toQStringNoThrow();
+ QString thatString = ctx->d()->callData->args[0].toQStringNoThrow();
return QV4::Encode(QString::localeAwareCompare(thisString, thatString));
}
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index cafe448313..8ec7cbf61f 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -129,25 +129,25 @@ private:
static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx);
};
-class QQmlLocaleData : public QV4::Object
+struct QQmlLocaleData : public QV4::Object
{
- V4_OBJECT
-public:
- QQmlLocaleData(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
- {
- setVTable(staticVTable());
- }
-
- QLocale locale;
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+ }
+ QLocale locale;
+ };
+ V4_OBJECT(Object)
static QLocale *getThisLocale(QV4::CallContext *ctx) {
- QQmlLocaleData *thisObject = ctx->callData->thisObject.asObject()->as<QQmlLocaleData>();
+ QQmlLocaleData *thisObject = ctx->d()->callData->thisObject.asObject()->as<QQmlLocaleData>();
if (!thisObject) {
ctx->throwTypeError();
return 0;
}
- return &thisObject->locale;
+ return &thisObject->d()->locale;
}
static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 42f67f3345..900ac5a2e4 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -233,7 +233,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
v4->popContext();
} else if (qobjectCallback && !qobjectApi(e)) {
v4->pushGlobalContext();
- setQObjectApi(e, qobjectCallback(e, e));
+ QObject *o = qobjectCallback(e, e);
+ setQObjectApi(e, o);
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(e, o);
v4->popContext();
} else if (!url.isEmpty() && !qobjectApi(e)) {
v4->pushGlobalContext();
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 1de467b0fa..72920f1ae2 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -184,8 +184,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context = new QQmlContextData;
context->isInternal = true;
- context->url = compiledData->url;
- context->urlString = compiledData->name;
+ context->url = compiledData->url();
+ context->urlString = compiledData->fileName();
context->imports = compiledData->importCache;
context->imports->addref();
context->setParent(parentContext);
@@ -273,7 +273,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount);
QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
- QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope));
+ QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, v4->memoryManager->alloc<QV4::QmlBindingWrapper>(v4->rootContext, qmlScope));
QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
qSwap(_qmlContext, qmlContext);
@@ -400,7 +400,7 @@ void QQmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::
QString string = binding->valueAsString(&qmlUnit->header);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(string));
+ QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string));
// Apply URL interceptor
if (engine->urlInterceptor())
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
@@ -595,7 +595,7 @@ void QQmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::
} else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(&qmlUnit->header);
- QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(urlString));
+ QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString));
QList<QUrl> value;
value.append(u);
argv[0] = reinterpret_cast<void *>(&value);
@@ -1022,7 +1022,7 @@ void QQmlObjectCreator::setupFunctions()
void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setUrl(compiledData->url);
+ error.setUrl(compiledData->url());
error.setLine(location.line);
error.setColumn(location.column);
error.setDescription(description);
@@ -1079,7 +1079,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
sharedState->allCreatedObjects.push(instance);
} else {
Q_ASSERT(typeRef->component);
- Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name,
+ Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->fileName(),
context->url, obj->location.line, obj->location.column));
if (typeRef->component->qmlUnit->isSingleton())
{
@@ -1139,10 +1139,19 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QBitArray bindingsToSkip;
if (customParser) {
- QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index);
- if (entry != compiledData->customParserData.constEnd()) {
- customParser->setCustomData(instance, entry->compilationArtifact, compiledData);
- bindingsToSkip = entry->bindings;
+ QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index);
+ if (customParserBindings != compiledData->customParserBindings.constEnd()) {
+ customParser->imports = compiledData->importCache;
+
+ QList<const QV4::CompiledData::Binding *> bindings;
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+ for (int i = 0; i < customParserBindings->count(); ++i)
+ if (customParserBindings->testBit(i))
+ bindings << obj->bindingTable() + i;
+ customParser->applyBindings(instance, compiledData, bindings);
+
+ customParser->imports = (QQmlTypeNameCache*)0;
+ bindingsToSkip = *customParserBindings;
}
}
@@ -1169,7 +1178,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QV4::Scope valueScope(v4);
QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject));
- QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope));
+ QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, v4->memoryManager->alloc<QV4::QmlBindingWrapper>(v4->rootContext, qmlScope));
QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context();
qSwap(_qmlContext, qmlContext);
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 1075b53c5e..96f303dcb5 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1427,7 +1427,8 @@ bool QQmlPropertyPrivate::write(QObject *object,
list << value.toInt();
v = QVariant::fromValue<QList<int> >(list);
ok = true;
- } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) {
+ } else if ((variantType == QVariant::Double || variantType == QVariant::Int)
+ && (propertyType == qMetaTypeId<QList<qreal> >())) {
QList<qreal> list;
list << value.toReal();
v = QVariant::fromValue<QList<qreal> >(list);
@@ -1533,7 +1534,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
return false;
} else if (isVarProperty) {
QV4::FunctionObject *f = result->asFunctionObject();
- if (f && f->bindingKeyFlag) {
+ if (f && f->bindingKeyFlag()) {
// we explicitly disallow this case to avoid confusion. Users can still store one
// in an array in a var property if they need to, but the common case is user error.
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
@@ -1551,7 +1552,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
writeValueProperty(object, core, QVariant(), context, flags);
} else if (type == qMetaTypeId<QJSValue>()) {
QV4::FunctionObject *f = result->asFunctionObject();
- if (f && f->bindingKeyFlag) {
+ if (f && f->bindingKeyFlag()) {
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
expression->delayedError()->setErrorObject(object);
return false;
@@ -1569,7 +1570,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
expression->delayedError()->setErrorObject(object);
return false;
} else if (QV4::FunctionObject *f = result->asFunctionObject()) {
- if (f->bindingKeyFlag)
+ if (f->bindingKeyFlag())
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 7fc08bd114..36dc17a085 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -897,11 +897,20 @@ QQmlDataLoader::QQmlDataLoader(QQmlEngine *engine)
/*! \internal */
QQmlDataLoader::~QQmlDataLoader()
{
+ invalidate();
+}
+
+void QQmlDataLoader::invalidate()
+{
for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
(*iter)->release();
+ m_networkReplies.clear();
- shutdownThread();
- delete m_thread;
+ if (m_thread) {
+ shutdownThread();
+ delete m_thread;
+ m_thread = 0;
+ }
}
void QQmlDataLoader::lock()
@@ -1228,7 +1237,7 @@ void QQmlDataLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::Cached
void QQmlDataLoader::shutdownThread()
{
- if (!m_thread->isShutdown())
+ if (m_thread && !m_thread->isShutdown())
m_thread->shutdown();
}
@@ -2207,7 +2216,7 @@ void QQmlTypeData::dataReceived(const Data &data)
QQmlEngine *qmlEngine = typeLoader()->engine();
m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0));
QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames());
- if (!compiler.generateFromQml(code, finalUrlString(), finalUrlString(), m_document.data())) {
+ if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) {
QQmlError e;
@@ -2332,10 +2341,8 @@ void QQmlTypeData::compile()
Q_ASSERT(m_compiledData == 0);
m_compiledData = new QQmlCompiledData(typeLoader()->engine());
- m_compiledData->url = finalUrl();
- m_compiledData->name = finalUrlString();
- QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, m_compiledData->name);
+ QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, finalUrlString());
QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data());
if (!compiler.compile()) {
@@ -2547,7 +2554,7 @@ void QQmlScriptData::initialize(QQmlEngine *engine)
QV8Engine *v8engine = ep->v8engine();
QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8engine);
- m_program = new QV4::Script(v4, QV4::ObjectRef::null(), m_precompiledScript);
+ m_program = new QV4::Script(v4, 0, m_precompiledScript);
addToEngine(engine);
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index b09ac15861..3d0b77e2a5 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -233,6 +233,7 @@ public:
QQmlEngine *engine() const;
void initializeEngine(QQmlExtensionInterface *, const char *);
+ void invalidate();
protected:
void shutdownThread();
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 573779acab..0ae3e31ec0 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -56,14 +56,15 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlTypeWrapper);
-QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine)
- : Object(QV8Engine::getV4(engine)),
- v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
+QmlTypeWrapper::Data::Data(QV8Engine *engine)
+ : Object::Data(QV8Engine::getV4(engine))
+ , v8(engine)
+ , mode(IncludeEnums)
{
setVTable(staticVTable());
}
-QmlTypeWrapper::~QmlTypeWrapper()
+QmlTypeWrapper::Data::~Data()
{
if (typeNamespace)
typeNamespace->release();
@@ -71,14 +72,25 @@ QmlTypeWrapper::~QmlTypeWrapper()
bool QmlTypeWrapper::isSingleton() const
{
- return type && type->isSingleton();
+ return d()->type && d()->type->isSingleton();
+}
+
+QObject* QmlTypeWrapper::singletonObject() const
+{
+ if (!isSingleton())
+ return 0;
+
+ QQmlEngine *e = d()->v8->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo();
+ siinfo->init(e);
+ return siinfo->qobjectApi(e);
}
QVariant QmlTypeWrapper::toVariant() const
{
- if (type && type->isSingleton()) {
- QQmlEngine *e = v8->engine();
- QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ if (d()->type && d()->type->isSingleton()) {
+ QQmlEngine *e = d()->v8->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo();
siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required.
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
@@ -98,8 +110,8 @@ ReturnedValue QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlType *t, Typ
ExecutionEngine *v4 = QV8Engine::getV4(v8);
Scope scope(v4);
- Scoped<QmlTypeWrapper> w(scope, new (v4->memoryManager) QmlTypeWrapper(v8));
- w->mode = mode; w->object = o; w->type = t;
+ Scoped<QmlTypeWrapper> w(scope, v4->memoryManager->alloc<QmlTypeWrapper>(v8));
+ w->d()->mode = mode; w->d()->object = o; w->d()->type = t;
return w.asReturnedValue();
}
@@ -112,14 +124,14 @@ ReturnedValue QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlTypeNameCach
ExecutionEngine *v4 = QV8Engine::getV4(v8);
Scope scope(v4);
- Scoped<QmlTypeWrapper> w(scope, new (v4->memoryManager) QmlTypeWrapper(v8));
- w->mode = mode; w->object = o; w->typeNamespace = t; w->importNamespace = importNamespace;
+ Scoped<QmlTypeWrapper> w(scope, v4->memoryManager->alloc<QmlTypeWrapper>(v8));
+ w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace;
t->addref();
return w.asReturnedValue();
}
-ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty)
{
QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
@@ -132,13 +144,13 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
if (hasProperty)
*hasProperty = true;
- QV8Engine *v8engine = w->v8;
+ QV8Engine *v8engine = w->d()->v8;
QQmlContextData *context = v8engine->callingContext();
- QObject *object = w->object;
+ QObject *object = w->d()->object;
- if (w->type) {
- QQmlType *type = w->type;
+ if (w->d()->type) {
+ QQmlType *type = w->d()->type;
// singleton types are handled differently to other types.
if (type->isSingleton()) {
@@ -150,7 +162,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
if (qobjectSingleton) {
// check for enum value
if (name->startsWithUpper()) {
- if (w->mode == IncludeEnums) {
+ if (w->d()->mode == IncludeEnums) {
// ### Optimize
QByteArray enumName = name->toQString().toUtf8();
const QMetaObject *metaObject = qobjectSingleton->metaObject();
@@ -165,7 +177,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
}
// check for property.
- return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
} else if (!siinfo->scriptApi(e).isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
QV4::ScopedObject o(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(v4));
@@ -185,10 +197,10 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
// Fall through to base implementation
- } else if (w->object) {
+ } else if (w->d()->object) {
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
// Fall through to base implementation
}
@@ -198,19 +210,19 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
// Fall through to base implementation
- } else if (w->typeNamespace) {
- Q_ASSERT(w->importNamespace);
- QQmlTypeNameCache::Result r = w->typeNamespace->query(name, w->importNamespace);
+ } else if (w->d()->typeNamespace) {
+ Q_ASSERT(w->d()->importNamespace);
+ QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace);
if (r.isValid()) {
QQmlContextData *context = v8engine->callingContext();
if (r.type) {
- return create(w->v8, object, r.type, w->mode);
+ return create(w->d()->v8, object, r.type, w->d()->mode);
} else if (r.scriptIndex != -1) {
QV4::ScopedObject scripts(scope, context->importedScripts);
return scripts->getIndexed(r.scriptIndex);
} else if (r.importNamespace) {
- return create(w->v8, object, context->imports, r.importNamespace);
+ return create(w->d()->v8, object, context->imports, r.importNamespace);
}
return QV4::Encode::undefined();
@@ -229,7 +241,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
}
-void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
+void QmlTypeWrapper::put(Managed *m, String *name, const ValueRef value)
{
QmlTypeWrapper *w = m->as<QmlTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
@@ -244,12 +256,12 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QV8Engine *v8engine = v4->v8Engine;
QQmlContextData *context = v8engine->callingContext();
- QQmlType *type = w->type;
- if (type && !type->isSingleton() && w->object) {
- QObject *object = w->object;
+ QQmlType *type = w->d()->type;
+ if (type && !type->isSingleton() && w->d()->object) {
+ QObject *object = w->d()->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
} else if (type && type->isSingleton()) {
QQmlEngine *e = v8engine->engine();
QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
@@ -257,7 +269,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
- QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
} else if (!siinfo->scriptApi(e).isUndefined()) {
QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value);
if (!apiprivate) {
@@ -271,19 +283,17 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
}
}
-PropertyAttributes QmlTypeWrapper::query(const Managed *m, StringRef name)
+PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
{
// ### Implement more efficiently.
- Scope scope(m->engine());
- ScopedString n(scope, name);
bool hasProperty = false;
- static_cast<Object *>(const_cast<Managed*>(m))->get(n, &hasProperty);
+ static_cast<Object *>(const_cast<Managed*>(m))->get(name, &hasProperty);
return hasProperty ? Attr_Data : Attr_Invalid;
}
void QmlTypeWrapper::destroy(Managed *that)
{
- static_cast<QmlTypeWrapper *>(that)->~QmlTypeWrapper();
+ static_cast<QmlTypeWrapper *>(that)->d()->~Data();
}
bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 355a6751a9..becd73eaf0 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -68,15 +68,26 @@ namespace QV4 {
struct Q_QML_EXPORT QmlTypeWrapper : Object
{
- V4_OBJECT
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
+
+ struct Data : Object::Data {
+ Data(QV8Engine *engine);
+ ~Data();
+ QV8Engine *v8;
+ TypeNameMode mode;
+ QPointer<QObject> object;
+
+ QQmlType *type;
+ QQmlTypeNameCache *typeNamespace;
+ const void *importNamespace;
+ };
+ V4_OBJECT(Object)
private:
- QmlTypeWrapper(QV8Engine *engine);
- ~QmlTypeWrapper();
public:
- enum TypeNameMode { IncludeEnums, ExcludeEnums };
bool isSingleton() const;
+ QObject *singletonObject() const;
QVariant toVariant() const;
@@ -84,22 +95,13 @@ public:
static ReturnedValue create(QV8Engine *, QObject *, QQmlTypeNameCache *, const void *, TypeNameMode = IncludeEnums);
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
- static PropertyAttributes query(const Managed *, StringRef name);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const ValueRef value);
+ static PropertyAttributes query(const Managed *, String *name);
static void destroy(Managed *that);
-protected:
static bool isEqualTo(Managed *that, Managed *o);
-private:
- QV8Engine *v8;
- TypeNameMode mode;
- QPointer<QObject> object;
-
- QQmlType *type;
- QQmlTypeNameCache *typeNamespace;
- const void *importNamespace;
};
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 9a87493e54..1de596b4d3 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -59,41 +59,46 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlValueTypeWrapper);
-class QmlValueTypeReference : public QmlValueTypeWrapper
+struct QmlValueTypeReference : public QmlValueTypeWrapper
{
-public:
- QmlValueTypeReference(QV8Engine *engine);
-
- QPointer<QObject> object;
- int property;
+ struct Data : QmlValueTypeWrapper::Data
+ {
+ Data(QV8Engine *engine);
+ QPointer<QObject> object;
+ int property;
+ };
+ V4_OBJECT(QmlValueTypeWrapper)
};
-class QmlValueTypeCopy : public QmlValueTypeWrapper
-{
-public:
- QmlValueTypeCopy(QV8Engine *engine);
+DEFINE_OBJECT_VTABLE(QmlValueTypeReference);
- QVariant value;
+struct QmlValueTypeCopy : public QmlValueTypeWrapper
+{
+ struct Data : QmlValueTypeWrapper::Data
+ {
+ Data(QV8Engine *engine);
+ QVariant value;
+ };
+ V4_OBJECT(QmlValueTypeWrapper)
};
-QmlValueTypeWrapper::QmlValueTypeWrapper(QV8Engine *engine, ObjectType objectType)
- : Object(QV8Engine::getV4(engine)), objectType(objectType)
-{
- v8 = engine;
- setVTable(staticVTable());
-}
+DEFINE_OBJECT_VTABLE(QmlValueTypeCopy);
-QmlValueTypeWrapper::~QmlValueTypeWrapper()
+QmlValueTypeWrapper::Data::Data(QV8Engine *engine, ObjectType objectType)
+ : Object::Data(QV8Engine::getV4(engine))
+ , v8(engine)
+ , objectType(objectType)
{
+ setVTable(staticVTable());
}
-QmlValueTypeReference::QmlValueTypeReference(QV8Engine *engine)
-: QmlValueTypeWrapper(engine, Reference)
+QmlValueTypeReference::Data::Data(QV8Engine *engine)
+ : QmlValueTypeWrapper::Data(engine, Reference)
{
}
-QmlValueTypeCopy::QmlValueTypeCopy(QV8Engine *engine)
-: QmlValueTypeWrapper(engine, Copy)
+QmlValueTypeCopy::Data::Data(QV8Engine *engine)
+ : QmlValueTypeWrapper::Data(engine, Copy)
{
}
@@ -102,30 +107,30 @@ static bool readReferenceValue(const QmlValueTypeReference *reference)
{
// A reference resource may be either a "true" reference (eg, to a QVector3D property)
// or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
- QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
+ QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
if (writebackProperty.userType() == QMetaType::QVariant) {
// variant-containing-value-type reference
QVariant variantReferenceValue;
- reference->type->readVariantValue(reference->object, reference->property, &variantReferenceValue);
+ reference->d()->type->readVariantValue(reference->d()->object, reference->d()->property, &variantReferenceValue);
int variantReferenceType = variantReferenceValue.userType();
- if (variantReferenceType != reference->type->userType()) {
+ if (variantReferenceType != reference->d()->type->userType()) {
// This is a stale VariantReference. That is, the variant has been
// overwritten with a different type in the meantime.
// We need to modify this reference to the updated value type, if
// possible, or return false if it is not a value type.
if (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
- reference->type = QQmlValueTypeFactory::valueType(variantReferenceType);
- if (!reference->type) {
+ reference->d()->type = QQmlValueTypeFactory::valueType(variantReferenceType);
+ if (!reference->d()->type) {
return false;
}
} else {
return false;
}
}
- reference->type->setValue(variantReferenceValue);
+ reference->d()->type->setValue(variantReferenceValue);
} else {
// value-type reference
- reference->type->read(reference->object, reference->property);
+ reference->d()->type->read(reference->d()->object, reference->d()->property);
}
return true;
}
@@ -147,10 +152,10 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, QObject *object, int pr
Scope scope(v4);
initProto(v4);
- Scoped<QmlValueTypeReference> r(scope, new (v4->memoryManager) QmlValueTypeReference(v8));
- r->setPrototype(v4->qmlExtensions()->valueTypeWrapperPrototype);
- r->type = type; r->object = object; r->property = property;
- return r.asReturnedValue();
+ QmlValueTypeReference *r = v4->memoryManager->alloc<QmlValueTypeReference>(v8);
+ r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype);
+ r->d()->type = type; r->d()->object = object; r->d()->property = property;
+ return r->asReturnedValue();
}
ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, QQmlValueType *type)
@@ -159,45 +164,44 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value,
Scope scope(v4);
initProto(v4);
- Scoped<QmlValueTypeCopy> r(scope, new (v4->memoryManager) QmlValueTypeCopy(v8));
- r->setPrototype(v4->qmlExtensions()->valueTypeWrapperPrototype);
- r->type = type; r->value = value;
- return r.asReturnedValue();
+ QmlValueTypeCopy *r = v4->memoryManager->alloc<QmlValueTypeCopy>(v8);
+ r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype);
+ r->d()->type = type; r->d()->value = value;
+ return r->asReturnedValue();
}
QVariant QmlValueTypeWrapper::toVariant() const
{
- if (objectType == QmlValueTypeWrapper::Reference) {
+ if (d()->objectType == QmlValueTypeWrapper::Reference) {
const QmlValueTypeReference *reference = static_cast<const QmlValueTypeReference *>(this);
- if (reference->object && readReferenceValue(reference)) {
- return reference->type->value();
+ if (reference->d()->object && readReferenceValue(reference)) {
+ return reference->d()->type->value();
} else {
return QVariant();
}
} else {
- Q_ASSERT(objectType == QmlValueTypeWrapper::Copy);
- return static_cast<const QmlValueTypeCopy *>(this)->value;
+ Q_ASSERT(d()->objectType == QmlValueTypeWrapper::Copy);
+ return static_cast<const QmlValueTypeCopy *>(this)->d()->value;
}
}
void QmlValueTypeWrapper::destroy(Managed *that)
{
QmlValueTypeWrapper *w = that->as<QmlValueTypeWrapper>();
- assert(w);
- if (w->objectType == Reference)
- static_cast<QmlValueTypeReference *>(w)->~QmlValueTypeReference();
+ if (w->d()->objectType == Reference)
+ static_cast<QmlValueTypeReference *>(w)->d()->~Data();
else
- static_cast<QmlValueTypeCopy *>(w)->~QmlValueTypeCopy();
+ static_cast<QmlValueTypeCopy *>(w)->d()->~Data();
}
bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other)
{
QV4::QmlValueTypeWrapper *lv = m->as<QmlValueTypeWrapper>();
- assert(lv);
+ Q_ASSERT(lv);
if (QV4::VariantObject *rv = other->as<VariantObject>())
- return lv->isEqual(rv->data);
+ return lv->isEqual(rv->d()->data);
if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>())
return lv->isEqual(v->toVariant());
@@ -205,7 +209,7 @@ bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other)
return false;
}
-PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name)
+PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, String *name)
{
const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
@@ -217,59 +221,59 @@ PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name)
QQmlPropertyData local;
QQmlPropertyData *result = 0;
{
- QQmlData *ddata = QQmlData::get(r->type, false);
+ QQmlData *ddata = QQmlData::get(r->d()->type, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name.getPointer(), 0, 0);
+ result = ddata->propertyCache->property(name, 0, 0);
else
- result = QQmlPropertyCache::property(r->v8->engine(), r->type, name.getPointer(), 0, local);
+ result = QQmlPropertyCache::property(r->d()->v8->engine(), r->d()->type, name, 0, local);
}
return result ? Attr_Data : Attr_Invalid;
}
bool QmlValueTypeWrapper::isEqual(const QVariant& value)
{
- if (objectType == QmlValueTypeWrapper::Reference) {
+ if (d()->objectType == QmlValueTypeWrapper::Reference) {
QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(this);
- if (reference->object && readReferenceValue(reference)) {
- return reference->type->isEqual(value);
+ if (reference->d()->object && readReferenceValue(reference)) {
+ return reference->d()->type->isEqual(value);
} else {
return false;
}
} else {
- Q_ASSERT(objectType == QmlValueTypeWrapper::Copy);
+ Q_ASSERT(d()->objectType == QmlValueTypeWrapper::Copy);
QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(this);
- type->setValue(copy->value);
- if (type->isEqual(value))
+ d()->type->setValue(copy->d()->value);
+ if (d()->type->isEqual(value))
return true;
- return (value == copy->value);
+ return (value == copy->d()->value);
}
}
ReturnedValue QmlValueTypeWrapper::method_toString(CallContext *ctx)
{
- Object *o = ctx->callData->thisObject.asObject();
+ Object *o = ctx->d()->callData->thisObject.asObject();
if (!o)
return ctx->throwTypeError();
QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>();
if (!w)
return ctx->throwTypeError();
- if (w->objectType == QmlValueTypeWrapper::Reference) {
+ if (w->d()->objectType == QmlValueTypeWrapper::Reference) {
QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w);
- if (reference->object && readReferenceValue(reference)) {
- return w->v8->toString(w->type->toString());
+ if (reference->d()->object && readReferenceValue(reference)) {
+ return w->d()->v8->toString(w->d()->type->toString());
} else {
return QV4::Encode::undefined();
}
} else {
- Q_ASSERT(w->objectType == QmlValueTypeWrapper::Copy);
+ Q_ASSERT(w->d()->objectType == QmlValueTypeWrapper::Copy);
QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(w);
- w->type->setValue(copy->value);
- return w->v8->toString(w->type->toString());
+ w->d()->type->setValue(copy->d()->value);
+ return w->d()->v8->toString(w->d()->type->toString());
}
}
-ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue QmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty)
{
QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
@@ -277,28 +281,28 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
return v4->currentContext()->throwTypeError();
// Note: readReferenceValue() can change the reference->type.
- if (r->objectType == QmlValueTypeWrapper::Reference) {
+ if (r->d()->objectType == QmlValueTypeWrapper::Reference) {
QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r);
- if (!reference->object || !readReferenceValue(reference))
+ if (!reference->d()->object || !readReferenceValue(reference))
return Primitive::undefinedValue().asReturnedValue();
} else {
- Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy);
+ Q_ASSERT(r->d()->objectType == QmlValueTypeWrapper::Copy);
QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r);
- r->type->setValue(copy->value);
+ r->d()->type->setValue(copy->d()->value);
}
QQmlPropertyData local;
QQmlPropertyData *result = 0;
{
- QQmlData *ddata = QQmlData::get(r->type, false);
+ QQmlData *ddata = QQmlData::get(r->d()->type, false);
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name.getPointer(), 0, 0);
+ result = ddata->propertyCache->property(name, 0, 0);
else
- result = QQmlPropertyCache::property(r->v8->engine(), r->type, name, 0, local);
+ result = QQmlPropertyCache::property(r->d()->v8->engine(), r->d()->type, name, 0, local);
}
if (!result)
@@ -307,31 +311,31 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
if (result->isFunction()) {
// calling a Q_INVOKABLE function of a value type
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->d()->type, name, QV4::QObjectWrapper::IgnoreRevision);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
if (result->propType == metatype) { \
cpptype v; \
void *args[] = { &v, 0 }; \
- r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
+ r->d()->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
return constructor(v); \
}
// These four types are the most common used by the value type wrappers
VALUE_TYPE_LOAD(QMetaType::QReal, qreal, QV4::Encode);
VALUE_TYPE_LOAD(QMetaType::Int, int, QV4::Encode);
- VALUE_TYPE_LOAD(QMetaType::QString, QString, r->v8->toString);
+ VALUE_TYPE_LOAD(QMetaType::QString, QString, r->d()->v8->toString);
VALUE_TYPE_LOAD(QMetaType::Bool, bool, QV4::Encode);
QVariant v(result->propType, (void *)0);
void *args[] = { v.data(), 0 };
- r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
- return r->v8->fromVariant(v);
+ r->d()->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
+ return r->d()->v8->fromVariant(v);
#undef VALUE_TYPE_ACCESSOR
}
-void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
+void QmlValueTypeWrapper::put(Managed *m, String *name, const ValueRef value)
{
ExecutionEngine *v4 = m->engine();
Scope scope(v4);
@@ -345,38 +349,38 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
}
QByteArray propName = name->toQString().toUtf8();
- if (r->objectType == QmlValueTypeWrapper::Reference) {
+ if (r->d()->objectType == QmlValueTypeWrapper::Reference) {
QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r.getPointer());
- QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
+ QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
- if (!reference->object || !writebackProperty.isWritable() || !readReferenceValue(reference))
+ if (!reference->d()->object || !writebackProperty.isWritable() || !readReferenceValue(reference))
return;
// we lookup the index after readReferenceValue() since it can change the reference->type.
- int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ int index = r->d()->type->metaObject()->indexOfProperty(propName.constData());
if (index == -1)
return;
- QMetaProperty p = r->type->metaObject()->property(index);
+ QMetaProperty p = r->d()->type->metaObject()->property(index);
QQmlBinding *newBinding = 0;
QV4::ScopedFunctionObject f(scope, value);
if (f) {
- if (!f->bindingKeyFlag) {
+ if (!f->bindingKeyFlag()) {
// assigning a JS function to a non-var-property is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
- Scoped<String> e(scope, r->v8->toString(error));
+ Scoped<String> e(scope, r->d()->v8->toString(error));
v4->currentContext()->throwError(e);
return;
}
- QQmlContextData *context = r->v8->callingContext();
+ QQmlContextData *context = r->d()->v8->callingContext();
QQmlPropertyData cacheData;
cacheData.setFlags(QQmlPropertyData::IsWritable |
QQmlPropertyData::IsValueTypeVirtual);
- cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
- cacheData.coreIndex = reference->property;
+ cacheData.propType = reference->d()->object->metaObject()->property(reference->d()->property).userType();
+ cacheData.coreIndex = reference->d()->property;
cacheData.valueTypeFlags = 0;
cacheData.valueTypeCoreIndex = index;
cacheData.valueTypePropType = p.userType();
@@ -384,46 +388,46 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, f);
bindingFunction->initBindingLocation();
- newBinding = new QQmlBinding(value, reference->object, context);
- newBinding->setTarget(reference->object, cacheData, context);
+ newBinding = new QQmlBinding(value, reference->d()->object, context);
+ newBinding->setTarget(reference->d()->object, cacheData, context);
}
QQmlAbstractBinding *oldBinding =
- QQmlPropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
+ QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, index, newBinding);
if (oldBinding)
oldBinding->destroy();
if (!f) {
- QVariant v = r->v8->toVariant(value, -1);
+ QVariant v = r->d()->v8->toVariant(value, -1);
if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
v = v.toInt();
- p.write(reference->type, v);
+ p.write(reference->d()->type, v);
if (writebackProperty.userType() == QMetaType::QVariant) {
- QVariant variantReferenceValue = r->type->value();
- reference->type->writeVariantValue(reference->object, reference->property, 0, &variantReferenceValue);
+ QVariant variantReferenceValue = r->d()->type->value();
+ reference->d()->type->writeVariantValue(reference->d()->object, reference->d()->property, 0, &variantReferenceValue);
} else {
- reference->type->write(reference->object, reference->property, 0);
+ reference->d()->type->write(reference->d()->object, reference->d()->property, 0);
}
}
} else {
- Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy);
+ Q_ASSERT(r->d()->objectType == QmlValueTypeWrapper::Copy);
QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r.getPointer());
- int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ int index = r->d()->type->metaObject()->indexOfProperty(propName.constData());
if (index == -1)
return;
- QVariant v = r->v8->toVariant(value, -1);
+ QVariant v = r->d()->v8->toVariant(value, -1);
- r->type->setValue(copy->value);
- QMetaProperty p = r->type->metaObject()->property(index);
- p.write(r->type, v);
- copy->value = r->type->value();
+ r->d()->type->setValue(copy->d()->value);
+ QMetaProperty p = r->d()->type->metaObject()->property(index);
+ p.write(r->d()->type, v);
+ copy->d()->value = r->d()->type->value();
}
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index d66dbbba0c..53d5ae95af 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -68,11 +68,14 @@ namespace QV4 {
struct Q_QML_EXPORT QmlValueTypeWrapper : Object
{
- V4_OBJECT
-protected:
enum ObjectType { Reference, Copy };
- QmlValueTypeWrapper(QV8Engine *engine, ObjectType type);
- ~QmlValueTypeWrapper();
+ struct Data : Object::Data {
+ Data(QV8Engine *engine, ObjectType type);
+ QV8Engine *v8;
+ ObjectType objectType;
+ mutable QQmlValueType *type;
+ };
+ V4_OBJECT(Object)
public:
@@ -82,19 +85,14 @@ public:
QVariant toVariant() const;
bool isEqual(const QVariant& value);
-
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
- static void put(Managed *m, const StringRef name, const ValueRef value);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const ValueRef value);
static void destroy(Managed *that);
static bool isEqualTo(Managed *m, Managed *other);
- static PropertyAttributes query(const Managed *, StringRef name);
+ static PropertyAttributes query(const Managed *, String *name);
static QV4::ReturnedValue method_toString(CallContext *ctx);
- QV8Engine *v8;
- ObjectType objectType;
- mutable QQmlValueType *type;
-
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 1ff95a245d..2f04984264 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1087,7 +1087,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// And, if the new value is a scarce resource, we need to ensure that it does not get
// automatically released by the engine until no other references to it exist.
QV4::ScopedValue newv(scope, QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value));
- QV4::VariantObjectRef v = newv;
+ QV4::Scoped<QV4::VariantObject> v(scope, newv);
if (!!v)
v->addVmePropertyReference();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index d89dc92b68..e7bea80a18 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -72,7 +72,7 @@ using namespace QV4;
#ifndef QT_NO_XMLSTREAMREADER
#define V4THROW_REFERENCE(string) { \
- Scoped<Object> error(scope, ctx->engine->newReferenceErrorObject(QStringLiteral(string))); \
+ Scoped<Object> error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \
return ctx->throwError(error); \
}
@@ -105,9 +105,9 @@ static ReturnedValue constructMeObject(const ValueRef thisObj, QV8Engine *e)
ExecutionEngine *v4 = QV8Engine::getV4(e);
Scope scope(v4);
Scoped<Object> meObj(scope, v4->newObject());
- meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj);
+ meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))).getPointer(), thisObj);
ScopedValue v(scope, QmlContextWrapper::qmlScope(e, e->callingContext(), 0));
- meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v);
+ meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))).getPointer(), v);
return meObj.asReturnedValue();
}
@@ -185,96 +185,101 @@ public:
class NamedNodeMap : public Object
{
- V4_OBJECT
public:
- NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
- : Object(engine)
- , list(list)
- , d(data)
- {
- setVTable(staticVTable());
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
+ : Object::Data(engine)
+ , list(list)
+ , d(data)
+ {
+ setVTable(staticVTable());
- if (d)
- d->addref();
- }
- ~NamedNodeMap() {
- if (d)
- d->release();
- }
+ if (d)
+ d->addref();
+ }
+ ~Data() {
+ if (d)
+ d->release();
+ }
+ QList<NodeImpl *> list; // Only used in NamedNodeMap
+ NodeImpl *d;
+ };
+ V4_OBJECT(Object)
// C++ API
static ReturnedValue create(QV8Engine *, NodeImpl *, const QList<NodeImpl *> &);
// JS API
static void destroy(Managed *that) {
- that->as<NamedNodeMap>()->~NamedNodeMap();
+ that->as<NamedNodeMap>()->d()->~Data();
}
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
-
- QList<NodeImpl *> list; // Only used in NamedNodeMap
- NodeImpl *d;
};
DEFINE_OBJECT_VTABLE(NamedNodeMap);
class NodeList : public Object
{
- V4_OBJECT
public:
- NodeList(ExecutionEngine *engine, NodeImpl *data)
- : Object(engine)
- , d(data)
- {
- setVTable(staticVTable());
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, NodeImpl *data)
+ : Object::Data(engine)
+ , d(data)
+ {
+ setVTable(staticVTable());
- if (d)
- d->addref();
- }
- ~NodeList() {
- if (d)
- d->release();
- }
+ if (d)
+ d->addref();
+ }
+ ~Data() {
+ if (d)
+ d->release();
+ }
+ NodeImpl *d;
+ };
+ V4_OBJECT(Object)
// JS API
static void destroy(Managed *that) {
- that->as<NodeList>()->~NodeList();
+ that->as<NodeList>()->d()->~Data();
}
- static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
+ static ReturnedValue get(Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
// C++ API
static ReturnedValue create(QV8Engine *, NodeImpl *);
- NodeImpl *d;
};
DEFINE_OBJECT_VTABLE(NodeList);
class NodePrototype : public Object
{
- V4_OBJECT
public:
- NodePrototype(ExecutionEngine *engine)
- : Object(engine)
- {
- setVTable(staticVTable());
-
- Scope scope(engine);
- ScopedObject protectThis(scope, this);
-
- defineAccessorProperty(QStringLiteral("nodeName"), method_get_nodeName, 0);
- defineAccessorProperty(QStringLiteral("nodeValue"), method_get_nodeValue, 0);
- defineAccessorProperty(QStringLiteral("nodeType"), method_get_nodeType, 0);
-
- defineAccessorProperty(QStringLiteral("parentNode"), method_get_parentNode, 0);
- defineAccessorProperty(QStringLiteral("childNodes"), method_get_childNodes, 0);
- defineAccessorProperty(QStringLiteral("firstChild"), method_get_firstChild, 0);
- defineAccessorProperty(QStringLiteral("lastChild"), method_get_lastChild, 0);
- defineAccessorProperty(QStringLiteral("previousSibling"), method_get_previousSibling, 0);
- defineAccessorProperty(QStringLiteral("nextSibling"), method_get_nextSibling, 0);
- defineAccessorProperty(QStringLiteral("attributes"), method_get_attributes, 0);
- }
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+
+ Scope scope(engine);
+ ScopedObject o(scope, this);
+
+ o->defineAccessorProperty(QStringLiteral("nodeName"), method_get_nodeName, 0);
+ o->defineAccessorProperty(QStringLiteral("nodeValue"), method_get_nodeValue, 0);
+ o->defineAccessorProperty(QStringLiteral("nodeType"), method_get_nodeType, 0);
+
+ o->defineAccessorProperty(QStringLiteral("parentNode"), method_get_parentNode, 0);
+ o->defineAccessorProperty(QStringLiteral("childNodes"), method_get_childNodes, 0);
+ o->defineAccessorProperty(QStringLiteral("firstChild"), method_get_firstChild, 0);
+ o->defineAccessorProperty(QStringLiteral("lastChild"), method_get_lastChild, 0);
+ o->defineAccessorProperty(QStringLiteral("previousSibling"), method_get_previousSibling, 0);
+ o->defineAccessorProperty(QStringLiteral("nextSibling"), method_get_nextSibling, 0);
+ o->defineAccessorProperty(QStringLiteral("attributes"), method_get_attributes, 0);
+ }
+ };
+ V4_OBJECT(Object)
static void initClass(ExecutionEngine *engine);
@@ -304,39 +309,40 @@ public:
DEFINE_OBJECT_VTABLE(NodePrototype);
-class Node : public Object
+struct Node : public Object
{
- V4_OBJECT
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, NodeImpl *data)
+ : Object::Data(engine)
+ , d(data)
+ {
+ setVTable(staticVTable());
- Node(ExecutionEngine *engine, NodeImpl *data)
- : Object(engine)
- , d(data)
- {
- setVTable(staticVTable());
+ if (d)
+ d->addref();
+ }
+ ~Data() {
+ if (d)
+ d->release();
+ }
+ NodeImpl *d;
+ };
+ V4_OBJECT(Object)
- if (d)
- d->addref();
- }
- ~Node() {
- if (d)
- d->release();
- }
// JS API
static void destroy(Managed *that) {
- that->as<Node>()->~Node();
+ that->as<Node>()->d()->~Data();
}
// C++ API
static ReturnedValue create(QV8Engine *, NodeImpl *);
- Node(const Node &o);
bool isNull() const;
- NodeImpl *d;
-
private:
Node &operator=(const Node &);
+ Node(const Node &o);
};
DEFINE_OBJECT_VTABLE(Node);
@@ -420,12 +426,12 @@ void NodeImpl::release()
ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
QString name;
- switch (r->d->type) {
+ switch (r->d()->d->type) {
case NodeImpl::Document:
name = QStringLiteral("#document");
break;
@@ -436,52 +442,52 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
name = QStringLiteral("#text");
break;
default:
- name = r->d->name;
+ name = r->d()->d->name;
break;
}
- return Encode(ctx->engine->newString(name));
+ return Encode(ctx->d()->engine->newString(name));
}
ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- if (r->d->type == NodeImpl::Document ||
- r->d->type == NodeImpl::DocumentFragment ||
- r->d->type == NodeImpl::DocumentType ||
- r->d->type == NodeImpl::Element ||
- r->d->type == NodeImpl::Entity ||
- r->d->type == NodeImpl::EntityReference ||
- r->d->type == NodeImpl::Notation)
+ if (r->d()->d->type == NodeImpl::Document ||
+ r->d()->d->type == NodeImpl::DocumentFragment ||
+ r->d()->d->type == NodeImpl::DocumentType ||
+ r->d()->d->type == NodeImpl::Element ||
+ r->d()->d->type == NodeImpl::Entity ||
+ r->d()->d->type == NodeImpl::EntityReference ||
+ r->d()->d->type == NodeImpl::Notation)
return Encode::null();
- return Encode(ctx->engine->newString(r->d->data));
+ return Encode(ctx->d()->engine->newString(r->d()->d->data));
}
ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- return Encode(r->d->type);
+ return Encode(r->d()->d->type);
}
ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (r->d->parent)
- return Node::create(engine, r->d->parent);
+ if (r->d()->d->parent)
+ return Node::create(engine, r->d()->d->parent);
else
return Encode::null();
}
@@ -489,63 +495,63 @@ ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx)
ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return NodeList::create(engine, r->d);
+ return NodeList::create(engine, r->d()->d);
}
ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (r->d->children.isEmpty())
+ if (r->d()->d->children.isEmpty())
return Encode::null();
else
- return Node::create(engine, r->d->children.first());
+ return Node::create(engine, r->d()->d->children.first());
}
ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (r->d->children.isEmpty())
+ if (r->d()->d->children.isEmpty())
return Encode::null();
else
- return Node::create(engine, r->d->children.last());
+ return Node::create(engine, r->d()->d->children.last());
}
ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (!r->d->parent)
+ if (!r->d()->d->parent)
return Encode::null();
- for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
- if (r->d->parent->children.at(ii) == r->d) {
+ for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if (ii == 0)
return Encode::null();
else
- return Node::create(engine, r->d->parent->children.at(ii - 1));
+ return Node::create(engine, r->d()->d->parent->children.at(ii - 1));
}
}
@@ -555,21 +561,21 @@ ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (!r->d->parent)
+ if (!r->d()->d->parent)
return Encode::null();
- for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
- if (r->d->parent->children.at(ii) == r->d) {
- if ((ii + 1) == r->d->parent->children.count())
+ for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ if (r->d()->d->parent->children.at(ii) == r->d()->d) {
+ if ((ii + 1) == r->d()->d->parent->children.count())
return Encode::null();
else
- return Node::create(engine, r->d->parent->children.at(ii + 1));
+ return Node::create(engine, r->d()->d->parent->children.at(ii + 1));
}
}
@@ -579,16 +585,16 @@ ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx)
ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return ctx->throwTypeError();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (r->d->type != NodeImpl::Element)
+ if (r->d()->d->type != NodeImpl::Element)
return Encode::null();
else
- return NamedNodeMap::create(engine, r->d, r->d->attributes);
+ return NamedNodeMap::create(engine, r->d()->d, r->d()->d->attributes);
}
ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
@@ -596,7 +602,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
Scope scope(v4);
QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
if (d->nodePrototype.isUndefined()) {
- ScopedObject p(scope, new (v4->memoryManager) NodePrototype(v4));
+ ScopedObject p(scope, v4->memoryManager->alloc<NodePrototype>(v4));
d->nodePrototype = p;
v4->v8Engine->freezeObject(p);
}
@@ -608,7 +614,7 @@ ReturnedValue Node::create(QV8Engine *engine, NodeImpl *data)
ExecutionEngine *v4 = QV8Engine::getV4(engine);
Scope scope(v4);
- Scoped<Node> instance(scope, new (v4->memoryManager) Node(v4, data));
+ Scoped<Node> instance(scope, v4->memoryManager->alloc<Node>(v4, data));
ScopedObject p(scope);
switch (data->type) {
@@ -673,45 +679,45 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine)
ReturnedValue Attr::method_name(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return engine->toString(r->d->name);
+ return engine->toString(r->d()->d->name);
}
ReturnedValue Attr::method_value(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return engine->toString(r->d->data);
+ return engine->toString(r->d()->d->data);
}
ReturnedValue Attr::method_ownerElement(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return Node::create(engine, r->d->parent);
+ return Node::create(engine, r->d()->d->parent);
}
ReturnedValue CharacterData::method_length(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
Q_UNUSED(engine)
- return Encode(r->d->data.length());
+ return Encode(r->d()->d->data.length());
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -733,21 +739,21 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r) return Encode::undefined();
- return Encode(r->d->data.trimmed().isEmpty());
+ return Encode(r->d()->d->data.trimmed().isEmpty());
}
ReturnedValue Text::method_wholeText(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
if (!r)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return engine->toString(r->d->data);
+ return engine->toString(r->d()->d->data);
}
ReturnedValue Text::prototype(ExecutionEngine *v4)
@@ -883,22 +889,15 @@ ReturnedValue Document::load(QV8Engine *engine, const QByteArray &data)
return Encode::null();
}
- ScopedObject instance(scope, new (v4->memoryManager) Node(v4, document));
+ ScopedObject instance(scope, v4->memoryManager->alloc<Node>(v4, document));
ScopedObject p(scope);
instance->setPrototype((p = Document::prototype(v4)).getPointer());
return instance.asReturnedValue();
}
-Node::Node(const Node &o)
- : Object(o.engine()), d(o.d)
-{
- if (d)
- d->addref();
-}
-
bool Node::isNull() const
{
- return d == 0;
+ return d()->d == 0;
}
ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty)
@@ -913,17 +912,17 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty
QV8Engine *engine = v4->v8Engine;
- if ((int)index < r->list.count()) {
+ if ((int)index < r->d()->list.count()) {
if (hasProperty)
*hasProperty = true;
- return Node::create(engine, r->list.at(index));
+ return Node::create(engine, r->d()->list.at(index));
}
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
-ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue NamedNodeMap::get(Managed *m, String *name, bool *hasProperty)
{
NamedNodeMap *r = m->as<NamedNodeMap>();
QV4::ExecutionEngine *v4 = m->engine();
@@ -932,16 +931,16 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope
name->makeIdentifier();
if (name->equals(v4->id_length))
- return Primitive::fromInt32(r->list.count()).asReturnedValue();
+ return Primitive::fromInt32(r->d()->list.count()).asReturnedValue();
QV8Engine *engine = v4->v8Engine;
QString str = name->toQString();
- for (int ii = 0; ii < r->list.count(); ++ii) {
- if (r->list.at(ii)->name == str) {
+ for (int ii = 0; ii < r->d()->list.count(); ++ii) {
+ if (r->d()->list.at(ii)->name == str) {
if (hasProperty)
*hasProperty = true;
- return Node::create(engine, r->list.at(ii));
+ return Node::create(engine, r->d()->list.at(ii));
}
}
@@ -953,10 +952,7 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope
ReturnedValue NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
{
ExecutionEngine *v4 = QV8Engine::getV4(engine);
- Scope scope(v4);
-
- Scoped<NamedNodeMap> instance(scope, new (v4->memoryManager) NamedNodeMap(v4, data, list));
- return instance.asReturnedValue();
+ return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue();
}
ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
@@ -971,17 +967,17 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
QV8Engine *engine = v4->v8Engine;
- if ((int)index < r->d->children.count()) {
+ if ((int)index < r->d()->d->children.count()) {
if (hasProperty)
*hasProperty = true;
- return Node::create(engine, r->d->children.at(index));
+ return Node::create(engine, r->d()->d->children.at(index));
}
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
-ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
+ReturnedValue NodeList::get(Managed *m, String *name, bool *hasProperty)
{
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
@@ -991,60 +987,58 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
name->makeIdentifier();
if (name->equals(v4->id_length))
- return Primitive::fromInt32(r->d->children.count()).asReturnedValue();
+ return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue();
return Object::get(m, name, hasProperty);
}
ReturnedValue NodeList::create(QV8Engine *engine, NodeImpl *data)
{
ExecutionEngine *v4 = QV8Engine::getV4(engine);
- Scope scope(v4);
- Scoped<NodeList> instance(scope, new (v4->memoryManager) NodeList(v4, data));
- return instance.asReturnedValue();
+ return (v4->memoryManager->alloc<NodeList>(v4, data))->asReturnedValue();
}
ReturnedValue Document::method_documentElement(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
- if (!r || r->d->type != NodeImpl::Document)
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
+ if (!r || r->d()->d->type != NodeImpl::Document)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
+ return Node::create(engine, static_cast<DocumentImpl *>(r->d()->d)->root);
}
ReturnedValue Document::method_xmlStandalone(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
- if (!r || r->d->type != NodeImpl::Document)
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
+ if (!r || r->d()->d->type != NodeImpl::Document)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
Q_UNUSED(engine)
- return Encode(static_cast<DocumentImpl *>(r->d)->isStandalone);
+ return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
}
ReturnedValue Document::method_xmlVersion(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
- if (!r || r->d->type != NodeImpl::Document)
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
+ if (!r || r->d()->d->type != NodeImpl::Document)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
+ return engine->toString(static_cast<DocumentImpl *>(r->d()->d)->version);
}
ReturnedValue Document::method_xmlEncoding(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>());
- if (!r || r->d->type != NodeImpl::Document)
+ Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>());
+ if (!r || r->d()->d->type != NodeImpl::Document)
return Encode::undefined();
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding);
+ return engine->toString(static_cast<DocumentImpl *>(r->d()->d)->encoding);
}
class QQmlXMLHttpRequest : public QObject
@@ -1551,21 +1545,21 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
}
ScopedString s(scope, v4->newString(QStringLiteral("ThisObject")));
- Scoped<Object> thisObj(scope, o->get(s));
+ Scoped<Object> thisObj(scope, o->get(s.getPointer()));
if (!thisObj) {
ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
return;
}
s = v4->newString(QStringLiteral("onreadystatechange"));
- Scoped<FunctionObject> callback(scope, thisObj->get(s));
+ Scoped<FunctionObject> callback(scope, thisObj->get(s.getPointer()));
if (!callback) {
// not an error, but no onreadystatechange function to call.
return;
}
s = v4->newString(QStringLiteral("ActivationObject"));
- Scoped<Object> activationObject(scope, o->get(s));
+ Scoped<Object> activationObject(scope, o->get(s.getPointer()));
if (!activationObject) {
v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
return;
@@ -1607,56 +1601,54 @@ void QQmlXMLHttpRequest::destroyNetwork()
struct QQmlXMLHttpRequestWrapper : public Object
{
- V4_OBJECT
- QQmlXMLHttpRequestWrapper(ExecutionEngine *engine, QQmlXMLHttpRequest *request)
- : Object(engine)
- , request(request)
- {
- setVTable(staticVTable());
- }
- ~QQmlXMLHttpRequestWrapper() {
- delete request;
- }
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine, QQmlXMLHttpRequest *request)
+ : Object::Data(engine)
+ , request(request)
+ {
+ setVTable(staticVTable());
+ }
+ ~Data() {
+ delete request;
+ }
+ QQmlXMLHttpRequest *request;
+ };
+ V4_OBJECT(Object)
static void destroy(Managed *that) {
- that->as<QQmlXMLHttpRequestWrapper>()->~QQmlXMLHttpRequestWrapper();
+ that->as<QQmlXMLHttpRequestWrapper>()->d()->~Data();
}
-
- QQmlXMLHttpRequest *request;
};
DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
- V4_OBJECT
- QQmlXMLHttpRequestCtor(ExecutionEngine *engine)
- : FunctionObject(engine->rootContext, QStringLiteral("XMLHttpRequest"))
- {
- setVTable(staticVTable());
- Scope scope(engine);
- ScopedValue protectThis(scope, this);
-
- defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0));
- defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1));
- defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2));
- defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3));
- defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4));
- if (!proto)
- setupProto();
- ScopedString s(scope, engine->id_prototype);
- defineDefaultProperty(s, ScopedObject(scope, proto));
- }
- ~QQmlXMLHttpRequestCtor()
- {}
-
- static void destroy(Managed *that) {
- that->as<QQmlXMLHttpRequestCtor>()->~QQmlXMLHttpRequestCtor();
- }
+ struct Data : FunctionObject::Data {
+ Data(ExecutionEngine *engine)
+ : FunctionObject::Data(engine->rootContext, QStringLiteral("XMLHttpRequest"))
+ {
+ setVTable(staticVTable());
+ Scope scope(engine);
+ Scoped<QQmlXMLHttpRequestCtor> ctor(scope, this);
+
+ ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0));
+ ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2));
+ ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3));
+ ctor->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4));
+ if (!ctor->d()->proto)
+ ctor->setupProto();
+ ScopedString s(scope, engine->id_prototype);
+ ctor->defineDefaultProperty(s.getPointer(), ScopedObject(scope, ctor->d()->proto));
+ }
+ Object *proto;
+ };
+ V4_OBJECT(FunctionObject)
static void markObjects(Managed *that, ExecutionEngine *e) {
QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>();
- if (c->proto)
- c->proto->mark(e);
+ if (c->d()->proto)
+ c->d()->proto->mark(e);
FunctionObject::markObjects(that, e);
}
static ReturnedValue construct(Managed *that, QV4::CallData *)
@@ -1668,8 +1660,8 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
QV8Engine *engine = that->engine()->v8Engine;
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, new (that->engine()->memoryManager) QQmlXMLHttpRequestWrapper(that->engine(), r));
- w->setPrototype(ctor->proto);
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, that->engine()->memoryManager->alloc<QQmlXMLHttpRequestWrapper>(that->engine(), r));
+ w->setPrototype(ctor->d()->proto);
return w.asReturnedValue();
}
@@ -1691,9 +1683,6 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static ReturnedValue method_get_statusText(CallContext *ctx);
static ReturnedValue method_get_responseText(CallContext *ctx);
static ReturnedValue method_get_responseXML(CallContext *ctx);
-
-
- Object *proto;
};
DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestCtor);
@@ -1703,29 +1692,29 @@ void QQmlXMLHttpRequestCtor::setupProto()
ExecutionEngine *v4 = engine();
Scope scope(v4);
Scoped<Object> p(scope, v4->newObject());
- proto = p.getPointer();
+ d()->proto = p.getPointer();
// Methods
- proto->defineDefaultProperty(QStringLiteral("open"), method_open);
- proto->defineDefaultProperty(QStringLiteral("setRequestHeader"), method_setRequestHeader);
- proto->defineDefaultProperty(QStringLiteral("send"), method_send);
- proto->defineDefaultProperty(QStringLiteral("abort"), method_abort);
- proto->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader);
- proto->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders);
+ d()->proto->defineDefaultProperty(QStringLiteral("open"), method_open);
+ d()->proto->defineDefaultProperty(QStringLiteral("setRequestHeader"), method_setRequestHeader);
+ d()->proto->defineDefaultProperty(QStringLiteral("send"), method_send);
+ d()->proto->defineDefaultProperty(QStringLiteral("abort"), method_abort);
+ d()->proto->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader);
+ d()->proto->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders);
// Read-only properties
- proto->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, 0);
- proto->defineAccessorProperty(QStringLiteral("status"),method_get_status, 0);
- proto->defineAccessorProperty(QStringLiteral("statusText"),method_get_statusText, 0);
- proto->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, 0);
- proto->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, 0);
+ d()->proto->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, 0);
+ d()->proto->defineAccessorProperty(QStringLiteral("status"),method_get_status, 0);
+ d()->proto->defineAccessorProperty(QStringLiteral("statusText"),method_get_statusText, 0);
+ d()->proto->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, 0);
+ d()->proto->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, 0);
// State values
- proto->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0));
- proto->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1));
- proto->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2));
- proto->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3));
- proto->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4));
+ d()->proto->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0));
+ d()->proto->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1));
+ d()->proto->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2));
+ d()->proto->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3));
+ d()->proto->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4));
}
@@ -1733,18 +1722,18 @@ void QQmlXMLHttpRequestCtor::setupProto()
ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->callData->argc < 2 || ctx->callData->argc > 5)
+ if (ctx->d()->callData->argc < 2 || ctx->d()->callData->argc > 5)
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
// Argument 0 - Method
- QString method = ctx->callData->args[0].toQStringNoThrow().toUpper();
+ QString method = ctx->d()->callData->args[0].toQStringNoThrow().toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
@@ -1753,21 +1742,21 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl(ctx->callData->args[1].toQStringNoThrow());
+ QUrl url = QUrl(ctx->d()->callData->args[1].toQStringNoThrow());
if (url.isRelative())
url = engine->callingContext()->resolvedUrl(url);
// Argument 2 - async (optional)
- if (ctx->callData->argc > 2 && !ctx->callData->args[2].booleanValue())
+ if (ctx->d()->callData->argc > 2 && !ctx->d()->callData->args[2].booleanValue())
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (ctx->callData->argc > 3)
- username = ctx->callData->args[3].toQStringNoThrow();
- if (ctx->callData->argc > 4)
- password = ctx->callData->args[4].toQStringNoThrow();
+ if (ctx->d()->callData->argc > 3)
+ username = ctx->d()->callData->args[3].toQStringNoThrow();
+ if (ctx->d()->callData->argc > 4)
+ password = ctx->d()->callData->args[4].toQStringNoThrow();
// Clear the fragment (if any)
url.setFragment(QString());
@@ -1776,26 +1765,26 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, engine));
+ ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, engine));
return r->open(meObject, method, url);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- QString name = ctx->callData->args[0].toQStringNoThrow();
- QString value = ctx->callData->args[1].toQStringNoThrow();
+ QString name = ctx->d()->callData->args[0].toQStringNoThrow();
+ QString value = ctx->d()->callData->args[1].toQStringNoThrow();
// ### Check that name and value are well formed
@@ -1830,48 +1819,48 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
if (r->readyState() != QQmlXMLHttpRequest::Opened ||
r->sendFlag())
V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (ctx->callData->argc > 0)
- data = ctx->callData->args[0].toQStringNoThrow().toUtf8();
+ if (ctx->d()->callData->argc > 0)
+ data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8();
- ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, engine));
+ ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, engine));
return r->send(meObject, data);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, ctx->engine->v8Engine));
+ ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, ctx->d()->engine->v8Engine));
return r->abort(meObject);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
@@ -1879,20 +1868,20 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx)
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return engine->toString(r->header(ctx->callData->args[0].toQStringNoThrow()));
+ return engine->toString(r->header(ctx->d()->callData->args[0].toQStringNoThrow()));
}
ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
- if (ctx->callData->argc != 0)
+ if (ctx->d()->callData->argc != 0)
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
@@ -1907,10 +1896,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *
ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
return Encode(r->readyState());
}
@@ -1918,10 +1907,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx)
ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
@@ -1936,12 +1925,12 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx)
ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
@@ -1956,12 +1945,12 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx)
ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = ctx->d()->engine->v8Engine;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
@@ -1973,17 +1962,17 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx)
ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
{
Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
- QQmlXMLHttpRequest *r = w->request;
+ QQmlXMLHttpRequest *r = w->d()->request;
if (!r->receivedXml() ||
(r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)) {
return Encode::null();
} else {
- return Document::load(ctx->engine->v8Engine, r->rawResponseBody());
+ return Document::load(ctx->d()->engine->v8Engine, r->rawResponseBody());
}
}
@@ -1998,9 +1987,9 @@ void *qt_add_qmlxmlhttprequest(QV8Engine *engine)
ExecutionEngine *v4 = QV8Engine::getV4(engine);
Scope scope(v4);
- Scoped<QQmlXMLHttpRequestCtor> ctor(scope, new (v4->memoryManager) QQmlXMLHttpRequestCtor(v4));
+ Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4));
ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest")));
- v4->globalObject->defineReadonlyProperty(s, ctor);
+ v4->globalObject->defineReadonlyProperty(s.getPointer(), ctor);
QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData;
return data;
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index a7db7d214e..e07d97e67c 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -47,6 +47,7 @@
#include <private/qqmlstringconverters_p.h>
#include <private/qqmllocale_p.h>
#include <private/qv8engine_p.h>
+#include <QFileInfo>
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlglobal_p.h>
@@ -85,15 +86,13 @@ struct StaticQtMetaObject : public QObject
{ return &staticQtMetaObject; }
};
-QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
- : Object(v4)
- , m_platform(0)
- , m_application(0)
+QV4::QtObject::Data::Data(ExecutionEngine *v4, QQmlEngine *qmlEngine)
+ : Object::Data(v4)
{
setVTable(staticVTable());
Scope scope(v4);
- ScopedObject protectThis(scope, this);
+ ScopedObject o(scope, this);
// Set all the enums from the "Qt" namespace
const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
@@ -102,54 +101,54 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
QMetaEnum enumerator = qtMetaObject->enumerator(ii);
for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
- put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
+ o->put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))).getPointer(), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
}
}
- put((str = v4->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
- put((str = v4->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
-
- defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
- defineDefaultProperty(QStringLiteral("isQtObject"), method_isQtObject);
- defineDefaultProperty(QStringLiteral("rgba"), method_rgba);
- defineDefaultProperty(QStringLiteral("hsla"), method_hsla);
- defineDefaultProperty(QStringLiteral("colorEqual"), method_colorEqual);
- defineDefaultProperty(QStringLiteral("rect"), method_rect);
- defineDefaultProperty(QStringLiteral("point"), method_point);
- defineDefaultProperty(QStringLiteral("size"), method_size);
- defineDefaultProperty(QStringLiteral("font"), method_font);
-
- defineDefaultProperty(QStringLiteral("vector2d"), method_vector2d);
- defineDefaultProperty(QStringLiteral("vector3d"), method_vector3d);
- defineDefaultProperty(QStringLiteral("vector4d"), method_vector4d);
- defineDefaultProperty(QStringLiteral("quaternion"), method_quaternion);
- defineDefaultProperty(QStringLiteral("matrix4x4"), method_matrix4x4);
-
- defineDefaultProperty(QStringLiteral("formatDate"), method_formatDate);
- defineDefaultProperty(QStringLiteral("formatTime"), method_formatTime);
- defineDefaultProperty(QStringLiteral("formatDateTime"), method_formatDateTime);
-
- defineDefaultProperty(QStringLiteral("openUrlExternally"), method_openUrlExternally);
- defineDefaultProperty(QStringLiteral("fontFamilies"), method_fontFamilies);
- defineDefaultProperty(QStringLiteral("md5"), method_md5);
- defineDefaultProperty(QStringLiteral("btoa"), method_btoa);
- defineDefaultProperty(QStringLiteral("atob"), method_atob);
- defineDefaultProperty(QStringLiteral("resolvedUrl"), method_resolvedUrl);
- defineDefaultProperty(QStringLiteral("locale"), method_locale);
- defineDefaultProperty(QStringLiteral("binding"), method_binding);
+ o->put((str = v4->newString(QStringLiteral("Asynchronous"))).getPointer(), (v = QV4::Primitive::fromInt32(0)));
+ o->put((str = v4->newString(QStringLiteral("Synchronous"))).getPointer(), (v = QV4::Primitive::fromInt32(1)));
+
+ o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
+ o->defineDefaultProperty(QStringLiteral("isQtObject"), method_isQtObject);
+ o->defineDefaultProperty(QStringLiteral("rgba"), method_rgba);
+ o->defineDefaultProperty(QStringLiteral("hsla"), method_hsla);
+ o->defineDefaultProperty(QStringLiteral("colorEqual"), method_colorEqual);
+ o->defineDefaultProperty(QStringLiteral("rect"), method_rect);
+ o->defineDefaultProperty(QStringLiteral("point"), method_point);
+ o->defineDefaultProperty(QStringLiteral("size"), method_size);
+ o->defineDefaultProperty(QStringLiteral("font"), method_font);
+
+ o->defineDefaultProperty(QStringLiteral("vector2d"), method_vector2d);
+ o->defineDefaultProperty(QStringLiteral("vector3d"), method_vector3d);
+ o->defineDefaultProperty(QStringLiteral("vector4d"), method_vector4d);
+ o->defineDefaultProperty(QStringLiteral("quaternion"), method_quaternion);
+ o->defineDefaultProperty(QStringLiteral("matrix4x4"), method_matrix4x4);
+
+ o->defineDefaultProperty(QStringLiteral("formatDate"), method_formatDate);
+ o->defineDefaultProperty(QStringLiteral("formatTime"), method_formatTime);
+ o->defineDefaultProperty(QStringLiteral("formatDateTime"), method_formatDateTime);
+
+ o->defineDefaultProperty(QStringLiteral("openUrlExternally"), method_openUrlExternally);
+ o->defineDefaultProperty(QStringLiteral("fontFamilies"), method_fontFamilies);
+ o->defineDefaultProperty(QStringLiteral("md5"), method_md5);
+ o->defineDefaultProperty(QStringLiteral("btoa"), method_btoa);
+ o->defineDefaultProperty(QStringLiteral("atob"), method_atob);
+ o->defineDefaultProperty(QStringLiteral("resolvedUrl"), method_resolvedUrl);
+ o->defineDefaultProperty(QStringLiteral("locale"), method_locale);
+ o->defineDefaultProperty(QStringLiteral("binding"), method_binding);
if (qmlEngine) {
- defineDefaultProperty(QStringLiteral("lighter"), method_lighter);
- defineDefaultProperty(QStringLiteral("darker"), method_darker);
- defineDefaultProperty(QStringLiteral("tint"), method_tint);
- defineDefaultProperty(QStringLiteral("quit"), method_quit);
- defineDefaultProperty(QStringLiteral("createQmlObject"), method_createQmlObject);
- defineDefaultProperty(QStringLiteral("createComponent"), method_createComponent);
+ o->defineDefaultProperty(QStringLiteral("lighter"), method_lighter);
+ o->defineDefaultProperty(QStringLiteral("darker"), method_darker);
+ o->defineDefaultProperty(QStringLiteral("tint"), method_tint);
+ o->defineDefaultProperty(QStringLiteral("quit"), method_quit);
+ o->defineDefaultProperty(QStringLiteral("createQmlObject"), method_createQmlObject);
+ o->defineDefaultProperty(QStringLiteral("createComponent"), method_createComponent);
}
- defineAccessorProperty(QStringLiteral("platform"), method_get_platform, 0);
- defineAccessorProperty(QStringLiteral("application"), method_get_application, 0);
+ o->defineAccessorProperty(QStringLiteral("platform"), method_get_platform, 0);
+ o->defineAccessorProperty(QStringLiteral("application"), method_get_application, 0);
#ifndef QT_NO_IM
- defineAccessorProperty(QStringLiteral("inputMethod"), method_get_inputMethod, 0);
+ o->defineAccessorProperty(QStringLiteral("inputMethod"), method_get_inputMethod, 0);
#endif
}
@@ -160,10 +159,10 @@ Returns true if \c object is a valid reference to a Qt or QML object, otherwise
*/
ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
{
- if (ctx->callData->argc == 0)
+ if (ctx->d()->callData->argc == 0)
return QV4::Encode(false);
- return QV4::Encode(ctx->callData->args[0].as<QV4::QObjectWrapper>() != 0);
+ return QV4::Encode(ctx->d()->callData->args[0].as<QV4::QObjectWrapper>() != 0);
}
/*!
@@ -174,14 +173,14 @@ All components should be in the range 0-1 inclusive.
*/
ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
{
- int argCount = ctx->callData->argc;
+ int argCount = ctx->d()->callData->argc;
if (argCount < 3 || argCount > 4)
V4THROW_ERROR("Qt.rgba(): Invalid arguments");
- double r = ctx->callData->args[0].toNumber();
- double g = ctx->callData->args[1].toNumber();
- double b = ctx->callData->args[2].toNumber();
- double a = (argCount == 4) ? ctx->callData->args[3].toNumber() : 1;
+ double r = ctx->d()->callData->args[0].toNumber();
+ double g = ctx->d()->callData->args[1].toNumber();
+ double b = ctx->d()->callData->args[2].toNumber();
+ double a = (argCount == 4) ? ctx->d()->callData->args[3].toNumber() : 1;
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
@@ -192,7 +191,7 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ return ctx->d()->engine->v8Engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
}
/*!
@@ -203,14 +202,14 @@ All components should be in the range 0-1 inclusive.
*/
ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
{
- int argCount = ctx->callData->argc;
+ int argCount = ctx->d()->callData->argc;
if (argCount < 3 || argCount > 4)
V4THROW_ERROR("Qt.hsla(): Invalid arguments");
- double h = ctx->callData->args[0].toNumber();
- double s = ctx->callData->args[1].toNumber();
- double l = ctx->callData->args[2].toNumber();
- double a = (argCount == 4) ? ctx->callData->args[3].toNumber() : 1;
+ double h = ctx->d()->callData->args[0].toNumber();
+ double s = ctx->d()->callData->args[1].toNumber();
+ double l = ctx->d()->callData->args[2].toNumber();
+ double a = (argCount == 4) ? ctx->d()->callData->args[3].toNumber() : 1;
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
@@ -221,7 +220,7 @@ ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ return ctx->d()->engine->v8Engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
}
/*!
@@ -234,14 +233,14 @@ basic type.
*/
ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
bool ok = false;
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- QVariant lhs = v8engine->toVariant(ctx->callData->args[0], -1);
+ QVariant lhs = v8engine->toVariant(ctx->d()->callData->args[0], -1);
if (lhs.userType() == QVariant::String) {
lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
if (!ok) {
@@ -251,7 +250,7 @@ ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx)
V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
}
- QVariant rhs = v8engine->toVariant(ctx->callData->args[1], -1);
+ QVariant rhs = v8engine->toVariant(ctx->d()->callData->args[1], -1);
if (rhs.userType() == QVariant::String) {
rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
if (!ok) {
@@ -274,15 +273,15 @@ The returned object has \c x, \c y, \c width and \c height attributes with the g
*/
ReturnedValue QtObject::method_rect(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 4)
+ if (ctx->d()->callData->argc != 4)
V4THROW_ERROR("Qt.rect(): Invalid arguments");
- double x = ctx->callData->args[0].toNumber();
- double y = ctx->callData->args[1].toNumber();
- double w = ctx->callData->args[2].toNumber();
- double h = ctx->callData->args[3].toNumber();
+ double x = ctx->d()->callData->args[0].toNumber();
+ double y = ctx->d()->callData->args[1].toNumber();
+ double w = ctx->d()->callData->args[2].toNumber();
+ double h = ctx->d()->callData->args[3].toNumber();
- return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
/*!
@@ -291,13 +290,13 @@ Returns a Point with the specified \c x and \c y coordinates.
*/
ReturnedValue QtObject::method_point(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.point(): Invalid arguments");
- double x = ctx->callData->args[0].toNumber();
- double y = ctx->callData->args[1].toNumber();
+ double x = ctx->d()->callData->args[0].toNumber();
+ double y = ctx->d()->callData->args[1].toNumber();
- return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
}
/*!
@@ -306,13 +305,13 @@ Returns a Size with the specified \c width and \c height.
*/
ReturnedValue QtObject::method_size(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.size(): Invalid arguments");
- double w = ctx->callData->args[0].toNumber();
- double h = ctx->callData->args[1].toNumber();
+ double w = ctx->d()->callData->args[0].toNumber();
+ double h = ctx->d()->callData->args[1].toNumber();
- return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
}
/*!
@@ -325,12 +324,12 @@ Invalid keys will be ignored.
*/
ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 1 || !ctx->callData->args[0].isObject())
+ if (ctx->d()->callData->argc != 1 || !ctx->d()->callData->args[0].isObject())
V4THROW_ERROR("Qt.font(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->callData->args[0]), v8engine, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->d()->callData->args[0]), v8engine, &ok);
if (!ok)
V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
return v8engine->fromVariant(v);
@@ -344,15 +343,15 @@ Returns a Vector2D with the specified \c x and \c y.
*/
ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.vector2d(): Invalid arguments");
float xy[3]; // qvector2d uses float internally
- xy[0] = ctx->callData->args[0].toNumber();
- xy[1] = ctx->callData->args[1].toNumber();
+ xy[0] = ctx->d()->callData->args[0].toNumber();
+ xy[1] = ctx->d()->callData->args[1].toNumber();
const void *params[] = { xy };
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
}
@@ -362,16 +361,16 @@ Returns a Vector3D with the specified \c x, \c y and \c z.
*/
ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 3)
+ if (ctx->d()->callData->argc != 3)
V4THROW_ERROR("Qt.vector3d(): Invalid arguments");
float xyz[3]; // qvector3d uses float internally
- xyz[0] = ctx->callData->args[0].toNumber();
- xyz[1] = ctx->callData->args[1].toNumber();
- xyz[2] = ctx->callData->args[2].toNumber();
+ xyz[0] = ctx->d()->callData->args[0].toNumber();
+ xyz[1] = ctx->d()->callData->args[1].toNumber();
+ xyz[2] = ctx->d()->callData->args[2].toNumber();
const void *params[] = { xyz };
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
}
@@ -381,17 +380,17 @@ Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
*/
ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 4)
+ if (ctx->d()->callData->argc != 4)
V4THROW_ERROR("Qt.vector4d(): Invalid arguments");
float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = ctx->callData->args[0].toNumber();
- xyzw[1] = ctx->callData->args[1].toNumber();
- xyzw[2] = ctx->callData->args[2].toNumber();
- xyzw[3] = ctx->callData->args[3].toNumber();
+ xyzw[0] = ctx->d()->callData->args[0].toNumber();
+ xyzw[1] = ctx->d()->callData->args[1].toNumber();
+ xyzw[2] = ctx->d()->callData->args[2].toNumber();
+ xyzw[3] = ctx->d()->callData->args[3].toNumber();
const void *params[] = { xyzw };
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
}
@@ -401,17 +400,17 @@ Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z.
*/
ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 4)
+ if (ctx->d()->callData->argc != 4)
V4THROW_ERROR("Qt.quaternion(): Invalid arguments");
qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = ctx->callData->args[0].toNumber();
- sxyz[1] = ctx->callData->args[1].toNumber();
- sxyz[2] = ctx->callData->args[2].toNumber();
- sxyz[3] = ctx->callData->args[3].toNumber();
+ sxyz[0] = ctx->d()->callData->args[0].toNumber();
+ sxyz[1] = ctx->d()->callData->args[1].toNumber();
+ sxyz[2] = ctx->d()->callData->args[2].toNumber();
+ sxyz[3] = ctx->d()->callData->args[3].toNumber();
const void *params[] = { sxyz };
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
}
@@ -424,36 +423,36 @@ matrix values.
*/
ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx)
{
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- if (ctx->callData->argc == 1 && ctx->callData->args[0].isObject()) {
+ if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isObject()) {
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->callData->args[0]), v8engine, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->d()->callData->args[0]), v8engine, &ok);
if (!ok)
V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
return v8engine->fromVariant(v);
}
- if (ctx->callData->argc != 16)
+ if (ctx->d()->callData->argc != 16)
V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = ctx->callData->args[0].toNumber();
- vals[1] = ctx->callData->args[1].toNumber();
- vals[2] = ctx->callData->args[2].toNumber();
- vals[3] = ctx->callData->args[3].toNumber();
- vals[4] = ctx->callData->args[4].toNumber();
- vals[5] = ctx->callData->args[5].toNumber();
- vals[6] = ctx->callData->args[6].toNumber();
- vals[7] = ctx->callData->args[7].toNumber();
- vals[8] = ctx->callData->args[8].toNumber();
- vals[9] = ctx->callData->args[9].toNumber();
- vals[10] = ctx->callData->args[10].toNumber();
- vals[11] = ctx->callData->args[11].toNumber();
- vals[12] = ctx->callData->args[12].toNumber();
- vals[13] = ctx->callData->args[13].toNumber();
- vals[14] = ctx->callData->args[14].toNumber();
- vals[15] = ctx->callData->args[15].toNumber();
+ vals[0] = ctx->d()->callData->args[0].toNumber();
+ vals[1] = ctx->d()->callData->args[1].toNumber();
+ vals[2] = ctx->d()->callData->args[2].toNumber();
+ vals[3] = ctx->d()->callData->args[3].toNumber();
+ vals[4] = ctx->d()->callData->args[4].toNumber();
+ vals[5] = ctx->d()->callData->args[5].toNumber();
+ vals[6] = ctx->d()->callData->args[6].toNumber();
+ vals[7] = ctx->d()->callData->args[7].toNumber();
+ vals[8] = ctx->d()->callData->args[8].toNumber();
+ vals[9] = ctx->d()->callData->args[9].toNumber();
+ vals[10] = ctx->d()->callData->args[10].toNumber();
+ vals[11] = ctx->d()->callData->args[11].toNumber();
+ vals[12] = ctx->d()->callData->args[12].toNumber();
+ vals[13] = ctx->d()->callData->args[13].toNumber();
+ vals[14] = ctx->d()->callData->args[14].toNumber();
+ vals[15] = ctx->d()->callData->args[15].toNumber();
const void *params[] = { vals };
return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
@@ -475,11 +474,11 @@ If \c factor is not supplied, returns a color 50% lighter than \c baseColor (fac
*/
ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 1 && ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 1 && ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.lighter(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
- QVariant v = v8engine->toVariant(ctx->callData->args[0], -1);
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QVariant v = v8engine->toVariant(ctx->d()->callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
@@ -491,8 +490,8 @@ ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx)
}
qreal factor = 1.5;
- if (ctx->callData->argc == 2)
- factor = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2)
+ factor = ctx->d()->callData->args[1].toNumber();
return v8engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
}
@@ -514,11 +513,11 @@ If \c factor is not supplied, returns a color 50% darker than \c baseColor (fact
*/
ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 1 && ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 1 && ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.darker(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
- QVariant v = v8engine->toVariant(ctx->callData->args[0], -1);
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QVariant v = v8engine->toVariant(ctx->d()->callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
@@ -530,8 +529,8 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
}
qreal factor = 2.0;
- if (ctx->callData->argc == 2)
- factor = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2)
+ factor = ctx->d()->callData->args[1].toNumber();
return v8engine->fromVariant(QQml_colorProvider()->darker(v, factor));
}
@@ -562,13 +561,13 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
*/
ReturnedValue QtObject::method_tint(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 2)
+ if (ctx->d()->callData->argc != 2)
V4THROW_ERROR("Qt.tint(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
// base color
- QVariant v1 = v8engine->toVariant(ctx->callData->args[0], -1);
+ QVariant v1 = v8engine->toVariant(ctx->d()->callData->args[0], -1);
if (v1.userType() == QVariant::String) {
bool ok = false;
v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
@@ -580,7 +579,7 @@ ReturnedValue QtObject::method_tint(QV4::CallContext *ctx)
}
// tint color
- QVariant v2 = v8engine->toVariant(ctx->callData->args[1], -1);
+ QVariant v2 = v8engine->toVariant(ctx->d()->callData->args[1], -1);
if (v2.userType() == QVariant::String) {
bool ok = false;
v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
@@ -612,22 +611,22 @@ If \a format is not specified, \a date is formatted using
*/
ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx)
{
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2)
V4THROW_ERROR("Qt.formatDate(): Invalid arguments");
QV4::Scope scope(ctx);
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = v8engine->toVariant(ctx->callData->args[0], -1).toDateTime().date();
+ QDate date = v8engine->toVariant(ctx->d()->callData->args[0], -1).toDateTime().date();
QString formattedDate;
- if (ctx->callData->argc == 2) {
- QV4::ScopedString s(scope, ctx->callData->args[1]);
+ if (ctx->d()->callData->argc == 2) {
+ QV4::ScopedString s(scope, ctx->d()->callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDate = date.toString(format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].asDouble();
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDate = date.toString(format);
} else {
@@ -637,7 +636,7 @@ ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx)
formattedDate = date.toString(enumFormat);
}
- return ctx->engine->newString(formattedDate)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
}
/*!
@@ -657,28 +656,28 @@ If \a format is not specified, \a time is formatted using
*/
ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx)
{
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2)
V4THROW_ERROR("Qt.formatTime(): Invalid arguments");
QV4::Scope scope(ctx);
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- QVariant argVariant = v8engine->toVariant(ctx->callData->args[0], -1);
+ QVariant argVariant = v8engine->toVariant(ctx->d()->callData->args[0], -1);
QTime time;
- if (ctx->callData->args[0].asDateObject() || (argVariant.type() == QVariant::String))
+ if (ctx->d()->callData->args[0].asDateObject() || (argVariant.type() == QVariant::String))
time = argVariant.toDateTime().time();
else // if (argVariant.type() == QVariant::Time), or invalid.
time = argVariant.toTime();
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
QString formattedTime;
- if (ctx->callData->argc == 2) {
- QV4::ScopedString s(scope, ctx->callData->args[1]);
+ if (ctx->d()->callData->argc == 2) {
+ QV4::ScopedString s(scope, ctx->d()->callData->args[1]);
if (s) {
QString format = s->toQString();
formattedTime = time.toString(format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].asDouble();
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedTime = time.toString(format);
} else {
@@ -688,7 +687,7 @@ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx)
formattedTime = time.toString(enumFormat);
}
- return ctx->engine->newString(formattedTime)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
}
/*!
@@ -783,22 +782,22 @@ with the \a format values below to produce the following results:
*/
ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
{
- if (ctx->callData->argc < 1 || ctx->callData->argc > 2)
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2)
V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
QV4::Scope scope(ctx);
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = v8engine->toVariant(ctx->callData->args[0], -1).toDateTime();
+ QDateTime dt = v8engine->toVariant(ctx->d()->callData->args[0], -1).toDateTime();
QString formattedDt;
- if (ctx->callData->argc == 2) {
- QV4::ScopedString s(scope, ctx->callData->args[1]);
+ if (ctx->d()->callData->argc == 2) {
+ QV4::ScopedString s(scope, ctx->d()->callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDt = dt.toString(format);
- } else if (ctx->callData->args[1].isNumber()) {
- quint32 intFormat = ctx->callData->args[1].asDouble();
+ } else if (ctx->d()->callData->args[1].isNumber()) {
+ quint32 intFormat = ctx->d()->callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDt = dt.toString(format);
} else {
@@ -808,7 +807,7 @@ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
formattedDt = dt.toString(enumFormat);
}
- return ctx->engine->newString(formattedDt)->asReturnedValue();
+ return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
}
/*!
@@ -817,10 +816,10 @@ Attempts to open the specified \c target url in an external application, based o
*/
ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
return QV4::Encode(false);
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
QUrl url(Value::fromReturnedValue(method_resolvedUrl(ctx)).toQStringNoThrow());
return v8engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
@@ -832,21 +831,21 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx)
*/
ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx)
{
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- QUrl url = v8engine->toVariant(ctx->callData->args[0], -1).toUrl();
+ QUrl url = v8engine->toVariant(ctx->d()->callData->args[0], -1).toUrl();
QQmlEngine *e = v8engine->engine();
QQmlEnginePrivate *p = 0;
if (e) p = QQmlEnginePrivate::get(e);
if (p) {
QQmlContextData *ctxt = v8engine->callingContext();
if (ctxt)
- return ctx->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue();
+ return ctx->d()->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue();
else
- return ctx->engine->newString(url.toString())->asReturnedValue();
+ return ctx->d()->engine->newString(url.toString())->asReturnedValue();
}
- return ctx->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue();
+ return ctx->d()->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue();
}
/*!
@@ -855,10 +854,10 @@ Returns a list of the font families available to the application.
*/
ReturnedValue QtObject::method_fontFamilies(CallContext *ctx)
{
- if (ctx->callData->argc != 0)
+ if (ctx->d()->callData->argc != 0)
V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
return v8engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
}
@@ -868,12 +867,12 @@ Returns a hex string of the md5 hash of \c data.
*/
ReturnedValue QtObject::method_md5(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("Qt.md5(): Invalid arguments");
- QByteArray data = ctx->callData->args[0].toQStringNoThrow().toUtf8();
+ QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8();
QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return ctx->engine->newString(QLatin1String(result.toHex()))->asReturnedValue();
+ return ctx->d()->engine->newString(QLatin1String(result.toHex()))->asReturnedValue();
}
/*!
@@ -882,12 +881,12 @@ Binary to ASCII - this function returns a base64 encoding of \c data.
*/
ReturnedValue QtObject::method_btoa(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("Qt.btoa(): Invalid arguments");
- QByteArray data = ctx->callData->args[0].toQStringNoThrow().toUtf8();
+ QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8();
- return ctx->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue();
+ return ctx->d()->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue();
}
/*!
@@ -896,12 +895,12 @@ ASCII to binary - this function returns a base64 decoding of \c data.
*/
ReturnedValue QtObject::method_atob(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("Qt.atob(): Invalid arguments");
- QByteArray data = ctx->callData->args[0].toQStringNoThrow().toLatin1();
+ QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toLatin1();
- return ctx->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue();
+ return ctx->d()->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue();
}
/*!
@@ -913,7 +912,7 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
*/
ReturnedValue QtObject::method_quit(CallContext *ctx)
{
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
QQmlEnginePrivate::get(v8engine->engine())->sendQuit();
return QV4::Encode::undefined();
@@ -946,7 +945,7 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
{
Scope scope(ctx);
- if (ctx->callData->argc < 2 || ctx->callData->argc > 3)
+ if (ctx->d()->callData->argc < 2 || ctx->d()->callData->argc > 3)
V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
struct Error {
@@ -962,21 +961,21 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
const QQmlError &error = errors.at(ii);
errorstr += QLatin1String("\n ") + error.toString();
qmlerror = v4->newObject();
- qmlerror->put((s = v4->newString(QStringLiteral("lineNumber"))), (v = QV4::Primitive::fromInt32(error.line())));
- qmlerror->put((s = v4->newString(QStringLiteral("columnNumber"))), (v = QV4::Primitive::fromInt32(error.column())));
- qmlerror->put((s = v4->newString(QStringLiteral("fileName"))), (v = v4->newString(error.url().toString())));
- qmlerror->put((s = v4->newString(QStringLiteral("message"))), (v = v4->newString(error.description())));
+ qmlerror->put((s = v4->newString(QStringLiteral("lineNumber"))).getPointer(), (v = QV4::Primitive::fromInt32(error.line())));
+ qmlerror->put((s = v4->newString(QStringLiteral("columnNumber"))).getPointer(), (v = QV4::Primitive::fromInt32(error.column())));
+ qmlerror->put((s = v4->newString(QStringLiteral("fileName"))).getPointer(), (v = v4->newString(error.url().toString())));
+ qmlerror->put((s = v4->newString(QStringLiteral("message"))).getPointer(), (v = v4->newString(error.description())));
qmlerrors->putIndexed(ii, qmlerror);
}
v = v4->newString(errorstr);
Scoped<Object> errorObject(scope, v4->newErrorObject(v));
- errorObject->put((s = v4->newString(QStringLiteral("qmlErrors"))), qmlerrors);
+ errorObject->put((s = v4->newString(QStringLiteral("qmlErrors"))).getPointer(), qmlerrors);
return errorObject.asReturnedValue();
}
};
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = v8engine->callingContext();
@@ -988,13 +987,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
effectiveContext = context->asQQmlContext();
Q_ASSERT(effectiveContext);
- QString qml = ctx->callData->args[0].toQStringNoThrow();
+ QString qml = ctx->d()->callData->args[0].toQStringNoThrow();
if (qml.isEmpty())
return QV4::Encode::null();
QUrl url;
- if (ctx->callData->argc > 2)
- url = QUrl(ctx->callData->args[2].toQStringNoThrow());
+ if (ctx->d()->callData->argc > 2)
+ url = QUrl(ctx->d()->callData->args[2].toQStringNoThrow());
else
url = QUrl(QLatin1String("inline"));
@@ -1002,7 +1001,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
url = context->resolvedUrl(url);
QObject *parentArg = 0;
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->callData->args[1]);
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->d()->callData->args[1]);
if (!!qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
@@ -1012,7 +1011,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
component.setData(qml.toUtf8(), url);
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->engine, component.errors()));
+ ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
return ctx->throwError(v);
}
@@ -1036,13 +1035,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
component.completeCreate();
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->engine, component.errors()));
+ ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
return ctx->throwError(v);
}
Q_ASSERT(obj);
- return QV4::QObjectWrapper::wrap(ctx->engine, obj);
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, obj);
}
/*!
@@ -1078,12 +1077,12 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
ReturnedValue QtObject::method_createComponent(CallContext *ctx)
{
- if (ctx->callData->argc < 1 || ctx->callData->argc > 3)
+ if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3)
return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
Scope scope(ctx);
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = v8engine->callingContext();
@@ -1092,7 +1091,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
if (context->isPragmaLibraryContext)
effectiveContext = 0;
- QString arg = ctx->callData->args[0].toQStringNoThrow();
+ QString arg = ctx->d()->callData->args[0].toQStringNoThrow();
if (arg.isEmpty())
return QV4::Encode::null();
@@ -1100,23 +1099,23 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
QObject *parentArg = 0;
int consumedCount = 1;
- if (ctx->callData->argc > 1) {
- ScopedValue lastArg(scope, ctx->callData->args[ctx->callData->argc-1]);
+ if (ctx->d()->callData->argc > 1) {
+ ScopedValue lastArg(scope, ctx->d()->callData->args[ctx->d()->callData->argc-1]);
// The second argument could be the mode enum
- if (ctx->callData->args[1].isInteger()) {
- int mode = ctx->callData->args[1].integerValue();
+ if (ctx->d()->callData->args[1].isInteger()) {
+ int mode = ctx->d()->callData->args[1].integerValue();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
compileMode = QQmlComponent::CompilationMode(mode);
consumedCount += 1;
} else {
// The second argument could be the parent only if there are exactly two args
- if ((ctx->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
+ if ((ctx->d()->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
}
- if (consumedCount < ctx->callData->argc) {
+ if (consumedCount < ctx->d()->callData->argc) {
if (lastArg->isObject()) {
Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg);
if (qobjectWrapper)
@@ -1137,7 +1136,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
QQmlData::get(c, true)->explicitIndestructibleSet = false;
QQmlData::get(c)->indestructible = false;
- return QV4::QObjectWrapper::wrap(ctx->engine, c);
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, c);
}
/*!
@@ -1163,20 +1162,20 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
ReturnedValue QtObject::method_locale(CallContext *ctx)
{
QString code;
- if (ctx->callData->argc > 1)
+ if (ctx->d()->callData->argc > 1)
V4THROW_ERROR("locale() requires 0 or 1 argument");
- if (ctx->callData->argc == 1 && !ctx->callData->args[0].isString())
+ if (ctx->d()->callData->argc == 1 && !ctx->d()->callData->args[0].isString())
V4THROW_TYPE("locale(): argument (locale code) must be a string");
- QV8Engine *v8engine = ctx->engine->v8Engine;
- if (ctx->callData->argc == 1)
- code = ctx->callData->args[0].toQStringNoThrow();
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ if (ctx->d()->callData->argc == 1)
+ code = ctx->d()->callData->args[0].toQStringNoThrow();
return QQmlLocale::locale(v8engine, code);
}
-QQmlBindingFunction::QQmlBindingFunction(FunctionObject *originalFunction)
- : QV4::FunctionObject(originalFunction->scope, originalFunction->name())
+QQmlBindingFunction::Data::Data(FunctionObject *originalFunction)
+ : QV4::FunctionObject::Data(originalFunction->scope(), originalFunction->name())
, originalFunction(originalFunction)
{
setVTable(staticVTable());
@@ -1186,20 +1185,20 @@ QQmlBindingFunction::QQmlBindingFunction(FunctionObject *originalFunction)
void QQmlBindingFunction::initBindingLocation()
{
QV4::StackFrame frame = engine()->currentStackFrame();
- bindingLocation.sourceFile = frame.source;
- bindingLocation.line = frame.line;
+ d()->bindingLocation.sourceFile = frame.source;
+ d()->bindingLocation.line = frame.line;
}
ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData)
{
QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that);
- return This->originalFunction->call(callData);
+ return This->d()->originalFunction->call(callData);
}
void QQmlBindingFunction::markObjects(Managed *that, ExecutionEngine *e)
{
QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that);
- This->originalFunction->mark(e);
+ This->d()->originalFunction->mark(e);
QV4::FunctionObject::markObjects(that, e);
}
@@ -1251,48 +1250,48 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
*/
ReturnedValue QtObject::method_binding(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("binding() requires 1 argument");
- QV4::FunctionObject *f = ctx->callData->args[0].asFunctionObject();
+ QV4::FunctionObject *f = ctx->d()->callData->args[0].asFunctionObject();
if (!f)
V4THROW_TYPE("binding(): argument (binding expression) must be a function");
- return (new (ctx->engine->memoryManager) QQmlBindingFunction(f))->asReturnedValue();
+ return (ctx->d()->engine->memoryManager->alloc<QQmlBindingFunction>(f))->asReturnedValue();
}
ReturnedValue QtObject::method_get_platform(CallContext *ctx)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->callData->thisObject.asObject();
+ Object *o = ctx->d()->callData->thisObject.asObject();
if (!o)
return ctx->throwTypeError();
QtObject *qt = o->as<QtObject>();
if (!qt)
return ctx->throwTypeError();
- if (!qt->m_platform)
+ if (!qt->d()->platform)
// Only allocate a platform object once
- qt->m_platform = new QQmlPlatform(ctx->engine->v8Engine->publicEngine());
+ qt->d()->platform = new QQmlPlatform(ctx->d()->engine->v8Engine->publicEngine());
- return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_platform);
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->platform);
}
ReturnedValue QtObject::method_get_application(CallContext *ctx)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->callData->thisObject.asObject();
+ Object *o = ctx->d()->callData->thisObject.asObject();
if (!o)
return ctx->throwTypeError();
QtObject *qt = o->as<QtObject>();
if (!qt)
return ctx->throwTypeError();
- if (!qt->m_application)
+ if (!qt->d()->application)
// Only allocate an application object once
- qt->m_application = QQml_guiProvider()->application(ctx->engine->v8Engine->publicEngine());
+ qt->d()->application = QQml_guiProvider()->application(ctx->d()->engine->v8Engine->publicEngine());
- return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_application);
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application);
}
#ifndef QT_NO_IM
@@ -1300,31 +1299,31 @@ ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx)
{
QObject *o = QQml_guiProvider()->inputMethod();
QQmlEngine::setObjectOwnership(o, QQmlEngine::CppOwnership);
- return QV4::QObjectWrapper::wrap(ctx->engine, o);
+ return QV4::QObjectWrapper::wrap(ctx->d()->engine, o);
}
#endif
-QV4::ConsoleObject::ConsoleObject(ExecutionEngine *v4)
- : Object(v4)
+QV4::ConsoleObject::Data::Data(ExecutionEngine *v4)
+ : Object::Data(v4)
{
QV4::Scope scope(v4);
- QV4::ScopedObject protectThis(scope, this);
-
- defineDefaultProperty(QStringLiteral("debug"), method_log);
- defineDefaultProperty(QStringLiteral("log"), method_log);
- defineDefaultProperty(QStringLiteral("info"), method_log);
- defineDefaultProperty(QStringLiteral("warn"), method_warn);
- defineDefaultProperty(QStringLiteral("error"), method_error);
- defineDefaultProperty(QStringLiteral("assert"), method_assert);
-
- defineDefaultProperty(QStringLiteral("count"), method_count);
- defineDefaultProperty(QStringLiteral("profile"), method_profile);
- defineDefaultProperty(QStringLiteral("profileEnd"), method_profileEnd);
- defineDefaultProperty(QStringLiteral("time"), method_time);
- defineDefaultProperty(QStringLiteral("timeEnd"), method_timeEnd);
- defineDefaultProperty(QStringLiteral("trace"), method_trace);
- defineDefaultProperty(QStringLiteral("exception"), method_exception);
+ QV4::ScopedObject o(scope, this);
+
+ o->defineDefaultProperty(QStringLiteral("debug"), method_log);
+ o->defineDefaultProperty(QStringLiteral("log"), method_log);
+ o->defineDefaultProperty(QStringLiteral("info"), method_log);
+ o->defineDefaultProperty(QStringLiteral("warn"), method_warn);
+ o->defineDefaultProperty(QStringLiteral("error"), method_error);
+ o->defineDefaultProperty(QStringLiteral("assert"), method_assert);
+
+ o->defineDefaultProperty(QStringLiteral("count"), method_count);
+ o->defineDefaultProperty(QStringLiteral("profile"), method_profile);
+ o->defineDefaultProperty(QStringLiteral("profileEnd"), method_profileEnd);
+ o->defineDefaultProperty(QStringLiteral("time"), method_time);
+ o->defineDefaultProperty(QStringLiteral("timeEnd"), method_timeEnd);
+ o->defineDefaultProperty(QStringLiteral("trace"), method_trace);
+ o->defineDefaultProperty(QStringLiteral("exception"), method_exception);
}
@@ -1364,16 +1363,16 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c
bool printStack = false)
{
QString result;
- QV4::ExecutionEngine *v4 = ctx->engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
- for (int i = 0; i < ctx->callData->argc; ++i) {
+ for (int i = 0; i < ctx->d()->callData->argc; ++i) {
if (i != 0)
result.append(QLatin1Char(' '));
- if (ctx->callData->args[i].asArrayObject())
- result.append(QStringLiteral("[") + ctx->callData->args[i].toQStringNoThrow() + QStringLiteral("]"));
+ if (ctx->d()->callData->args[i].asArrayObject())
+ result.append(QStringLiteral("[") + ctx->d()->callData->args[i].toQStringNoThrow() + QStringLiteral("]"));
else
- result.append(ctx->callData->args[i].toQStringNoThrow());
+ result.append(ctx->d()->callData->args[i].toQStringNoThrow());
}
if (printStack) {
@@ -1423,7 +1422,7 @@ QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1441,7 +1440,7 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1460,24 +1459,24 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("console.time(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- QString name = ctx->callData->args[0].toQStringNoThrow();
+ QString name = ctx->d()->callData->args[0].toQStringNoThrow();
v8engine->startTimer(name);
return QV4::Encode::undefined();
}
QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("console.time(): Invalid arguments");
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
- QString name = ctx->callData->args[0].toQStringNoThrow();
+ QString name = ctx->d()->callData->args[0].toQStringNoThrow();
bool wasRunning;
qint64 elapsed = v8engine->stopTimer(name, &wasRunning);
if (wasRunning) {
@@ -1490,11 +1489,11 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
{
// first argument: name to print. Ignore any additional arguments
QString name;
- if (ctx->callData->argc > 0)
- name = ctx->callData->args[0].toQStringNoThrow();
+ if (ctx->d()->callData->argc > 0)
+ name = ctx->d()->callData->args[0].toQStringNoThrow();
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV8Engine *v8engine = ctx->engine->v8Engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
QV4::StackFrame frame = v4->currentStackFrame();
@@ -1512,10 +1511,10 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
{
- if (ctx->callData->argc != 0)
+ if (ctx->d()->callData->argc != 0)
V4THROW_ERROR("console.trace(): Invalid arguments");
- QV4::ExecutionEngine *v4 = ctx->engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
QString stack = jsStack(v4);
@@ -1534,18 +1533,18 @@ QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
{
- if (ctx->callData->argc == 0)
+ if (ctx->d()->callData->argc == 0)
V4THROW_ERROR("console.assert(): Missing argument");
- QV4::ExecutionEngine *v4 = ctx->engine;
+ QV4::ExecutionEngine *v4 = ctx->d()->engine;
- if (!ctx->callData->args[0].toBoolean()) {
+ if (!ctx->d()->callData->args[0].toBoolean()) {
QString message;
- for (int i = 1; i < ctx->callData->argc; ++i) {
+ for (int i = 1; i < ctx->d()->callData->argc; ++i) {
if (i != 1)
message.append(QLatin1Char(' '));
- message.append(ctx->callData->args[i].toQStringNoThrow());
+ message.append(ctx->d()->callData->args[i].toQStringNoThrow());
}
QString stack = jsStack(v4);
@@ -1561,7 +1560,7 @@ QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx)
{
- if (ctx->callData->argc == 0)
+ if (ctx->d()->callData->argc == 0)
V4THROW_ERROR("console.exception(): Missing argument");
writeToConsole(Error, ctx, true);
@@ -1588,10 +1587,10 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
globalObject->defineDefaultProperty(QStringLiteral("print"), ConsoleObject::method_log);
globalObject->defineDefaultProperty(QStringLiteral("gc"), method_gc);
- ScopedValue console(scope, new (v4->memoryManager) QV4::ConsoleObject(v4));
+ ScopedObject console(scope, v4->memoryManager->alloc<QV4::ConsoleObject>(v4));
globalObject->defineDefaultProperty(QStringLiteral("console"), console);
- ScopedValue qt(scope, new (v4->memoryManager) QV4::QtObject(v4, qmlEngine));
+ ScopedObject qt(scope, v4->memoryManager->alloc<QV4::QtObject>(v4, qmlEngine));
globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
// string prototype extension
@@ -1619,36 +1618,36 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
*/
ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
{
- if (ctx->callData->argc < 2)
+ if (ctx->d()->callData->argc < 2)
V4THROW_ERROR("qsTranslate() requires at least two arguments");
- if (!ctx->callData->args[0].isString())
+ if (!ctx->d()->callData->args[0].isString())
V4THROW_ERROR("qsTranslate(): first argument (context) must be a string");
- if (!ctx->callData->args[1].isString())
+ if (!ctx->d()->callData->args[1].isString())
V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string");
- if ((ctx->callData->argc > 2) && !ctx->callData->args[2].isString())
+ if ((ctx->d()->callData->argc > 2) && !ctx->d()->callData->args[2].isString())
V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
- QString context = ctx->callData->args[0].toQStringNoThrow();
- QString text = ctx->callData->args[1].toQStringNoThrow();
+ QString context = ctx->d()->callData->args[0].toQStringNoThrow();
+ QString text = ctx->d()->callData->args[1].toQStringNoThrow();
QString comment;
- if (ctx->callData->argc > 2) comment = ctx->callData->args[2].toQStringNoThrow();
+ if (ctx->d()->callData->argc > 2) comment = ctx->d()->callData->args[2].toQStringNoThrow();
int i = 3;
- if (ctx->callData->argc > i && ctx->callData->args[i].isString()) {
+ if (ctx->d()->callData->argc > i && ctx->d()->callData->args[i].isString()) {
qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated");
++i;
}
int n = -1;
- if (ctx->callData->argc > i)
- n = ctx->callData->args[i].toInt32();
+ if (ctx->d()->callData->argc > i)
+ n = ctx->d()->callData->args[i].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(),
text.toUtf8().constData(),
comment.toUtf8().constData(),
n);
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
/*!
@@ -1675,9 +1674,9 @@ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
*/
ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
{
- if (ctx->callData->argc < 2)
+ if (ctx->d()->callData->argc < 2)
return QV4::Encode::undefined();
- return ctx->callData->args[1].asReturnedValue();
+ return ctx->d()->callData->args[1].asReturnedValue();
}
/*!
@@ -1699,36 +1698,54 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
*/
ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
{
- if (ctx->callData->argc < 1)
+ if (ctx->d()->callData->argc < 1)
V4THROW_ERROR("qsTr() requires at least one argument");
- if (!ctx->callData->args[0].isString())
+ if (!ctx->d()->callData->args[0].isString())
V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string");
- if ((ctx->callData->argc > 1) && !ctx->callData->args[1].isString())
+ if ((ctx->d()->callData->argc > 1) && !ctx->d()->callData->args[1].isString())
V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string");
- if ((ctx->callData->argc > 2) && !ctx->callData->args[2].isNumber())
+ if ((ctx->d()->callData->argc > 2) && !ctx->d()->callData->args[2].isNumber())
V4THROW_ERROR("qsTr(): third argument (n) must be a number");
- QV8Engine *v8engine = ctx->engine->v8Engine;
- QQmlContextData *ctxt = v8engine->callingContext();
-
- QString path = ctxt->url.toString();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- int lastDot = path.lastIndexOf(QLatin1Char('.'));
- int length = lastDot - (lastSlash + 1);
- QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
+ QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QString context;
+ if (QQmlContextData *ctxt = v8engine->callingContext()) {
+ QString path = ctxt->url.toString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
+ } else if (QV4::ExecutionContext *parentCtx = ctx->d()->parent) {
+ // 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) {
+ QString fileName = unit->fileName();
+ QUrl url(unit->fileName());
+ if (url.isValid() && url.isRelative()) {
+ context = url.fileName();
+ } else {
+ context = QQmlFile::urlToLocalFileOrQrc(fileName);
+ if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
+ context = fileName;
+ }
+ context = QFileInfo(context).baseName();
+ }
+ parentCtx = parentCtx->d()->parent;
+ }
+ }
- QString text = ctx->callData->args[0].toQStringNoThrow();
+ QString text = ctx->d()->callData->args[0].toQStringNoThrow();
QString comment;
- if (ctx->callData->argc > 1)
- comment = ctx->callData->args[1].toQStringNoThrow();
+ if (ctx->d()->callData->argc > 1)
+ comment = ctx->d()->callData->args[1].toQStringNoThrow();
int n = -1;
- if (ctx->callData->argc > 2)
- n = ctx->callData->args[2].toInt32();
+ if (ctx->d()->callData->argc > 2)
+ n = ctx->d()->callData->args[2].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
comment.toUtf8().constData(), n);
- return ctx->engine->newString(result)->asReturnedValue();
+ return ctx->d()->engine->newString(result)->asReturnedValue();
}
/*!
@@ -1755,9 +1772,9 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
*/
ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
{
- if (ctx->callData->argc < 1)
+ if (ctx->d()->callData->argc < 1)
return QV4::Encode::undefined();
- return ctx->callData->args[0].asReturnedValue();
+ return ctx->d()->callData->args[0].asReturnedValue();
}
/*!
@@ -1792,18 +1809,18 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
*/
ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
{
- if (ctx->callData->argc < 1)
+ if (ctx->d()->callData->argc < 1)
V4THROW_ERROR("qsTrId() requires at least one argument");
- if (!ctx->callData->args[0].isString())
+ if (!ctx->d()->callData->args[0].isString())
V4THROW_TYPE("qsTrId(): first argument (id) must be a string");
- if (ctx->callData->argc > 1 && !ctx->callData->args[1].isNumber())
+ if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isNumber())
V4THROW_TYPE("qsTrId(): second argument (n) must be a number");
int n = -1;
- if (ctx->callData->argc > 1)
- n = ctx->callData->args[1].toInt32();
+ if (ctx->d()->callData->argc > 1)
+ n = ctx->d()->callData->args[1].toInt32();
- return ctx->engine->newString(qtTrId(ctx->callData->args[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue();
+ return ctx->d()->engine->newString(qtTrId(ctx->d()->callData->args[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue();
}
/*!
@@ -1824,16 +1841,16 @@ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
*/
ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx)
{
- if (ctx->callData->argc < 1)
+ if (ctx->d()->callData->argc < 1)
return QV4::Encode::undefined();
- return ctx->callData->args[0].asReturnedValue();
+ return ctx->d()->callData->args[0].asReturnedValue();
}
#endif // QT_NO_TRANSLATION
QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx)
{
- ctx->engine->memoryManager->runGC();
+ ctx->d()->engine->memoryManager->runGC();
return QV4::Encode::undefined();
}
@@ -1842,21 +1859,21 @@ QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx)
ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
{
- if (ctx->callData->argc != 1)
+ if (ctx->d()->callData->argc != 1)
V4THROW_ERROR("String.arg(): Invalid arguments");
- QString value = ctx->callData->thisObject.toQString();
+ QString value = ctx->d()->callData->thisObject.toQString();
QV4::Scope scope(ctx);
- QV4::ScopedValue arg(scope, ctx->callData->args[0]);
+ QV4::ScopedValue arg(scope, ctx->d()->callData->args[0]);
if (arg->isInteger())
- return ctx->engine->newString(value.arg(arg->integerValue()))->asReturnedValue();
+ return ctx->d()->engine->newString(value.arg(arg->integerValue()))->asReturnedValue();
else if (arg->isDouble())
- return ctx->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue();
+ return ctx->d()->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue();
else if (arg->isBoolean())
- return ctx->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue();
+ return ctx->d()->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue();
- return ctx->engine->newString(value.arg(arg->toQString()))->asReturnedValue();
+ return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue();
}
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index adc0c6ce4f..9732a468df 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -65,8 +65,13 @@ namespace QV4 {
struct QtObject : Object
{
- V4_OBJECT
- QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine);
+ struct Data : Object::Data {
+ Data(ExecutionEngine *v4, QQmlEngine *qmlEngine);
+ QObject *platform;
+ QObject *application;
+ };
+ V4_OBJECT(Object)
+
static ReturnedValue method_isQtObject(CallContext *ctx);
static ReturnedValue method_rgba(CallContext *ctx);
@@ -104,14 +109,13 @@ struct QtObject : Object
#ifndef QT_NO_IM
static ReturnedValue method_get_inputMethod(CallContext *ctx);
#endif
-
- QObject *m_platform;
- QObject *m_application;
};
struct ConsoleObject : Object
{
- ConsoleObject(ExecutionEngine *v4);
+ struct Data : Object::Data {
+ Data(ExecutionEngine *engine);
+ };
static ReturnedValue method_error(CallContext *ctx);
static ReturnedValue method_log(CallContext *ctx);
@@ -147,18 +151,23 @@ struct GlobalExtensions {
struct QQmlBindingFunction : public QV4::FunctionObject
{
- V4_OBJECT
- QQmlBindingFunction(FunctionObject *originalFunction);
+ struct Data : FunctionObject::Data {
+ Data(FunctionObject *originalFunction);
+ QV4::FunctionObject *originalFunction;
+ // Set when the binding is created later
+ QQmlSourceLocation bindingLocation;
+ };
+ V4_OBJECT(QV4::FunctionObject)
void initBindingLocation(); // from caller stack trace
static ReturnedValue call(Managed *that, CallData *callData);
static void markObjects(Managed *that, ExecutionEngine *e);
+ static void destroy(Managed *that) {
+ static_cast<QQmlBindingFunction *>(that)->d()->~Data();
+ }
- QV4::FunctionObject *originalFunction;
- // Set when the binding is created later
- QQmlSourceLocation bindingLocation;
};
}
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
index faf52ce1ad..30cbd61467 100644
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ b/src/qml/qml/v8/qv4domerrors_p.h
@@ -77,9 +77,9 @@ QT_BEGIN_NAMESPACE
#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
#define V4THROW_DOM(error, string) { \
- QV4::ScopedValue v(scope, ctx->engine->newString(QStringLiteral(string))); \
- QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \
+ QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
+ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \
return ctx->throwError(ex); \
}
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 8305649177..68f312353a 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -130,7 +130,7 @@ QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint)
QV4::Scope scope(m_v4Engine);
if (QV4::VariantObject *v = value->as<QV4::VariantObject>())
- return v->data;
+ return v->d()->data;
if (typeHint == QVariant::Bool)
return QVariant(value->toBoolean());
@@ -229,9 +229,9 @@ static QV4::ReturnedValue objectFromVariantMap(QV8Engine *engine, const QVariant
for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter) {
s = e->newString(iter.key());
uint idx = s->asArrayIndex();
- if (idx > 16 && (!o->arrayData || idx > o->arrayData->length() * 2))
+ if (idx > 16 && (!o->arrayData() || idx > o->arrayData()->length() * 2))
o->initSparseArray();
- o->put(s, (v = engine->fromVariant(iter.value())));
+ o->put(s.getPointer(), (v = engine->fromVariant(iter.value())));
}
return o.asReturnedValue();
}
@@ -261,7 +261,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(ptr));
case QMetaType::QString:
- return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
+ return m_v4Engine->currentContext()->d()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(ptr));
case QMetaType::Short:
@@ -398,7 +398,7 @@ QVariant QV8Engine::toBasicVariant(const QV4::ValueRef value)
if (value->isString())
return value->stringValue()->toQString();
if (QQmlLocaleData *ld = value->as<QQmlLocaleData>())
- return ld->locale;
+ return ld->d()->locale;
if (QV4::DateObject *d = value->asDateObject())
return d->toQDateTime();
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
@@ -444,9 +444,9 @@ void QV8Engine::initializeGlobal()
qt_add_sqlexceptions(m_v4Engine);
{
- for (uint i = 0; i < m_v4Engine->globalObject->internalClass->size; ++i) {
- if (m_v4Engine->globalObject->internalClass->nameMap.at(i))
- m_illegalNames.insert(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString());
+ for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) {
+ if (m_v4Engine->globalObject->internalClass()->nameMap.at(i))
+ m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->toQString());
}
}
@@ -469,7 +469,7 @@ void QV8Engine::initializeGlobal()
" }"\
"})"
- QV4::Scoped<QV4::FunctionObject> result(scope, QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), QV4::ObjectRef::null()));
+ QV4::Scoped<QV4::FunctionObject> result(scope, QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), 0));
Q_ASSERT(!!result);
m_freezeObject = result;
#undef FREEZE_SOURCE
@@ -486,11 +486,6 @@ void QV8Engine::freezeObject(const QV4::ValueRef value)
f->call(callData);
}
-void QV8Engine::gc()
-{
- m_v4Engine->memoryManager->runGC();
-}
-
struct QV8EngineRegistrationData
{
QV8EngineRegistrationData() : extensionCount(0) {}
@@ -560,8 +555,7 @@ QV4::ReturnedValue QV8Engine::variantListToJS(const QVariantList &lst)
// The result is a QVariantList with length equal to the length
// of the JS Array, and elements being the JS Array's elements
// converted to QVariants, recursively.
-QVariantList QV8Engine::variantListFromJS(QV4::ArrayObjectRef a,
- V8ObjectSet &visitedObjects)
+QVariantList QV8Engine::variantListFromJS(QV4::ArrayObject *a, V8ObjectSet &visitedObjects)
{
QVariantList result;
if (!a)
@@ -605,7 +599,7 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap)
if (idx < UINT_MAX)
o->arraySet(idx, v);
else
- o->insertMember(s, v);
+ o->insertMember(s.getPointer(), v);
}
return o.asReturnedValue();
}
@@ -614,8 +608,7 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap)
// The result is a QVariantMap with keys being the property names
// of the object, and values being the values of the JS object's
// properties converted to QVariants, recursively.
-QVariantMap QV8Engine::variantMapFromJS(QV4::ObjectRef o,
- V8ObjectSet &visitedObjects)
+QVariantMap QV8Engine::variantMapFromJS(QV4::Object *o, V8ObjectSet &visitedObjects)
{
QVariantMap result;
@@ -679,7 +672,7 @@ QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(data));
case QMetaType::QString:
- return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
+ return m_v4Engine->currentContext()->d()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(data));
case QMetaType::Short:
@@ -882,7 +875,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
return true;
if (value->as<QV4::VariantObject>() && name.endsWith('*')) {
int valueType = QMetaType::type(name.left(name.size()-1));
- QVariant &var = value->as<QV4::VariantObject>()->data;
+ QVariant &var = value->as<QV4::VariantObject>()->d()->data;
if (valueType == var.userType()) {
// We have T t, T* is requested, so return &t.
*reinterpret_cast<void* *>(data) = var.data();
@@ -893,12 +886,12 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
while (proto) {
bool canCast = false;
if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
- const QVariant &v = vo->data;
+ const QVariant &v = vo->d()->data;
canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
}
else if (proto->as<QV4::QObjectWrapper>()) {
QByteArray className = name.left(name.size()-1);
- QV4::ScopedObject p(scope, proto);
+ QV4::ScopedObject p(scope, proto.getPointer());
if (QObject *qobject = qtObjectFromJS(p))
canCast = qobject->qt_metacast(className) != 0;
}
@@ -969,7 +962,7 @@ QVariant QV8Engine::variantFromJS(const QV4::ValueRef value,
if (QV4::RegExpObject *re = value->as<QV4::RegExpObject>())
return re->toQRegExp();
if (QV4::VariantObject *v = value->as<QV4::VariantObject>())
- return v->data;
+ return v->d()->data;
if (value->as<QV4::QObjectWrapper>())
return qVariantFromValue(qtObjectFromJS(value));
if (QV4::QmlValueTypeWrapper *v = value->as<QV4::QmlValueTypeWrapper>())
@@ -1003,7 +996,7 @@ QObject *QV8Engine::qtObjectFromJS(const QV4::ValueRef value)
QV4::Scoped<QV4::VariantObject> v(scope, value);
if (v) {
- QVariant variant = v->data;
+ QVariant variant = v->d()->data;
int type = variant.userType();
if (type == QMetaType::QObjectStar)
return *reinterpret_cast<QObject* const *>(variant.constData());
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index 1295e671f0..a5b94e8bdf 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -219,8 +219,6 @@ public:
// Return the list of illegal id names (the names of the properties on the global object)
const QSet<QString> &illegalNames() const;
- void gc();
-
static QMutex *registrationMutex();
static int registerExtension();
@@ -228,11 +226,11 @@ public:
void setExtensionData(int, Deletable *);
QV4::ReturnedValue variantListToJS(const QVariantList &lst);
- inline QVariantList variantListFromJS(QV4::ArrayObjectRef array)
+ inline QVariantList variantListFromJS(QV4::ArrayObject *array)
{ V8ObjectSet visitedObjects; return variantListFromJS(array, visitedObjects); }
QV4::ReturnedValue variantMapToJS(const QVariantMap &vmap);
- inline QVariantMap variantMapFromJS(QV4::ObjectRef object)
+ inline QVariantMap variantMapFromJS(QV4::Object *object)
{ V8ObjectSet visitedObjects; return variantMapFromJS(object, visitedObjects); }
QV4::ReturnedValue variantToJS(const QVariant &value);
@@ -280,8 +278,8 @@ protected:
void initializeGlobal();
private:
- QVariantList variantListFromJS(QV4::ArrayObjectRef array, V8ObjectSet &visitedObjects);
- QVariantMap variantMapFromJS(QV4::ObjectRef object, V8ObjectSet &visitedObjects);
+ QVariantList variantListFromJS(QV4::ArrayObject *array, V8ObjectSet &visitedObjects);
+ QVariantMap variantMapFromJS(QV4::Object *object, V8ObjectSet &visitedObjects);
QVariant variantFromJS(const QV4::ValueRef value, V8ObjectSet &visitedObjects);
Q_DISABLE_COPY(QV8Engine)
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 99ec0b55de..b0e814d285 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -68,8 +68,8 @@ public:
bool ignoreUnknownSignals;
bool componentcomplete;
- QByteArray data;
QQmlRefPointer<QQmlCompiledData> cdata;
+ QList<const QV4::CompiledData::Binding *> bindings;
};
/*!
@@ -205,18 +205,15 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore)
d->ignoreUnknownSignals = ignore;
}
-QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
- QByteArray rv;
- QDataStream ds(&rv, QIODevice::WriteOnly);
-
for (int ii = 0; ii < props.count(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
- return QByteArray();
+ return;
}
@@ -226,56 +223,48 @@ QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlU
error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
else
error(binding, QQmlConnections::tr("Connections: syntax error"));
- return QByteArray();
+ return;
} if (binding->type != QV4::CompiledData::Binding::Type_Script) {
error(binding, QQmlConnections::tr("Connections: script expected"));
- return QByteArray();
- } else {
- ds << propName;
- ds << bindingIdentifier(binding);
+ return;
}
}
-
- return rv;
}
-void QQmlConnectionsParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata)
+void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQmlConnectionsPrivate *p =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
- p->data = data;
p->cdata = cdata;
+ p->bindings = bindings;
}
-
void QQmlConnections::connectSignals()
{
Q_D(QQmlConnections);
if (!d->componentcomplete || (d->targetSet && !target()))
return;
- QDataStream ds(d->data);
- while (!ds.atEnd()) {
- QString propName;
- ds >> propName;
- int bindingId;
- ds >> bindingId;
+ if (d->bindings.isEmpty())
+ return;
+ QObject *target = this->target();
+ QQmlData *ddata = QQmlData::get(this);
+ QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0;
+
+ const QV4::CompiledData::QmlUnit *qmlUnit = d->cdata->qmlUnit;
+ foreach (const QV4::CompiledData::Binding *binding, d->bindings) {
+ Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
- QQmlProperty prop(target(), propName);
+ QQmlProperty prop(target, propName);
if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
QQmlBoundSignal *signal =
- new QQmlBoundSignal(target(), signalIndex, this, qmlEngine(this));
-
- QQmlContextData *ctxtdata = 0;
- QQmlData *ddata = QQmlData::get(this);
- if (ddata) {
- ctxtdata = ddata->outerContext;
- }
+ new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
QQmlBoundSignalExpression *expression = ctxtdata ?
- new QQmlBoundSignalExpression(target(), signalIndex,
- ctxtdata, this, d->cdata->functionForBindingId(bindingId)) : 0;
+ new QQmlBoundSignalExpression(target, signalIndex,
+ ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
signal->takeExpression(expression);
d->boundsignals += signal;
} else {
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index f169eeb53f..e829828bd8 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -84,8 +84,8 @@ private:
class QQmlConnectionsParser : public QQmlCustomParser
{
public:
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata);
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
+ virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
};
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index aab385ceb5..91ddcf57e5 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -61,17 +61,23 @@ class QQmlDelegateModelItem;
struct DelegateModelGroupFunction: QV4::FunctionObject
{
- V4_OBJECT
+ struct Data : FunctionObject::Data {
+ Data(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg))
+ : FunctionObject::Data(scope, QStringLiteral("DelegateModelGroupFunction"))
+ , flag(flag)
+ , code(code)
+ {
+ setVTable(staticVTable());
+ }
- QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg);
- uint flag;
+ uint flag;
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg);
+ };
+ V4_OBJECT(QV4::FunctionObject)
- DelegateModelGroupFunction(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg))
- : FunctionObject(scope, QStringLiteral("DelegateModelGroupFunction"))
- , code(code)
- , flag(flag)
+ static DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg))
{
- setVTable(staticVTable());
+ return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code);
}
static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *)
@@ -89,7 +95,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QV4::ScopedValue v(scope, callData->argument(0));
- return f->code(o->item, f->flag, v);
+ return f->d()->code(o->d()->item, f->d()->flag, v);
}
};
@@ -103,8 +109,7 @@ public:
QQmlDelegateModelEngineData(QV8Engine *engine);
~QQmlDelegateModelEngineData();
- QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Remove> &changes);
- QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Insert> &changes);
+ QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Change> &changes);
QV4::PersistentValue changeProto;
};
@@ -722,8 +727,8 @@ void QQmlDelegateModelPrivate::updateFilterGroup()
QQmlDelegateModelGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Remove> removes;
- QVector<QQmlChangeSet::Insert> inserts;
+ QVector<QQmlChangeSet::Change> removes;
+ QVector<QQmlChangeSet::Change> inserts;
m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
QQmlChangeSet changeSet;
@@ -903,7 +908,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
return 0;
- } else if (!m_context->isValid()) {
+ } else if (!m_context || !m_context->isValid()) {
return 0;
}
@@ -946,7 +951,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
cacheItem->incubationTask->index[i] = it.index[i];
QQmlContextData *ctxt = new QQmlContextData;
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context));
+ ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
@@ -1143,7 +1148,7 @@ static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const
void QQmlDelegateModelPrivate::itemsInserted(
const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
{
int cacheIndex = 0;
@@ -1159,7 +1164,7 @@ void QQmlDelegateModelPrivate::itemsInserted(
for (int i = 1; i < m_groupCount; ++i) {
if (insert.inGroup(i)) {
(*translatedInserts)[i].append(
- QQmlChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
+ QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId));
inserted[i] += insert.count;
}
}
@@ -1200,7 +1205,7 @@ void QQmlDelegateModelPrivate::itemsInserted(
void QQmlDelegateModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
{
- QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
itemsInserted(inserts, &translatedInserts);
Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
if (!m_delegate)
@@ -1234,7 +1239,7 @@ void QQmlDelegateModel::_q_itemsInserted(int index, int count)
void QQmlDelegateModelPrivate::itemsRemoved(
const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
{
int cacheIndex = 0;
@@ -1251,7 +1256,7 @@ void QQmlDelegateModelPrivate::itemsRemoved(
for (int i = 1; i < m_groupCount; ++i) {
if (remove.inGroup(i)) {
(*translatedRemoves)[i].append(
- QQmlChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
+ QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId));
removed[i] -= remove.count;
}
}
@@ -1318,7 +1323,7 @@ void QQmlDelegateModelPrivate::itemsRemoved(
void QQmlDelegateModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
{
- QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
itemsRemoved(removes, &translatedRemoves);
Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
if (!m_delegate)
@@ -1356,10 +1361,10 @@ void QQmlDelegateModelPrivate::itemsMoved(
{
QHash<int, QList<QQmlDelegateModelItem *> > movedItems;
- QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
itemsRemoved(removes, &translatedRemoves, &movedItems);
- QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
itemsInserted(inserts, &translatedInserts, &movedItems);
Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
Q_ASSERT(movedItems.isEmpty());
@@ -1409,7 +1414,7 @@ void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet,
void QQmlDelegateModelPrivate::emitChanges()
{
- if (m_transaction || !m_complete || !m_context->isValid())
+ if (m_transaction || !m_complete || !m_context || !m_context->isValid())
return;
m_transaction = true;
@@ -1603,7 +1608,7 @@ QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj
bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::ValueRef object, int groups)
{
- if (!m_context->isValid())
+ if (!m_context || !m_context->isValid())
return false;
QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
@@ -1696,43 +1701,44 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
QV4::ScopedProperty p(scope);
s = v4->newString(QStringLiteral("isUnresolved"));
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member));
+ QV4::ScopedFunctionObject f(scope);
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, 30, QQmlDelegateModelItem::get_member)));
p->setSetter(0);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("inItems"));
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("inPersistedItems"));
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("itemsIndex"));
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index));
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
p->setSetter(0);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
for (int i = 2; i < groupNames.count(); ++i) {
QString propertyName = QStringLiteral("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4->newString(propertyName);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member));
- p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member)));
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.count(); ++i) {
const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
s = v4->newString(propertyName);
- p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index));
+ p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(0);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
modelItemProto = proto;
}
@@ -1780,46 +1786,46 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::ValueRef groups) const
QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!o->item->metaType->model)
+ if (!o->d()->item->metaType->model)
return QV4::Encode::undefined();
- return o->item->get();
+ return o->d()->item->get();
}
QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QStringList groups;
- for (int i = 1; i < o->item->metaType->groupCount; ++i) {
- if (o->item->groups & (1 << i))
- groups.append(o->item->metaType->groupNames.at(i - 1));
+ for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
+ if (o->d()->item->groups & (1 << i))
+ groups.append(o->d()->item->metaType->groupNames.at(i - 1));
}
- return ctx->engine->v8Engine->fromVariant(groups);
+ return scope.engine->v8Engine->fromVariant(groups);
}
QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return ctx->throwTypeError();
- if (!o->item->metaType->model)
+ if (!o->d()->item->metaType->model)
return QV4::Encode::undefined();
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->item->metaType->model);
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
- const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->callData->args[0]);
- const int cacheIndex = model->m_cache.indexOf(o->item);
+ const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->d()->callData->args[0]);
+ const int cacheIndex = model->m_cache.indexOf(o->d()->item);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
model->setGroups(it, 1, Compositor::Cache, groupFlags);
return QV4::Encode::undefined();
@@ -1861,14 +1867,14 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_index(QQmlDelegateModelItem *thisI
DEFINE_OBJECT_VTABLE(QQmlDelegateModelItemObject);
-QQmlDelegateModelItemObject::~QQmlDelegateModelItemObject()
+QQmlDelegateModelItemObject::Data::~Data()
{
item->Dispose();
}
void QQmlDelegateModelItemObject::destroy(Managed *that)
{
- static_cast<QQmlDelegateModelItemObject *>(that)->~QQmlDelegateModelItemObject();
+ static_cast<QQmlDelegateModelItemObject *>(that)->d()->~Data();
}
@@ -2442,7 +2448,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
return QQmlV4Handle(QV4::Encode::undefined());
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (!model->m_context->isValid()) {
+ if (!model->m_context || !model->m_context->isValid()) {
return QQmlV4Handle(QV4::Encode::undefined());
} else if (index < 0 || index >= model->m_compositor.count(d->group)) {
qmlInfo(this) << tr("get: index out of range");
@@ -2470,7 +2476,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
QV8Engine *v8 = model->m_cacheMetaType->v8Engine;
QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8);
QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, new (v4->memoryManager) QQmlDelegateModelItemObject(v4, cacheItem));
+ QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, cacheItem));
QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
o->setPrototype(p.getPointer());
++cacheItem->scriptRef;
@@ -2493,7 +2499,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::ValueRef value, int *i
QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value);
if (object) {
- QQmlDelegateModelItem * const cacheItem = object->item;
+ QQmlDelegateModelItem * const cacheItem = object->d()->item;
if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
? QQmlDelegateModelPrivate::get(cacheItem->metaType->model)
: 0) {
@@ -3070,8 +3076,8 @@ void QQmlPartsModel::updateFilterGroup()
QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Remove> removes;
- QVector<QQmlChangeSet::Insert> inserts;
+ QVector<QQmlChangeSet::Change> removes;
+ QVector<QQmlChangeSet::Change> inserts;
model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
QQmlChangeSet changeSet;
@@ -3212,59 +3218,70 @@ void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset
struct QQmlDelegateModelGroupChange : QV4::Object
{
- V4_OBJECT
- QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine)
- : Object(engine)
- {
- setVTable(staticVTable());
+ struct Data : QV4::Object::Data {
+ Data(QV4::ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+ }
+ QQmlChangeSet::Change change;
+ };
+ V4_OBJECT(QV4::Object)
+
+ static QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
+ return e->memoryManager->alloc<QQmlDelegateModelGroupChange>(e);
}
static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
return ctx->throwTypeError();
- return QV4::Encode(that->change.index);
+ return QV4::Encode(that->d()->change.index);
}
static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
return ctx->throwTypeError();
- return QV4::Encode(that->change.count);
+ return QV4::Encode(that->d()->change.count);
}
static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) {
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>());
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
return ctx->throwTypeError();
- if (that->change.moveId < 0)
+ if (that->d()->change.moveId < 0)
return QV4::Encode::undefined();
- return QV4::Encode(that->change.moveId);
+ return QV4::Encode(that->d()->change.moveId);
}
-
- QQmlChangeSet::Change change;
};
DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChange);
-class QQmlDelegateModelGroupChangeArray : public QV4::Object
-{
- V4_OBJECT
+struct QQmlDelegateModelGroupChangeArray : public QV4::Object
+{
+ struct Data : QV4::Object::Data {
+ Data(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
+ : Object::Data(engine)
+ , changes(changes)
+ {
+ setVTable(staticVTable());
+ QV4::Scope scope(engine);
+ QV4::ScopedObject o(scope, this);
+ o->setArrayType(QV4::ArrayData::Custom);
+ }
+ QVector<QQmlChangeSet::Change> changes;
+ };
+ V4_OBJECT(QV4::Object)
public:
- QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine)
- : Object(engine)
+ static QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
{
- setVTable(staticVTable());
- QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
- Q_UNUSED(protectThis);
- setArrayType(QV4::ArrayData::Custom);
+ return engine->memoryManager->alloc<QQmlDelegateModelGroupChangeArray>(engine, changes);
}
- virtual ~QQmlDelegateModelGroupChangeArray() {}
- virtual quint32 count() const = 0;
- virtual const QQmlChangeSet::Change &at(int index) const = 0;
+ quint32 count() const { return d()->changes.count(); }
+ const QQmlChangeSet::Change &at(int index) const { return d()->changes.at(index); }
static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty)
{
@@ -3283,16 +3300,16 @@ public:
const QQmlChangeSet::Change &change = array->at(index);
QV4::ScopedObject changeProto(scope, engineData(v4->v8Engine)->changeProto.value());
- QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, new (v4->memoryManager) QQmlDelegateModelGroupChange(v4));
+ QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4));
object->setPrototype(changeProto.getPointer());
- object->change = change;
+ object->d()->change = change;
if (hasProperty)
*hasProperty = true;
return object.asReturnedValue();
}
- static QV4::ReturnedValue get(QV4::Managed *m, const QV4::StringRef name, bool *hasProperty)
+ static QV4::ReturnedValue get(QV4::Managed *m, QV4::String *name, bool *hasProperty)
{
QQmlDelegateModelGroupChangeArray *array = m->as<QQmlDelegateModelGroupChangeArray>();
if (!array)
@@ -3308,46 +3325,13 @@ public:
}
static void destroy(Managed *that) {
QQmlDelegateModelGroupChangeArray *array = that->as<QQmlDelegateModelGroupChangeArray>();
- assert(array);
- array->~QQmlDelegateModelGroupChangeArray();
+ array->d()->~Data();
}
};
DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChangeArray);
-class QQmlDelegateModelGroupRemoveArray : public QQmlDelegateModelGroupChangeArray
-{
-public:
- QQmlDelegateModelGroupRemoveArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Remove> &changes)
- : QQmlDelegateModelGroupChangeArray(engine)
- , changes(changes)
- {
- }
-
- quint32 count() const { return changes.count(); }
- const QQmlChangeSet::Change &at(int index) const { return changes.at(index); }
-
-private:
- QVector<QQmlChangeSet::Remove> changes;
-};
-
-class QQmlDelegateModelGroupInsertArray : public QQmlDelegateModelGroupChangeArray
-{
-public:
- QQmlDelegateModelGroupInsertArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Insert> &changes)
- : QQmlDelegateModelGroupChangeArray(engine)
- , changes(changes)
- {
- }
-
- quint32 count() const { return changes.count(); }
- const QQmlChangeSet::Change &at(int index) const { return changes.at(index); }
-
-private:
- QVector<QQmlChangeSet::Insert> changes;
-};
-
QQmlDelegateModelEngineData::QQmlDelegateModelEngineData(QV8Engine *e)
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(e);
@@ -3364,16 +3348,12 @@ QQmlDelegateModelEngineData::~QQmlDelegateModelEngineData()
{
}
-QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Remove> &changes)
+QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Change> &changes)
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- return (new (v4->memoryManager) QQmlDelegateModelGroupRemoveArray(v4, changes))->asReturnedValue();
-}
-
-QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Insert> &changes)
-{
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- return (new (v4->memoryManager) QQmlDelegateModelGroupInsertArray(v4, changes))->asReturnedValue();
+ QV4::Scope scope(v4);
+ QV4::ScopedObject o(scope, QQmlDelegateModelGroupChangeArray::create(v4, changes));
+ return o.asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index d64f641a1b..7846992e5d 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -161,16 +161,19 @@ protected:
struct QQmlDelegateModelItemObject : QV4::Object
{
- V4_OBJECT;
- QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item)
- : Object(engine)
- , item(item)
- { setVTable(staticVTable()); }
- ~QQmlDelegateModelItemObject();
+ struct Data : QV4::Object::Data {
+ Data(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item)
+ : Object::Data(engine)
+ , item(item)
+ {
+ setVTable(staticVTable());
+ }
+ ~Data();
+ QQmlDelegateModelItem *item;
+ };
+ V4_OBJECT(QV4::Object)
static void destroy(Managed *that);
-
- QQmlDelegateModelItem *item;
};
@@ -275,12 +278,12 @@ public:
void itemsInserted(
const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = 0);
void itemsInserted(const QVector<Compositor::Insert> &inserts);
void itemsRemoved(
const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
+ QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = 0);
void itemsRemoved(const QVector<Compositor::Remove> &removes);
void itemsMoved(
@@ -303,7 +306,7 @@ public:
QQmlListCompositor m_compositor;
QQmlComponent *m_delegate;
QQmlDelegateModelItemMetaType *m_cacheMetaType;
- QQmlContext *m_context;
+ QPointer<QQmlContext> m_context;
QQmlDelegateModelParts *m_parts;
QQmlDelegateModelGroupEmitterList m_pendingParts;
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index 724a76825b..73e4ba851a 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -137,7 +137,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
int difference = 0;
QHash<int, QVector<QPointer<QObject> > > moved;
- foreach (const QQmlChangeSet::Remove &remove, changeSet.removes()) {
+ foreach (const QQmlChangeSet::Change &remove, changeSet.removes()) {
int index = qMin(remove.index, objects.count());
int count = qMin(remove.index + remove.count, objects.count()) - index;
if (remove.isMove()) {
@@ -156,7 +156,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
difference -= remove.count;
}
- foreach (const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
+ foreach (const QQmlChangeSet::Change &insert, changeSet.inserts()) {
int index = qMin(insert.index, objects.count());
if (insert.isMove()) {
QVector<QPointer<QObject> > movedObjects = moved.value(insert.moveId);
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index be49b6e5a0..46916656b6 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -44,7 +44,7 @@
#include <private/qqmlopenmetaobject_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
-
+#include <private/qqmlcompiler_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlengine_p.h>
@@ -103,9 +103,9 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::Da
return createRole(key, type);
}
-const ListLayout::Role &ListLayout::getRoleOrCreate(const QV4::StringRef key, Role::DataType type)
+const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::DataType type)
{
- QStringHash<Role *>::Node *node = roleHash.findNode(key.getPointer());
+ QStringHash<Role *>::Node *node = roleHash.findNode(key);
if (node) {
const Role &r = *node->value;
if (type != r.type)
@@ -239,10 +239,10 @@ const ListLayout::Role *ListLayout::getExistingRole(const QString &key)
return r;
}
-const ListLayout::Role *ListLayout::getExistingRole(const QV4::StringRef key)
+const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key)
{
Role *r = 0;
- QStringHash<Role *>::Node *node = roleHash.findNode(key.getPointer());
+ QStringHash<Role *>::Node *node = roleHash.findNode(key);
if (node)
r = node->value;
return r;
@@ -409,7 +409,7 @@ ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &
return e->getListProperty(role);
}
-void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles, QV8Engine *eng)
+void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles, QV8Engine *eng)
{
ListElement *e = elements[elementIndex];
@@ -432,13 +432,13 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles
// Add the value now
if ((s = propertyValue)) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::String);
roleIndex = e->setStringProperty(r, s->toQString());
} else if (propertyValue->isNumber()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Number);
roleIndex = e->setDoubleProperty(r, propertyValue->asDouble());
} else if ((a = propertyValue)) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::List);
ListModel *subModel = new ListModel(r.subLayout, 0, -1);
int arrayLength = a->getLength();
@@ -449,16 +449,16 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles
roleIndex = e->setListProperty(r, subModel);
} else if (propertyValue->isBoolean()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Bool);
roleIndex = e->setBoolProperty(r, propertyValue->booleanValue());
} else if (QV4::DateObject *dd = propertyValue->asDateObject()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::DateTime);
QDateTime dt = dd->toQDateTime();
roleIndex = e->setDateTimeProperty(r, dt);
} else if (QV4::Object *o = propertyValue->asObject()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
QObject *o = wrapper->object();
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::QObject);
if (role.type == ListLayout::Role::QObject)
roleIndex = e->setQObjectProperty(role, o);
} else {
@@ -483,7 +483,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles
}
}
-void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng)
+void ListModel::set(int elementIndex, QV4::Object *object, QV8Engine *eng)
{
if (!object)
return;
@@ -580,13 +580,13 @@ void ListModel::remove(int index, int count)
updateCacheIndices();
}
-void ListModel::insert(int elementIndex, QV4::ObjectRef object, QV8Engine *eng)
+void ListModel::insert(int elementIndex, QV4::Object *object, QV8Engine *eng)
{
insertElement(elementIndex);
set(elementIndex, object, eng);
}
-int ListModel::append(QV4::ObjectRef object, QV8Engine *eng)
+int ListModel::append(QV4::Object *object, QV8Engine *eng)
{
int elementIndex = appendElement();
set(elementIndex, object, eng);
@@ -883,7 +883,7 @@ int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
return roleIndex;
}
-int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng)
+int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng)
{
int roleIndex = -1;
@@ -970,7 +970,7 @@ void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m
*value = m;
}
-void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng)
+void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng)
{
char *mem = getPropertyMemory(role);
QVariantMap *map = new (mem) QVariantMap;
@@ -1430,11 +1430,6 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
}
}
-QQmlListModelParser::ListInstruction *QQmlListModelParser::ListModelData::instructions() const
-{
- return (QQmlListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData));
-}
-
/*!
\qmltype ListModel
\instantiates QQmlListModel
@@ -2290,7 +2285,7 @@ void QQmlListModel::sync()
qmlInfo(this) << "List sync() can only be called from a WorkerScript";
}
-bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data)
+bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
{
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
@@ -2305,13 +2300,6 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
listElementTypeName = objName; // cache right name for next time
}
- {
- ListInstruction li;
- li.type = ListInstruction::Push;
- li.dataIdx = -1;
- instr << li;
- }
-
if (!qmlUnit->header.stringAt(target->idIndex).isEmpty()) {
error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
return false;
@@ -2324,208 +2312,116 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU
error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements"));
return false;
}
- ListInstruction li;
- int ref = data.count();
- data.append(propName.toUtf8());
- data.append('\0');
- li.type = ListInstruction::Set;
- li.dataIdx = ref;
- instr << li;
-
- if (!compileProperty(qmlUnit, binding, instr, data))
+ if (!verifyProperty(qmlUnit, binding))
+ return false;
+ }
+ } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QString scriptStr = binding->valueAsScriptString(&qmlUnit->header);
+ if (!definesEmptyList(scriptStr)) {
+ QByteArray script = scriptStr.toUtf8();
+ bool ok;
+ evaluateEnum(script, &ok);
+ if (!ok) {
+ error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
return false;
+ }
+ }
+ }
- li.type = ListInstruction::Pop;
- li.dataIdx = -1;
- instr << li;
+ return true;
+}
+
+bool QQmlListModelParser::applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex)
+{
+ const QString elementName = qmlUnit->header.stringAt(binding->propertyNameIndex);
+
+ bool roleSet = false;
+ if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const quint32 targetObjectIndex = binding->value.objectIndex;
+ const QV4::CompiledData::Object *target = qmlUnit->objectAt(targetObjectIndex);
+
+ ListModel *subModel = 0;
+ if (outterElementIndex == -1) {
+ subModel = model;
+ } else {
+ const ListLayout::Role &role = model->getOrCreateListRole(elementName);
+ if (role.type == ListLayout::Role::List) {
+ subModel = model->getListProperty(outterElementIndex, role);
+ if (subModel == 0) {
+ subModel = new ListModel(role.subLayout, 0, -1);
+ QVariant vModel = QVariant::fromValue(subModel);
+ model->setOrCreateProperty(outterElementIndex, elementName, vModel);
+ }
+ }
}
- {
- ListInstruction li;
- li.type = ListInstruction::Pop;
- li.dataIdx = -1;
- instr << li;
+ int elementIndex = subModel ? subModel->appendElement() : -1;
+
+ const QV4::CompiledData::Binding *subBinding = target->bindingTable();
+ for (quint32 i = 0; i < target->nBindings; ++i, ++subBinding) {
+ roleSet |= applyProperty(qmlUnit, subBinding, subModel, elementIndex);
}
} else {
- int ref = data.count();
+ QVariant value;
- QByteArray d;
-
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
- d += char(String);
- d += binding->valueAsString(&qmlUnit->header).toUtf8();
+ if (binding->evaluatesToString()) {
+ value = binding->valueAsString(&qmlUnit->header);
} else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- d += char(Number);
- d += QByteArray::number(binding->valueAsNumber(),'g',20);
+ value = binding->valueAsNumber();
} else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
- d += char(Boolean);
- d += char(binding->valueAsBoolean());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Translation
- || binding->type == QV4::CompiledData::Binding::Type_TranslationById) {
- error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
- return false;
+ value = binding->valueAsBoolean();
} else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = binding->valueAsScriptString(&qmlUnit->header);
if (definesEmptyList(scriptStr)) {
- d[0] = char(Invalid); // marks empty list
+ const ListLayout::Role &role = model->getOrCreateListRole(elementName);
+ ListModel *emptyModel = new ListModel(role.subLayout, 0, -1);
+ value = QVariant::fromValue(emptyModel);
} else {
QByteArray script = scriptStr.toUtf8();
bool ok;
- int v = evaluateEnum(script, &ok);
- if (!ok) {
- error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
- return false;
- } else {
- d[0] = char(Number);
- d += QByteArray::number(v);
- }
+ value = evaluateEnum(script, &ok);
}
} else {
Q_UNREACHABLE();
}
- d.append('\0');
- data.append(d);
-
- ListInstruction li;
- li.type = ListInstruction::Value;
- li.dataIdx = ref;
- instr << li;
+ model->setOrCreateProperty(outterElementIndex, elementName, value);
+ roleSet = true;
}
-
- return true;
+ return roleSet;
}
-QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void QQmlListModelParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
- QList<ListInstruction> instr;
- QByteArray data;
listElementTypeName = QString(); // unknown
foreach (const QV4::CompiledData::Binding *binding, bindings) {
QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex);
if (!propName.isEmpty()) { // isn't default property
error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
- return QByteArray();
+ return;
}
- if (!compileProperty(qmlUnit, binding, instr, data))
- return QByteArray();
+ if (!verifyProperty(qmlUnit, binding))
+ return;
}
-
- int size = sizeof(ListModelData) +
- instr.count() * sizeof(ListInstruction) +
- data.count();
-
- QByteArray rv;
- rv.resize(size);
-
- ListModelData *lmd = (ListModelData *)rv.data();
- lmd->dataOffset = sizeof(ListModelData) +
- instr.count() * sizeof(ListInstruction);
- lmd->instrCount = instr.count();
- for (int ii = 0; ii < instr.count(); ++ii)
- lmd->instructions()[ii] = instr.at(ii);
- ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
-
- return rv;
}
-void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d, QQmlCompiledData *)
+void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
QV8Engine *engine = QQmlEnginePrivate::getV8Engine(qmlEngine(rv));
rv->m_engine = engine;
- const ListModelData *lmd = (const ListModelData *)d.constData();
- const char *data = ((const char *)lmd) + lmd->dataOffset;
+ const QV4::CompiledData::QmlUnit *qmlUnit = cdata->qmlUnit;
bool setRoles = false;
- QStack<DataStackElement> stack;
-
- for (int ii = 0; ii < lmd->instrCount; ++ii) {
- const ListInstruction &instr = lmd->instructions()[ii];
-
- switch(instr.type) {
- case ListInstruction::Push:
- {
- Q_ASSERT(!rv->m_dynamicRoles);
-
- ListModel *subModel = 0;
-
- if (stack.count() == 0) {
- subModel = rv->m_listModel;
- } else {
- const DataStackElement &e0 = stack.at(stack.size() - 1);
- DataStackElement &e1 = stack[stack.size() - 2];
-
- const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name);
- if (role.type == ListLayout::Role::List) {
- subModel = e1.model->getListProperty(e1.elementIndex, role);
-
- if (subModel == 0) {
- subModel = new ListModel(role.subLayout, 0, -1);
- QVariant vModel = QVariant::fromValue(subModel);
- e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel);
- }
- }
- }
-
- DataStackElement e;
- e.model = subModel;
- e.elementIndex = subModel ? subModel->appendElement() : -1;
- stack.push(e);
- }
- break;
-
- case ListInstruction::Pop:
- stack.pop();
- break;
-
- case ListInstruction::Value:
- {
- const DataStackElement &e0 = stack.at(stack.size() - 1);
- DataStackElement &e1 = stack[stack.size() - 2];
-
- QString name = e0.name;
- QVariant value;
-
- switch (PropertyType(data[instr.dataIdx])) {
- case Invalid:
- {
- const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name);
- ListModel *emptyModel = new ListModel(role.subLayout, 0, -1);
- value = QVariant::fromValue(emptyModel);
- }
- break;
- case Boolean:
- value = bool(data[1 + instr.dataIdx]);
- break;
- case Number:
- value = QByteArray(data + 1 + instr.dataIdx).toDouble();
- break;
- case String:
- value = QString::fromUtf8(data + 1 + instr.dataIdx);
- break;
- default:
- Q_ASSERT("Format error in ListInstruction");
- }
-
- e1.model->setOrCreateProperty(e1.elementIndex, name, value);
- setRoles = true;
- }
- break;
-
- case ListInstruction::Set:
- {
- DataStackElement e;
- e.name = QString::fromUtf8(data + instr.dataIdx);
- stack.push(e);
- }
- break;
- }
+ foreach (const QV4::CompiledData::Binding *binding, bindings) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ continue;
+ setRoles |= applyProperty(qmlUnit, binding, rv->m_listModel, /*outter element index*/-1);
}
if (setRoles == false)
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 3d84e14698..8c12173425 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -171,41 +171,20 @@ public:
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
- QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
- void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *);
+
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
+ virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
private:
- struct ListInstruction
- {
- enum { Push, Pop, Value, Set } type;
- int dataIdx;
- };
- struct ListModelData
- {
- int dataOffset;
- int instrCount;
- ListInstruction *instructions() const;
- };
- bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data);
+ bool verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
+ // returns true if a role was set
+ bool applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex);
bool definesEmptyList(const QString &);
QString listElementTypeName;
-
- struct DataStackElement
- {
- DataStackElement() : model(0), elementIndex(0) {}
-
- QString name;
- ListModel *model;
- int elementIndex;
- };
-
- friend class QTypeInfo<QQmlListModelParser::ListInstruction>;
};
-Q_DECLARE_TYPEINFO(QQmlListModelParser::ListInstruction, Q_PRIMITIVE_TYPE);
-
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlListModel)
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index 924d89c52d..a27b8026d7 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -209,12 +209,12 @@ public:
};
const Role *getRoleOrCreate(const QString &key, const QVariant &data);
- const Role &getRoleOrCreate(const QV4::StringRef key, Role::DataType type);
+ const Role &getRoleOrCreate(QV4::String *key, Role::DataType type);
const Role &getRoleOrCreate(const QString &key, Role::DataType type);
const Role &getExistingRole(int index) { return *roles.at(index); }
const Role *getExistingRole(const QString &key);
- const Role *getExistingRole(const QV4::StringRef key);
+ const Role *getExistingRole(QV4::String *key);
int roleCount() const { return roles.count(); }
@@ -260,7 +260,7 @@ private:
int setBoolProperty(const ListLayout::Role &role, bool b);
int setListProperty(const ListLayout::Role &role, ListModel *m);
int setQObjectProperty(const ListLayout::Role &role, QObject *o);
- int setVariantMapProperty(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng);
+ int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng);
int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
@@ -269,7 +269,7 @@ private:
void setBoolPropertyFast(const ListLayout::Role &role, bool b);
void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o);
void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
- void setVariantMapFast(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng);
+ void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng);
void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
void clearProperty(const ListLayout::Role &role);
@@ -333,11 +333,11 @@ public:
return elements.count();
}
- void set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles, QV8Engine *eng);
- void set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng);
+ void set(int elementIndex, QV4::Object *object, QVector<int> *roles, QV8Engine *eng);
+ void set(int elementIndex, QV4::Object *object, QV8Engine *eng);
- int append(QV4::ObjectRef object, QV8Engine *eng);
- void insert(int elementIndex, QV4::ObjectRef object, QV8Engine *eng);
+ int append(QV4::Object *object, QV8Engine *eng);
+ void insert(int elementIndex, QV4::Object *object, QV8Engine *eng);
void clear();
void remove(int index, int count);
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index b9e28b881c..9d502433c8 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -49,7 +49,10 @@
QT_BEGIN_NAMESPACE
-
+namespace {
+ const QEvent::Type QEvent_MaybeTick = QEvent::Type(QEvent::User + 1);
+ const QEvent::Type QEvent_Triggered = QEvent::Type(QEvent::User + 2);
+}
class QQmlTimerPrivate : public QObjectPrivate, public QAnimationJobChangeListener
{
@@ -57,10 +60,18 @@ class QQmlTimerPrivate : public QObjectPrivate, public QAnimationJobChangeListen
public:
QQmlTimerPrivate()
: interval(1000), running(false), repeating(false), triggeredOnStart(false)
- , classBegun(false), componentComplete(false), firstTick(true) {}
+ , classBegun(false), componentComplete(false), firstTick(true), awaitingTick(false) {}
virtual void animationFinished(QAbstractAnimationJob *);
- virtual void animationCurrentLoopChanged(QAbstractAnimationJob *) { Q_Q(QQmlTimer); q->ticked(); }
+ virtual void animationCurrentLoopChanged(QAbstractAnimationJob *) { maybeTick(); }
+
+ void maybeTick() {
+ Q_Q(QQmlTimer);
+ if (!awaitingTick) {
+ awaitingTick = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent_MaybeTick));
+ }
+ }
int interval;
QPauseAnimationJob pause;
@@ -70,6 +81,7 @@ public:
bool classBegun : 1;
bool componentComplete : 1;
bool firstTick : 1;
+ bool awaitingTick : 1;
};
/*!
@@ -281,10 +293,8 @@ void QQmlTimer::update()
d->pause.setLoopCount(d->repeating ? -1 : 1);
d->pause.setDuration(d->interval);
d->pause.start();
- if (d->triggeredOnStart && d->firstTick) {
- QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
- QMetaObject::invokeMethod(this, "ticked", Qt::QueuedConnection);
- }
+ if (d->triggeredOnStart && d->firstTick)
+ d->maybeTick();
}
}
@@ -316,6 +326,23 @@ void QQmlTimer::ticked()
d->firstTick = false;
}
+/*!
+ \internal
+ */
+bool QQmlTimer::event(QEvent *e)
+{
+ Q_D(QQmlTimer);
+ if (e->type() == QEvent_MaybeTick) {
+ d->awaitingTick = false;
+ ticked();
+ return true;
+ } else if (e->type() == QEvent_Triggered) {
+ emit triggered();
+ return true;
+ }
+ return QObject::event(e);
+}
+
void QQmlTimerPrivate::animationFinished(QAbstractAnimationJob *)
{
Q_Q(QQmlTimer);
@@ -323,7 +350,7 @@ void QQmlTimerPrivate::animationFinished(QAbstractAnimationJob *)
return;
running = false;
firstTick = false;
- emit q->triggered();
+ QCoreApplication::postEvent(q, new QEvent(QEvent_Triggered));
emit q->runningChanged();
}
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index c625522851..b51bb7f480 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -81,6 +81,8 @@ protected:
void classBegin();
void componentComplete();
+ bool event(QEvent *);
+
public Q_SLOTS:
void start();
void stop();
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 4e842c5133..a9f748cde1 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -235,7 +235,7 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
QV4::Scoped<QV4::FunctionObject> createsendconstructor(scope, createsendscript.run());
Q_ASSERT(!scope.engine->hasException);
QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage")));
- QV4::ScopedValue function(scope, m_v4Engine->newBuiltinFunction(m_v4Engine->rootContext, name,
+ QV4::ScopedValue function(scope, QV4::BuiltinFunction::create(m_v4Engine->rootContext, name.getPointer(),
QQuickWorkerScriptEnginePrivate::method_sendMessage));
QV4::ScopedCallData callData(scope, 1);
callData->args[0] = function;
@@ -283,12 +283,12 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng
QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx)
{
- WorkerEngine *engine = (WorkerEngine*)ctx->engine->v8Engine;
+ WorkerEngine *engine = (WorkerEngine*)ctx->engine()->v8Engine;
- int id = ctx->callData->argc > 1 ? ctx->callData->args[1].toInt32() : 0;
+ int id = ctx->d()->callData->argc > 1 ? ctx->d()->callData->args[1].toInt32() : 0;
QV4::Scope scope(ctx);
- QV4::ScopedValue v(scope, ctx->callData->argument(2));
+ QV4::ScopedValue v(scope, ctx->d()->callData->argument(2));
QByteArray data = QV4::Serialize::serialize(v, engine);
QMutexLocker locker(&engine->p->m_lock);
@@ -315,9 +315,9 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri
w->setReadOnly(false);
QV4::Scoped<QV4::Object> api(scope, v4->newObject());
- api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id)));
+ api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))).getPointer(), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id)));
- w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))), api);
+ w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))).getPointer(), api);
w->setReadOnly(true);
}
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index c1c8bfa81d..6349c6fa31 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -66,11 +66,11 @@ V8_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
static QV4::ReturnedValue get_index(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- return QV4::Encode(o->item->index);
+ return QV4::Encode(o->d()->item->index);
}
template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
@@ -198,14 +198,14 @@ public:
static QV4::ReturnedValue get_hasModelChildren(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->item)->type->model;
- if (o->item->index >= 0 && *model) {
+ const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model;
+ if (o->d()->item->index >= 0 && *model) {
const QAbstractItemModel * const aim = model->aim();
- return QV4::Encode(aim->hasChildren(aim->index(o->item->index, 0, model->rootIndex)));
+ return QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex)));
} else {
return QV4::Encode(false);
}
@@ -227,9 +227,11 @@ public:
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- p->setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
- p->setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
- proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
+ QV4::ScopedFunctionObject g(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property));
+ QV4::ScopedFunctionObject s(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property));
+ p->setGetter(g);
+ p->setSetter(s);
+ proto->insertMember(name.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
}
prototype = proto;
}
@@ -343,18 +345,18 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx)
QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, uint propertyId)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item);
- if (o->item->index == -1) {
+ QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
+ if (o->d()->item->index == -1) {
if (!modelData->cachedData.isEmpty()) {
- return ctx->engine->v8Engine->fromVariant(
+ return ctx->d()->engine->v8Engine->fromVariant(
modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId));
}
} else if (*modelData->type->model) {
- return ctx->engine->v8Engine->fromVariant(
+ return ctx->d()->engine->v8Engine->fromVariant(
modelData->value(modelData->type->propertyRoles.at(propertyId)));
}
return QV4::Encode::undefined();
@@ -363,22 +365,22 @@ QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, ui
QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::CallContext *ctx, uint propertyId)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return ctx->throwTypeError();
- if (o->item->index == -1) {
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item);
+ if (o->d()->item->index == -1) {
+ QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
if (!modelData->cachedData.isEmpty()) {
if (modelData->cachedData.count() > 1) {
- modelData->cachedData[propertyId] = ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid);
- QMetaObject::activate(o->item, o->item->metaObject(), propertyId, 0);
+ modelData->cachedData[propertyId] = scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid);
+ QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, 0);
} else if (modelData->cachedData.count() == 1) {
- modelData->cachedData[0] = ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid);
- QMetaObject::activate(o->item, o->item->metaObject(), 0, 0);
- QMetaObject::activate(o->item, o->item->metaObject(), 1, 0);
+ modelData->cachedData[0] = scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid);
+ QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, 0);
+ QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, 0);
}
}
}
@@ -431,7 +433,7 @@ public:
}
QV4::Scope scope(v4);
QV4::ScopedObject proto(scope, type->prototype.value());
- QV4::ScopedObject o(scope, new (proto->engine()->memoryManager) QQmlDelegateModelItemObject(proto->engine(), this));
+ QV4::ScopedObject o(scope, proto->engine()->memoryManager->alloc<QQmlDelegateModelItemObject>(proto->engine(), this));
o->setPrototype(proto.getPointer());
++scriptRef;
return o.asReturnedValue();
@@ -585,23 +587,23 @@ public:
static QV4::ReturnedValue get_modelData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- return ctx->engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->item)->cachedData);
+ return scope.engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
}
static QV4::ReturnedValue set_modelData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>());
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>());
if (!o)
return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return ctx->throwTypeError();
- static_cast<QQmlDMListAccessorData *>(o->item)->setModelData(ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid));
+ static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid));
return QV4::Encode::undefined();
}
@@ -609,7 +611,7 @@ public:
{
QQmlAdaptorModelEngineData *data = engineData(v4->v8Engine);
QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, new (v4->memoryManager) QQmlDelegateModelItemObject(v4, this));
+ QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, this));
QV4::ScopedObject p(scope, data->listItemProto.value());
o->setPrototype(p.getPointer());
++scriptRef;
diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qml/util/qqmlchangeset.cpp
index 831cb063a5..4e5e619d39 100644
--- a/src/qml/util/qqmlchangeset.cpp
+++ b/src/qml/util/qqmlchangeset.cpp
@@ -111,7 +111,7 @@ QQmlChangeSet &QQmlChangeSet::operator =(const QQmlChangeSet &changeSet)
void QQmlChangeSet::insert(int index, int count)
{
- insert(QVector<Insert>() << Insert(index, count));
+ insert(QVector<Change>() << Change(index, count));
}
/*!
@@ -120,8 +120,8 @@ void QQmlChangeSet::insert(int index, int count)
void QQmlChangeSet::remove(int index, int count)
{
- QVector<Remove> removes;
- removes.append(Remove(index, count));
+ QVector<Change> removes;
+ removes.append(Change(index, count));
remove(&removes, 0);
}
@@ -134,10 +134,10 @@ void QQmlChangeSet::remove(int index, int count)
void QQmlChangeSet::move(int from, int to, int count, int moveId)
{
- QVector<Remove> removes;
- removes.append(Remove(from, count, moveId));
- QVector<Insert> inserts;
- inserts.append(Insert(to, count, moveId));
+ QVector<Change> removes;
+ removes.append(Change(from, count, moveId));
+ QVector<Change> inserts;
+ inserts.append(Change(to, count, moveId));
remove(&removes, &inserts);
insert(inserts);
}
@@ -159,8 +159,8 @@ void QQmlChangeSet::change(int index, int count)
void QQmlChangeSet::apply(const QQmlChangeSet &changeSet)
{
- QVector<Remove> r = changeSet.m_removes;
- QVector<Insert> i = changeSet.m_inserts;
+ QVector<Change> r = changeSet.m_removes;
+ QVector<Change> i = changeSet.m_inserts;
QVector<Change> c = changeSet.m_changes;
remove(&r, &i);
insert(i);
@@ -174,19 +174,19 @@ void QQmlChangeSet::apply(const QQmlChangeSet &changeSet)
corresponding intersection in the optional \a inserts list.
*/
-void QQmlChangeSet::remove(const QVector<Remove> &removes, QVector<Insert> *inserts)
+void QQmlChangeSet::remove(const QVector<Change> &removes, QVector<Change> *inserts)
{
- QVector<Remove> r = removes;
+ QVector<Change> r = removes;
remove(&r, inserts);
}
-void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
+void QQmlChangeSet::remove(QVector<Change> *removes, QVector<Change> *inserts)
{
int removeCount = 0;
int insertCount = 0;
- QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
- QVector<Remove>::iterator rit = removes->begin();
+ QVector<Change>::iterator rit = removes->begin();
for (; rit != removes->end(); ++rit) {
int index = rit->index + removeCount;
int count = rit->count;
@@ -223,7 +223,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
// a new delta for that portion and subtract the size of that delta from the current
// one.
if (offset < 0 && rit->moveId != -1) {
- rit = removes->insert(rit, Remove(
+ rit = removes->insert(rit, Change(
rit->index, -offset, rit->moveId, rit->offset));
++rit;
rit->count -= -offset;
@@ -233,7 +233,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
removeCount += -offset;
offset = 0;
} else if (offset > 0 && insert->moveId != -1) {
- insert = m_inserts.insert(insert, Insert(
+ insert = m_inserts.insert(insert, Change(
insert->index - removeCount, offset, insert->moveId, insert->offset));
++insert;
insert->index += offset;
@@ -246,7 +246,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
// If the current remove has a move id, find any inserts with the same move id and
// replace the corresponding sections with the insert removed from the change set.
if (rit->moveId != -1 && difference > 0 && inserts) {
- for (QVector<Insert>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) {
+ for (QVector<Change>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) {
if (iit->moveId != rit->moveId
|| rit->offset > iit->offset + iit->count
|| iit->offset > rit->offset + difference) {
@@ -256,7 +256,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
// a new insert for the portion prior to the replacement insert.
const int overlapOffset = rit->offset - iit->offset;
if (overlapOffset > 0) {
- iit = inserts->insert(iit, Insert(
+ iit = inserts->insert(iit, Change(
iit->index, overlapOffset, iit->moveId, iit->offset));
++iit;
iit->index += overlapOffset;
@@ -275,7 +275,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
const int count
= qMin(iit->offset + iit->count, rit->offset + difference)
- qMax(iit->offset, rit->offset);
- iit = inserts->insert(iit, Insert(
+ iit = inserts->insert(iit, Change(
iit->index,
count,
insert->moveId,
@@ -316,12 +316,12 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
insert->index -= removeCount;
removeCount = 0;
- QVector<Remove>::iterator remove = m_removes.begin();
+ QVector<Change>::iterator remove = m_removes.begin();
for (rit = removes->begin(); rit != removes->end(); ++rit) {
if (rit->count == 0)
continue;
// Accumulate consecutive removes into a single delta before attempting to apply.
- for (QVector<Remove>::iterator next = rit + 1; next != removes->end()
+ for (QVector<Change>::iterator next = rit + 1; next != removes->end()
&& next->index == rit->index
&& next->moveId == -1
&& rit->moveId == -1; ++next) {
@@ -336,7 +336,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
while (remove != m_removes.end() && index + rit->count >= remove->index) {
int count = 0;
const int offset = remove->index - index;
- QVector<Remove>::iterator rend = remove;
+ QVector<Change>::iterator rend = remove;
for (; rend != m_removes.end()
&& rit->moveId == -1
&& rend->moveId == -1
@@ -366,7 +366,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
// Insert a remove for the portion of the unmergable current remove prior to the
// point of intersection.
if (offset > 0) {
- remove = m_removes.insert(remove, Remove(
+ remove = m_removes.insert(remove, Change(
rit->index, offset, rit->moveId, rit->offset));
++remove;
rit->count -= offset;
@@ -395,19 +395,19 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
Applies a list of \a inserts to a change set.
*/
-void QQmlChangeSet::insert(const QVector<Insert> &inserts)
+void QQmlChangeSet::insert(const QVector<Change> &inserts)
{
int insertCount = 0;
- QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Insert>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) {
+ for (QVector<Change>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) {
if (iit->count == 0)
continue;
int index = iit->index - insertCount;
- Insert current = *iit;
+ Change current = *iit;
// Accumulate consecutive inserts into a single delta before attempting to insert.
- for (QVector<Insert>::const_iterator next = iit + 1; next != inserts.end()
+ for (QVector<Change>::const_iterator next = iit + 1; next != inserts.end()
&& next->index == iit->index + iit->count
&& next->moveId == -1
&& iit->moveId == -1; ++next) {
@@ -459,7 +459,7 @@ void QQmlChangeSet::insert(const QVector<Insert> &inserts)
// If either insert has a moveId then split the existing insert and insert the
// current one in the middle.
if (offset > 0) {
- insert = m_inserts.insert(insert, Insert(
+ insert = m_inserts.insert(insert, Change(
insert->index + insertCount, offset, insert->moveId, insert->offset));
++insert;
insert->index += offset;
@@ -487,10 +487,10 @@ void QQmlChangeSet::insert(const QVector<Insert> &inserts)
calling \l remove() followed by \l insert() with the same lists.
*/
-void QQmlChangeSet::move(const QVector<Remove> &removes, const QVector<Insert> &inserts)
+void QQmlChangeSet::move(const QVector<Change> &removes, const QVector<Change> &inserts)
{
- QVector<Remove> r = removes;
- QVector<Insert> i = inserts;
+ QVector<Change> r = removes;
+ QVector<Change> i = inserts;
remove(&r, &i);
insert(i);
}
@@ -507,7 +507,7 @@ void QQmlChangeSet::change(const QVector<Change> &changes)
void QQmlChangeSet::change(QVector<Change> *changes)
{
- QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
for (QVector<Change>::iterator cit = changes->begin(); cit != changes->end(); ++cit) {
for (; insert != m_inserts.end() && insert->end() < cit->index; ++insert) {}
@@ -560,55 +560,13 @@ void QQmlChangeSet::change(QVector<Change> *changes)
QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
{
debug.nospace() << "QQmlChangeSet(";
- foreach (const QQmlChangeSet::Remove &remove, set.removes()) debug << remove;
- foreach (const QQmlChangeSet::Insert &insert, set.inserts()) debug << insert;
+ foreach (const QQmlChangeSet::Change &remove, set.removes()) debug << remove;
+ foreach (const QQmlChangeSet::Change &insert, set.inserts()) debug << insert;
foreach (const QQmlChangeSet::Change &change, set.changes()) debug << change;
return debug.nospace() << ')';
}
/*!
- Prints a \a remove to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet::Remove &remove)
-{
- if (remove.moveId == -1) {
- return (debug.nospace()
- << "Remove(" << remove.index
- << ',' << remove.count
- << ')').space();
- } else {
- return (debug.nospace()
- << "Remove(" << remove.index
- << ',' << remove.count
- << ',' << remove.moveId
- << ',' << remove.offset
- << ')').space();
- }
-}
-
-/*!
- Prints an \a insert to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet::Insert &insert)
-{
- if (insert.moveId == -1) {
- return (debug.nospace()
- << "Insert(" << insert.index
- << ',' << insert.count
- << ')').space();
- } else {
- return (debug.nospace()
- << "Insert(" << insert.index
- << ',' << insert.count
- << ',' << insert.moveId
- << ',' << insert.offset
- << ')').space();
- }
-}
-
-/*!
Prints a \a change to the \a debug stream.
*/
diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qml/util/qqmlchangeset_p.h
index acafbd4eec..e79bc4a832 100644
--- a/src/qml/util/qqmlchangeset_p.h
+++ b/src/qml/util/qqmlchangeset_p.h
@@ -90,29 +90,14 @@ public:
int end() const { return index + count; }
};
-
- struct Insert : public Change
- {
- Insert() {}
- Insert(int index, int count, int moveId = -1, int offset = 0)
- : Change(index, count, moveId, offset) {}
- };
-
- struct Remove : public Change
- {
- Remove() {}
- Remove(int index, int count, int moveId = -1, int offset = 0)
- : Change(index, count, moveId, offset) {}
- };
-
QQmlChangeSet();
QQmlChangeSet(const QQmlChangeSet &changeSet);
~QQmlChangeSet();
QQmlChangeSet &operator =(const QQmlChangeSet &changeSet);
- const QVector<Remove> &removes() const { return m_removes; }
- const QVector<Insert> &inserts() const { return m_inserts; }
+ const QVector<Change> &removes() const { return m_removes; }
+ const QVector<Change> &inserts() const { return m_inserts; }
const QVector<Change> &changes() const { return m_changes; }
void insert(int index, int count);
@@ -120,9 +105,9 @@ public:
void move(int from, int to, int count, int moveId);
void change(int index, int count);
- void insert(const QVector<Insert> &inserts);
- void remove(const QVector<Remove> &removes, QVector<Insert> *inserts = 0);
- void move(const QVector<Remove> &removes, const QVector<Insert> &inserts);
+ void insert(const QVector<Change> &inserts);
+ void remove(const QVector<Change> &removes, QVector<Change> *inserts = 0);
+ void move(const QVector<Change> &removes, const QVector<Change> &inserts);
void change(const QVector<Change> &changes);
void apply(const QQmlChangeSet &changeSet);
@@ -139,26 +124,22 @@ public:
int difference() const { return m_difference; }
private:
- void remove(QVector<Remove> *removes, QVector<Insert> *inserts);
+ void remove(QVector<Change> *removes, QVector<Change> *inserts);
void change(QVector<Change> *changes);
- QVector<Remove> m_removes;
- QVector<Insert> m_inserts;
+ QVector<Change> m_removes;
+ QVector<Change> m_inserts;
QVector<Change> m_changes;
int m_difference;
};
Q_DECLARE_TYPEINFO(QQmlChangeSet::Change, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlChangeSet::Remove, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlChangeSet::Insert, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QQmlChangeSet::MoveKey, Q_PRIMITIVE_TYPE);
inline uint qHash(const QQmlChangeSet::MoveKey &key) { return qHash(qMakePair(key.moveId, key.offset)); }
inline bool operator ==(const QQmlChangeSet::MoveKey &l, const QQmlChangeSet::MoveKey &r) {
return l.moveId == r.moveId && l.offset == r.offset; }
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Remove &remove);
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Insert &insert);
Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp
index 830a24e752..64528dafd2 100644
--- a/src/qml/util/qqmllistcompositor.cpp
+++ b/src/qml/util/qqmllistcompositor.cpp
@@ -951,7 +951,7 @@ void QQmlListCompositor::clear()
void QQmlListCompositor::listItemsInserted(
QVector<Insert> *translatedInsertions,
void *list,
- const QVector<QQmlChangeSet::Insert> &insertions,
+ const QVector<QQmlChangeSet::Change> &insertions,
const QVector<MovedFlags> *movedFlags)
{
QT_QML_TRACE_LISTCOMPOSITOR(<< list << insertions)
@@ -966,7 +966,7 @@ void QQmlListCompositor::listItemsInserted(
it.incrementIndexes(it->count);
continue;
}
- foreach (const QQmlChangeSet::Insert &insertion, insertions) {
+ foreach (const QQmlChangeSet::Change &insertion, insertions) {
int offset = insertion.index - it->index;
if ((offset > 0 && offset < it->count)
|| (offset == 0 && it->prepend())
@@ -1064,8 +1064,8 @@ void QQmlListCompositor::listItemsInserted(
QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
Q_ASSERT(count > 0);
- QVector<QQmlChangeSet::Insert> insertions;
- insertions.append(QQmlChangeSet::Insert(index, count));
+ QVector<QQmlChangeSet::Change> insertions;
+ insertions.append(QQmlChangeSet::Change(index, count));
listItemsInserted(translatedInsertions, list, insertions);
}
@@ -1073,8 +1073,8 @@ void QQmlListCompositor::listItemsInserted(
void QQmlListCompositor::listItemsRemoved(
QVector<Remove> *translatedRemovals,
void *list,
- QVector<QQmlChangeSet::Remove> *removals,
- QVector<QQmlChangeSet::Insert> *insertions,
+ QVector<QQmlChangeSet::Change> *removals,
+ QVector<QQmlChangeSet::Change> *insertions,
QVector<MovedFlags> *movedFlags)
{
QT_QML_TRACE_LISTCOMPOSITOR(<< list << *removals)
@@ -1086,7 +1086,7 @@ void QQmlListCompositor::listItemsRemoved(
continue;
}
bool removed = false;
- for (QVector<QQmlChangeSet::Remove>::iterator removal = removals->begin();
+ for (QVector<QQmlChangeSet::Change>::iterator removal = removals->begin();
!removed && removal != removals->end();
++removal) {
int relativeIndex = removal->index - it->index;
@@ -1104,7 +1104,7 @@ void QQmlListCompositor::listItemsRemoved(
}
if (removal->isMove()) {
// If the removal was part of a move find the corresponding insert.
- QVector<QQmlChangeSet::Insert>::iterator insertion = insertions->begin();
+ QVector<QQmlChangeSet::Change>::iterator insertion = insertions->begin();
for (; insertion != insertions->end() && insertion->moveId != removal->moveId;
++insertion) {}
Q_ASSERT(insertion != insertions->end());
@@ -1114,11 +1114,11 @@ void QQmlListCompositor::listItemsRemoved(
// If the remove started before the current range, split it and the
// corresponding insert so we're only working with intersecting part.
int splitMoveId = ++m_moveId;
- removal = removals->insert(removal, QQmlChangeSet::Remove(
+ removal = removals->insert(removal, QQmlChangeSet::Change(
removal->index, -relativeIndex, splitMoveId));
++removal;
removal->count -= -relativeIndex;
- insertion = insertions->insert(insertion, QQmlChangeSet::Insert(
+ insertion = insertions->insert(insertion, QQmlChangeSet::Change(
insertion->index, -relativeIndex, splitMoveId));
++insertion;
insertion->index += -relativeIndex;
@@ -1135,10 +1135,10 @@ void QQmlListCompositor::listItemsRemoved(
if (removeCount < removal->count) {
// If the remove doesn't encompass all of the current range,
// split it and the corresponding insert.
- removal = removals->insert(removal, QQmlChangeSet::Remove(
+ removal = removals->insert(removal, QQmlChangeSet::Change(
removal->index, removeCount, translatedRemoval.moveId));
++removal;
- insertion = insertions->insert(insertion, QQmlChangeSet::Insert(
+ insertion = insertions->insert(insertion, QQmlChangeSet::Change(
insertion->index, removeCount, translatedRemoval.moveId));
++insertion;
@@ -1253,8 +1253,8 @@ void QQmlListCompositor::listItemsRemoved(
QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
Q_ASSERT(count >= 0);
- QVector<QQmlChangeSet::Remove> removals;
- removals.append(QQmlChangeSet::Remove(index, count));
+ QVector<QQmlChangeSet::Change> removals;
+ removals.append(QQmlChangeSet::Change(index, count));
listItemsRemoved(translatedRemovals, list, &removals, 0, 0);
}
@@ -1280,11 +1280,11 @@ void QQmlListCompositor::listItemsMoved(
QT_QML_TRACE_LISTCOMPOSITOR(<< list << from << to << count)
Q_ASSERT(count >= 0);
- QVector<QQmlChangeSet::Remove> removals;
- QVector<QQmlChangeSet::Insert> insertions;
+ QVector<QQmlChangeSet::Change> removals;
+ QVector<QQmlChangeSet::Change> insertions;
QVector<MovedFlags> movedFlags;
- removals.append(QQmlChangeSet::Remove(from, count, 0));
- insertions.append(QQmlChangeSet::Insert(to, count, 0));
+ removals.append(QQmlChangeSet::Change(from, count, 0));
+ insertions.append(QQmlChangeSet::Change(to, count, 0));
listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags);
listItemsInserted(translatedInsertions, list, insertions, &movedFlags);
@@ -1342,16 +1342,16 @@ void QQmlListCompositor::listItemsChanged(
void QQmlListCompositor::transition(
Group from,
Group to,
- QVector<QQmlChangeSet::Remove> *removes,
- QVector<QQmlChangeSet::Insert> *inserts)
+ QVector<QQmlChangeSet::Change> *removes,
+ QVector<QQmlChangeSet::Change> *inserts)
{
int removeCount = 0;
for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
if (it == from && it != to) {
- removes->append(QQmlChangeSet::Remove(it.index[from]- removeCount, it->count));
+ removes->append(QQmlChangeSet::Change(it.index[from]- removeCount, it->count));
removeCount += it->count;
} else if (it != from && it == to) {
- inserts->append(QQmlChangeSet::Insert(it.index[to], it->count));
+ inserts->append(QQmlChangeSet::Change(it.index[to], it->count));
}
it.incrementIndexes(it->count);
}
diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qml/util/qqmllistcompositor_p.h
index 5d87051582..c26b62a38c 100644
--- a/src/qml/util/qqmllistcompositor_p.h
+++ b/src/qml/util/qqmllistcompositor_p.h
@@ -263,8 +263,8 @@ public:
void transition(
Group from,
Group to,
- QVector<QQmlChangeSet::Remove> *removes,
- QVector<QQmlChangeSet::Insert> *inserts);
+ QVector<QQmlChangeSet::Change> *removes,
+ QVector<QQmlChangeSet::Change> *inserts);
private:
Range m_ranges;
@@ -290,13 +290,13 @@ private:
void listItemsRemoved(
QVector<Remove> *translatedRemovals,
void *list,
- QVector<QQmlChangeSet::Remove> *removals,
- QVector<QQmlChangeSet::Insert> *insertions = 0,
+ QVector<QQmlChangeSet::Change> *removals,
+ QVector<QQmlChangeSet::Change> *insertions = 0,
QVector<MovedFlags> *movedFlags = 0);
void listItemsInserted(
QVector<Insert> *translatedInsertions,
void *list,
- const QVector<QQmlChangeSet::Insert> &insertions,
+ const QVector<QQmlChangeSet::Change> &insertions,
const QVector<MovedFlags> *movedFlags = 0);
void listItemsChanged(
QVector<Change> *translatedChanges,
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index 4b4c06b27e..04588f110c 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -8,7 +8,7 @@ QT_PRIVATE = testlib-private quick qml-private gui core-private
# inheriting CONFIG+=console transitively. Make it explicit.
MODULE_CONFIG = console
-!contains(QT_CONFIG, no-widgets) {
+qtHaveModule(widgets) {
QT += widgets
DEFINES += QT_QMLTEST_WITH_WIDGETS
}
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index 44256f3f8c..3329fd72e6 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -694,6 +694,12 @@ QObject *QuickTestResult::grabImage(QQuickItem *item)
}
return 0;
}
+
+QObject *QuickTestResult::findChild(QObject *parent, const QString &objectName)
+{
+ return parent ? parent->findChild<QObject*>(objectName) : 0;
+}
+
namespace QTest {
void qtest_qParseArgs(int argc, char *argv[], bool qml);
};
diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h
index 4639c1b776..45165ca295 100644
--- a/src/qmltest/quicktestresult_p.h
+++ b/src/qmltest/quicktestresult_p.h
@@ -147,6 +147,8 @@ public Q_SLOTS:
QObject *grabImage(QQuickItem *item);
+ QObject *findChild(QObject *parent, const QString &objectName);
+
public:
// Helper functions for the C++ main() shell.
static void parseArgs(int argc, char *argv[]);
diff --git a/src/quick/accessible/accessible.pri b/src/quick/accessible/accessible.pri
new file mode 100644
index 0000000000..88ff747488
--- /dev/null
+++ b/src/quick/accessible/accessible.pri
@@ -0,0 +1,16 @@
+
+QT += core-private gui-private qml-private
+
+#DEFINES+=Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION
+
+SOURCES += \
+ $$PWD/qqmlaccessible.cpp \
+ $$PWD/qaccessiblequickview.cpp \
+ $$PWD/qaccessiblequickitem.cpp \
+ $$PWD/qquickaccessiblefactory.cpp \
+
+HEADERS += \
+ $$PWD/qqmlaccessible_p.h \
+ $$PWD/qaccessiblequickview_p.h \
+ $$PWD/qaccessiblequickitem_p.h \
+ $$PWD/qquickaccessiblefactory_p.h \
diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index be7ada442a..72c19f8004 100644
--- a/src/plugins/accessible/quick/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#include "qaccessiblequickitem.h"
+#include "qaccessiblequickitem_p.h"
#include <QtGui/qtextdocument.h>
@@ -165,10 +165,6 @@ QAccessible::State QAccessibleQuickItem::state() const
st.focusable = true;
if (item()->hasActiveFocus())
st.focused = true;
-
- if (role() == QAccessible::ComboBox)
- st.editable = item()->property("editable").toBool();
-
return st;
}
diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.h b/src/quick/accessible/qaccessiblequickitem_p.h
index b486720c68..d1facf2199 100644
--- a/src/plugins/accessible/quick/qaccessiblequickitem.h
+++ b/src/quick/accessible/qaccessiblequickitem_p.h
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -44,7 +44,7 @@
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
-#include "qqmlaccessible.h"
+#include <QtQuick/private/qqmlaccessible_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/quick/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp
index 1240b2ef4c..05e37d6240 100644
--- a/src/plugins/accessible/quick/qaccessiblequickview.cpp
+++ b/src/quick/accessible/qaccessiblequickview.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,15 +39,15 @@
**
****************************************************************************/
-#include "qaccessiblequickview.h"
+#include "qaccessiblequickview_p.h"
#include <QtGui/qguiapplication.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquickitem_p.h>
-#include "qaccessiblequickitem.h"
-#include "qqmlaccessible.h"
+#include "qaccessiblequickitem_p.h"
+#include "qqmlaccessible_p.h"
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/plugins/accessible/quick/qaccessiblequickview.h b/src/quick/accessible/qaccessiblequickview_p.h
index 41c34c5432..f14d4c9584 100644
--- a/src/plugins/accessible/quick/qaccessiblequickview.h
+++ b/src/quick/accessible/qaccessiblequickview_p.h
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
diff --git a/src/plugins/accessible/shared/qqmlaccessible.cpp b/src/quick/accessible/qqmlaccessible.cpp
index ecf4e56acf..abe94537a9 100644
--- a/src/plugins/accessible/shared/qqmlaccessible.cpp
+++ b/src/quick/accessible/qqmlaccessible.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include <qnamespace.h>
-#include "qqmlaccessible.h"
+#include "qqmlaccessible_p.h"
#ifndef QT_NO_ACCESSIBILITY
@@ -148,8 +148,8 @@ void QQmlAccessible::doAction(const QString &actionName)
{
// Look for and call the accessible[actionName]Action() function on the item.
// This allows for overriding the default action handling.
- const QByteArray functionName = "accessible" + actionName.toLatin1() + "Action";
- if (object()->metaObject()->indexOfMethod(functionName + "()") != -1) {
+ const QByteArray functionName = QByteArrayLiteral("accessible") + actionName.toLatin1() + QByteArrayLiteral("Action");
+ if (object()->metaObject()->indexOfMethod(QByteArray(functionName + QByteArrayLiteral("()"))) != -1) {
QMetaObject::invokeMethod(object(), functionName);
return;
}
diff --git a/src/plugins/accessible/shared/qqmlaccessible.h b/src/quick/accessible/qqmlaccessible_p.h
index b6da016b2d..b6da016b2d 100644
--- a/src/plugins/accessible/shared/qqmlaccessible.h
+++ b/src/quick/accessible/qqmlaccessible_p.h
diff --git a/src/plugins/accessible/quick/main.cpp b/src/quick/accessible/qquickaccessiblefactory.cpp
index 6c7be155ce..d0e7f0f5e8 100644
--- a/src/plugins/accessible/quick/main.cpp
+++ b/src/quick/accessible/qquickaccessiblefactory.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,50 +39,16 @@
**
****************************************************************************/
+#include "qquickaccessiblefactory_p.h"
-#include "qqmlaccessible.h"
-#include "qaccessiblequickview.h"
-#include "qaccessiblequickitem.h"
-
-#include <QtQuick/QQuickWindow>
-#include <QtQuick/QQuickItem>
+#include "qaccessiblequickview_p.h"
+#include "qaccessiblequickitem_p.h"
#include <QtQuick/private/qquickitem_p.h>
-#include <QtQuick/private/qquickaccessibleattached_p.h>
-
-#include <qaccessibleplugin.h>
-#include <qvariant.h>
-#include <qplugin.h>
-#include <qaccessible.h>
-
-#ifndef QT_NO_ACCESSIBILITY
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_ACCESSIBILITY
-class AccessibleQuickFactory : public QAccessiblePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QAccessibleFactoryInterface" FILE "accessible.json")
-
-public:
- AccessibleQuickFactory();
-
- QStringList keys() const;
- QAccessibleInterface *create(const QString &classname, QObject *object);
-};
-
-AccessibleQuickFactory::AccessibleQuickFactory()
-{
-}
-
-QStringList AccessibleQuickFactory::keys() const
-{
- QStringList list;
- list << QLatin1String("QQuickWindow");
- list << QLatin1String("QQuickItem");
- return list;
-}
-
-QAccessibleInterface *AccessibleQuickFactory::create(const QString &classname, QObject *object)
+QAccessibleInterface *qQuickAccessibleFactory(const QString &classname, QObject *object)
{
if (classname == QLatin1String("QQuickWindow")) {
return new QAccessibleQuickWindow(qobject_cast<QQuickWindow *>(object));
@@ -98,8 +64,5 @@ QAccessibleInterface *AccessibleQuickFactory::create(const QString &classname, Q
return 0;
}
+#endif
QT_END_NAMESPACE
-
-#include "main.moc"
-
-#endif // QT_NO_ACCESSIBILITY
diff --git a/src/quick/accessible/qquickaccessiblefactory_p.h b/src/quick/accessible/qquickaccessiblefactory_p.h
new file mode 100644
index 0000000000..792364b7fa
--- /dev/null
+++ b/src/quick/accessible/qquickaccessiblefactory_p.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKACCESSIBLEFACTORY_H
+#define QQUICKACCESSIBLEFACTORY_H
+
+#include <QtGui/qaccessible.h>
+
+QT_BEGIN_NAMESPACE
+#ifndef QT_NO_ACCESSIBILITY
+
+QAccessibleInterface *qQuickAccessibleFactory(const QString &classname, QObject *object);
+
+#endif
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 959a54b7d8..1f800d2a31 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -21,7 +21,7 @@ qhp.QtQuick.customFilters.Qt.filterAttributes = qtquick $QT_VERSION
qhp.QtQuick.subprojects = qmltypes classes examples
qhp.QtQuick.subprojects.qmltypes.title = QML Types
qhp.QtQuick.subprojects.qmltypes.indexTitle = Qt Quick QML Types
-qhp.QtQuick.subprojects.qmltypes.selectors = fake:qmlclass
+qhp.QtQuick.subprojects.qmltypes.selectors = qmlclass
qhp.QtQuick.subprojects.qmltypes.sortPages = true
qhp.QtQuick.subprojects.classes.title = Classes
qhp.QtQuick.subprojects.classes.title = C++ Classes
diff --git a/src/quick/doc/snippets/qml/itemGrab.qml b/src/quick/doc/snippets/qml/itemGrab.qml
new file mode 100644
index 0000000000..4ceaea6133
--- /dev/null
+++ b/src/quick/doc/snippets/qml/itemGrab.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.4
+
+Item {
+ width: 320
+ height: 480
+
+//! [grab-source]
+Rectangle {
+ id: source
+ width: 100
+ height: 100
+ gradient: Gradient {
+ GradientStop { position: 0; color: "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+}
+//! [grab-source]
+
+//! [grab-image-target]
+Image {
+ id: image
+}
+//! [grab-image-target]
+ Timer {
+ repeat: false
+ running: true
+ interval: 1000
+ onTriggered: {
+//! [grab-to-file]
+
+ // ...
+ source.grabToImage(function(result) {
+ result.save("something.png");
+ });
+//! [grab-to-file]
+
+//! [grab-to-cache]
+
+ // ...
+ source.grabToImage(function(result) {
+ image.source = result.url;
+ },
+ Qt.size(50, 50));
+//! [grab-to-cache]
+ }
+ }
+}
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 7a54b7a021..f07d981e5f 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -244,11 +244,11 @@ animations, process events, etc.
\endlist
-The threaded renderer is currently used by default on Linux, Mac OS X
-and EGLFS based QPA platforms, but this is subject to change. It is
-possible to force use of the threaded renderer by setting \c
-{QML_FORCE_THREADED_RENDERER=1} in the environment.
-
+The threaded renderer is currently used by default on Linux with
+non-Mesa based drivers, OS X and EGLFS based QPA platforms, but this
+is subject to change. It is possible to force use of the threaded
+renderer by setting \c {QSG_RENDER_LOOP=threaded} in the
+environment.
\section2 Non-threaded Render Loop
@@ -267,6 +267,16 @@ sequence in the non-threaded renderer.
\image sg-renderloop-singlethreaded.jpg
+\section2 Custom control over rendering with QQuickRenderControl
+
+When using QQuickRenderControl, the responsibility for driving the
+rendering loop is transferred to the application. In this case no
+built-in render loop is used. Instead, it is up to the application to
+invoke the polish, synchronize and rendering steps at the appropriate
+time. It is possible to implement either a threaded or non-threaded
+behavior similar to the ones shown above.
+
+
\section2 Mixing Scene Graph and OpenGL
The scene graph offers two methods for integrating OpenGL content:
@@ -315,7 +325,29 @@ framebuffer object (FBO), so the rendering is a two-step
operation. First rasterize the surface, then draw the surface. Using
scene graph API directly is always significantly faster.
+\section1 Logging Support
+
+The scene graph has support for a number of logging categories. These
+can be useful in tracking down both performance issues and bugs in
+addition to being helpful to Qt contributors.
+
+\list
+
+\li \c {qt.scenegraph.time.texture} - logs the time spent doing texture uploads
+\li \c {qt.scenegraph.time.compilation} - logs the time spent doing shader compilation
+
+\li \c {qt.scenegraph.time.renderer} - logs the time spent in the various steps of the renderer
+
+\li \c {qt.scenegraph.time.renderloop} - logs the time spent in the various steps of the render loop
+
+\li \c {qt.scenegraph.time.glyph} - logs the time spent preparing distance field glyphs
+
+\li \c {qt.scenegraph.info} - logs general information about various parts of the scene graph and the graphics stack
+
+\li \c {qt.scenegraph.renderloop} - creates a detailed log of the various stages involved in rendering. This log mode is primarily useful for developers working on Qt.
+
+\endlist
\section1 Scene Graph Backend
diff --git a/src/quick/doc/src/concepts/visualtypes/topic.qdoc b/src/quick/doc/src/concepts/visualtypes/topic.qdoc
index af8e673640..d30c7767c0 100644
--- a/src/quick/doc/src/concepts/visualtypes/topic.qdoc
+++ b/src/quick/doc/src/concepts/visualtypes/topic.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -36,9 +36,7 @@ for example, haptic feedback and sounds to notify the user of changes in the
state of an application), visual objects in a user-interface are able to convey
a huge amount of information to the user at a glance.
-See the \l{qtquick-qmltypereference.html}{Qt Quick QML type reference} for the
-complete list of visual object types provided by Qt Quick.
+See the \l{Qt Quick QML Types} page for the complete list of visual object types
+provided by Qt Quick.
*/
-
-
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index f048186d58..4d3341aac4 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -26,21 +26,13 @@
****************************************************************************/
/*!
-\page qtquick-qmltypereference.html
+\qmlmodule QtQuick 2.3
\title Qt Quick QML Types
\ingroup qmlmodules
-\brief Description of the QML types provided by the Qt Quick module
-
-The \c QtQuick QML module provides a variety of QML types for creating user
-interfaces and applications with QML. This page lists every QML type provided
-by this module, organized according to category and purpose.
-
-
-\target importing-qtquick
-\section1 Importing Qt Quick
+\brief Provides graphical QML types.
-The types provided by the \l {Qt Quick} module are only available in a QML document
-if that document imports the \c QtQuick namespace.
+The \l{Qt Quick} module provides graphical primitive types. These types are only
+available in a QML document if that document imports the \c QtQuick namespace.
The current version of the \c QtQuick module is version 2.3, and thus it may be
imported via the following statement:
@@ -49,10 +41,10 @@ imported via the following statement:
import QtQuick 2.3
\endqml
-See the \l {Qt Quick} module documentation for more
+Visit the \l {Qt Quick} module documentation for more
information about the concepts which are central to \c QtQuick.
-\section2 Submodules
+\section1 Submodules
Qt Quick includes several submodules which contain additional types.
@@ -71,7 +63,9 @@ information about the concepts which are central to \c QtQuick.
UI components
\li \l{Qt Quick Layouts QML Types}{Layouts} - contains types that are used
to arrange items in the user interface
+ \li \l{Qt Quick Test QML Types}{Tests} - types for testing QML applications.
\endlist
+
\target basic-types
\section1 Basic Types
@@ -79,258 +73,17 @@ There are a number of basic types that are
\l{qtqml-typesystem-basictypes.html#basic-types-provided-by-the-qml-language}
{supported by default in the QML language}.
-In addition, the \c QtQuick module provides the following basic types:
+In addition, the \c QtQuick import provides the following basic types:
\annotatedlist qtquickbasictypes
-\target object-types
-\section1 Object Types
-All of the object types provided by \c QtQuick are based on the \l{Item} type,
-which itself derives from \l{QtQml::QtObject}{QtObject}. \l{Qt QML QML Types#Object Types}
-{QML object types} provided by the Qt QML module
-(such as \l{QtQml::QtObject}{QtObject} and \l{QtQml::Component}{Component}) are also available when
-you import \c QtQuick.
-\target visual-types
-\section2 Visual Types
-
-\list
-\li \l {Item} - Basic visual object type inherited by visual object types (visual items)
-\li \l {Rectangle} - A rectangle type
-\li \l {Image} - For incorporating bitmaps into a scene
-\li \l {BorderImage} - Allows the use of images as borders
-\li \l {AnimatedImage} - For playing animations stored as an animated GIF
-\li \l {AnimatedSprite} - For playing animations stored as a series of frames
-\li \l {SpriteSequence} - For playing and transitioning between multiple animations stored as a series of frames
-\li \l {Text} - For inserting formatted text into a scene
-\li \l {Window} - Provides a top-level window
-\endlist
-
-Visual Item Utility
-\list
-\li \l {Accessible} - Attached property to make components accessible
-\li \l {Gradient} - For defining a color gradient
-\li \l {GradientStop} - Used to define a color within a \l {Gradient}
-\li \l {SystemPalette} - Provides access to the Qt palettes
-\li \l {Screen} - Provides information about the screen on which an \l {Item} is displayed
-\li \l {Sprite} - Specifies sprite animations for other Items to display
-\li \l {FontLoader} - Loads fonts by name or URL
-\endlist
-
-Visual Item Generation
-
-\list
-\li \l {Repeater} - Uses a model to create multiple Item instances
-\li \l {Loader} - Eases on-demand loading of Items
-\endlist
-
-Visual Item Transformations
-\list
-\li \l {Transform} - Allows specification of advanced transformations on Items
-\li \l {Scale} - Assigns item scaling behaviors
-\li \l {Rotation} - Assigns item rotation behaviors
-\li \l {Translate} - Assigns item translation behaviors
-\endlist
-
-\target user-input
-\section2 User Input
-
-\list
-\li \l {MouseArea} - Sets up an area for mouse interaction
-\li \l {Keys} - Provides components with attached properties to handle key input.
-\li \l {KeyNavigation} - Supports key navigation by arrow keys
-\li \l {FocusScope} - Mediates keyboard focus changes
-\li \l {Flickable} - Provides a surface that can be "flicked"
-\li \l {PinchArea} - Enables simple pinch gesture handling
-\li \l {MultiPointTouchArea} - Enables handling of multiple touch points
-\li \l {Drag} - For specifying drag and drop events for visual items
-\li \l {DropArea} - For specifying drag and drop event handling in an area
-\li \l {TextInput} - Captures user key input
-\li \l {TextEdit} - Displays multiple lines of editable formatted text
-\endlist
-
-Text Input Utility
-
-\list
-\li \l {IntValidator} - Validates values as integers
-\li \l {DoubleValidator} - Validates real values
-\li \l {RegExpValidator} - Validator for string regular expressions
-\endlist
-
-User Input Events
-\list
-\li \l {TouchPoint} - Describes a touch point in a MultiPointTouchArea
-\li \l {PinchEvent} - Specifies information about a pinch event
-\li \l {WheelEvent} - Provides information about a mouse wheel event
-\li \l {MouseEvent} - Provides information about a mouse click event
-\li \l {KeyEvent} - Provides information about a key press event
-\li \l {DragEvent} -Provides information about a drag event
-\endlist
-\target positioning
-\section2 Positioning
-
-\list
-\li \l {Positioner} - Attached property which provides information about where an Item has been positioned
-\li \l {Column} - Arranges its children vertically
-\li \l {Row} - Arranges its children horizontally
-\li \l {Grid} - Positions its children in a grid
-\li \l {Flow} - Positions its children with wrapping support
-\li \l {LayoutMirroring} - Attached property used to mirror layout behavior
-\endlist
-\target states-transitions-and-animations
-\section2 States, Transitions and Animations
-
-States
-\list
-\li \l {State} - Defines sets of configurations of objects and properties
-\li \l {PropertyChanges} - Describes property changes within a state
-\li \l {StateGroup} - Contains a set of states and state transitions
-\li \l {StateChangeScript} - Allows script binding in a state
-\li \l {ParentChange} - Re-parent an Item in a state change
-\li \l {AnchorChanges} - Change the anchors of an item in a state
-\endlist
-
-Transitions and Animations
-\list
-\li \l {Transition} - Animates transitions during state changes
-\li \l {ViewTransition} - Specifies items under transition in a view
-\li \l {SequentialAnimation} - Runs animations sequentially
-\li \l {ParallelAnimation} - Runs animations in parallel
-\li \l {Behavior} - Specifies a default animation for property changes
-\li \l {PropertyAction} - Sets immediate property changes during animation
-\li \l {PauseAnimation} - Introduces a pause in an animation
-\li \l {SmoothedAnimation} - Allows a property to smoothly track a value
-\li \l {SpringAnimation} - Allows a property to track a value in a spring-like motion
-\li \l {ScriptAction} - Runs scripts during an animation
-\endlist
-
-Type-specific Animations
-\list
-\li \l {PropertyAnimation} - Animates property changes
-\li \l {NumberAnimation} - Animates properties of type qreal
-\li \l {Vector3dAnimation} - Animates properties of type QVector3d
-\li \l {ColorAnimation} - Animates color changes
-\li \l {RotationAnimation} - Animates rotations
-\li \l {ParentAnimation} - Animates parent changes
-\li \l {AnchorAnimation} - Animates anchor changes
-\li \l {PathAnimation} - Animates position along a path
-\li \l {XAnimator} - Animates x position asynchronously
-\li \l {YAnimator} - Animates y position asynchronously
-\li \l {ScaleAnimator} - Animates scale asynchronously
-\li \l {RotationAnimator} - Animates rotation asynchronously
-\li \l {OpacityAnimator} - Animates opacity asynchronously
-\li \l {UniformAnimator} - Animates a \l ShaderEffect uniform asynchronously
-\endlist
-
-Lower-level Animation Types
-\list
-\li \l {PathInterpolator} - Allows manual animation along a path
-\li \l {AnimationController} - Allows manual control of animation progress
-\endlist
-
-Animation paths
-\list
-\li \l {Path} - Defines a path used by \l {PathView}
-\li \l {PathLine} - Defines a line in \l {Path}
-\li \l {PathQuad} - Defines a quadratic Bezier curve in a \l {Path}
-\li \l {PathCubic} - Defines a cubic Bezier curve in a \l {Path}
-\li \l {PathArc} - Defines an arc in a \l {Path}
-\li \l {PathCurve} - Defines a point on a Catmull-Rom curve in a \l {Path}
-\li \l {PathSvg} - Defines a sub-path specified as a SVG path data string in a \l {Path}
-\li \l {PathAttribute} - Allows the setting of attributes along a \l {Path}
-\li \l {PathPercent} - Modifies the item distribution along a \l {Path}
-\endlist
-\target model-view-types-and-data-storage-and-access
-\section2 Model/View Types And Data Storage And Access
-
-QML Lists and Models
-
-The \l{Qt QML Models QML Types}{Qt QML Models} submodule provides the types for
-structuring data with models and lists.
-\list
-\li \l{ListModel} - Defines a list of data
-\li \l{ListElement} - Defines a data item in a \l{ListModel}
-\endlist
-
-These QML types are part of Qt Quick for backwards compatibility, but for
-newer applications, \l{Qt QML Models QML Types}{Qt QML Models} provides
-the same functionality.
-\list
-\li \l {VisualItemModel} - Contains items that already defines its own visual delegate
-\li \l {VisualDataModel} - Encapsulates a model and a delegate
-\li \l {VisualDataGroup} - Encapsulates a filtered set of visual data items
-\endlist
-
-XML Lists
-\list
-\li \l {XmlListModel} - Specifies a model using XPath expressions
-\li \l {XmlRole} - Specifies a role for an \l {XmlListModel}
-\endlist
-
-Views
-\list
-\li \l {ListView} - Provides a list visualization of a model
-\li \l {GridView} - Provides a grid visualization of a model
-\li \l {PathView} - Visualizes a model's contents along a path. See \l Path for more information.
-\li \l {Package} - Collection that enables sharing of items within different views
-\endlist
-
-Data Storage
-\list
-\li \l {Qt Quick Local Storage QML Types}{QtQuick.LocalStorage 2} - Singleton
-type providing simplified SQL access
-\endlist
-\target graphical-effects
-\section2 Graphical Effects
-
-\list
-\li \l {Flipable} - Provides a surface that produces "flipping" effects
-\li \l {ShaderEffect} - Allows GLSL shaders to be used as graphical effects
-\li \l {ShaderEffectSource} - Usable as a texture in ShaderEffect
-\li \l {GridMesh} - Generates a grid mesh of vertices for use by ShaderEffect
-\li The \l{Qt Quick Particles QML Types}{QtQuick.Particles 2} module provides a
-set of Particle System types for Qt Quick 2
-\endlist
-\target convenience-types
-\section2 Convenience Types
-
-\list
-\li \l {Connections} - Explicitly connects signals and signal handlers
-\li \l {Binding} - Binds any value to any property
-\li \l {Timer} - Provides timed triggers
-\li \l {WorkerScript} - Enables the use of threads in a Qt Quick application
-\endlist
-\target canvas-similar-to-html5-canvas
-\section2 Canvas (similar to HTML5 canvas)
-
-\list
-\li \l {Canvas} - Provides a 2D canvas type similar to the HTML5 canvas
-\li \l {Context2D} - Provides 2D context for shapes on a Canvas item
-\li \l {CanvasGradient} - Allows specification of a gradient on a Canvas
-\li \l {CanvasPixelArray} - Allows specification of a pixel array for use in a Canvas
-\li \l {CanvasImageData} - Allows specification of image data for use in a Canvas
-\li \l {TextMetrics} - Provides text and font measurement data for use in a Canvas
-\endlist
-
-\target qttest-types
-\section2 QtTest Types
-
-\list
-\li \l {QtTest::TestCase}{TestCase} - Represents a unit test case
-\li \l {QtTest::SignalSpy}{SignalSpy} - Enables introspection of signal emission
-\endlist
-
-*/
-
-/*!
-\qmlmodule QtQuick 2.3
-\brief The Provides graphical primitives for use in QML.
+\section1 Object Types
-The \l{Qt Quick} module provides graphical primitive types. They can be used with the following import
-\code
-import QtQuick 2.3
-\endcode
+All object types provided by the \c QtQuick import are based on the \l{Item}
+type, which itself derives from \l{QtQml::QtObject}{QtObject}. \l{Qt QML QML
+Types#Object Types} {QML object types} provided by the Qt QML module (such as
+\l{QtQml::QtObject}{QtObject} and \l{QtQml::Component}{Component}) are also
+available when you import \c QtQuick.
-For a more detailed listing of types in the \c {QtQuick} import, see the \l{Qt Quick QML Types} page.
-For more details about the module itself, see the \l{Qt Quick} module page.
*/
/*!
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index 5f7ff48bb2..95c59b5c1a 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -76,34 +76,15 @@ Essentials from the \l{QML Applications} page.
To find out more about using the QML language, see the \l{Qt QML} module documentation.
-
-\section1 Qt Quick Module Documentation
+\section1 C++ Extension Points
\list
- \li \l{Qt Quick QML Types}
- \list
- \li \l{importing-qtquick}{Importing QtQuick}
- \li \l{basic-types}{Basic Types}
- \li \l{object-types}{Object Types}
- \list
- \li \l{visual-types}{Visual Types}
- \li \l{user-input}{User Input}
- \li \l{positioning}{Positioning}
- \li \l{states-transitions-and-animations}{States, Transitions And Animations}
- \li \l{model-view-types-and-data-storage-and-access}{Model/View Types And Data Storage And Access}
- \li \l{graphical-effects}{Graphical Effects}
- \li \l{convenience-types}{Convenience Types}
- \li \l{canvas-similar-to-html5-canvas}{Canvas (similar to HTML5 Canvas)}
- \endlist
- \endlist
-
\li \l{C++ Extension Points Provided By Qt Quick}{C++ Extension Points}
\list
\li \l{user-defined-qquickitem-derived-types}{Creating User-Defined QQuickItem-Derived Types}
\li \l{scene-graph-related-classes}{Scene Graph-Related Classes}
\li \l{pixmap-and-threaded-image-support}{Pixmap and Threaded Image Support}
\endlist
-
\endlist
\section1 Reference Documentation
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 7d3be0865b..d184003b82 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -284,6 +284,7 @@ QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
: QQuickItem(*(new QQuickCanvasItemPrivate), parent)
{
setFlag(ItemHasContents);
+ connect(this, SIGNAL(sceneGraphInvalidated()), this, SLOT(invalidateSG()));
}
QQuickCanvasItem::~QQuickCanvasItem()
@@ -606,6 +607,13 @@ void QQuickCanvasItem::releaseResources()
}
}
+void QQuickCanvasItem::invalidateSG()
+{
+ Q_D(QQuickCanvasItem);
+ d->context->deleteLater();
+ d->context = 0;
+}
+
void QQuickCanvasItem::componentComplete()
{
QQuickItem::componentComplete();
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 3baf68d418..2e17b0463c 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -164,6 +164,7 @@ public Q_SLOTS:
private Q_SLOTS:
void sceneGraphInitialized();
void checkAnimationCallbacks();
+ void invalidateSG();
protected:
void componentComplete();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 7964f650d6..57c7bd4a00 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -122,10 +122,10 @@ static const double Q_PI = 3.14159265358979323846; // pi
#define DEGREES(t) ((t) * 180.0 / Q_PI)
-#define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->bufferValid()) \
+#define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
V4THROW_ERROR("Not a Context2D object");
-#define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->bufferValid()) \
+#define CHECK_CONTEXT_SETTER(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
V4THROW_ERROR("Not a Context2D object");
#define qClamp(val, min, max) qMin(qMax(val, min), max)
#define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
@@ -479,16 +479,17 @@ public:
V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
-class QQuickJSContext2D : public QV4::Object
+struct QQuickJSContext2D : public QV4::Object
{
- V4_OBJECT
-public:
- QQuickJSContext2D(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
- {
- setVTable(staticVTable());
- }
- QQuickContext2D* context;
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+ }
+ QQuickContext2D* context;
+ };
+ V4_OBJECT(QV4::Object)
static QV4::ReturnedValue method_get_globalAlpha(QV4::CallContext *ctx);
static QV4::ReturnedValue method_set_globalAlpha(QV4::CallContext *ctx);
@@ -529,12 +530,6 @@ public:
static QV4::ReturnedValue method_set_textAlign(QV4::CallContext *ctx);
static QV4::ReturnedValue method_get_textBaseline(QV4::CallContext *ctx);
static QV4::ReturnedValue method_set_textBaseline(QV4::CallContext *ctx);
-
-protected:
- static void destroy(Managed *that)
- {
- static_cast<QQuickJSContext2D *>(that)->~QQuickJSContext2D();
- }
};
DEFINE_OBJECT_VTABLE(QQuickJSContext2D);
@@ -542,58 +537,59 @@ DEFINE_OBJECT_VTABLE(QQuickJSContext2D);
struct QQuickJSContext2DPrototype : public QV4::Object
{
- V4_OBJECT
+ V4_OBJECT(QV4::Object)
public:
- QQuickJSContext2DPrototype(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
+ static QQuickJSContext2DPrototype *create(QV4::ExecutionEngine *engine)
{
QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
-
- defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
- defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
- defineDefaultProperty(QStringLiteral("moveTo"), method_moveTo, 0);
- defineDefaultProperty(QStringLiteral("lineTo"), method_lineTo, 0);
- defineDefaultProperty(QStringLiteral("caretBlinkRate"), method_caretBlinkRate, 0);
- defineDefaultProperty(QStringLiteral("clip"), method_clip, 0);
- defineDefaultProperty(QStringLiteral("setTransform"), method_setTransform, 0);
- defineDefaultProperty(QStringLiteral("text"), method_text, 0);
- defineDefaultProperty(QStringLiteral("roundedRect"), method_roundedRect, 0);
- defineDefaultProperty(QStringLiteral("createPattern"), method_createPattern, 0);
- defineDefaultProperty(QStringLiteral("stroke"), method_stroke, 0);
- defineDefaultProperty(QStringLiteral("arc"), method_arc, 0);
- defineDefaultProperty(QStringLiteral("createImageData"), method_createImageData, 0);
- defineDefaultProperty(QStringLiteral("measureText"), method_measureText, 0);
- defineDefaultProperty(QStringLiteral("ellipse"), method_ellipse, 0);
- defineDefaultProperty(QStringLiteral("fill"), method_fill, 0);
- defineDefaultProperty(QStringLiteral("save"), method_save, 0);
- defineDefaultProperty(QStringLiteral("scale"), method_scale, 0);
- defineDefaultProperty(QStringLiteral("drawImage"), method_drawImage, 0);
- defineDefaultProperty(QStringLiteral("transform"), method_transform, 0);
- defineDefaultProperty(QStringLiteral("fillText"), method_fillText, 0);
- defineDefaultProperty(QStringLiteral("strokeText"), method_strokeText, 0);
- defineDefaultProperty(QStringLiteral("translate"), method_translate, 0);
- defineDefaultProperty(QStringLiteral("createRadialGradient"), method_createRadialGradient, 0);
- defineDefaultProperty(QStringLiteral("shear"), method_shear, 0);
- defineDefaultProperty(QStringLiteral("isPointInPath"), method_isPointInPath, 0);
- defineDefaultProperty(QStringLiteral("bezierCurveTo"), method_bezierCurveTo, 0);
- defineDefaultProperty(QStringLiteral("resetTransform"), method_resetTransform, 0);
- defineDefaultProperty(QStringLiteral("arcTo"), method_arcTo, 0);
- defineDefaultProperty(QStringLiteral("fillRect"), method_fillRect, 0);
- defineDefaultProperty(QStringLiteral("createConicalGradient"), method_createConicalGradient, 0);
- defineDefaultProperty(QStringLiteral("drawFocusRing"), method_drawFocusRing, 0);
- defineDefaultProperty(QStringLiteral("beginPath"), method_beginPath, 0);
- defineDefaultProperty(QStringLiteral("clearRect"), method_clearRect, 0);
- defineDefaultProperty(QStringLiteral("rect"), method_rect, 0);
- defineDefaultProperty(QStringLiteral("reset"), method_reset, 0);
- defineDefaultProperty(QStringLiteral("rotate"), method_rotate, 0);
- defineDefaultProperty(QStringLiteral("setCaretSelectionRect"), method_setCaretSelectionRect, 0);
- defineDefaultProperty(QStringLiteral("putImageData"), method_putImageData, 0);
- defineDefaultProperty(QStringLiteral("getImageData"), method_getImageData, 0);
- defineDefaultProperty(QStringLiteral("createLinearGradient"), method_createLinearGradient, 0);
- defineDefaultProperty(QStringLiteral("strokeRect"), method_strokeRect, 0);
- defineDefaultProperty(QStringLiteral("closePath"), method_closePath, 0);
- defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, 0);
+ QV4::ScopedObject o(scope, engine->memoryManager->alloc<QQuickJSContext2DPrototype>(engine));
+
+ o->defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
+ o->defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
+ o->defineDefaultProperty(QStringLiteral("moveTo"), method_moveTo, 0);
+ o->defineDefaultProperty(QStringLiteral("lineTo"), method_lineTo, 0);
+ o->defineDefaultProperty(QStringLiteral("caretBlinkRate"), method_caretBlinkRate, 0);
+ o->defineDefaultProperty(QStringLiteral("clip"), method_clip, 0);
+ o->defineDefaultProperty(QStringLiteral("setTransform"), method_setTransform, 0);
+ o->defineDefaultProperty(QStringLiteral("text"), method_text, 0);
+ o->defineDefaultProperty(QStringLiteral("roundedRect"), method_roundedRect, 0);
+ o->defineDefaultProperty(QStringLiteral("createPattern"), method_createPattern, 0);
+ o->defineDefaultProperty(QStringLiteral("stroke"), method_stroke, 0);
+ o->defineDefaultProperty(QStringLiteral("arc"), method_arc, 0);
+ o->defineDefaultProperty(QStringLiteral("createImageData"), method_createImageData, 0);
+ o->defineDefaultProperty(QStringLiteral("measureText"), method_measureText, 0);
+ o->defineDefaultProperty(QStringLiteral("ellipse"), method_ellipse, 0);
+ o->defineDefaultProperty(QStringLiteral("fill"), method_fill, 0);
+ o->defineDefaultProperty(QStringLiteral("save"), method_save, 0);
+ o->defineDefaultProperty(QStringLiteral("scale"), method_scale, 0);
+ o->defineDefaultProperty(QStringLiteral("drawImage"), method_drawImage, 0);
+ o->defineDefaultProperty(QStringLiteral("transform"), method_transform, 0);
+ o->defineDefaultProperty(QStringLiteral("fillText"), method_fillText, 0);
+ o->defineDefaultProperty(QStringLiteral("strokeText"), method_strokeText, 0);
+ o->defineDefaultProperty(QStringLiteral("translate"), method_translate, 0);
+ o->defineDefaultProperty(QStringLiteral("createRadialGradient"), method_createRadialGradient, 0);
+ o->defineDefaultProperty(QStringLiteral("shear"), method_shear, 0);
+ o->defineDefaultProperty(QStringLiteral("isPointInPath"), method_isPointInPath, 0);
+ o->defineDefaultProperty(QStringLiteral("bezierCurveTo"), method_bezierCurveTo, 0);
+ o->defineDefaultProperty(QStringLiteral("resetTransform"), method_resetTransform, 0);
+ o->defineDefaultProperty(QStringLiteral("arcTo"), method_arcTo, 0);
+ o->defineDefaultProperty(QStringLiteral("fillRect"), method_fillRect, 0);
+ o->defineDefaultProperty(QStringLiteral("createConicalGradient"), method_createConicalGradient, 0);
+ o->defineDefaultProperty(QStringLiteral("drawFocusRing"), method_drawFocusRing, 0);
+ o->defineDefaultProperty(QStringLiteral("beginPath"), method_beginPath, 0);
+ o->defineDefaultProperty(QStringLiteral("clearRect"), method_clearRect, 0);
+ o->defineDefaultProperty(QStringLiteral("rect"), method_rect, 0);
+ o->defineDefaultProperty(QStringLiteral("reset"), method_reset, 0);
+ o->defineDefaultProperty(QStringLiteral("rotate"), method_rotate, 0);
+ o->defineDefaultProperty(QStringLiteral("setCaretSelectionRect"), method_setCaretSelectionRect, 0);
+ o->defineDefaultProperty(QStringLiteral("putImageData"), method_putImageData, 0);
+ o->defineDefaultProperty(QStringLiteral("getImageData"), method_getImageData, 0);
+ o->defineDefaultProperty(QStringLiteral("createLinearGradient"), method_createLinearGradient, 0);
+ o->defineDefaultProperty(QStringLiteral("strokeRect"), method_strokeRect, 0);
+ o->defineDefaultProperty(QStringLiteral("closePath"), method_closePath, 0);
+ o->defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, 0);
+
+ return static_cast<QQuickJSContext2DPrototype*>(o.getPointer());
}
static QV4::ReturnedValue method_get_canvas(QV4::CallContext *ctx);
@@ -646,26 +642,27 @@ public:
DEFINE_OBJECT_VTABLE(QQuickJSContext2DPrototype);
-class QQuickContext2DStyle : public QV4::Object
+struct QQuickContext2DStyle : public QV4::Object
{
- V4_OBJECT
-public:
- QQuickContext2DStyle(QV4::ExecutionEngine *e)
- : QV4::Object(e)
- , patternRepeatX(false)
- , patternRepeatY(false)
- {
- setVTable(staticVTable());
- }
- QBrush brush;
- bool patternRepeatX:1;
- bool patternRepeatY:1;
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *e)
+ : Object::Data(e)
+ {
+ patternRepeatX = false;
+ patternRepeatY = false;
+ setVTable(staticVTable());
+ }
+ QBrush brush;
+ bool patternRepeatX:1;
+ bool patternRepeatY:1;
+ };
+ V4_OBJECT(QV4::Object)
static QV4::ReturnedValue gradient_proto_addColorStop(QV4::CallContext *ctx);
protected:
static void destroy(Managed *that)
{
- static_cast<QQuickContext2DStyle *>(that)->~QQuickContext2DStyle();
+ static_cast<QQuickContext2DStyle *>(that)->d()->~Data();
}
};
@@ -868,63 +865,60 @@ static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
struct QQuickJSContext2DPixelData : public QV4::Object
{
- V4_OBJECT
- QQuickJSContext2DPixelData(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
- {
- setVTable(staticVTable());
- QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
- Q_UNUSED(protectThis);
- setArrayType(QV4::ArrayData::Custom);
- }
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+ QV4::Scope scope(engine);
+ QV4::ScopedObject o(scope, this);
+ o->setArrayType(QV4::ArrayData::Custom);
+ }
+ QImage image;
+ };
+ V4_OBJECT(QV4::Object)
static void destroy(QV4::Managed *that) {
- static_cast<QQuickJSContext2DPixelData *>(that)->~QQuickJSContext2DPixelData();
+ static_cast<QQuickJSContext2DPixelData *>(that)->d()->~Data();
}
static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty);
static void putIndexed(QV4::Managed *m, uint index, const QV4::ValueRef value);
static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx);
-
- QImage image;
};
DEFINE_OBJECT_VTABLE(QQuickJSContext2DPixelData);
struct QQuickJSContext2DImageData : public QV4::Object
{
- V4_OBJECT
- QQuickJSContext2DImageData(QV4::ExecutionEngine *engine)
- : QV4::Object(engine)
- {
- setVTable(staticVTable());
- pixelData = QV4::Primitive::undefinedValue();
+ struct Data : Object::Data {
+ Data(QV4::ExecutionEngine *engine)
+ : Object::Data(engine)
+ {
+ setVTable(staticVTable());
+ pixelData = QV4::Primitive::undefinedValue();
- QV4::Scope scope(engine);
- QV4::ScopedObject protectThis(scope, this);
+ QV4::Scope scope(engine);
+ QV4::ScopedObject o(scope, this);
- defineAccessorProperty(QStringLiteral("width"), method_get_width, 0);
- defineAccessorProperty(QStringLiteral("height"), method_get_height, 0);
- defineAccessorProperty(QStringLiteral("data"), method_get_data, 0);
- }
+ o->defineAccessorProperty(QStringLiteral("width"), method_get_width, 0);
+ o->defineAccessorProperty(QStringLiteral("height"), method_get_height, 0);
+ o->defineAccessorProperty(QStringLiteral("data"), method_get_data, 0);
+ }
+ QV4::Value pixelData;
+ };
+ V4_OBJECT(QV4::Object)
static QV4::ReturnedValue method_get_width(QV4::CallContext *ctx);
static QV4::ReturnedValue method_get_height(QV4::CallContext *ctx);
static QV4::ReturnedValue method_get_data(QV4::CallContext *ctx);
static void markObjects(Managed *that, QV4::ExecutionEngine *engine) {
- static_cast<QQuickJSContext2DImageData *>(that)->pixelData.mark(engine);
+ static_cast<QQuickJSContext2DImageData *>(that)->d()->pixelData.mark(engine);
QV4::Object::markObjects(that, engine);
}
-
-
-
- QV4::Value pixelData;
};
-DEFINE_REF(QQuickJSContext2DImageData, QV4::Object);
-
DEFINE_OBJECT_VTABLE(QQuickJSContext2DImageData);
static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
@@ -932,20 +926,20 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV8Engine* engi
QQuickContext2DEngineData *ed = engineData(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, new (v4->memoryManager) QQuickJSContext2DPixelData(v4));
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->alloc<QQuickJSContext2DPixelData>(v4));
QV4::ScopedObject p(scope, ed->pixelArrayProto.value());
pixelData->setPrototype(p.getPointer());
if (image.isNull()) {
- pixelData->image = QImage(w, h, QImage::Format_ARGB32);
- pixelData->image.fill(0x00000000);
+ pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32);
+ pixelData->d()->image.fill(0x00000000);
} else {
Q_ASSERT(image.width() == int(w) && image.height() == int(h));
- pixelData->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
+ pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, new (v4->memoryManager) QQuickJSContext2DImageData(v4));
- imageData->pixelData = pixelData.asReturnedValue();
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->alloc<QQuickJSContext2DImageData>(v4));
+ imageData->d()->pixelData = pixelData.asReturnedValue();
return imageData.asReturnedValue();
}
@@ -959,12 +953,11 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV8Engine* engi
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::QObjectWrapper::wrap(ctx->engine, r->context->canvas());
+ return QV4::QObjectWrapper::wrap(scope.engine, r->d()->context->canvas());
}
/*!
@@ -975,13 +968,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::CallContex
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->context->popState();
- return ctx->callData->thisObject.asReturnedValue();
+ r->d()->context->popState();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -990,14 +982,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::CallContext *
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->context->reset();
+ r->d()->context->reset();
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1032,14 +1023,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->context->pushState();
+ r->d()->context->pushState();
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
// transformations
@@ -1062,14 +1052,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::CallContext *ctx
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 1)
- r->context->rotate(ctx->callData->args[0].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 1)
+ r->d()->context->rotate(ctx->d()->callData->args[0].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1091,15 +1080,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::CallContext *c
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 2)
- r->context->scale(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 2)
+ r->d()->context->scale(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1138,21 +1126,20 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 6)
- r->context->setTransform( ctx->callData->args[0].toNumber()
- , ctx->callData->args[1].toNumber()
- , ctx->callData->args[2].toNumber()
- , ctx->callData->args[3].toNumber()
- , ctx->callData->args[4].toNumber()
- , ctx->callData->args[5].toNumber());
+ if (ctx->d()->callData->argc == 6)
+ r->d()->context->setTransform( ctx->d()->callData->args[0].toNumber()
+ , ctx->d()->callData->args[1].toNumber()
+ , ctx->d()->callData->args[2].toNumber()
+ , ctx->d()->callData->args[3].toNumber()
+ , ctx->d()->callData->args[4].toNumber()
+ , ctx->d()->callData->args[5].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1168,20 +1155,19 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::CallCont
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 6)
- r->context->transform( ctx->callData->args[0].toNumber()
- , ctx->callData->args[1].toNumber()
- , ctx->callData->args[2].toNumber()
- , ctx->callData->args[3].toNumber()
- , ctx->callData->args[4].toNumber()
- , ctx->callData->args[5].toNumber());
+ if (ctx->d()->callData->argc == 6)
+ r->d()->context->transform( ctx->d()->callData->args[0].toNumber()
+ , ctx->d()->callData->args[1].toNumber()
+ , ctx->d()->callData->args[2].toNumber()
+ , ctx->d()->callData->args[3].toNumber()
+ , ctx->d()->callData->args[4].toNumber()
+ , ctx->d()->callData->args[5].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1195,14 +1181,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 2)
- r->context->translate(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 2)
+ r->d()->context->translate(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
@@ -1216,14 +1201,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- r->context->setTransform(1, 0, 0, 1, 0, 0);
+ r->d()->context->setTransform(1, 0, 0, 1, 0, 0);
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
@@ -1235,15 +1219,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::CallCo
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 2)
- r->context->shear(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber());
+ if (ctx->d()->callData->argc == 2)
+ r->d()->context->shear(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
// compositing
@@ -1256,29 +1239,27 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.globalAlpha);
+ return QV4::Encode(r->d()->context->state.globalAlpha);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- double globalAlpha = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
+ double globalAlpha = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
if (!qIsFinite(globalAlpha))
return QV4::Encode::undefined();
- if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
- r->context->state.globalAlpha = globalAlpha;
- r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
+ if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context->state.globalAlpha != globalAlpha) {
+ r->d()->context->state.globalAlpha = globalAlpha;
+ r->d()->context->buffer()->setGlobalAlpha(r->d()->context->state.globalAlpha);
}
return QV4::Encode::undefined();
}
@@ -1311,32 +1292,30 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *c
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::Encode(ctx->engine->newString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation)));
+ return QV4::Encode(scope.engine->newString(qt_composite_mode_to_string(r->d()->context->state.globalCompositeOperation)));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return ctx->throwTypeError();
- QString mode = ctx->callData->args[0].toQString();
+ QString mode = ctx->d()->callData->args[0].toQString();
QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
return QV4::Encode::undefined();
- if (cm != r->context->state.globalCompositeOperation) {
- r->context->state.globalCompositeOperation = cm;
- r->context->buffer()->setGlobalCompositeOperation(cm);
+ if (cm != r->d()->context->state.globalCompositeOperation) {
+ r->d()->context->state.globalCompositeOperation = cm;
+ r->d()->context->buffer()->setGlobalCompositeOperation(cm);
}
return QV4::Encode::undefined();
}
@@ -1366,58 +1345,56 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::C
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QColor color = r->context->state.fillStyle.color();
+ QColor color = r->d()->context->state.fillStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
- return QV4::Encode(ctx->engine->newString(color.name()));
+ return QV4::Encode(scope.engine->newString(color.name()));
QString alphaString = QString::number(color.alphaF(), 'f');
while (alphaString.endsWith(QLatin1Char('0')))
alphaString.chop(1);
if (alphaString.endsWith(QLatin1Char('.')))
alphaString += QLatin1Char('0');
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
- return QV4::Encode(ctx->engine->newString(str));
+ return QV4::Encode(scope.engine->newString(str));
}
- return r->context->m_fillStyle.value();
+ return r->d()->context->m_fillStyle.value();
}
QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
QV4::ScopedValue value(scope, ctx->argument(0));
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
if (value->asObject()) {
QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- r->context->state.fillStyle = color;
- r->context->buffer()->setFillStyle(color);
- r->context->m_fillStyle = value;
+ r->d()->context->state.fillStyle = color;
+ r->d()->context->buffer()->setFillStyle(color);
+ r->d()->context->m_fillStyle = value;
} else {
QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>());
- if (style && style->brush != r->context->state.fillStyle) {
- r->context->state.fillStyle = style->brush;
- r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
- r->context->m_fillStyle = value;
- r->context->state.fillPatternRepeatX = style->patternRepeatX;
- r->context->state.fillPatternRepeatY = style->patternRepeatY;
+ if (style && style->d()->brush != r->d()->context->state.fillStyle) {
+ r->d()->context->state.fillStyle = style->d()->brush;
+ r->d()->context->buffer()->setFillStyle(style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
+ r->d()->context->m_fillStyle = value;
+ r->d()->context->state.fillPatternRepeatX = style->d()->patternRepeatX;
+ r->d()->context->state.fillPatternRepeatY = style->d()->patternRepeatY;
}
}
} else if (value->isString()) {
QColor color = qt_color_from_string(value);
- if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
- r->context->state.fillStyle = QBrush(color);
- r->context->buffer()->setFillStyle(r->context->state.fillStyle);
- r->context->m_fillStyle = value;
+ if (color.isValid() && r->d()->context->state.fillStyle != QBrush(color)) {
+ r->d()->context->state.fillStyle = QBrush(color);
+ r->d()->context->buffer()->setFillStyle(r->d()->context->state.fillStyle);
+ r->d()->context->m_fillStyle = value;
}
}
return QV4::Encode::undefined();
@@ -1436,34 +1413,32 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
- return engine->fromVariant(r->context->state.fillRule);
+ QV8Engine *engine = scope.engine->v8Engine;
+ return engine->fromVariant(r->d()->context->state.fillRule);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
QV4::ScopedValue value(scope, ctx->argument(0));
if ((value->isString() && value->toQString() == QStringLiteral("WindingFill"))
|| (value->isInt32() && value->integerValue() == Qt::WindingFill)) {
- r->context->state.fillRule = Qt::WindingFill;
+ r->d()->context->state.fillRule = Qt::WindingFill;
} else if ((value->isString() && value->toQStringNoThrow() == QStringLiteral("OddEvenFill"))
|| (value->isInt32() && value->integerValue() == Qt::OddEvenFill)) {
- r->context->state.fillRule = Qt::OddEvenFill;
+ r->d()->context->state.fillRule = Qt::OddEvenFill;
} else {
//error
}
- r->context->m_path.setFillRule(r->context->state.fillRule);
+ r->d()->context->m_path.setFillRule(r->d()->context->state.fillRule);
return QV4::Encode::undefined();
}
/*!
@@ -1481,59 +1456,57 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QColor color = r->context->state.strokeStyle.color();
+ QColor color = r->d()->context->state.strokeStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
- return QV4::Encode(ctx->engine->newString(color.name()));
+ return QV4::Encode(scope.engine->newString(color.name()));
QString alphaString = QString::number(color.alphaF(), 'f');
while (alphaString.endsWith(QLatin1Char('0')))
alphaString.chop(1);
if (alphaString.endsWith(QLatin1Char('.')))
alphaString += QLatin1Char('0');
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
- return QV4::Encode(ctx->engine->newString(str));
+ return QV4::Encode(scope.engine->newString(str));
}
- return r->context->m_strokeStyle.value();
+ return r->d()->context->m_strokeStyle.value();
}
QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
QV4::ScopedValue value(scope, ctx->argument(0));
if (value->asObject()) {
QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- r->context->state.fillStyle = color;
- r->context->buffer()->setStrokeStyle(color);
- r->context->m_strokeStyle = value;
+ r->d()->context->state.fillStyle = color;
+ r->d()->context->buffer()->setStrokeStyle(color);
+ r->d()->context->m_strokeStyle = value;
} else {
QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>());
- if (style && style->brush != r->context->state.strokeStyle) {
- r->context->state.strokeStyle = style->brush;
- r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
- r->context->m_strokeStyle = value;
- r->context->state.strokePatternRepeatX = style->patternRepeatX;
- r->context->state.strokePatternRepeatY = style->patternRepeatY;
+ if (style && style->d()->brush != r->d()->context->state.strokeStyle) {
+ r->d()->context->state.strokeStyle = style->d()->brush;
+ r->d()->context->buffer()->setStrokeStyle(style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY);
+ r->d()->context->m_strokeStyle = value;
+ r->d()->context->state.strokePatternRepeatX = style->d()->patternRepeatX;
+ r->d()->context->state.strokePatternRepeatY = style->d()->patternRepeatY;
}
}
} else if (value->isString()) {
QColor color = qt_color_from_string(value);
- if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
- r->context->state.strokeStyle = QBrush(color);
- r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
- r->context->m_strokeStyle = value;
+ if (color.isValid() && r->d()->context->state.strokeStyle != QBrush(color)) {
+ r->d()->context->state.strokeStyle = QBrush(color);
+ r->d()->context->buffer()->setStrokeStyle(r->d()->context->state.strokeStyle);
+ r->d()->context->m_strokeStyle = value;
}
}
return QV4::Encode::undefined();
@@ -1558,19 +1531,18 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c
QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 4) {
- qreal x0 = ctx->callData->args[0].toNumber();
- qreal y0 = ctx->callData->args[1].toNumber();
- qreal x1 = ctx->callData->args[2].toNumber();
- qreal y1 = ctx->callData->args[3].toNumber();
+ if (ctx->d()->callData->argc == 4) {
+ qreal x0 = ctx->d()->callData->args[0].toNumber();
+ qreal y0 = ctx->d()->callData->args[1].toNumber();
+ qreal x1 = ctx->d()->callData->args[2].toNumber();
+ qreal y1 = ctx->d()->callData->args[3].toNumber();
if (!qIsFinite(x0)
|| !qIsFinite(y0)
@@ -1580,14 +1552,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
}
QQuickContext2DEngineData *ed = engineData(engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, new (v4->memoryManager) QQuickContext2DStyle(v4));
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->alloc<QQuickContext2DStyle>(scope.engine));
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p.getPointer());
- gradient->brush = QLinearGradient(x0, y0, x1, y1);
+ gradient->d()->brush = QLinearGradient(x0, y0, x1, y1);
return gradient.asReturnedValue();
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1605,21 +1577,20 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 6) {
- qreal x0 = ctx->callData->args[0].toNumber();
- qreal y0 = ctx->callData->args[1].toNumber();
- qreal r0 = ctx->callData->args[2].toNumber();
- qreal x1 = ctx->callData->args[3].toNumber();
- qreal y1 = ctx->callData->args[4].toNumber();
- qreal r1 = ctx->callData->args[5].toNumber();
+ if (ctx->d()->callData->argc == 6) {
+ qreal x0 = ctx->d()->callData->args[0].toNumber();
+ qreal y0 = ctx->d()->callData->args[1].toNumber();
+ qreal r0 = ctx->d()->callData->args[2].toNumber();
+ qreal x1 = ctx->d()->callData->args[3].toNumber();
+ qreal y1 = ctx->d()->callData->args[4].toNumber();
+ qreal r1 = ctx->d()->callData->args[5].toNumber();
if (!qIsFinite(x0)
|| !qIsFinite(y0)
@@ -1635,14 +1606,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
QQuickContext2DEngineData *ed = engineData(engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, new (v4->memoryManager) QQuickContext2DStyle(v4));
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->alloc<QQuickContext2DStyle>(scope.engine));
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p.getPointer());
- gradient->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
+ gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
return gradient.asReturnedValue();
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -1660,18 +1631,17 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 3) {
- qreal x = ctx->callData->args[0].toNumber();
- qreal y = ctx->callData->args[1].toNumber();
- qreal angle = DEGREES(ctx->callData->args[2].toNumber());
+ if (ctx->d()->callData->argc == 3) {
+ qreal x = ctx->d()->callData->args[0].toNumber();
+ qreal y = ctx->d()->callData->args[1].toNumber();
+ qreal angle = DEGREES(ctx->d()->callData->args[2].toNumber());
if (!qIsFinite(x) || !qIsFinite(y)) {
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
}
@@ -1682,14 +1652,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
QQuickContext2DEngineData *ed = engineData(engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, new (v4->memoryManager) QQuickContext2DStyle(v4));
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->alloc<QQuickContext2DStyle>(scope.engine));
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p.getPointer());
- gradient->brush = QConicalGradient(x, y, angle);
+ gradient->d()->brush = QConicalGradient(x, y, angle);
return gradient.asReturnedValue();
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
\qmlmethod variant QtQuick::Context2D::createPattern(color color, enumeration patternMode)
@@ -1736,53 +1706,52 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 2) {
- QV4::Scoped<QQuickContext2DStyle> pattern(scope, new (v4->memoryManager) QQuickContext2DStyle(v4));
+ if (ctx->d()->callData->argc == 2) {
+ QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->alloc<QQuickContext2DStyle>(scope.engine));
- QColor color = engine->toVariant(ctx->callData->args[0], qMetaTypeId<QColor>()).value<QColor>();
+ QColor color = engine->toVariant(ctx->d()->callData->args[0], qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- int patternMode = ctx->callData->args[1].toInt32();
+ int patternMode = ctx->d()->callData->args[1].toInt32();
Qt::BrushStyle style = Qt::SolidPattern;
if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
style = static_cast<Qt::BrushStyle>(patternMode);
}
- pattern->brush = QBrush(color, style);
+ pattern->d()->brush = QBrush(color, style);
} else {
QImage patternTexture;
- if (QV4::Object *o = ctx->callData->args[0].asObject()) {
- QV4::ScopedString s(scope, ctx->engine->newString(QStringLiteral("data")));
- QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s));
+ if (QV4::Object *o = ctx->d()->callData->args[0].asObject()) {
+ QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data")));
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s.getPointer()));
if (!!pixelData) {
- patternTexture = pixelData->image;
+ patternTexture = pixelData->d()->image;
}
} else {
- patternTexture = r->context->createPixmap(QUrl(ctx->callData->args[0].toQStringNoThrow()))->image();
+ patternTexture = r->d()->context->createPixmap(QUrl(ctx->d()->callData->args[0].toQStringNoThrow()))->image();
}
if (!patternTexture.isNull()) {
- pattern->brush.setTextureImage(patternTexture);
+ pattern->d()->brush.setTextureImage(patternTexture);
- QString repetition = ctx->callData->args[1].toQStringNoThrow();
+ QString repetition = ctx->d()->callData->args[1].toQStringNoThrow();
if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
- pattern->patternRepeatX = true;
- pattern->patternRepeatY = true;
+ pattern->d()->patternRepeatX = true;
+ pattern->d()->patternRepeatY = true;
} else if (repetition == QStringLiteral("repeat-x")) {
- pattern->patternRepeatX = true;
- pattern->patternRepeatY = false;
+ pattern->d()->patternRepeatX = true;
+ pattern->d()->patternRepeatY = false;
} else if (repetition == QStringLiteral("repeat-y")) {
- pattern->patternRepeatX = false;
- pattern->patternRepeatY = true;
+ pattern->d()->patternRepeatX = false;
+ pattern->d()->patternRepeatY = true;
} else if (repetition == QStringLiteral("no-repeat")) {
- pattern->patternRepeatX = false;
- pattern->patternRepeatY = false;
+ pattern->d()->patternRepeatX = false;
+ pattern->d()->patternRepeatY = false;
} else {
//TODO: exception: SYNTAX_ERR
}
@@ -1810,31 +1779,29 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- switch (r->context->state.lineCap) {
+ switch (r->d()->context->state.lineCap) {
case Qt::RoundCap:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("round")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("round")));
case Qt::SquareCap:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("square")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("square")));
case Qt::FlatCap:
default:
break;
}
- return QV4::Encode(ctx->engine->newString(QStringLiteral("butt")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("butt")));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QString lineCap = ctx->callData->args[0].toQString();
+ QString lineCap = ctx->d()->callData->args[0].toQString();
Qt::PenCapStyle cap;
if (lineCap == QStringLiteral("round"))
cap = Qt::RoundCap;
@@ -1845,9 +1812,9 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
else
return QV4::Encode::undefined();
- if (cap != r->context->state.lineCap) {
- r->context->state.lineCap = cap;
- r->context->buffer()->setLineCap(cap);
+ if (cap != r->d()->context->state.lineCap) {
+ r->d()->context->state.lineCap = cap;
+ r->d()->context->buffer()->setLineCap(cap);
}
return QV4::Encode::undefined();
}
@@ -1868,34 +1835,32 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- switch (r->context->state.lineJoin) {
+ switch (r->d()->context->state.lineJoin) {
case Qt::RoundJoin:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("round")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("round")));
case Qt::BevelJoin:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("bevel")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("bevel")));
case Qt::MiterJoin:
default:
break;
}
- return QV4::Encode(ctx->engine->newString(QStringLiteral("miter")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("miter")));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- if (!ctx->callData->argc)
+ if (!ctx->d()->callData->argc)
return ctx->throwTypeError();
- QString lineJoin = ctx->callData->args[0].toQString();
+ QString lineJoin = ctx->d()->callData->args[0].toQString();
Qt::PenJoinStyle join;
if (lineJoin == QStringLiteral("round"))
join = Qt::RoundJoin;
@@ -1906,9 +1871,9 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
else
return QV4::Encode::undefined();
- if (join != r->context->state.lineJoin) {
- r->context->state.lineJoin = join;
- r->context->buffer()->setLineJoin(join);
+ if (join != r->d()->context->state.lineJoin) {
+ r->d()->context->state.lineJoin = join;
+ r->d()->context->buffer()->setLineJoin(join);
}
return QV4::Encode::undefined();
}
@@ -1919,26 +1884,24 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.lineWidth);
+ return QV4::Encode(r->d()->context->state.lineWidth);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal w = ctx->callData->argc ? ctx->callData->args[0].toNumber() : -1;
+ qreal w = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : -1;
- if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
- r->context->state.lineWidth = w;
- r->context->buffer()->setLineWidth(w);
+ if (w > 0 && qIsFinite(w) && w != r->d()->context->state.lineWidth) {
+ r->d()->context->state.lineWidth = w;
+ r->d()->context->buffer()->setLineWidth(w);
}
return QV4::Encode::undefined();
}
@@ -1950,26 +1913,24 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.miterLimit);
+ return QV4::Encode(r->d()->context->state.miterLimit);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal ml = ctx->callData->argc ? ctx->callData->args[0].toNumber() : -1;
+ qreal ml = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : -1;
- if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
- r->context->state.miterLimit = ml;
- r->context->buffer()->setMiterLimit(ml);
+ if (ml > 0 && qIsFinite(ml) && ml != r->d()->context->state.miterLimit) {
+ r->d()->context->state.miterLimit = ml;
+ r->d()->context->buffer()->setMiterLimit(ml);
}
return QV4::Encode::undefined();
}
@@ -1981,26 +1942,24 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.shadowBlur);
+ return QV4::Encode(r->d()->context->state.shadowBlur);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal blur = ctx->callData->argc ? ctx->callData->args[0].toNumber() : -1;
+ qreal blur = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : -1;
- if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
- r->context->state.shadowBlur = blur;
- r->context->buffer()->setShadowBlur(blur);
+ if (blur > 0 && qIsFinite(blur) && blur != r->d()->context->state.shadowBlur) {
+ r->d()->context->state.shadowBlur = blur;
+ r->d()->context->buffer()->setShadowBlur(blur);
}
return QV4::Encode::undefined();
}
@@ -2011,28 +1970,26 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(ctx->engine->newString(r->context->state.shadowColor.name()));
+ return QV4::Encode(scope.engine->newString(r->d()->context->state.shadowColor.name()));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QColor color;
- if (ctx->callData->argc)
- color = qt_color_from_string(ctx->callData->args[0]);
+ if (ctx->d()->callData->argc)
+ color = qt_color_from_string(ctx->d()->callData->args[0]);
- if (color.isValid() && color != r->context->state.shadowColor) {
- r->context->state.shadowColor = color;
- r->context->buffer()->setShadowColor(color);
+ if (color.isValid() && color != r->d()->context->state.shadowColor) {
+ r->d()->context->state.shadowColor = color;
+ r->d()->context->buffer()->setShadowColor(color);
}
return QV4::Encode::undefined();
}
@@ -2046,25 +2003,23 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::CallContext *c
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.shadowOffsetX);
+ return QV4::Encode(r->d()->context->state.shadowOffsetX);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetX = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
- r->context->state.shadowOffsetX = offsetX;
- r->context->buffer()->setShadowOffsetX(offsetX);
+ qreal offsetX = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ if (qIsFinite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) {
+ r->d()->context->state.shadowOffsetX = offsetX;
+ r->d()->context->buffer()->setShadowOffsetX(offsetX);
}
return QV4::Encode::undefined();
}
@@ -2076,57 +2031,53 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->context->state.shadowOffsetY);
+ return QV4::Encode(r->d()->context->state.shadowOffsetY);
}
QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetY = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN();
- if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
- r->context->state.shadowOffsetY = offsetY;
- r->context->buffer()->setShadowOffsetY(offsetY);
+ qreal offsetY = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();
+ if (qIsFinite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) {
+ r->d()->context->state.shadowOffsetY = offsetY;
+ r->d()->context->buffer()->setShadowOffsetY(offsetY);
}
return QV4::Encode::undefined();
}
QV4::ReturnedValue QQuickJSContext2D::method_get_path(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return r->context->m_v4path.value();
+ return r->d()->context->m_v4path.value();
}
QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::ScopedValue value(scope, ctx->argument(0));
- r->context->beginPath();
- QV4::QObjectWrapperRef qobjectWrapper = value;
+ r->d()->context->beginPath();
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, value);
if (!!qobjectWrapper) {
if (QQuickPath *path = qobject_cast<QQuickPath*>(qobjectWrapper->object()))
- r->context->m_path = path->path();
+ r->d()->context->m_path = path->path();
} else {
QString path =value->toQStringNoThrow();
- QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
+ QQuickSvgParser::parsePathDataFast(path, r->d()->context->m_path);
}
- r->context->m_v4path = value;
+ r->d()->context->m_v4path = value;
return QV4::Encode::undefined();
}
@@ -2137,19 +2088,18 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4)
- r->context->clearRect(ctx->callData->args[0].toNumber(),
- ctx->callData->args[1].toNumber(),
- ctx->callData->args[2].toNumber(),
- ctx->callData->args[3].toNumber());
+ if (ctx->d()->callData->argc == 4)
+ r->d()->context->clearRect(ctx->d()->callData->args[0].toNumber(),
+ ctx->d()->callData->args[1].toNumber(),
+ ctx->d()->callData->args[2].toNumber(),
+ ctx->d()->callData->args[3].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
\qmlmethod object QtQuick::Context2D::fillRect(real x, real y, real w, real h)
@@ -2159,14 +2109,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4)
- r->context->fillRect(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber(), ctx->callData->args[2].toNumber(), ctx->callData->args[3].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 4)
+ r->d()->context->fillRect(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber(), ctx->d()->callData->args[2].toNumber(), ctx->d()->callData->args[3].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2181,15 +2130,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4)
- r->context->strokeRect(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber(), ctx->callData->args[2].toNumber(), ctx->callData->args[3].toNumber());
+ if (ctx->d()->callData->argc == 4)
+ r->d()->context->strokeRect(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber(), ctx->d()->callData->args[2].toNumber(), ctx->d()->callData->args[3].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
// Complex shapes (paths) API
@@ -2215,31 +2163,30 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::CallContex
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc >= 5) {
+ if (ctx->d()->callData->argc >= 5) {
bool antiClockwise = false;
- if (ctx->callData->argc == 6)
- antiClockwise = ctx->callData->args[5].toBoolean();
+ if (ctx->d()->callData->argc == 6)
+ antiClockwise = ctx->d()->callData->args[5].toBoolean();
- qreal radius = ctx->callData->args[2].toNumber();
+ qreal radius = ctx->d()->callData->args[2].toNumber();
if (qIsFinite(radius) && radius < 0)
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->context->arc(ctx->callData->args[0].toNumber(),
- ctx->callData->args[1].toNumber(),
+ r->d()->context->arc(ctx->d()->callData->args[0].toNumber(),
+ ctx->d()->callData->args[1].toNumber(),
radius,
- ctx->callData->args[3].toNumber(),
- ctx->callData->args[4].toNumber(),
+ ctx->d()->callData->args[3].toNumber(),
+ ctx->d()->callData->args[4].toNumber(),
antiClockwise);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2267,25 +2214,24 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 5) {
- qreal radius = ctx->callData->args[4].toNumber();
+ if (ctx->d()->callData->argc == 5) {
+ qreal radius = ctx->d()->callData->args[4].toNumber();
if (qIsFinite(radius) && radius < 0)
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->context->arcTo(ctx->callData->args[0].toNumber(),
- ctx->callData->args[1].toNumber(),
- ctx->callData->args[2].toNumber(),
- ctx->callData->args[3].toNumber(),
+ r->d()->context->arcTo(ctx->d()->callData->args[0].toNumber(),
+ ctx->d()->callData->args[1].toNumber(),
+ ctx->d()->callData->args[2].toNumber(),
+ ctx->d()->callData->args[3].toNumber(),
radius);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2295,14 +2241,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ct
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- r->context->beginPath();
+ r->d()->context->beginPath();
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2326,27 +2271,26 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 6) {
- qreal cp1x = ctx->callData->args[0].toNumber();
- qreal cp1y = ctx->callData->args[1].toNumber();
- qreal cp2x = ctx->callData->args[2].toNumber();
- qreal cp2y = ctx->callData->args[3].toNumber();
- qreal x = ctx->callData->args[4].toNumber();
- qreal y = ctx->callData->args[5].toNumber();
+ if (ctx->d()->callData->argc == 6) {
+ qreal cp1x = ctx->d()->callData->args[0].toNumber();
+ qreal cp1y = ctx->d()->callData->args[1].toNumber();
+ qreal cp2x = ctx->d()->callData->args[2].toNumber();
+ qreal cp2y = ctx->d()->callData->args[3].toNumber();
+ qreal x = ctx->d()->callData->args[4].toNumber();
+ qreal y = ctx->d()->callData->args[5].toNumber();
if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
- r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
+ r->d()->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2375,13 +2319,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallCon
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- r->context->clip();
- return ctx->callData->thisObject.asReturnedValue();
+ r->d()->context->clip();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2393,15 +2336,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::CallContext *ctx
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- r->context->closePath();
+ r->d()->context->closePath();
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2415,12 +2357,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::CallContext
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r);
- r->context->fill();
- return ctx->callData->thisObject.asReturnedValue();
+ r->d()->context->fill();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2431,21 +2372,21 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::CallContext *ctx
QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 2) {
- qreal x = ctx->callData->args[0].toNumber();
- qreal y = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2) {
+ qreal x = ctx->d()->callData->args[0].toNumber();
+ qreal y = ctx->d()->callData->args[1].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
- r->context->lineTo(x, y);
+ r->d()->context->lineTo(x, y);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2456,18 +2397,18 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *c
QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 2) {
- qreal x = ctx->callData->args[0].toNumber();
- qreal y = ctx->callData->args[1].toNumber();
+ if (ctx->d()->callData->argc == 2) {
+ qreal x = ctx->d()->callData->args[0].toNumber();
+ qreal y = ctx->d()->callData->args[1].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
- r->context->moveTo(x, y);
+ return ctx->d()->callData->thisObject.asReturnedValue();
+ r->d()->context->moveTo(x, y);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2480,22 +2421,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *c
QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4) {
- qreal cpx = ctx->callData->args[0].toNumber();
- qreal cpy = ctx->callData->args[1].toNumber();
- qreal x = ctx->callData->args[2].toNumber();
- qreal y = ctx->callData->args[3].toNumber();
+ if (ctx->d()->callData->argc == 4) {
+ qreal cpx = ctx->d()->callData->args[0].toNumber();
+ qreal cpy = ctx->d()->callData->args[1].toNumber();
+ qreal x = ctx->d()->callData->args[2].toNumber();
+ qreal y = ctx->d()->callData->args[3].toNumber();
if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
- r->context->quadraticCurveTo(cpx, cpy, x, y);
+ r->d()->context->quadraticCurveTo(cpx, cpy, x, y);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2506,12 +2447,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::Call
QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4)
- r->context->rect(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber(), ctx->callData->args[2].toNumber(), ctx->callData->args[3].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 4)
+ r->d()->context->rect(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber(), ctx->d()->callData->args[2].toNumber(), ctx->d()->callData->args[3].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2523,17 +2464,17 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::CallContext *ctx
QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 6)
- r->context->roundedRect(ctx->callData->args[0].toNumber()
- , ctx->callData->args[1].toNumber()
- , ctx->callData->args[2].toNumber()
- , ctx->callData->args[3].toNumber()
- , ctx->callData->args[4].toNumber()
- , ctx->callData->args[5].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 6)
+ r->d()->context->roundedRect(ctx->d()->callData->args[0].toNumber()
+ , ctx->d()->callData->args[1].toNumber()
+ , ctx->d()->callData->args[2].toNumber()
+ , ctx->d()->callData->args[3].toNumber()
+ , ctx->d()->callData->args[4].toNumber()
+ , ctx->d()->callData->args[5].toNumber());
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2547,14 +2488,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::CallConte
QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 4)
- r->context->ellipse(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber(), ctx->callData->args[2].toNumber(), ctx->callData->args[3].toNumber());
+ if (ctx->d()->callData->argc == 4)
+ r->d()->context->ellipse(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber(), ctx->d()->callData->args[2].toNumber(), ctx->d()->callData->args[3].toNumber());
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2566,18 +2507,18 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::CallContext *
QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 3) {
- qreal x = ctx->callData->args[1].toNumber();
- qreal y = ctx->callData->args[2].toNumber();
+ if (ctx->d()->callData->argc == 3) {
+ qreal x = ctx->d()->callData->args[1].toNumber();
+ qreal y = ctx->d()->callData->args[2].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
- r->context->text(ctx->callData->args[0].toQStringNoThrow(), x, y);
+ return ctx->d()->callData->thisObject.asReturnedValue();
+ r->d()->context->text(ctx->d()->callData->args[0].toQStringNoThrow(), x, y);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2592,11 +2533,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx
QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- r->context->stroke();
- return ctx->callData->thisObject.asReturnedValue();
+ r->d()->context->stroke();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2608,14 +2549,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::CallContext *c
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(QV4::CallContext *ctx)
{
- QV4::ExecutionEngine *v4 = ctx->engine;
- QV4::Scope scope(v4);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scope scope(ctx);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
bool pointInPath = false;
- if (ctx->callData->argc == 2)
- pointInPath = r->context->isPointInPath(ctx->callData->args[0].toNumber(), ctx->callData->args[1].toNumber());
+ if (ctx->d()->callData->argc == 2)
+ pointInPath = r->d()->context->isPointInPath(ctx->d()->callData->args[0].toNumber(), ctx->d()->callData->args[1].toNumber());
return QV4::Primitive::fromBoolean(pointInPath).asReturnedValue();
}
@@ -2666,24 +2606,24 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::CallCo
QV4::ReturnedValue QQuickJSContext2D::method_get_font(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(ctx->engine->newString(r->context->state.font.toString()));
+ return QV4::Encode(scope.engine->newString(r->d()->context->state.font.toString()));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
if (scope.engine->hasException)
return QV4::Encode::undefined();
- QFont font = qt_font_from_string(s->toQString(), r->context->state.font);
- if (font != r->context->state.font) {
- r->context->state.font = font;
+ QFont font = qt_font_from_string(s->toQString(), r->d()->context->state.font);
+ if (font != r->d()->context->state.font) {
+ r->d()->context->state.font = font;
}
return QV4::Encode::undefined();
}
@@ -2705,29 +2645,29 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::CallContext *ctx)
QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- switch (r->context->state.textAlign) {
+ switch (r->d()->context->state.textAlign) {
case QQuickContext2D::End:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("end")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("end")));
case QQuickContext2D::Left:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("left")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("left")));
case QQuickContext2D::Right:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("right")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("right")));
case QQuickContext2D::Center:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("center")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("center")));
case QQuickContext2D::Start:
default:
break;
}
- return QV4::Encode(ctx->engine->newString(QStringLiteral("start")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("start")));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
@@ -2749,8 +2689,8 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
else
return QV4::Encode::undefined();
- if (ta != r->context->state.textAlign)
- r->context->state.textAlign = ta;
+ if (ta != r->d()->context->state.textAlign)
+ r->d()->context->state.textAlign = ta;
return QV4::Encode::undefined();
}
@@ -2773,29 +2713,29 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- switch (r->context->state.textBaseline) {
+ switch (r->d()->context->state.textBaseline) {
case QQuickContext2D::Hanging:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("hanging")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("hanging")));
case QQuickContext2D::Top:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("top")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("top")));
case QQuickContext2D::Bottom:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("bottom")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("bottom")));
case QQuickContext2D::Middle:
- return QV4::Encode(ctx->engine->newString(QStringLiteral("middle")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("middle")));
case QQuickContext2D::Alphabetic:
default:
break;
}
- return QV4::Encode(ctx->engine->newString(QStringLiteral("alphabetic")));
+ return QV4::Encode(scope.engine->newString(QStringLiteral("alphabetic")));
}
QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QV4::Scoped<QV4::String> s(scope, ctx->argument(0), QV4::Scoped<QV4::String>::Convert);
if (scope.engine->hasException)
@@ -2816,8 +2756,8 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *
else
return QV4::Encode::undefined();
- if (tb != r->context->state.textBaseline)
- r->context->state.textBaseline = tb;
+ if (tb != r->d()->context->state.textBaseline)
+ r->d()->context->state.textBaseline = tb;
return QV4::Encode::undefined();
}
@@ -2833,18 +2773,18 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *
QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 3) {
- qreal x = ctx->callData->args[1].toNumber();
- qreal y = ctx->callData->args[2].toNumber();
+ if (ctx->d()->callData->argc == 3) {
+ qreal x = ctx->d()->callData->args[1].toNumber();
+ qreal y = ctx->d()->callData->args[2].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
- return ctx->callData->thisObject.asReturnedValue();
- QPainterPath textPath = r->context->createTextGlyphs(x, y, ctx->callData->args[0].toQStringNoThrow());
- r->context->buffer()->fill(textPath);
+ return ctx->d()->callData->thisObject.asReturnedValue();
+ QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, ctx->d()->callData->args[0].toQStringNoThrow());
+ r->d()->context->buffer()->fill(textPath);
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
\qmlmethod object QtQuick::Context2D::strokeText(text, x, y)
@@ -2857,12 +2797,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext
QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 3)
- r->context->drawText(ctx->callData->args[0].toQStringNoThrow(), ctx->callData->args[1].toNumber(), ctx->callData->args[2].toNumber(), false);
- return ctx->callData->thisObject.asReturnedValue();
+ if (ctx->d()->callData->argc == 3)
+ r->d()->context->drawText(ctx->d()->callData->args[0].toQStringNoThrow(), ctx->d()->callData->args[1].toNumber(), ctx->d()->callData->args[2].toNumber(), false);
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -2892,14 +2832,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContex
QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->callData->argc == 1) {
- QFontMetrics fm(r->context->state.font);
- uint width = fm.width(ctx->callData->args[0].toQStringNoThrow());
- QV4::Scoped<QV4::Object> tm(scope, ctx->engine->newObject());
- tm->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("width"))),
+ if (ctx->d()->callData->argc == 1) {
+ QFontMetrics fm(r->d()->context->state.font);
+ uint width = fm.width(ctx->d()->callData->args[0].toQStringNoThrow());
+ QV4::Scoped<QV4::Object> tm(scope, scope.engine->newObject());
+ tm->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("width"))).getPointer(),
QV4::ScopedValue(scope, QV4::Primitive::fromDouble(width)));
return tm.asReturnedValue();
}
@@ -2968,32 +2908,32 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallConte
QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject);
CHECK_CONTEXT(r)
qreal sx, sy, sw, sh, dx, dy, dw, dh;
- if (!ctx->callData->argc)
- return ctx->callData->thisObject.asReturnedValue();
+ if (!ctx->d()->callData->argc)
+ return ctx->d()->callData->thisObject.asReturnedValue();
//FIXME:This function should be moved to QQuickContext2D::drawImage(...)
- if (!r->context->state.invertibleCTM)
- return ctx->callData->thisObject.asReturnedValue();
+ if (!r->d()->context->state.invertibleCTM)
+ return ctx->d()->callData->thisObject.asReturnedValue();
QQmlRefPointer<QQuickCanvasPixmap> pixmap;
- QV4::ScopedValue arg(scope, ctx->callData->args[0]);
+ QV4::ScopedValue arg(scope, ctx->d()->callData->args[0]);
if (arg->isString()) {
QUrl url(arg->toQString());
if (!url.isValid())
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
- pixmap = r->context->createPixmap(url);
+ pixmap = r->d()->context->createPixmap(url);
} else if (arg->isObject()) {
- QV4::QObjectWrapperRef qobjectWrapper = arg;
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, arg);
if (!!qobjectWrapper) {
if (QQuickImage *imageItem = qobject_cast<QQuickImage*>(qobjectWrapper->object())) {
- pixmap = r->context->createPixmap(imageItem->source());
+ pixmap = r->d()->context->createPixmap(imageItem->source());
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
@@ -3002,18 +2942,18 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
- QQuickJSContext2DImageDataRef imageData = arg;
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg);
if (!!imageData) {
- QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
- if (pix && !pix->image.isNull()) {
- pixmap.take(new QQuickCanvasPixmap(pix->image));
+ QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
+ if (pix && !pix->d()->image.isNull()) {
+ pixmap.take(new QQuickCanvasPixmap(pix->d()->image));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
QUrl url(arg->toQStringNoThrow());
if (url.isValid())
- pixmap = r->context->createPixmap(url);
+ pixmap = r->d()->context->createPixmap(url);
else
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
@@ -3023,37 +2963,37 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
}
if (pixmap.isNull() || !pixmap->isValid())
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
- if (ctx->callData->argc == 3) {
- dx = ctx->callData->args[1].toNumber();
- dy = ctx->callData->args[2].toNumber();
+ if (ctx->d()->callData->argc == 3) {
+ dx = ctx->d()->callData->args[1].toNumber();
+ dy = ctx->d()->callData->args[2].toNumber();
sx = 0;
sy = 0;
sw = pixmap->width();
sh = pixmap->height();
dw = sw;
dh = sh;
- } else if (ctx->callData->argc == 5) {
+ } else if (ctx->d()->callData->argc == 5) {
sx = 0;
sy = 0;
sw = pixmap->width();
sh = pixmap->height();
- dx = ctx->callData->args[1].toNumber();
- dy = ctx->callData->args[2].toNumber();
- dw = ctx->callData->args[3].toNumber();
- dh = ctx->callData->args[4].toNumber();
- } else if (ctx->callData->argc == 9) {
- sx = ctx->callData->args[1].toNumber();
- sy = ctx->callData->args[2].toNumber();
- sw = ctx->callData->args[3].toNumber();
- sh = ctx->callData->args[4].toNumber();
- dx = ctx->callData->args[5].toNumber();
- dy = ctx->callData->args[6].toNumber();
- dw = ctx->callData->args[7].toNumber();
- dh = ctx->callData->args[8].toNumber();
+ dx = ctx->d()->callData->args[1].toNumber();
+ dy = ctx->d()->callData->args[2].toNumber();
+ dw = ctx->d()->callData->args[3].toNumber();
+ dh = ctx->d()->callData->args[4].toNumber();
+ } else if (ctx->d()->callData->argc == 9) {
+ sx = ctx->d()->callData->args[1].toNumber();
+ sy = ctx->d()->callData->args[2].toNumber();
+ sw = ctx->d()->callData->args[3].toNumber();
+ sh = ctx->d()->callData->args[4].toNumber();
+ dx = ctx->d()->callData->args[5].toNumber();
+ dy = ctx->d()->callData->args[6].toNumber();
+ dw = ctx->d()->callData->args[7].toNumber();
+ dh = ctx->d()->callData->args[8].toNumber();
} else {
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
if (!qIsFinite(sx)
@@ -3064,7 +3004,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
|| !qIsFinite(dy)
|| !qIsFinite(dw)
|| !qIsFinite(dh))
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
if (sx < 0
|| sy < 0
@@ -3076,9 +3016,9 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
}
- r->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
+ r->d()->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
// pixel manipulation
@@ -3108,13 +3048,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject);
if (!imageData)
return ctx->throwTypeError();
- QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (!r)
return QV4::Encode(0);
- return QV4::Encode(r->image.width());
+ return QV4::Encode(r->d()->image.width());
}
/*!
@@ -3124,13 +3064,13 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext
QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject);
if (!imageData)
return ctx->throwTypeError();
- QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (!r)
return QV4::Encode(0);
- return QV4::Encode(r->image.height());
+ return QV4::Encode(r->d()->image.height());
}
/*!
@@ -3140,10 +3080,10 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContex
QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->callData->thisObject);
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject);
if (!imageData)
return ctx->throwTypeError();
- return imageData->pixelData.asReturnedValue();
+ return imageData->d()->pixelData.asReturnedValue();
}
/*!
@@ -3167,11 +3107,11 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext
QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DPixelData> r(scope, ctx->callData->thisObject.as<QQuickJSContext2DPixelData>());
- if (!r || r->image.isNull())
+ QV4::Scoped<QQuickJSContext2DPixelData> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2DPixelData>());
+ if (!r || r->d()->image.isNull())
return QV4::Encode::undefined();
- return QV4::Encode(r->image.width() * r->image.height() * 4);
+ return QV4::Encode(r->d()->image.width() * r->d()->image.height() * 4);
}
QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint index, bool *hasProperty)
@@ -3180,13 +3120,13 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
- if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
+ if (r && index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4)) {
if (hasProperty)
*hasProperty = true;
- const quint32 w = r->image.width();
+ const quint32 w = r->d()->image.width();
const quint32 row = (index / 4) / w;
const quint32 col = (index / 4) % w;
- const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
+ const QRgb* pixel = reinterpret_cast<const QRgb*>(r->d()->image.constScanLine(row));
pixel += col;
switch (index % 4) {
case 0:
@@ -3213,17 +3153,17 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!r) {
- v4->currentContext()->throwTypeError();
+ scope.engine->currentContext()->throwTypeError();
return;
}
const int v = value->toInt32();
- if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v >= 0 && v <= 255) {
- const quint32 w = r->image.width();
+ if (r && index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4) && v >= 0 && v <= 255) {
+ const quint32 w = r->d()->image.width();
const quint32 row = (index / 4) / w;
const quint32 col = (index / 4) % w;
- QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
+ QRgb* pixel = reinterpret_cast<QRgb*>(r->d()->image.scanLine(row));
pixel += col;
switch (index % 4) {
case 0:
@@ -3265,28 +3205,28 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 1) {
- QV4::ScopedValue arg0(scope, ctx->callData->args[0]);
- QQuickJSContext2DImageDataRef imgData = arg0;
+ if (ctx->d()->callData->argc == 1) {
+ QV4::ScopedValue arg0(scope, ctx->d()->callData->args[0]);
+ QV4::Scoped<QQuickJSContext2DImageData> imgData(scope, arg0);
if (!!imgData) {
- QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->pixelData.as<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (pa) {
- qreal w = pa->image.width();
- qreal h = pa->image.height();
+ qreal w = pa->d()->image.width();
+ qreal h = pa->d()->image.height();
return qt_create_image_data(w, h, engine, QImage());
}
} else if (arg0->isString()) {
- QImage image = r->context->createPixmap(QUrl(arg0->toQStringNoThrow()))->image();
+ QImage image = r->d()->context->createPixmap(QUrl(arg0->toQStringNoThrow()))->image();
return qt_create_image_data(image.width(), image.height(), engine, image);
}
- } else if (ctx->callData->argc == 2) {
- qreal w = ctx->callData->args[0].toNumber();
- qreal h = ctx->callData->args[1].toNumber();
+ } else if (ctx->d()->callData->argc == 2) {
+ qreal w = ctx->d()->callData->args[0].toNumber();
+ qreal h = ctx->d()->callData->args[1].toNumber();
if (!qIsFinite(w) || !qIsFinite(h))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
@@ -3306,22 +3246,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallC
QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- QV8Engine *engine = ctx->engine->v8Engine;
- if (ctx->callData->argc == 4) {
- qreal x = ctx->callData->args[0].toNumber();
- qreal y = ctx->callData->args[1].toNumber();
- qreal w = ctx->callData->args[2].toNumber();
- qreal h = ctx->callData->args[3].toNumber();
+ QV8Engine *engine = scope.engine->v8Engine;
+ if (ctx->d()->callData->argc == 4) {
+ qreal x = ctx->d()->callData->args[0].toNumber();
+ qreal y = ctx->d()->callData->args[1].toNumber();
+ qreal w = ctx->d()->callData->args[2].toNumber();
+ qreal h = ctx->d()->callData->args[3].toNumber();
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
if (w <= 0 || h <= 0)
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
- QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
+ QImage image = r->d()->context->canvas()->toImage(QRectF(x, y, w, h));
return qt_create_image_data(w, h, engine, image);
}
return QV4::Encode::null();
@@ -3334,36 +3274,36 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallCont
QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->callData->thisObject.as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, ctx->d()->callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->callData->argc != 3 && ctx->callData->argc != 7)
+ if (ctx->d()->callData->argc != 3 && ctx->d()->callData->argc != 7)
return QV4::Encode::undefined();
- QV4::ScopedValue arg0(scope, ctx->callData->args[0]);
+ QV4::ScopedValue arg0(scope, ctx->d()->callData->args[0]);
if (!arg0->isObject())
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
- qreal dx = ctx->callData->args[1].toNumber();
- qreal dy = ctx->callData->args[2].toNumber();
+ qreal dx = ctx->d()->callData->args[1].toNumber();
+ qreal dy = ctx->d()->callData->args[2].toNumber();
qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
if (!qIsFinite(dx) || !qIsFinite(dy))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
- QQuickJSContext2DImageDataRef imageData = arg0;
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg0);
if (!imageData)
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
- QV4::Scoped<QQuickJSContext2DPixelData> pixelArray(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelArray(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (pixelArray) {
- w = pixelArray->image.width();
- h = pixelArray->image.height();
+ w = pixelArray->d()->image.width();
+ h = pixelArray->d()->image.height();
- if (ctx->callData->argc == 7) {
- dirtyX = ctx->callData->args[3].toNumber();
- dirtyY = ctx->callData->args[4].toNumber();
- dirtyWidth = ctx->callData->args[5].toNumber();
- dirtyHeight = ctx->callData->args[6].toNumber();
+ if (ctx->d()->callData->argc == 7) {
+ dirtyX = ctx->d()->callData->args[3].toNumber();
+ dirtyY = ctx->d()->callData->args[4].toNumber();
+ dirtyWidth = ctx->d()->callData->args[5].toNumber();
+ dirtyHeight = ctx->d()->callData->args[6].toNumber();
if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
@@ -3398,7 +3338,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
}
if (dirtyWidth <=0 || dirtyHeight <= 0)
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
} else {
dirtyX = 0;
dirtyY = 0;
@@ -3406,10 +3346,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
dirtyHeight = h;
}
- QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
- r->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
+ QImage image = pixelArray->d()->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+ r->d()->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
/*!
@@ -3435,24 +3375,24 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallContext *ctx)
{
QV4::Scope scope(ctx);
- QV4::Scoped<QQuickContext2DStyle> style(scope, ctx->callData->thisObject.as<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> style(scope, ctx->d()->callData->thisObject.as<QQuickContext2DStyle>());
if (!style)
V4THROW_ERROR("Not a CanvasGradient object");
- QV8Engine *engine = ctx->engine->v8Engine;
+ QV8Engine *engine = scope.engine->v8Engine;
- if (ctx->callData->argc == 2) {
+ if (ctx->d()->callData->argc == 2) {
- if (!style->brush.gradient())
+ if (!style->d()->brush.gradient())
V4THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
- QGradient gradient = *(style->brush.gradient());
- qreal pos = ctx->callData->args[0].toNumber();
+ QGradient gradient = *(style->d()->brush.gradient());
+ qreal pos = ctx->d()->callData->args[0].toNumber();
QColor color;
- if (ctx->callData->args[1].asObject()) {
- color = engine->toVariant(ctx->callData->args[1], qMetaTypeId<QColor>()).value<QColor>();
+ if (ctx->d()->callData->args[1].asObject()) {
+ color = engine->toVariant(ctx->d()->callData->args[1], qMetaTypeId<QColor>()).value<QColor>();
} else {
- color = qt_color_from_string(ctx->callData->args[1]);
+ color = qt_color_from_string(ctx->d()->callData->args[1]);
}
if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
@@ -3463,10 +3403,10 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo
} else {
V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
}
- style->brush = gradient;
+ style->d()->brush = gradient;
}
- return ctx->callData->thisObject.asReturnedValue();
+ return ctx->d()->callData->thisObject.asReturnedValue();
}
void QQuickContext2D::scale(qreal x, qreal y)
@@ -4084,6 +4024,13 @@ public:
QOffscreenSurface *surface;
};
+class QQuickContext2DTextureCleanup : public QRunnable
+{
+public:
+ QQuickContext2DTexture *texture;
+ void run() Q_DECL_OVERRIDE { delete texture; }
+};
+
QMutex QQuickContext2D::mutex;
QQuickContext2D::QQuickContext2D(QObject *parent)
@@ -4116,7 +4063,13 @@ QQuickContext2D::~QQuickContext2D()
cleaner->moveToThread(m_texture->thread());
cleaner->deleteLater();
} else {
- m_texture->deleteLater();
+ if (m_canvas->window()) {
+ QQuickContext2DTextureCleanup *c = new QQuickContext2DTextureCleanup;
+ c->texture = m_texture;
+ m_canvas->window()->scheduleRenderJob(c, QQuickWindow::AfterSynchronizingStage);
+ } else {
+ m_texture->deleteLater();
+ }
}
} else {
// Image based does not have GL resources, but must still be deleted
@@ -4261,7 +4214,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Scope scope(v4);
- QV4::Scoped<QV4::Object> proto(scope, new (v4->memoryManager) QQuickJSContext2DPrototype(v4));
+ QV4::Scoped<QV4::Object> proto(scope, QQuickJSContext2DPrototype::create(v4));
proto->defineAccessorProperty(QStringLiteral("strokeStyle"), QQuickJSContext2D::method_get_strokeStyle, QQuickJSContext2D::method_set_strokeStyle);
proto->defineAccessorProperty(QStringLiteral("font"), QQuickJSContext2D::method_get_font, QQuickJSContext2D::method_set_font);
proto->defineAccessorProperty(QStringLiteral("fillRule"), QQuickJSContext2D::method_get_fillRule, QQuickJSContext2D::method_set_fillRule);
@@ -4281,13 +4234,12 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
proto->defineAccessorProperty(QStringLiteral("shadowBlur"), QQuickJSContext2D::method_get_shadowBlur, QQuickJSContext2D::method_set_shadowBlur);
contextPrototype = proto;
- proto = v4->newObject();
+ proto = scope.engine->newObject();
proto->defineDefaultProperty(QStringLiteral("addColorStop"), QQuickContext2DStyle::gradient_proto_addColorStop, 0);
gradientProto = proto;
- proto = v4->newObject();
- QV4::ScopedString s(scope, v4->id_length);
- proto->defineAccessorProperty(s, QQuickJSContext2DPixelData::proto_get_length, 0);
+ proto = scope.engine->newObject();
+ proto->defineAccessorProperty(scope.engine->id_length, QQuickJSContext2DPixelData::proto_get_length, 0);
pixelArrayProto = proto;
}
@@ -4377,10 +4329,10 @@ void QQuickContext2D::setV8Engine(QV8Engine *engine)
QQuickContext2DEngineData *ed = engineData(engine);
QV4::ExecutionEngine *v4Engine = QV8Engine::getV4(engine);
QV4::Scope scope(v4Engine);
- QV4::Scoped<QQuickJSContext2D> wrapper(scope, new (v4Engine->memoryManager) QQuickJSContext2D(v4Engine));
+ QV4::Scoped<QQuickJSContext2D> wrapper(scope, v4Engine->memoryManager->alloc<QQuickJSContext2D>(v4Engine));
QV4::ScopedObject p(scope, ed->contextPrototype.value());
wrapper->setPrototype(p.getPointer());
- wrapper->context = this;
+ wrapper->d()->context = this;
m_v4value = wrapper;
}
}
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index cb09c9d4ff..7b114ae45e 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -258,13 +258,14 @@ static void qt_drawImage(QPainter *p, QQuickContext2D::State& state, QImage imag
p->endNativePainting();
}
-void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& state)
+void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& state, const QVector2D &scaleFactor)
{
if (!p)
return;
reset();
+ p->scale(scaleFactor.x(), scaleFactor.y());
QTransform originMatrix = p->worldTransform();
QPen pen = makePen(state);
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 9e79333a0c..8c7ffb0524 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -232,7 +232,8 @@ public:
inline QColor takeColor() { return colors[colorIdx++]; }
inline QBrush takeBrush() { return brushes[brushIdx++]; }
- void replay(QPainter* painter, QQuickContext2D::State& state);
+ void replay(QPainter* painter, QQuickContext2D::State& state, const QVector2D &scaleFactor);
+
private:
QPen makePen(const QQuickContext2D::State& state);
void setPainterState(QPainter* painter, const QQuickContext2D::State& state, const QPen& pen);
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index c8bea6f97e..17d4feae6b 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -233,7 +233,7 @@ void QQuickContext2DTexture::paintWithoutTiles(QQuickContext2DCommandBuffer *ccb
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
- ccb->replay(&p, m_state);
+ ccb->replay(&p, m_state, scaleFactor());
endPainting();
markDirtyTexture();
}
@@ -277,7 +277,7 @@ void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb)
QQuickContext2D::State oldState = m_state;
foreach (QQuickContext2DTile* tile, m_tiles) {
if (tile->dirty()) {
- ccb->replay(tile->createPainter(m_smooth, m_antialiasing), oldState);
+ ccb->replay(tile->createPainter(m_smooth, m_antialiasing), oldState, scaleFactor());
tile->drawFinished();
tile->markDirty(false);
}
@@ -424,7 +424,15 @@ QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
delete m_paint_device;
if (QOpenGLContext::currentContext())
- glDeleteTextures(2, m_displayTextures);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(2, m_displayTextures);
+}
+
+QVector2D QQuickContext2DFBOTexture::scaleFactor() const
+{
+ if (!m_fbo)
+ return QVector2D(1, 1);
+ return QVector2D(m_fbo->width() / m_fboSize.width(),
+ m_fbo->height() / m_fboSize.height());
}
QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
@@ -508,7 +516,7 @@ void QQuickContext2DFBOTexture::grabImage(const QRectF& rf)
} else {
QImage grabbed;
GLAcquireContext ctx(m_gl, m_surface);
- grabbed = m_fbo->toImage().mirrored().copy(rf.toRect());
+ grabbed = m_fbo->toImage().scaled(m_fboSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).mirrored().copy(rf.toRect());
m_context->setGrabbedImage(grabbed);
}
}
@@ -570,7 +578,14 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
} else {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- m_fbo = new QOpenGLFramebufferObject(m_fboSize, format);
+ QSize s = m_fboSize;
+ if (m_antialiasing) { // do supersampling since multisampling is not available
+ GLint max;
+ QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+ if (s.width() * 2 <= max && s.height() * 2 <= max)
+ s = s * 2;
+ }
+ m_fbo = new QOpenGLFramebufferObject(s, format);
}
}
@@ -611,15 +626,16 @@ void QQuickContext2DFBOTexture::endPainting()
if (m_onCustomThread)
m_mutex.lock();
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (m_displayTextures[0] == 0) {
m_displayTexture = 1;
- glGenTextures(2, m_displayTextures);
+ funcs->glGenTextures(2, m_displayTextures);
}
m_fbo->bind();
GLuint target = m_displayTexture == 0 ? 1 : 0;
- glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]);
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]);
+ funcs->glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0);
if (m_onCustomThread)
m_mutex.unlock();
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index e41a4809e4..169eef8b95 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -129,6 +129,8 @@ public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF()) = 0;
protected:
+ virtual QVector2D scaleFactor() const { return QVector2D(1, 1); }
+
void paintWithoutTiles(QQuickContext2DCommandBuffer *ccb);
virtual QPaintDevice* beginPainting() {m_painting = true; return 0; }
virtual void endPainting() {m_painting = false;}
@@ -181,6 +183,9 @@ public:
QSGTexture *textureForNextFrame(QSGTexture *);
+protected:
+ QVector2D scaleFactor() const Q_DECL_OVERRIDE;
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index cb378b424b..0b98782566 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -10,7 +10,6 @@ HEADERS += \
$$PWD/qquickrectangle_p_p.h \
$$PWD/qquickwindow.h \
$$PWD/qquickwindow_p.h \
- $$PWD/qquickrendercontrol_p.h \
$$PWD/qquickfocusscope_p.h \
$$PWD/qquickitemsmodule_p.h \
$$PWD/qquickpainteditem.h \
@@ -74,8 +73,13 @@ HEADERS += \
$$PWD/qquickitemview_p_p.h \
$$PWD/qquickitemviewtransition_p.h \
$$PWD/qquickscreen_p.h \
+ $$PWD/qquickwindowattached_p.h \
$$PWD/qquickwindowmodule_p.h \
- $$PWD/qquickframebufferobject.h
+ $$PWD/qquickframebufferobject.h \
+ $$PWD/qquickitemgrabresult.h \
+ $$PWD/qquickrendercontrol.h \
+ $$PWD/qquickrendercontrol_p.h \
+ $$PWD/qquickopenglinfo_p.h
SOURCES += \
$$PWD/qquickevents.cpp \
@@ -83,7 +87,6 @@ SOURCES += \
$$PWD/qquickitem.cpp \
$$PWD/qquickrectangle.cpp \
$$PWD/qquickwindow.cpp \
- $$PWD/qquickrendercontrol.cpp \
$$PWD/qquickfocusscope.cpp \
$$PWD/qquickitemsmodule.cpp \
$$PWD/qquickpainteditem.cpp \
@@ -128,7 +131,11 @@ SOURCES += \
$$PWD/qquickitemviewtransition.cpp \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
- $$PWD/qquickframebufferobject.cpp
+ $$PWD/qquickwindowattached.cpp \
+ $$PWD/qquickframebufferobject.cpp \
+ $$PWD/qquickitemgrabresult.cpp \
+ $$PWD/qquickrendercontrol.cpp \
+ $$PWD/qquickopenglinfo.cpp
SOURCES += \
$$PWD/qquickshadereffect.cpp \
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 16f684ce77..94b2ae533f 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -187,6 +187,33 @@ QT_BEGIN_NAMESPACE
By default this property is \c false.
*/
+/*! \qmlproperty bool QtQuick::Accessible::ignored
+ \brief This property holds whether this item should be ignored by the accessibility framework.
+
+ Sometimes an item is part of a group of items that should be treated as one. For example two labels might be
+ visually placed next to each other, but separate items. For accessibility purposes they should be treated as one
+ and thus they are represented by a third invisible item with the right geometry.
+
+ For example a speed display adds "m/s" as a smaller label:
+ \qml
+ Row {
+ Label {
+ id: speedLabel
+ text: "Speed: 5"
+ Accessible.ignored: true
+ }
+ Label {
+ text: qsTr("m/s")
+ Accessible.ignored: true
+ }
+ Accessible.role: Accessible.StaticText
+ Accessible.name: speedLabel.text + " meters per second"
+ }
+ \endqml
+
+ \since 5.4
+ By default this property is \c false.
+*/
/*! \qmlproperty bool QtQuick::Accessible::multiLine
\brief This property holds whether this item has multiple text lines.
@@ -268,6 +295,19 @@ QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObjec
return new QQuickAccessibleAttached(obj);
}
+bool QQuickAccessibleAttached::ignored() const
+{
+ return !item()->d_func()->isAccessible;
+}
+
+void QQuickAccessibleAttached::setIgnored(bool ignored)
+{
+ if (m_ignored != ignored) {
+ item()->d_func()->isAccessible = !ignored;
+ emit ignoredChanged();
+ }
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 1f2c6bf532..4440f2a616 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -78,6 +78,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAccessibleAttached : public QObject
Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged FINAL)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
+ Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged FINAL)
public:
Q_ENUMS(QAccessible::Role QAccessible::Event)
@@ -193,6 +194,7 @@ public:
}
QAccessible::State state() { return m_state; }
+ bool ignored() const;
public Q_SLOTS:
void valueChanged() {
@@ -204,10 +206,13 @@ public Q_SLOTS:
QAccessible::updateAccessibility(&ev);
}
+ void setIgnored(bool ignored);
+
Q_SIGNALS:
void roleChanged();
void nameChanged();
void descriptionChanged();
+ void ignoredChanged();
private:
QQuickItem *item() const { return static_cast<QQuickItem*>(parent()); }
@@ -216,6 +221,7 @@ private:
QAccessible::State m_state;
QString m_name;
QString m_description;
+ bool m_ignored;
public:
using QObject::property;
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index 3f31884cd3..19c6d13b2a 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -52,6 +52,36 @@
#include <QtNetwork/qnetworkreply.h>
QT_BEGIN_NAMESPACE
+
+QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine)
+{
+ if (!_movie)
+ return 0;
+
+ int current = _movie->currentFrameNumber();
+ if (!frameMap.contains(current)) {
+ QUrl requestedUrl;
+ QQuickPixmap *pixmap = 0;
+ if (engine && !_movie->fileName().isEmpty()) {
+ requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2")
+ .arg(_movie->fileName())
+ .arg(current));
+ }
+ if (!requestedUrl.isEmpty()) {
+ if (QQuickPixmap::isCached(requestedUrl, QSize()))
+ pixmap = new QQuickPixmap(engine, requestedUrl);
+ else
+ pixmap = new QQuickPixmap(requestedUrl, _movie->currentImage());
+ } else {
+ pixmap = new QQuickPixmap;
+ pixmap->setImage(_movie->currentImage());
+ }
+ frameMap.insert(current, pixmap);
+ }
+
+ return frameMap.value(current);
+}
+
/*!
\qmltype AnimatedImage
\instantiates QQuickAnimatedImage
@@ -111,6 +141,8 @@ QQuickAnimatedImage::~QQuickAnimatedImage()
if (d->reply)
d->reply->deleteLater();
delete d->_movie;
+ qDeleteAll(d->frameMap);
+ d->frameMap.clear();
}
/*!
@@ -231,6 +263,10 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
d->reply = 0;
}
+ d->setImage(QImage());
+ qDeleteAll(d->frameMap);
+ d->frameMap.clear();
+
d->oldPlaying = isPlaying();
if (d->_movie) {
delete d->_movie;
@@ -357,7 +393,7 @@ void QQuickAnimatedImage::movieRequestFinished()
d->_movie->jumpToFrame(d->preset_currentframe);
d->preset_currentframe = 0;
}
- d->setImage(d->_movie->currentPixmap().toImage());
+ d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
if (isPlaying() != d->oldPlaying)
emit playingChanged();
@@ -372,7 +408,7 @@ void QQuickAnimatedImage::movieUpdate()
Q_D(QQuickAnimatedImage);
if (d->_movie) {
- d->setImage(d->_movie->currentPixmap().toImage());
+ d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
emit frameChanged();
}
}
diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h
index 21b891eadd..0be24dece5 100644
--- a/src/quick/items/qquickanimatedimage_p_p.h
+++ b/src/quick/items/qquickanimatedimage_p_p.h
@@ -72,6 +72,8 @@ public:
{
}
+ QQuickPixmap *infoForCurrentFrame(QQmlEngine *engine);
+
bool playing;
bool paused;
int preset_currentframe;
@@ -79,6 +81,7 @@ public:
QNetworkReply *reply;
int redirectCount;
bool oldPlaying;
+ QMap<int, QQuickPixmap *> frameMap;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index bfe957e943..533f1cabed 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -498,7 +498,6 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode()
return 0;
m_sheetSize = QSizeF(image.size());
m_material->texture = window()->createTextureFromImage(image);
- m_material->texture->setFiltering(QSGTexture::Linear);
m_spriteEngine->start(0);
m_material->animT = 0;
m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width();
@@ -677,6 +676,7 @@ void QQuickAnimatedSprite::prepareNextFrame()
m_material->animW = w;
m_material->animH = h;
m_material->animT = m_interpolate ? progress : 0.0;
+ m_material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 6c36032d3c..7e5b357e9c 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -791,7 +791,7 @@ void QQuickDragAttached::startDrag(QQmlV4Function *args)
QQuickDrag::QQuickDrag(QObject *parent)
: QObject(parent), _target(0), _axis(XAndYAxis), _xmin(-FLT_MAX),
_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false),
- _threshold(qApp->styleHints()->startDragDistance())
+ _smoothed(true), _threshold(qApp->styleHints()->startDragDistance())
{
}
@@ -885,6 +885,18 @@ void QQuickDrag::setYmax(qreal m)
emit maximumYChanged();
}
+bool QQuickDrag::smoothed() const
+{
+ return _smoothed;
+}
+
+void QQuickDrag::setSmoothed(bool smooth)
+{
+ if (_smoothed != smooth) {
+ _smoothed = smooth;
+ emit smoothedChanged();
+ }
+}
qreal QQuickDrag::threshold() const
{
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index d9021d0f6d..eebe07469a 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -157,6 +157,7 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
+ Q_PROPERTY(bool smoothed READ smoothed WRITE setSmoothed NOTIFY smoothedChanged)
// Note, threshold was added in QtQuick 2.2 but REVISION is not supported (or needed) for grouped
// properties See QTBUG-33179
Q_PROPERTY(qreal threshold READ threshold WRITE setThreshold NOTIFY thresholdChanged RESET resetThreshold)
@@ -185,6 +186,9 @@ public:
qreal ymax() const;
void setYmax(qreal);
+ bool smoothed() const;
+ void setSmoothed(bool smooth);
+
qreal threshold() const;
void setThreshold(qreal);
void resetThreshold();
@@ -206,6 +210,7 @@ Q_SIGNALS:
void maximumYChanged();
void activeChanged();
void filterChildrenChanged();
+ void smoothedChanged();
void thresholdChanged();
private:
@@ -217,6 +222,7 @@ private:
qreal _ymax;
bool _active : 1;
bool _filterChildren: 1;
+ bool _smoothed : 1;
qreal _threshold;
Q_DISABLE_COPY(QQuickDrag)
};
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 63dde661d9..9736559e92 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1373,7 +1373,7 @@ void QQuickFlickablePrivate::replayDelayedPress()
// Use the event handler that will take care of finding the proper item to propagate the event
replayingPressEvent = true;
- QQuickWindowPrivate::get(w)->deliverMouseEvent(mouseEvent.data());
+ QCoreApplication::sendEvent(w, mouseEvent.data());
replayingPressEvent = false;
}
}
@@ -2062,6 +2062,7 @@ bool QQuickFlickable::sendMouseEvent(QQuickItem *item, QMouseEvent *event)
break;
case QEvent::MouseButtonRelease:
d->handleMouseReleaseEvent(mouseEvent.data());
+ stealThisEvent = d->stealMouse;
break;
default:
break;
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 4c43292f7c..fea6aadc23 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -186,7 +186,7 @@ public Q_SLOTS:
if (renderPending) {
renderPending = false;
fbo->bind();
- glViewport(0, 0, fbo->width(), fbo->height());
+ QOpenGLContext::currentContext()->functions()->glViewport(0, 0, fbo->width(), fbo->height());
renderer->render();
fbo->bindDefault();
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index c9a051c9bb..5b928310cd 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -198,7 +198,7 @@ public:
virtual void setPosition(qreal pos);
virtual void layoutVisibleItems(int fromModelIndex = 0);
- virtual bool applyInsertionChange(const QQmlChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
+ virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
virtual void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
virtual bool needsRefillForAddedOrRemovedIndex(int index) const;
@@ -2325,7 +2325,7 @@ void QQuickGridView::moveCurrentIndexRight()
}
}
-bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
+bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
{
Q_Q(QQuickGridView);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 781fcccd9f..14dc6c3377 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -49,6 +49,7 @@
#include <QtGui/qpainter.h>
#include <qmath.h>
+#include <QtCore/QRunnable>
QT_BEGIN_NAMESPACE
@@ -100,6 +101,14 @@ QQuickImagePrivate::QQuickImagePrivate()
{
}
+class QQuickImageCleanup : public QRunnable
+{
+public:
+ QQuickImageCleanup(QQuickImageTextureProvider *p) : provider(p) { }
+ void run() Q_DECL_OVERRIDE { delete provider; }
+ QQuickImageTextureProvider *provider;
+};
+
/*!
\qmltype Image
\instantiates QQuickImage
@@ -159,18 +168,24 @@ QQuickImagePrivate::QQuickImagePrivate()
QQuickImage::QQuickImage(QQuickItem *parent)
: QQuickImageBase(*(new QQuickImagePrivate), parent)
{
+ connect(this, SIGNAL(sceneGraphInvalidated()), this, SLOT(invalidateSG()));
}
QQuickImage::QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent)
: QQuickImageBase(dd, parent)
{
+ connect(this, SIGNAL(sceneGraphInvalidated()), this, SLOT(invalidateSG()));
}
QQuickImage::~QQuickImage()
{
Q_D(QQuickImage);
- if (d->provider)
- d->provider->deleteLater();
+ if (QQuickWindow *w = window()) {
+ w->scheduleRenderJob(new QQuickImageCleanup(d->provider), QQuickWindow::AfterSynchronizingStage);
+ } else {
+ // Should have been released already in releaseResources or in invalidateSG.
+ Q_ASSERT(!d->provider);
+ }
}
void QQuickImagePrivate::setImage(const QImage &image)
@@ -184,6 +199,17 @@ void QQuickImagePrivate::setImage(const QImage &image)
q->update();
}
+void QQuickImagePrivate::setPixmap(const QQuickPixmap &pixmap)
+{
+ Q_Q(QQuickImage);
+ pix.setPixmap(pixmap);
+
+ q->pixmapChange();
+ status = pix.isNull() ? QQuickImageBase::Null : QQuickImageBase::Ready;
+
+ q->update();
+}
+
/*!
\qmlproperty enumeration QtQuick::Image::fillMode
@@ -560,6 +586,22 @@ QSGTextureProvider *QQuickImage::textureProvider() const
return d->provider;
}
+void QQuickImage::invalidateSG()
+{
+ Q_D(QQuickImage);
+ delete d->provider;
+ d->provider = 0;
+}
+
+void QQuickImage::releaseResources()
+{
+ Q_D(QQuickImage);
+ if (d->provider) {
+ window()->scheduleRenderJob(new QQuickImageCleanup(d->provider), QQuickWindow::AfterSynchronizingStage);
+ d->provider = 0;
+ }
+}
+
QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickImage);
diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h
index 56b064f525..82ac776762 100644
--- a/src/quick/items/qquickimage_p.h
+++ b/src/quick/items/qquickimage_p.h
@@ -102,10 +102,14 @@ Q_SIGNALS:
void verticalAlignmentChanged(VAlignment alignment);
Q_REVISION(1) void mipmapChanged(bool);
+private Q_SLOTS:
+ void invalidateSG();
+
protected:
QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent);
void pixmapChange();
void updatePaintedGeometry();
+ void releaseResources() Q_DECL_OVERRIDE;
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h
index de88662ab8..7ed0a6b989 100644
--- a/src/quick/items/qquickimage_p_p.h
+++ b/src/quick/items/qquickimage_p_p.h
@@ -71,6 +71,7 @@ public:
qreal paintedWidth;
qreal paintedHeight;
void setImage(const QImage &img);
+ void setPixmap(const QQuickPixmap &pixmap);
bool pixmapChanged : 1;
bool mipmap : 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 442080a335..d1d9a7cd71 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -59,6 +59,7 @@
#include <QtCore/qcoreevent.h>
#include <QtCore/qnumeric.h>
#include <QtGui/qpa/qplatformtheme.h>
+#include <QtCore/qloggingcategory.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -87,25 +88,24 @@ QT_BEGIN_NAMESPACE
static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
#endif
-#ifdef FOCUS_DEBUG
-void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
-void printFocusTree(QQuickItem *item, QQuickItem *scope, int depth)
-{
- qWarning()
- << QByteArray(depth, '\t').constData()
- << (scope && QQuickItemPrivate::get(scope)->subFocusItem == item ? '*' : ' ')
- << item->hasFocus()
- << item->hasActiveFocus()
- << item->isFocusScope()
- << item;
- foreach (QQuickItem *child, item->childItems()) {
- printFocusTree(
- child,
- item->isFocusScope() || !scope ? item : scope,
- item->isFocusScope() || !scope ? depth + 1 : depth);
+void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1)
+{
+ if (DBG_FOCUS().isEnabled(QtDebugMsg)) {
+ qCDebug(DBG_FOCUS)
+ << QByteArray(depth, '\t').constData()
+ << (scope && QQuickItemPrivate::get(scope)->subFocusItem == item ? '*' : ' ')
+ << item->hasFocus()
+ << item->hasActiveFocus()
+ << item->isFocusScope()
+ << item;
+ foreach (QQuickItem *child, item->childItems()) {
+ debugFocusTree(
+ child,
+ item->isFocusScope() || !scope ? item : scope,
+ item->isFocusScope() || !scope ? depth + 1 : depth);
+ }
}
}
-#endif
static void QQuickItem_parentNotifier(QObject *o, qintptr, QQmlNotifier **n)
{
@@ -657,13 +657,13 @@ void QQuickKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
break;
case Qt::Key_Tab:
if (d->tab) {
- setFocusNavigation(d->tab, "tab");
+ setFocusNavigation(d->tab, "tab", Qt::TabFocusReason);
event->accept();
}
break;
case Qt::Key_Backtab:
if (d->backtab) {
- setFocusNavigation(d->backtab, "backtab");
+ setFocusNavigation(d->backtab, "backtab", Qt::BacktabFocusReason);
event->accept();
}
break;
@@ -725,14 +725,15 @@ void QQuickKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
if (!event->isAccepted()) QQuickItemKeyFilter::keyReleased(event, post);
}
-void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, const char *dir)
+void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, const char *dir,
+ Qt::FocusReason reason)
{
QQuickItem *initialItem = currentItem;
bool isNextItem = false;
do {
isNextItem = false;
if (currentItem->isVisible() && currentItem->isEnabled()) {
- currentItem->forceActiveFocus(Qt::OtherFocusReason);
+ currentItem->forceActiveFocus(reason);
} else {
QObject *attached =
qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(currentItem, false);
@@ -1686,6 +1687,63 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
\note All classes with QSG prefix should be used solely on the scene graph's
rendering thread. See \l {Scene Graph and Rendering} for more information.
+ \section2 Graphics Resource Handling
+
+ The preferred way to handle cleanup of graphics resources used in
+ the scene graph, is to rely on the automatic cleanup of nodes. A
+ QSGNode returned from QQuickItem::updatePaintNode() is
+ automatically deleted on the right thread at the right time. Trees
+ of QSGNode instances are managed through the use of
+ QSGNode::OwnedByParent, which is set by default. So, for the
+ majority of custom scene graph items, no extra work will be
+ required.
+
+ Implementations that store graphics resources outside the node
+ tree, such as an item implementing QQuickItem::textureProvider(),
+ will need to take care in cleaning it up correctly depending on
+ how the item is used in QML. The situations to handle are:
+
+ \list
+
+ \li The scene graph is invalidated; This can happen, for instance,
+ if the window is hidden using QQuickWindow::hide(). The signal
+ QQuickItem::sceneGraphInvalidated() is emitted on the rendering
+ thread and the GUI thread is blocked for the duration of this
+ call. Graphics resources can be deleted directly when this signal
+ is connected to using a Qt::DirectConnection.
+
+ \li The item is removed from the scene; If an item is taken out of
+ the scene, for instance because it's parent was set to \c null or
+ an item in another window, the QQuickItem::releaseResources() will
+ be called on the GUI thread. QQuickWindow::scheduleRenderJob()
+ should be used to schedule cleanup of rendering resources.
+
+ \li The item is deleted; When the destructor if an item runs, it
+ should delete any graphics resources it has. If neither of the two
+ conditions above were already met, the item will be part of a
+ window and it is possible to use QQuickWindow::scheduleRenderJob()
+ to have them cleaned up. If an implementation ignores the call to
+ QQuickItem::releaseResources(), the item will in many cases no
+ longer have access to a QQuickWindow and thus no means of
+ scheduling cleanup.
+
+ \endlist
+
+ When scheduling cleanup of graphics resources using
+ QQuickWindow::scheduleRenderJob(), one should use either
+ QQuickWindow::BeforeSynchronizingStage or
+ QQuickWindow::AfterSynchronizingStage. The \l {Scene Graph and
+ Rendering}{synchronization stage} is where the scene graph is
+ changed as a result of changes to the QML tree. If cleanup is
+ scheduled at any other time, it may result in other parts of the
+ scene graph referencing the newly deleted objects as these parts
+ have not been updated.
+
+ \note Use of QObject::deleteLater() to clean up graphics resources
+ is not recommended as this will run at an arbitrary time and it is
+ unknown if there will be an OpenGL context bound when the deletion
+ takes place.
+
\section1 Custom QPainter Items
The QQuickItem provides a subclass, QQuickPaintedItem, which
@@ -2263,14 +2321,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
if (current == startItem && from == firstFromItem) {
// wrapped around, avoid endless loops
if (originalItem == contentItem) {
-#ifdef FOCUS_DEBUG
- qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
-#endif
+ qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
return item->window()->contentItem();
} else {
-#ifdef FOCUS_DEBUG
- qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem;
-#endif
+ qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem;
return startItem;
}
}
@@ -2509,6 +2563,12 @@ void QQuickItem::stackAfter(const QQuickItem *sibling)
*/
/*!
+ \qmlproperty Window QtQuick::Item::window
+ \since 5.4
+ This property holds the window in which the item is rendered.
+ */
+
+/*!
Returns the window in which this item is rendered.
The item does not have a window until it has been assigned into a scene. The
@@ -2619,6 +2679,11 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c)
Q_ASSERT(window == 0);
window = c;
+ if (q->flags() & QQuickItem::ItemHasContents) {
+ QObject::connect(window, SIGNAL(sceneGraphInvalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
+ QObject::connect(window, SIGNAL(sceneGraphInitialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
+ }
+
if (polishScheduled)
QQuickWindowPrivate::get(window)->itemsToPolish.insert(q);
@@ -2648,6 +2713,11 @@ void QQuickItemPrivate::derefWindow()
if (--windowRefCount > 0)
return; // There are still other references, so don't set window to null yet.
+ if (q->flags() & QQuickItem::ItemHasContents) {
+ QObject::disconnect(window, SIGNAL(sceneGraphInvalidated()), q, SIGNAL(sceneGraphInvalidated()));
+ QObject::disconnect(window, SIGNAL(sceneGraphInitialized()), q, SIGNAL(sceneGraphInitialized()));
+ }
+
q->releaseResources();
removeFromDirtyList();
QQuickWindowPrivate *c = QQuickWindowPrivate::get(window);
@@ -3430,7 +3500,7 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
rendering thread. See \l {Scene Graph and Rendering} for more information.
\sa QSGMaterial, QSGSimpleMaterial, QSGGeometryNode, QSGGeometry,
- QSGFlatColorMaterial, QSGTextureMaterial, QSGNode::markDirty()
+ QSGFlatColorMaterial, QSGTextureMaterial, QSGNode::markDirty(), {Graphics Resource Handling}
*/
QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
@@ -3441,16 +3511,20 @@ QSGNode *QQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *upda
}
/*!
- This function is called when the item's scene graph resources are no longer needed.
- It allows items to free its resources, for instance textures, that are not owned by scene graph
- nodes. Note that scene graph nodes are managed by QQuickWindow and should not be deleted by
- this function. Scene graph resources are no longer needed when the parent is set to null and
- the item is not used by any \l ShaderEffect or \l ShaderEffectSource.
+ This function is called when an item should release graphics
+ resources which are not already managed by the nodes returend from
+ QQuickItem::updatePaintNode().
- This function is called from the main thread. Therefore, resources used by the scene graph
- should not be deleted directly, but by calling \l QObject::deleteLater().
+ This happens when the item is about to be removed from window it
+ was previously rendering to. The item is guaranteed to have a
+ \l {QQuickItem::window()}{window} when the function is called.
- \note The item destructor still needs to free its scene graph resources if not already done.
+ The function is called on the GUI thread and the state of the
+ rendering thread, when it is used, is unknown. Objects should
+ not be deleted directly, but instead scheduled for cleanup
+ using QQuickWindow::scheduleRenderJob().
+
+ \sa {Graphics Resource Handling}
*/
void QQuickItem::releaseResources()
@@ -3999,15 +4073,15 @@ void QQuickItem::mapFromItem(QQmlV4Function *args) const
QRectF r = mapRectFromItem(itemObj, QRectF(x, y, w, h));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(r.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(r.y())));
- rv->put((s = v4->newString(QStringLiteral("width"))), (v = QV4::Primitive::fromDouble(r.width())));
- rv->put((s = v4->newString(QStringLiteral("height"))), (v = QV4::Primitive::fromDouble(r.height())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(r.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(r.y())));
+ rv->put((s = v4->newString(QStringLiteral("width"))).getPointer(), (v = QV4::Primitive::fromDouble(r.width())));
+ rv->put((s = v4->newString(QStringLiteral("height"))).getPointer(), (v = QV4::Primitive::fromDouble(r.height())));
} else {
QPointF p = mapFromItem(itemObj, QPointF(x, y));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(p.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(p.y())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(p.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(p.y())));
}
}
}
@@ -4079,15 +4153,15 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const
QRectF r = mapRectToItem(itemObj, QRectF(x, y, w, h));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(r.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(r.y())));
- rv->put((s = v4->newString(QStringLiteral("width"))), (v = QV4::Primitive::fromDouble(r.width())));
- rv->put((s = v4->newString(QStringLiteral("height"))), (v = QV4::Primitive::fromDouble(r.height())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(r.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(r.y())));
+ rv->put((s = v4->newString(QStringLiteral("width"))).getPointer(), (v = QV4::Primitive::fromDouble(r.width())));
+ rv->put((s = v4->newString(QStringLiteral("height"))).getPointer(), (v = QV4::Primitive::fromDouble(r.height())));
} else {
QPointF p = mapToItem(itemObj, QPointF(x, y));
- rv->put((s = v4->newString(QStringLiteral("x"))), (v = QV4::Primitive::fromDouble(p.x())));
- rv->put((s = v4->newString(QStringLiteral("y"))), (v = QV4::Primitive::fromDouble(p.y())));
+ rv->put((s = v4->newString(QStringLiteral("x"))).getPointer(), (v = QV4::Primitive::fromDouble(p.x())));
+ rv->put((s = v4->newString(QStringLiteral("y"))).getPointer(), (v = QV4::Primitive::fromDouble(p.y())));
}
}
}
@@ -5392,6 +5466,17 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
emit q->enabledChanged();
}
+bool QQuickItemPrivate::isTransparentForPositioner() const
+{
+ return extra.isAllocated() && extra.value().transparentForPositioner;
+}
+
+void QQuickItemPrivate::setTransparentForPositioner(bool transparent)
+{
+ extra.value().transparentForPositioner = transparent;
+}
+
+
QString QQuickItemPrivate::dirtyToString() const
{
#define DIRTY_TO_STRING(value) if (dirtyAttributes & value) { \
@@ -5780,10 +5865,67 @@ void QQuickItem::setFlags(Flags flags)
if (int(flags & ItemClipsChildrenToShape) != int(d->flags & ItemClipsChildrenToShape))
d->dirty(QQuickItemPrivate::Clip);
+ if (window() && (flags & ItemHasContents) ^ (d->flags & ItemHasContents)) {
+ if (flags & ItemHasContents) {
+ connect(window(), SIGNAL(sceneGraphInvalidated()), this, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
+ connect(window(), SIGNAL(sceneGraphInitialized()), this, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
+ } else {
+ disconnect(window(), SIGNAL(sceneGraphInvalidated()), this, SIGNAL(sceneGraphInvalidated()));
+ disconnect(window(), SIGNAL(sceneGraphInitialized()), this, SIGNAL(sceneGraphInitialized()));
+ }
+ }
+
d->flags = flags;
}
/*!
+ \fn void QQuickItem::sceneGraphInvalidated()
+
+ This signal is emitted when the scene graph is invalidated for
+ items that have the ItemHasContents flag set.
+
+ QSGNode instances will be cleaned up by the scene graph
+ automatically. An application will only need to react to this signal
+ to clean up resources that are stored and managed outside the
+ QSGNode structure returned from updatePaintNode().
+
+ When the scene graph is using a dedicated render thread, this
+ signal will be emitted on the scene graph's render thread. The
+ GUI thread is blocked for the duration of this call. Connections
+ should for this reason be made using Qt::DirectConnection.
+
+ The OpenGL context of this item's window will be bound when this
+ signal is emitted. The only exception is if the native OpenGL has
+ been destroyed outside Qt's control, for instance through
+ EGL_CONTEXT_LOST.
+
+ \since 5.4
+ \since QtQuick 2.4
+
+ \sa QQuickWindow::sceneGraphInvalidated(), {Graphics Resource Handling}
+ */
+
+/*!
+ \fn void QQuickItem::sceneGraphInitialized()
+
+ This signal is emitted when the scene graph is is initialized for
+ items that have the ItemHasContents flag set.
+
+ When the scene graph is using a dedicated render thread, this
+ function will be called on the scene graph's render thread. The
+ GUI thread is blocked for the duration of this call. Connections
+ should for this reason be made using Qt::DirectConnection.
+
+ The OpenGL context of this item's window will be bound when
+ this signal is emitted.
+
+ \since 5.4
+ \since QtQuick 2.4
+
+ \sa QQuickWindow::sceneGraphInitialized()
+ */
+
+/*!
\qmlproperty real QtQuick::Item::x
\qmlproperty real QtQuick::Item::y
\qmlproperty real QtQuick::Item::width
@@ -5820,10 +5962,6 @@ qreal QQuickItem::y() const
}
/*!
- \property QQuickItem::pos
- \internal
- */
-/*!
\internal
*/
QPointF QQuickItem::position() const
@@ -7251,6 +7389,7 @@ void QQuickItemLayer::activate()
{
Q_ASSERT(!m_effectSource);
m_effectSource = new QQuickShaderEffectSource();
+ QQuickItemPrivate::get(m_effectSource)->setTransparentForPositioner(true);
QQuickItem *parentItem = m_item->parentItem();
if (parentItem) {
@@ -7316,6 +7455,7 @@ void QQuickItemLayer::activateEffect()
}
m_effect->setVisible(m_item->isVisible());
m_effect->setProperty(m_name, qVariantFromValue<QObject *>(m_effectSource));
+ QQuickItemPrivate::get(m_effect)->setTransparentForPositioner(true);
m_effectComponent->completeCreate();
}
@@ -7632,7 +7772,8 @@ QQuickItemPrivate::ExtraData::ExtraData()
#endif
effectRefCount(0), hideRefCount(0),
opacityNode(0), clipNode(0), rootNode(0), beforePaintNode(0),
- acceptedMouseButtons(0), origin(QQuickItem::Center)
+ acceptedMouseButtons(0), origin(QQuickItem::Center),
+ transparentForPositioner(false)
{
}
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 2b08cc2598..fee04984a4 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -52,6 +52,7 @@
#include <QtGui/qfont.h>
#include <QtGui/qaccessible.h>
+
QT_BEGIN_NAMESPACE
class QQuickItem;
@@ -92,6 +93,7 @@ class QTouchEvent;
class QSGNode;
class QSGTransformNode;
class QSGTextureProvider;
+class QQuickItemGrabResult;
class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
{
@@ -145,6 +147,8 @@ class Q_QUICK_EXPORT QQuickItem : public QObject, public QQmlParserStatus
Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged)
Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged)
+ Q_PROPERTY(QQuickWindow *window READ window NOTIFY windowChanged REVISION 2)
+
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQuickItemLayer *layer READ layer DESIGNABLE false CONSTANT FINAL)
Q_ENUMS(TransformOrigin)
@@ -308,6 +312,10 @@ public:
bool keepTouchGrab() const;
void setKeepTouchGrab(bool);
+ // implemented in qquickitemgrabresult.cpp
+ Q_REVISION(2) Q_INVOKABLE bool grabToImage(const QJSValue &callback, const QSize &targetSize = QSize());
+ QSharedPointer<QQuickItemGrabResult> grabToImage(const QSize &targetSize = QSize());
+
Q_INVOKABLE virtual bool contains(const QPointF &point) const;
QTransform itemTransform(QQuickItem *, bool *) const;
@@ -377,6 +385,9 @@ Q_SIGNALS:
void implicitWidthChanged();
void implicitHeightChanged();
+ Q_REVISION(2) void sceneGraphInvalidated();
+ Q_REVISION(2) void sceneGraphInitialized();
+
protected:
virtual bool event(QEvent *);
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 96cb9e8843..9ac4758182 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -297,6 +297,7 @@ public:
static void transform_clear(QQmlListProperty<QQuickTransform> *list);
void _q_resourceObjectDeleted(QObject *);
+ void _q_windowChanged(QQuickWindow *w);
enum ChangeType {
Geometry = 0x01,
@@ -368,6 +369,7 @@ public:
Qt::MouseButtons acceptedMouseButtons;
QQuickItem::TransformOrigin origin:5;
+ uint transparentForPositioner : 1;
QObjectList resourcesList;
};
@@ -545,6 +547,9 @@ public:
void deliverInputMethodEvent(QInputMethodEvent *);
#endif
+ bool isTransparentForPositioner() const;
+ void setTransparentForPositioner(bool trans);
+
bool calcEffectiveVisible() const;
bool setEffectiveVisibleRecur(bool);
bool calcEffectiveEnable() const;
@@ -686,7 +691,8 @@ Q_SIGNALS:
private:
virtual void keyPressed(QKeyEvent *event, bool post);
virtual void keyReleased(QKeyEvent *event, bool post);
- void setFocusNavigation(QQuickItem *currentItem, const char *dir);
+ void setFocusNavigation(QQuickItem *currentItem, const char *dir,
+ Qt::FocusReason reason = Qt::OtherFocusReason);
};
class QQuickLayoutMirroringAttached : public QObject
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
new file mode 100644
index 0000000000..93b9261c44
--- /dev/null
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -0,0 +1,399 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemgrabresult.h"
+
+#include "qquickwindow.h"
+#include "qquickitem.h"
+#include "qquickshadereffectsource_p.h"
+
+#include <QtQml/QQmlEngine>
+
+#include <private/qquickpixmapcache_p.h>
+#include <private/qquickitem_p.h>
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+const QEvent::Type Event_Grab_Completed = static_cast<QEvent::Type>(QEvent::User + 1);
+
+class QQuickItemGrabResultPrivate : public QObjectPrivate
+{
+public:
+ QQuickItemGrabResultPrivate()
+ : cacheEntry(0)
+ , texture(0)
+ {
+ }
+
+ ~QQuickItemGrabResultPrivate()
+ {
+ delete cacheEntry;
+ }
+
+ void ensureImageInCache() const {
+ if (url.isEmpty() && !image.isNull()) {
+ url.setScheme(QStringLiteral("ItemGrabber"));
+ url.setPath(QVariant::fromValue(item.data()).toString());
+ static uint counter = 0;
+ url.setFragment(QString::number(++counter));
+ cacheEntry = new QQuickPixmap(url, image);
+ }
+ }
+
+ static QQuickItemGrabResult *create(QQuickItem *item, const QSize &size);
+
+ QImage image;
+
+ mutable QUrl url;
+ mutable QQuickPixmap *cacheEntry;
+
+ QQmlEngine *qmlEngine;
+ QJSValue callback;
+
+ QPointer<QQuickItem> item;
+ QPointer<QQuickWindow> window;
+ QQuickShaderEffectTexture *texture;
+ QSizeF itemSize;
+ QSize textureSize;
+};
+
+/*!
+ * \qmlproperty url QtQuick::ItemGrabResult::url
+ *
+ * This property holds a URL which can be used in conjunction with
+ * URL based image consumers, such as the QtQuick::Image type.
+ *
+ * The URL is valid while there is a reference in QML or JavaScript
+ * to the ItemGrabResult or while the image the URL references is
+ * actively used.
+ *
+ * The URL does not represent a valid file or location to read it from, it
+ * is primarily a key to access images through Qt Quick's image-based types.
+ */
+
+/*!
+ * \property QQuickItemGrabResult::url
+ *
+ * This property holds a URL which can be used in conjunction with
+ * URL based image consumers, such as the QtQuick::Image type.
+ *
+ * The URL is valid until the QQuickItemGrabResult object is deleted.
+ *
+ * The URL does not represent a valid file or location to read it from, it
+ * is primarily a key to access images through Qt Quick's image-based types.
+ */
+
+/*!
+ * \qmlproperty variant QtQuick::ItemGrabResult::image
+ *
+ * This property holds the pixel results from a grab in the
+ * form of a QImage.
+ */
+
+/*!
+ * \property QQuickItemGrabResult::image
+ *
+ * This property holds the pixel results from a grab.
+ *
+ * If the grab is not yet complete or if it failed,
+ * an empty image is returned.
+ */
+
+/*!
+ \class QQuickItemGrabResult
+ \inmodule QtQuick
+ \brief The QQuickItemGrabResult contains the result from QQuickItem::grabToImage().
+
+ \sa QQuickItem::grabToImage()
+ */
+
+/*!
+ * \fn void QQuickItemGrabResult::ready()
+ *
+ * This signal is emitted when the grab has completed.
+ */
+
+/*!
+ * \qmltype ItemGrabResult
+ * \instantiates QQuickItemGrabResult
+ * \inherits QtObject
+ * \inqmlmodule QtQuick
+ * \ingroup qtquick-visual
+ * \brief Contains the results from a call to Item::grabToImage().
+ *
+ * The ItemGrabResult is a small container used to encapsulate
+ * the results from Item::grabToImage().
+ *
+ * \sa Item::grabToImage()
+ */
+
+QQuickItemGrabResult::QQuickItemGrabResult(QObject *parent)
+ : QObject(*new QQuickItemGrabResultPrivate, parent)
+{
+}
+
+/*!
+ * \qmlmethod bool QtQuick::ItemGrabResult::saveToFile(fileName)
+ *
+ * Saves the grab result as an image to \a fileName. Returns true
+ * if successful; otherwise returns false.
+ */
+
+/*!
+ * Saves the grab result as an image to \a fileName. Returns true
+ * if successful; otherwise returns false.
+ */
+bool QQuickItemGrabResult::saveToFile(const QString &fileName)
+{
+ Q_D(QQuickItemGrabResult);
+ return d->image.save(fileName);
+}
+
+QUrl QQuickItemGrabResult::url() const
+{
+ Q_D(const QQuickItemGrabResult);
+ d->ensureImageInCache();
+ return d->url;
+}
+
+QImage QQuickItemGrabResult::image() const
+{
+ Q_D(const QQuickItemGrabResult);
+ return d->image;
+}
+
+/*!
+ * \internal
+ */
+bool QQuickItemGrabResult::event(QEvent *e)
+{
+ Q_D(QQuickItemGrabResult);
+ if (e->type() == Event_Grab_Completed) {
+ // JS callback
+ if (d->qmlEngine && d->callback.isCallable())
+ d->callback.call(QJSValueList() << d->qmlEngine->newQObject(this));
+ else
+ Q_EMIT ready();
+ return true;
+ }
+ return QObject::event(e);
+}
+
+void QQuickItemGrabResult::setup()
+{
+ Q_D(QQuickItemGrabResult);
+ if (!d->item) {
+ disconnect(d->window.data(), &QQuickWindow::beforeSynchronizing, this, &QQuickItemGrabResult::setup);
+ disconnect(d->window.data(), &QQuickWindow::afterRendering, this, &QQuickItemGrabResult::render);
+ QCoreApplication::postEvent(this, new QEvent(Event_Grab_Completed));
+ return;
+ }
+
+ d->texture = new QQuickShaderEffectTexture(d->item);
+ d->texture->setItem(QQuickItemPrivate::get(d->item)->itemNode());
+ d->itemSize = QSizeF(d->item->width(), d->item->height());
+}
+
+void QQuickItemGrabResult::render()
+{
+ Q_D(QQuickItemGrabResult);
+ if (!d->texture)
+ return;
+
+ d->texture->setRect(QRectF(0, d->itemSize.height(), d->itemSize.width(), -d->itemSize.height()));
+ QSGContext *sg = QSGRenderContext::from(QOpenGLContext::currentContext())->sceneGraphContext();
+ const QSize minSize = sg->minimumFBOSize();
+ d->texture->setSize(QSize(qMax(minSize.width(), d->textureSize.width()),
+ qMax(minSize.height(), d->textureSize.height())));
+ d->texture->scheduleUpdate();
+ d->texture->updateTexture();
+ d->image = d->texture->toImage();
+
+ delete d->texture;
+ d->texture = 0;
+
+ disconnect(d->window.data(), &QQuickWindow::beforeSynchronizing, this, &QQuickItemGrabResult::setup);
+ disconnect(d->window.data(), &QQuickWindow::afterRendering, this, &QQuickItemGrabResult::render);
+ QCoreApplication::postEvent(this, new QEvent(Event_Grab_Completed));
+}
+
+QQuickItemGrabResult *QQuickItemGrabResultPrivate::create(QQuickItem *item, const QSize &targetSize)
+{
+ QSize size = targetSize;
+ if (size.isEmpty())
+ size = QSize(item->width(), item->height());
+
+ if (size.width() < 1 || size.height() < 1) {
+ qWarning("Item::grabToImage: item has invalid dimensions");
+ return 0;
+ }
+
+ if (!item->window()) {
+ qWarning("Item::grabToImage: item is not attached to a window");
+ return 0;
+ }
+
+ if (!item->window()->isVisible()) {
+ qWarning("Item::grabToImage: item's window is not visible");
+ return 0;
+ }
+
+ QQuickItemGrabResult *result = new QQuickItemGrabResult();
+ QQuickItemGrabResultPrivate *d = result->d_func();
+ d->item = item;
+ d->window = item->window();
+ d->textureSize = size;
+
+ QQuickItemPrivate::get(item)->refFromEffectItem(false);
+
+ // trigger sync & render
+ item->window()->update();
+
+ return result;
+}
+
+/*!
+ * Grabs the item into an in-memory image.
+ *
+ * The grab happens asynchronously and the signal QQuickItemGrabResult::ready()
+ * is emitted when the grab has been completed.
+ *
+ * Use \a targetSize to specify the size of the target image. By default, the
+ * result will have the same size as item.
+ *
+ * If the grab could not be initiated, the function returns a \c null.
+ *
+ * \note This function will render the item to an offscreen surface and
+ * copy that surface from the GPU's memory into the CPU's memory, which can
+ * be quite costly. For "live" preview, use \l {QtQuick::Item::layer.enabled} {layers}
+ * or ShaderEffectSource.
+ *
+ * \sa QQuickWindow::grabWindow()
+ */
+QSharedPointer<QQuickItemGrabResult> QQuickItem::grabToImage(const QSize &targetSize)
+{
+ QQuickItemGrabResult *result = QQuickItemGrabResultPrivate::create(this, targetSize);
+ if (!result)
+ return QSharedPointer<QQuickItemGrabResult>();
+
+ connect(window(), &QQuickWindow::beforeSynchronizing, result, &QQuickItemGrabResult::setup, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::afterRendering, result, &QQuickItemGrabResult::render, Qt::DirectConnection);
+
+ return QSharedPointer<QQuickItemGrabResult>(result);
+}
+
+/*!
+ * \qmlmethod bool QtQuick::Item::grabToImage(callback, targetSize)
+ *
+ * Grabs the item into an in-memory image.
+ *
+ * The grab happens asynchronously and the JavaScript function \a callback is
+ * invoked when the grab is completed.
+ *
+ * Use \a targetSize to specify the size of the target image. By default, the result
+ * will have the same size as the item.
+ *
+ * If the grab could not be initiated, the function returns \c false.
+ *
+ * The following snippet shows how to grab an item and store the results to
+ * a file.
+ *
+ * \snippet qml/itemGrab.qml grab-source
+ * \snippet qml/itemGrab.qml grab-to-file
+ *
+ * The following snippet shows how to grab an item and use the results in
+ * another image element.
+ *
+ * \snippet qml/itemGrab.qml grab-image-target
+ * \snippet qml/itemGrab.qml grab-to-cache
+ *
+ * \note This function will render the item to an offscreen surface and
+ * copy that surface from the GPU's memory into the CPU's memory, which can
+ * be quite costly. For "live" preview, use \l {QtQuick::Item::layer.enabled} {layers}
+ * or ShaderEffectSource.
+ */
+
+/*!
+ * \internal
+ * Only visible from QML.
+ */
+bool QQuickItem::grabToImage(const QJSValue &callback, const QSize &targetSize)
+{
+ QQmlEngine *engine = qmlEngine(this);
+ if (!engine) {
+ qWarning("Item::grabToImage: no QML Engine");
+ return false;
+ }
+
+ if (!callback.isCallable()) {
+ qWarning("Item::grabToImage: 'callback' is not a function");
+ return false;
+ }
+
+ QSize size = targetSize;
+ if (size.isEmpty())
+ size = QSize(width(), height());
+
+ if (size.width() < 1 || size.height() < 1) {
+ qWarning("Item::grabToImage: item has invalid dimensions");
+ return false;
+ }
+
+ if (!window()) {
+ qWarning("Item::grabToImage: item is not attached to a window");
+ return false;
+ }
+
+ QQuickItemGrabResult *result = QQuickItemGrabResultPrivate::create(this, size);
+ if (!result)
+ return false;
+
+ connect(window(), &QQuickWindow::beforeSynchronizing, result, &QQuickItemGrabResult::setup, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::afterRendering, result, &QQuickItemGrabResult::render, Qt::DirectConnection);
+
+ QQuickItemGrabResultPrivate *d = result->d_func();
+ d->qmlEngine = engine;
+ d->callback = callback;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
new file mode 100644
index 0000000000..5297002bb8
--- /dev/null
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKITEMGRABRESULT_H
+#define QQUICKITEMGRABRESULT_H
+
+#include <QtCore/QObject>
+#include <QtCore/QSize>
+#include <QtCore/QUrl>
+#include <QtGui/QImage>
+#include <QtQml/QJSValue>
+#include <QtQuick/qtquickglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+
+class QQuickItemGrabResultPrivate;
+
+class Q_QUICK_EXPORT QQuickItemGrabResult : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickItemGrabResult)
+
+ Q_PROPERTY(QImage image READ image CONSTANT)
+ Q_PROPERTY(QUrl url READ url CONSTANT)
+public:
+ QImage image() const;
+ QUrl url() const;
+
+ Q_INVOKABLE bool saveToFile(const QString &fileName);
+
+protected:
+ bool event(QEvent *);
+
+Q_SIGNALS:
+ void ready();
+
+private Q_SLOTS:
+ void setup();
+ void render();
+
+private:
+ friend class QQuickItem;
+
+ QQuickItemGrabResult(QObject *parent = 0);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 10c1780799..b325158165 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -43,6 +43,7 @@
#include "qquickitem.h"
#include "qquickitem_p.h"
+#include "qquickitemgrabresult.h"
#include "qquickevents_p_p.h"
#include "qquickrectangle_p.h"
#include "qquickfocusscope_p.h"
@@ -82,6 +83,7 @@
#include "qquickdrag_p.h"
#include "qquickdroparea_p.h"
#include "qquickmultipointtoucharea_p.h"
+#include "qquickopenglinfo_p.h"
#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
@@ -183,8 +185,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
+ qmlRegisterType<QQuickTextInput,3>(uri,2,4,"TextInput");
qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
+ qmlRegisterType<QQuickItemGrabResult>();
qmlRegisterType<QQuickItemLayer>();
qmlRegisterType<QQuickAnchors>();
qmlRegisterType<QQuickKeyEvent>();
@@ -265,6 +269,12 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickText, 3>(uri, 2, 3, "Text");
qmlRegisterType<QQuickTextEdit, 3>(uri, 2, 3, "TextEdit");
qmlRegisterType<QQuickImage, 1>(uri, 2, 3,"Image");
+
+ qmlRegisterType<QQuickItem, 2>(uri, 2, 4, "Item");
+ qmlRegisterType<QQuickListView, 2>(uri, 2, 4, "ListView");
+ qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
+ qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
+ qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
}
static void initResources()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index ff8c69a9c0..2a686b4342 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -176,7 +176,7 @@ void QQuickItemViewChangeSet::applyChanges(const QQmlChangeSet &changeSet)
int moveId = -1;
int moveOffset = 0;
- foreach (const QQmlChangeSet::Remove &r, changeSet.removes()) {
+ foreach (const QQmlChangeSet::Change &r, changeSet.removes()) {
itemCount -= r.count;
if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
newCurrentIndex -= r.count;
@@ -195,7 +195,7 @@ void QQuickItemViewChangeSet::applyChanges(const QQmlChangeSet &changeSet)
currentChanged = true;
}
}
- foreach (const QQmlChangeSet::Insert &i, changeSet.inserts()) {
+ foreach (const QQmlChangeSet::Change &i, changeSet.inserts()) {
if (moveId == -1) {
if (itemCount && newCurrentIndex >= i.index) {
newCurrentIndex += i.count;
@@ -1038,7 +1038,7 @@ void QQuickItemViewPrivate::applyPendingChanges()
layout();
}
-int QQuickItemViewPrivate::findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Remove> &changes) const
+int QQuickItemViewPrivate::findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const
{
for (int i=0; i<changes.count(); i++) {
for (int j=changes[i].index; j<changes[i].index + changes[i].count; j++) {
@@ -1945,8 +1945,8 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
totalInsertionResult->visiblePos = prevViewPos;
totalRemovalResult->visiblePos = prevViewPos;
- const QVector<QQmlChangeSet::Remove> &removals = currentChanges.pendingChanges.removes();
- const QVector<QQmlChangeSet::Insert> &insertions = currentChanges.pendingChanges.inserts();
+ const QVector<QQmlChangeSet::Change> &removals = currentChanges.pendingChanges.removes();
+ const QVector<QQmlChangeSet::Change> &insertions = currentChanges.pendingChanges.inserts();
ChangeResult insertionResult(prevViewPos);
ChangeResult removalResult(prevViewPos);
@@ -1966,7 +1966,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
}
}
if (runDelayedRemoveTransition) {
- QQmlChangeSet::Remove removal;
+ QQmlChangeSet::Change removal;
for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end();) {
FxViewItem *item = *it;
if (item->index == -1 && !item->attached->delayRemove()) {
@@ -2063,7 +2063,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
return visibleAffected;
}
-bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Remove &removal, ChangeResult *removeResult, int *removedCount)
+bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *removeResult, int *removedCount)
{
Q_Q(QQuickItemView);
bool visibleAffected = false;
@@ -2113,7 +2113,7 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Remove &remo
return visibleAffected;
}
-void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QQmlChangeSet::Remove &removal, ChangeResult *removeResult)
+void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QQmlChangeSet::Change &removal, ChangeResult *removeResult)
{
if (removeResult->visiblePos.isValid()) {
if (item->position() < removeResult->visiblePos)
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 297b9a1471..7c8656cced 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -209,8 +209,8 @@ public:
void applyPendingChanges();
bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult);
- bool applyRemovalChange(const QQmlChangeSet::Remove &removal, ChangeResult *changeResult, int *removedCount);
- void removeItem(FxViewItem *item, const QQmlChangeSet::Remove &removal, ChangeResult *removeResult);
+ bool applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *changeResult, int *removedCount);
+ void removeItem(FxViewItem *item, const QQmlChangeSet::Change &removal, ChangeResult *removeResult);
virtual void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult);
void repositionFirstItem(FxViewItem *prevVisibleItemsFirst, qreal prevVisibleItemsFirstPos,
FxViewItem *prevFirstVisible, ChangeResult *insertionResult, ChangeResult *removalResult);
@@ -221,7 +221,7 @@ public:
bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds);
virtual void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item);
- int findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Remove> &changes) const;
+ int findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const;
void checkVisible() const;
void showVisibleItems() const;
@@ -350,7 +350,7 @@ protected:
virtual void layoutVisibleItems(int fromModelIndex = 0) = 0;
virtual void changedVisibleIndex(int newIndex) = 0;
- virtual bool applyInsertionChange(const QQmlChangeSet::Insert &insert, ChangeResult *changeResult,
+ virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult,
QList<FxViewItem *> *newItems, QList<MovedItem> *movingIntoView) = 0;
virtual bool needsRefillForAddedOrRemovedIndex(int) const { return false; }
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index e5b9f9cf59..1b268eccf3 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -107,7 +107,7 @@ public:
virtual void setPosition(qreal pos);
virtual void layoutVisibleItems(int fromModelIndex = 0);
- virtual bool applyInsertionChange(const QQmlChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
+ virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
virtual void updateSectionCriteria();
@@ -125,6 +125,8 @@ public:
virtual bool showFooterForIndex(int index) const;
virtual void updateHeader();
virtual void updateFooter();
+ bool hasStickyHeader() const;
+ bool hasStickyFooter() const;
virtual void changedVisibleIndex(int newIndex);
virtual void initializeCurrentItem();
@@ -143,6 +145,9 @@ public:
qreal spacing;
QQuickListView::SnapMode snapMode;
+ QQuickListView::HeaderPositioning headerPositioning;
+ QQuickListView::FooterPositioning footerPositioning;
+
QSmoothedAnimation *highlightPosAnimator;
QSmoothedAnimation *highlightWidthAnimator;
QSmoothedAnimation *highlightHeightAnimator;
@@ -170,6 +175,8 @@ public:
, visiblePos(0)
, averageSize(100.0), spacing(0.0)
, snapMode(QQuickListView::NoSnap)
+ , headerPositioning(QQuickListView::InlineHeader)
+ , footerPositioning(QQuickListView::InlineFooter)
, highlightPosAnimator(0), highlightWidthAnimator(0), highlightHeightAnimator(0)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
@@ -1048,6 +1055,9 @@ void QQuickListViewPrivate::updateStickySections()
bool isFlowReversed = isContentFlowReversed();
qreal viewPos = isFlowReversed ? -position()-size() : position();
+ qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
+ qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
+
QQuickItem *sectionItem = 0;
QQuickItem *lastSectionItem = 0;
int index = 0;
@@ -1059,18 +1069,18 @@ void QQuickListViewPrivate::updateStickySections()
qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
bool visTop = true;
if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
- visTop = isFlowReversed ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
+ visTop = isFlowReversed ? -sectionPos-sectionSize >= startPos : sectionPos >= startPos;
bool visBot = true;
if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
- visBot = isFlowReversed ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
+ visBot = isFlowReversed ? -sectionPos <= endPos : sectionPos + sectionSize < endPos;
section->setVisible(visBot && visTop);
if (visTop && !sectionItem)
sectionItem = section;
if (isFlowReversed) {
- if (-sectionPos <= viewPos + size())
+ if (-sectionPos <= endPos)
lastSectionItem = section;
} else {
- if (sectionPos + sectionSize < viewPos + size())
+ if (sectionPos + sectionSize < endPos)
lastSectionItem = section;
}
}
@@ -1092,14 +1102,14 @@ void QQuickListViewPrivate::updateStickySections()
qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
- currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
- qreal pos = isFlowReversed ? position() + size() - sectionSize : viewPos;
+ currentSectionItem->setVisible(!atBeginning && (!header || hasStickyHeader() || header->endPosition() < viewPos));
+ qreal pos = isFlowReversed ? position() + size() - sectionSize : startPos;
+ if (header)
+ pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
if (sectionItem) {
qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
}
- if (header)
- pos = isFlowReversed ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
if (footer)
pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
if (orient == QQuickListView::Vertical)
@@ -1125,13 +1135,15 @@ void QQuickListViewPrivate::updateStickySections()
qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
nextSectionItem->setVisible(!nextSection.isEmpty());
- qreal pos = isFlowReversed ? position() : viewPos + size() - sectionSize;
+ qreal pos = isFlowReversed ? position() : endPos - sectionSize;
+ if (footer)
+ pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
if (lastSectionItem) {
qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
}
if (header)
- pos = isFlowReversed ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
+ pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
if (orient == QQuickListView::Vertical)
nextSectionItem->setY(pos);
else
@@ -1192,12 +1204,11 @@ void QQuickListViewPrivate::updateCurrentSection()
return;
}
bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
- qreal sectionThreshold = position();
- if (currentSectionItem && !inlineSections)
- sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
+ qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
+ qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
int index = 0;
int modelIndex = visibleIndex;
- while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
+ while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= startPos) {
if (visibleItems.at(index)->index != -1)
modelIndex = visibleItems.at(index)->index;
++index;
@@ -1220,7 +1231,7 @@ void QQuickListViewPrivate::updateCurrentSection()
// section when that changes. Clearing lastVisibleSection will also
// force searching.
QString lastSection = currentSection;
- qreal endPos = isContentFlowReversed() ? -position() : position() + size();
+ qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
if (nextSectionItem && !inlineSections)
endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
@@ -1315,13 +1326,21 @@ void QQuickListViewPrivate::updateFooter()
FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
if (visibleItems.count()) {
- qreal endPos = lastPosition();
- if (findLastVisibleIndex() == model->count()-1) {
- listItem->setPosition(endPos);
+ if (footerPositioning == QQuickListView::OverlayFooter) {
+ listItem->setPosition(isContentFlowReversed() ? -position() - footerSize() : position() + size() - footerSize());
+ } else if (footerPositioning == QQuickListView::PullBackFooter) {
+ qreal viewPos = isContentFlowReversed() ? -position() : position() + size();
+ qreal clampedPos = qBound(originPosition() - footerSize() + size(), listItem->position(), lastPosition());
+ listItem->setPosition(qBound(viewPos - footerSize(), clampedPos, viewPos));
} else {
- qreal visiblePos = position() + q->height();
- if (endPos <= visiblePos || listItem->position() < endPos)
+ qreal endPos = lastPosition();
+ if (findLastVisibleIndex() == model->count()-1) {
listItem->setPosition(endPos);
+ } else {
+ qreal visiblePos = position() + q->height();
+ if (endPos <= visiblePos || listItem->position() < endPos)
+ listItem->setPosition(endPos);
+ }
}
} else {
listItem->setPosition(visiblePos);
@@ -1347,12 +1366,20 @@ void QQuickListViewPrivate::updateHeader()
FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
if (listItem) {
if (visibleItems.count()) {
- qreal startPos = originPosition();
- if (visibleIndex == 0) {
- listItem->setPosition(startPos - headerSize());
+ if (headerPositioning == QQuickListView::OverlayHeader) {
+ listItem->setPosition(isContentFlowReversed() ? -position() - size() : position());
+ } else if (headerPositioning == QQuickListView::PullBackHeader) {
+ qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
+ qreal clampedPos = qBound(originPosition() - headerSize(), listItem->position(), lastPosition() - headerSize() - size());
+ listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos));
} else {
- if (position() <= startPos || listItem->position() > startPos - headerSize())
+ qreal startPos = originPosition();
+ if (visibleIndex == 0) {
listItem->setPosition(startPos - headerSize());
+ } else {
+ if (position() <= startPos || listItem->position() > startPos - headerSize())
+ listItem->setPosition(startPos - headerSize());
+ }
}
} else {
listItem->setPosition(-headerSize());
@@ -1363,6 +1390,16 @@ void QQuickListViewPrivate::updateHeader()
emit q->headerItemChanged();
}
+bool QQuickListViewPrivate::hasStickyHeader() const
+{
+ return header && headerPositioning != QQuickListView::InlineHeader;
+}
+
+bool QQuickListViewPrivate::hasStickyFooter() const
+{
+ return footer && footerPositioning != QQuickListView::InlineFooter;
+}
+
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_Q(QQuickListView);
@@ -1378,6 +1415,8 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
// position all subsequent items
if (visibleItems.count() && item == visibleItems.first()->item) {
FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.first());
+ if (listItem->transitionScheduledOrRunning())
+ return;
if (orient == QQuickListView::Vertical) {
const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
qreal diff = newGeometry.height() - oldGeometry.height();
@@ -2441,6 +2480,80 @@ void QQuickListView::setSnapMode(SnapMode mode)
*/
/*!
+ \qmlproperty enumeration QtQuick::ListView::headerPositioning
+ \since Qt 5.4
+
+ This property determines the positioning of the \l{headerItem}{header item}.
+
+ The possible values are:
+ \list
+ \li ListView.InlineHeader (default) - the header is positioned in the beginning
+ of the content and moves together with the content like an ordinary item.
+ \li ListView.OverlayHeader - the header is positioned in the beginning of the view.
+ \li ListView.PullBackHeader - the header is positioned in the beginning of the view.
+ The header can be pushed away by moving the content forwards, and pulled back by
+ moving the content backwards.
+ \endlist
+*/
+QQuickListView::HeaderPositioning QQuickListView::headerPositioning() const
+{
+ Q_D(const QQuickListView);
+ return d->headerPositioning;
+}
+
+void QQuickListView::setHeaderPositioning(QQuickListView::HeaderPositioning positioning)
+{
+ Q_D(QQuickListView);
+ if (d->headerPositioning != positioning) {
+ d->applyPendingChanges();
+ d->headerPositioning = positioning;
+ if (isComponentComplete()) {
+ d->updateHeader();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit headerPositioningChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::ListView::footerPositioning
+ \since Qt 5.4
+
+ This property determines the positioning of the \l{footerItem}{footer item}.
+
+ The possible values are:
+ \list
+ \li ListView.InlineFooter (default) - the footer is positioned in the end
+ of the content and moves together with the content like an ordinary item.
+ \li ListView.OverlayFooter - the footer is positioned in the end of the view.
+ \li ListView.PullBackFooter - the footer is positioned in the end of the view.
+ The footer can be pushed away by moving the content backwards, and pulled back by
+ moving the content forwards.
+ \endlist
+*/
+QQuickListView::FooterPositioning QQuickListView::footerPositioning() const
+{
+ Q_D(const QQuickListView);
+ return d->footerPositioning;
+}
+
+void QQuickListView::setFooterPositioning(QQuickListView::FooterPositioning positioning)
+{
+ Q_D(QQuickListView);
+ if (d->footerPositioning != positioning) {
+ d->applyPendingChanges();
+ d->footerPositioning = positioning;
+ if (isComponentComplete()) {
+ d->updateFooter();
+ d->updateViewport();
+ d->fixupPosition();
+ }
+ emit footerPositioningChanged();
+ }
+}
+
+/*!
\qmlproperty Transition QtQuick::ListView::populate
This property holds the transition to apply to the items that are initially created
@@ -2814,6 +2927,10 @@ void QQuickListView::viewportMoved(Qt::Orientations orient)
}
d->inFlickCorrection = false;
}
+ if (d->hasStickyHeader())
+ d->updateHeader();
+ if (d->hasStickyFooter())
+ d->updateFooter();
if (d->sectionCriteria) {
d->updateCurrentSection();
d->updateStickySections();
@@ -2940,7 +3057,7 @@ void QQuickListViewPrivate::updateSectionCriteria()
}
}
-bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
+bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
{
int modelIndex = change.index;
int count = change.count;
diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h
index 2494e101cd..3e799b05e3 100644
--- a/src/quick/items/qquicklistview_p.h
+++ b/src/quick/items/qquicklistview_p.h
@@ -111,8 +111,13 @@ class Q_AUTOTEST_EXPORT QQuickListView : public QQuickItemView
Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+ Q_PROPERTY(HeaderPositioning headerPositioning READ headerPositioning WRITE setHeaderPositioning NOTIFY headerPositioningChanged REVISION 2)
+ Q_PROPERTY(FooterPositioning footerPositioning READ footerPositioning WRITE setFooterPositioning NOTIFY footerPositioningChanged REVISION 2)
+
Q_ENUMS(Orientation)
Q_ENUMS(SnapMode)
+ Q_ENUMS(HeaderPositioning)
+ Q_ENUMS(FooterPositioning)
Q_CLASSINFO("DefaultProperty", "data")
public:
@@ -146,6 +151,14 @@ public:
SnapMode snapMode() const;
void setSnapMode(SnapMode mode);
+ enum HeaderPositioning { InlineHeader, OverlayHeader, PullBackHeader };
+ HeaderPositioning headerPositioning() const;
+ void setHeaderPositioning(HeaderPositioning positioning);
+
+ enum FooterPositioning { InlineFooter, OverlayFooter, PullBackFooter };
+ FooterPositioning footerPositioning() const;
+ void setFooterPositioning(FooterPositioning positioning);
+
static QQuickListViewAttached *qmlAttachedProperties(QObject *);
public Q_SLOTS:
@@ -160,6 +173,8 @@ Q_SIGNALS:
void highlightResizeVelocityChanged();
void highlightResizeDurationChanged();
void snapModeChanged();
+ Q_REVISION(2) void headerPositioningChanged();
+ Q_REVISION(2) void footerPositioningChanged();
protected:
virtual void viewportMoved(Qt::Orientations orient);
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index bac52f04f8..d0c362456f 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -483,6 +483,10 @@ qreal QQuickMouseArea::mouseY() const
\qmlproperty bool QtQuick::MouseArea::enabled
This property holds whether the item accepts mouse events.
+ \note Due to historical reasons, this property is not equivalent to
+ Item.enabled. It only affects mouse events, and its effect does not
+ propagate to child items.
+
By default, this property is true.
*/
bool QQuickMouseArea::isEnabled() const
@@ -719,7 +723,9 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
|| QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold()))) {
setKeepMouseGrab(true);
d->stealMouse = true;
- d->startScene = event->windowPos();
+
+ if (d->drag->smoothed())
+ d->startScene = event->windowPos();
}
d->moved = true;
@@ -854,6 +860,7 @@ void QQuickMouseArea::ungrabMouse()
emit canceled();
emit pressedChanged();
+ emit containsPressChanged();
emit pressedButtonsChanged();
if (d->hovered && !isUnderMouse()) {
@@ -911,6 +918,7 @@ bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
ungrabMouse();
emit canceled();
emit pressedChanged();
+ emit containsPressChanged();
if (d->hovered) {
d->hovered = false;
emit hoveredChanged();
@@ -1056,6 +1064,24 @@ bool QQuickMouseArea::pressed() const
return d->pressed;
}
+/*!
+ \qmlproperty bool QtQuick::MouseArea::containsPress
+ \since 5.4
+ This is a convenience property equivalent to \c {pressed && containsMouse},
+ i.e. it holds whether any of the \l acceptedButtons are currently pressed
+ and the mouse is currently within the MouseArea.
+
+ This property is particularly useful for highlighting an item while the mouse
+ is pressed within its bounds.
+
+ \sa pressed, containsMouse
+*/
+bool QQuickMouseArea::containsPress() const
+{
+ Q_D(const QQuickMouseArea);
+ return d->pressed && d->hovered;
+}
+
void QQuickMouseArea::setHovered(bool h)
{
Q_D(QQuickMouseArea);
@@ -1063,6 +1089,8 @@ void QQuickMouseArea::setHovered(bool h)
d->hovered = h;
emit hoveredChanged();
d->hovered ? emit entered() : emit exited();
+ if (d->pressed)
+ emit containsPressChanged();
}
}
@@ -1122,15 +1150,19 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p)
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
emit mouseYChanged(&me);
- if (!oldPressed)
+ if (!oldPressed) {
emit pressedChanged();
+ emit containsPressChanged();
+ }
emit pressedButtonsChanged();
} else {
d->pressed &= ~button;
emit released(&me);
me.setPosition(d->lastPos);
- if (!d->pressed)
+ if (!d->pressed) {
emit pressedChanged();
+ emit containsPressChanged();
+ }
emit pressedButtonsChanged();
if (isclick && !d->longPress && !d->doubleClick){
me.setAccepted(d->isClickConnected());
@@ -1246,6 +1278,10 @@ void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
start. By default this is bound to a platform dependent value. This property was added in
Qt Quick 2.2.
+ If \c drag.smoothed is \c true, the target will be moved only after the drag operation has
+ started. If set to \c false, the target will be moved straight to the current mouse position.
+ By default, this property is \c true. This property was added in Qt Quick 2.4
+
\snippet qml/mousearea/mouseareadragfilter.qml dragfilter
*/
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index 1ffa95771b..5dcb6b46a4 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -73,6 +73,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
#ifndef QT_NO_CURSOR
Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET unsetCursor NOTIFY cursorShapeChanged)
#endif
+ Q_PROPERTY(bool containsPress READ containsPress NOTIFY containsPressChanged REVISION 1)
public:
QQuickMouseArea(QQuickItem *parent=0);
@@ -86,6 +87,7 @@ public:
bool hovered() const;
bool pressed() const;
+ bool containsPress() const;
Qt::MouseButtons pressedButtons() const;
@@ -135,6 +137,7 @@ Q_SIGNALS:
void entered();
void exited();
void canceled();
+ Q_REVISION(1) void containsPressChanged();
protected:
void setHovered(bool);
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index ee31c018af..f09c761ff3 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -349,7 +349,6 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
: QQuickItem(parent),
_minimumTouchPoints(0),
_maximumTouchPoints(INT_MAX),
- _mouseTouchPoint(Q_NULLPTR),
_stealMouse(false),
_mouseEnabled(true)
{
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 9dbca2be54..a6bb6ba81d 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -45,6 +45,7 @@
#include "qquickitem.h"
#include "qevent.h"
+#include <QPointer>
#include <QMap>
#include <QList>
#include <QtGui/qguiapplication.h>
@@ -271,7 +272,7 @@ private:
QList<QObject*> _movedTouchPoints;
int _minimumTouchPoints;
int _maximumTouchPoints;
- QQuickTouchPoint *_mouseTouchPoint; // exists when mouse button is down and _mouseEnabled is true; null otherwise
+ QPointer<QQuickTouchPoint> _mouseTouchPoint; // exists when mouse button is down and _mouseEnabled is true; null otherwise
QTouchEvent::TouchPoint _mouseQpaTouchPoint; // synthetic QPA touch point to hold state and position of the mouse
QPointF _mousePos;
bool _stealMouse;
diff --git a/src/quick/items/qquickopenglinfo.cpp b/src/quick/items/qquickopenglinfo.cpp
new file mode 100644
index 0000000000..dbaa92abe1
--- /dev/null
+++ b/src/quick/items/qquickopenglinfo.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Ltd.
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickopenglinfo_p.h"
+#include "qopenglcontext.h"
+#include "qquickwindow.h"
+#include "qquickitem.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype OpenGLInfo
+ \instantiates QQuickOpenGLInfo
+ \inqmlmodule QtQuick
+ \ingroup qtquick-effects
+ \since 5.4
+ \brief Provides information about the used OpenGL version
+
+ The OpenGLInfo attached type provides information about the OpenGL
+ version being used to render the surface of the attachee item.
+
+ If the attachee item is not currently associated with any graphical
+ surface, the properties are set to the values of the default surface
+ format. When it becomes associated with a surface, all properties
+ will update.
+
+ \sa ShaderEffect
+ */
+QQuickOpenGLInfo::QQuickOpenGLInfo(QQuickItem *item)
+ : QObject(item)
+ , m_window(0)
+ , m_majorVersion(2)
+ , m_minorVersion(0)
+ , m_profile(NoProfile)
+ , m_renderableType(Unspecified)
+{
+ connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(setWindow(QQuickWindow*)));
+ setWindow(item->window());
+}
+
+/*!
+ \qmlproperty int QtQuick::OpenGLInfo::majorVersion
+
+ This property holds the major OpenGL version.
+
+ The default version is \c 2.0.
+
+ \sa minorVersion, profile
+ */
+int QQuickOpenGLInfo::majorVersion() const
+{
+ return m_majorVersion;
+}
+
+/*!
+ \qmlproperty int QtQuick::OpenGLInfo::minorVersion
+
+ This property holds the minor OpenGL version.
+
+ The default version is \c 2.0.
+
+ \sa majorVersion, profile
+ */
+int QQuickOpenGLInfo::minorVersion() const
+{
+ return m_minorVersion;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::OpenGLInfo::profile
+
+ This property holds the configured OpenGL context profile.
+
+ The possible values are:
+ \list
+ \li OpenGLInfo.NoProfile (default) - OpenGL version is lower than 3.2.
+ \li OpenGLInfo.CoreProfile - Functionality deprecated in OpenGL version 3.0 is not available.
+ \li OpenGLInfo.CompatibilityProfile - Functionality from earlier OpenGL versions is available.
+ \endlist
+
+ Reusable QML components will typically use this property in bindings in order to
+ choose between core and non core profile compatible shader sources.
+
+ \sa majorVersion, minorVersion
+ */
+QQuickOpenGLInfo::ContextProfile QQuickOpenGLInfo::profile() const
+{
+ return m_profile;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::OpenGLInfo::renderableType
+
+ This property holds the renderable type.
+
+ The possible values are:
+ \list
+ \li OpenGLInfo.Unspecified (default) - Unspecified rendering method
+ \li OpenGLInfo.OpenGL - Desktop OpenGL rendering
+ \li OpenGLInfo.OpenGLES - OpenGL ES rendering
+ \endlist
+ */
+QQuickOpenGLInfo::RenderableType QQuickOpenGLInfo::renderableType() const
+{
+ return m_renderableType;
+}
+
+QQuickOpenGLInfo *QQuickOpenGLInfo::qmlAttachedProperties(QObject *object)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
+ return new QQuickOpenGLInfo(item);
+ return 0;
+}
+
+void QQuickOpenGLInfo::updateFormat()
+{
+ QOpenGLContext *context = 0;
+ if (m_window)
+ context = m_window->openglContext();
+ QSurfaceFormat format = context ? context->format() : QSurfaceFormat::defaultFormat();
+
+ if (m_majorVersion != format.majorVersion()) {
+ m_majorVersion = format.majorVersion();
+ emit majorVersionChanged();
+ }
+
+ if (m_minorVersion != format.minorVersion()) {
+ m_minorVersion = format.minorVersion();
+ emit minorVersionChanged();
+ }
+
+ ContextProfile profile = static_cast<ContextProfile>(format.profile());
+ if (m_profile != profile) {
+ m_profile = profile;
+ emit profileChanged();
+ }
+
+ RenderableType renderableType = static_cast<RenderableType>(format.renderableType());
+ if (m_renderableType != renderableType) {
+ m_renderableType = renderableType;
+ emit renderableTypeChanged();
+ }
+}
+
+void QQuickOpenGLInfo::setWindow(QQuickWindow *window)
+{
+ if (m_window != window) {
+ if (m_window) {
+ disconnect(m_window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateFormat()));
+ disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateFormat()));
+ }
+ if (window) {
+ connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateFormat()));
+ connect(window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateFormat()));
+ }
+ m_window = window;
+ }
+ updateFormat();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickopenglinfo_p.h b/src/quick/items/qquickopenglinfo_p.h
new file mode 100644
index 0000000000..70684a2f40
--- /dev/null
+++ b/src/quick/items/qquickopenglinfo_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 BlackBerry Ltd.
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKOPENGLINFO_P_H
+#define QQUICKOPENGLINFO_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 <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickWindow;
+
+class QQuickOpenGLInfo : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int majorVersion READ majorVersion NOTIFY majorVersionChanged FINAL)
+ Q_PROPERTY(int minorVersion READ minorVersion NOTIFY minorVersionChanged FINAL)
+ Q_PROPERTY(ContextProfile profile READ profile NOTIFY profileChanged FINAL)
+ Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL)
+ Q_ENUMS(ContextProfile RenderableType)
+
+public:
+ QQuickOpenGLInfo(QQuickItem *item = 0);
+
+ int majorVersion() const;
+ int minorVersion() const;
+
+ // keep in sync with QSurfaceFormat::OpenGLContextProfile
+ enum ContextProfile {
+ NoProfile = QSurfaceFormat::NoProfile,
+ CoreProfile = QSurfaceFormat::CoreProfile,
+ CompatibilityProfile = QSurfaceFormat::CompatibilityProfile
+ };
+ ContextProfile profile() const;
+
+ // keep in sync with QSurfaceFormat::RenderableType
+ enum RenderableType {
+ Unspecified = QSurfaceFormat::DefaultRenderableType,
+ OpenGL = QSurfaceFormat::OpenGL,
+ OpenGLES = QSurfaceFormat::OpenGLES
+ };
+ RenderableType renderableType() const;
+
+ static QQuickOpenGLInfo *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void majorVersionChanged();
+ void minorVersionChanged();
+ void profileChanged();
+ void renderableTypeChanged();
+
+private Q_SLOTS:
+ void updateFormat();
+ void setWindow(QQuickWindow *window);
+
+private:
+ QPointer<QQuickWindow> m_window;
+ int m_majorVersion;
+ int m_minorVersion;
+ ContextProfile m_profile;
+ RenderableType m_renderableType;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QQuickOpenGLInfo, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKOPENGLINFO_P_H
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 601618d05e..216b7cc7c1 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -2050,7 +2050,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
int moveOffset = 0;
bool currentChanged = false;
bool changedOffset = false;
- foreach (const QQmlChangeSet::Remove &r, changeSet.removes()) {
+ foreach (const QQmlChangeSet::Change &r, changeSet.removes()) {
if (moveId == -1 && d->currentIndex >= r.index + r.count) {
d->currentIndex -= r.count;
currentChanged = true;
@@ -2076,7 +2076,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
}
d->modelCount -= r.count;
}
- foreach (const QQmlChangeSet::Insert &i, changeSet.inserts()) {
+ foreach (const QQmlChangeSet::Change &i, changeSet.inserts()) {
if (d->modelCount) {
if (moveId == -1 && i.index <= d->currentIndex) {
d->currentIndex += i.count;
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 1f00e6a74d..d8478806c6 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -268,8 +268,6 @@ QQuickPinchArea::QQuickPinchArea(QQuickItem *parent)
{
Q_D(QQuickPinchArea);
d->init();
- setAcceptedMouseButtons(Qt::LeftButton);
- setFiltersChildMouseEvents(true);
#ifdef Q_OS_OSX
setAcceptHoverEvents(true); // needed to enable touch events on mouse hover.
#endif
@@ -320,7 +318,6 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
// it's always going to accept the touches, and that means the item underneath
// will not get them (unless the PA's parent is doing parent filtering,
// as the Flickable does, for example).
-
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
@@ -333,18 +330,52 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
updatePinch();
break;
case QEvent::TouchEnd:
- d->touchPoints.clear();
- updatePinch();
+ clearPinch();
break;
default:
QQuickItem::event(event);
}
}
+void QQuickPinchArea::clearPinch()
+{
+ Q_D(QQuickPinchArea);
+
+ d->touchPoints.clear();
+ if (d->inPinch) {
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QQuickPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(pinchCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(mapFromScene(d->lastPoint1));
+ pe.setPoint2(mapFromScene(d->lastPoint2));
+ emit pinchFinished(&pe);
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ d->pinchStartDist = 0;
+ d->pinchActivated = false;
+ d->initPinch = false;
+ d->pinchRejected = false;
+ d->stealMouse = false;
+ d->id1 = -1;
+ QQuickWindow *win = window();
+ if (win && win->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+}
+
void QQuickPinchArea::updatePinch()
{
Q_D(QQuickPinchArea);
+ QQuickWindow *win = window();
+
if (d->touchPoints.count() < 2) {
setKeepMouseGrab(false);
QQuickWindow *c = window();
@@ -379,6 +410,13 @@ void QQuickPinchArea::updatePinch()
QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
+
+ if (touchPoint1.state() == Qt::TouchPointPressed)
+ d->sceneStartPoint1 = touchPoint1.scenePos();
+
+ if (touchPoint2.state() == Qt::TouchPointPressed)
+ d->sceneStartPoint2 = touchPoint2.scenePos();
+
QRectF bounds = clipRect();
// Pinch is not started unless there are exactly two touch points
// AND one or more of the points has just now been pressed (wasn't pressed already)
@@ -387,10 +425,15 @@ void QQuickPinchArea::updatePinch()
&& (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed) &&
bounds.contains(touchPoint1.pos()) && bounds.contains(touchPoint2.pos())) {
d->id1 = touchPoint1.id();
- d->sceneStartPoint1 = touchPoint1.scenePos();
- d->sceneStartPoint2 = touchPoint2.scenePos();
d->pinchActivated = true;
d->initPinch = true;
+
+ int touchMouseId = QQuickWindowPrivate::get(win)->touchMouseId;
+ if (touchPoint1.id() == touchMouseId || touchPoint2.id() == touchMouseId) {
+ if (win && win->mouseGrabberItem() != this) {
+ grabMouse();
+ }
+ }
}
if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = qApp->styleHints()->startDragDistance();
@@ -449,10 +492,12 @@ void QQuickPinchArea::updatePinch()
if (pe.accepted()) {
d->inPinch = true;
d->stealMouse = true;
- QQuickWindow *c = window();
- if (c && c->mouseGrabberItem() != this)
+ if (win && win->mouseGrabberItem() != this)
grabMouse();
setKeepMouseGrab(true);
+ grabTouchPoints(QVector<int>() << touchPoint1.id() << touchPoint2.id());
+ d->inPinch = true;
+ d->stealMouse = true;
if (d->pinch && d->pinch->target()) {
d->pinchStartPos = pinch()->target()->position();
d->pinchStartScale = d->pinch->target()->scale();
@@ -528,22 +573,19 @@ bool QQuickPinchArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
return QQuickItem::childMouseEventFilter(i, e);
switch (e->type()) {
case QEvent::TouchBegin:
+ clearPinch(); // fall through
case QEvent::TouchUpdate: {
- QTouchEvent *touch = static_cast<QTouchEvent*>(e);
- if (touch->touchPoints().count() > 1) {
- touchEvent(touch);
- } else {
- d->touchPoints.clear();
- for (int i = 0; i < touch->touchPoints().count(); ++i)
- if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
- d->touchPoints << touch->touchPoints().at(i);
- updatePinch();
- }
+ QTouchEvent *touch = static_cast<QTouchEvent*>(e);
+ d->touchPoints.clear();
+ for (int i = 0; i < touch->touchPoints().count(); ++i)
+ if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
+ d->touchPoints << touch->touchPoints().at(i);
+ updatePinch();
}
+ e->setAccepted(d->inPinch);
return d->inPinch;
case QEvent::TouchEnd:
- d->touchPoints.clear();
- updatePinch();
+ clearPinch();
break;
default:
break;
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index 81bdbda3a1..7f2a379a8f 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -289,6 +289,7 @@ protected:
#endif
private:
+ void clearPinch();
void updatePinch();
void handlePress();
void handleRelease();
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index 0ef871be43..6236f0047b 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -305,6 +305,8 @@ void QQuickBasePositioner::prePositioning()
for (int ii = 0; ii < children.count(); ++ii) {
QQuickItem *child = children.at(ii);
+ if (QQuickItemPrivate::get(child)->isTransparentForPositioner())
+ continue;
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
PositionedItem posItem(child);
int wIdx = oldItems.find(posItem);
@@ -1038,7 +1040,7 @@ void QQuickRow::reportConflictingAnchors()
\image gridLayout_example.png
- If an item within a Column is not \l {Item::}{visible}, or if it has a width or
+ If an item within a Grid is not \l {Item::}{visible}, or if it has a width or
height of 0, the item will not be laid out and it will not be visible within the
column. Also, since a Grid automatically positions its children, a child
item within a Grid should not set its \l {Item::x}{x} or \l {Item::y}{y} positions
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index e28669ceb3..f3e51649c6 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include "qquickrendercontrol.h"
#include "qquickrendercontrol_p.h"
#include <QtCore/QCoreApplication>
@@ -53,7 +54,6 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
-#include <QtQuick/private/qsgcontext_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <QtCore/private/qobject_p.h>
@@ -61,59 +61,139 @@ QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-class QQuickRenderControlPrivate : public QObjectPrivate
-{
-public:
- QQuickRenderControlPrivate()
- : window(0)
- {
- sg = QSGContext::createDefaultContext();
- rc = new QSGRenderContext(sg);
- }
+/*!
+ \class QQuickRenderControl
- ~QQuickRenderControlPrivate()
- {
- delete rc;
- delete sg;
- }
+ \brief The QQuickRenderControl class provides a mechanism for rendering the Qt
+ Quick scenegraph onto an offscreen render target in a fully
+ application-controlled manner.
- QQuickWindow *window;
- QSGContext *sg;
- QSGRenderContext *rc;
-};
+ \since 5.4
-/*!
- \class QQuickRenderControl
- \brief The QQuickRenderControl class provides a mechanism for rendering the Qt Quick scenegraph.
+ QQuickWindow and QQuickView and their associated internal render loops render
+ the Qt Quick scene onto a native window. In some cases, for example when
+ integrating with 3rd party OpenGL renderers, it might be beneficial to get the
+ scene into a texture that can then be used in arbitrary ways by the external
+ rendering engine. QQuickRenderControl makes this possible in a hardware
+ accelerated manner, unlike the performance-wise limited alternative of using
+ QQuickWindow::grabWindow()
+
+ When using a QQuickRenderControl, the QQuickWindow does not have to be shown
+ or even created at all. This means there will not be an underlying native
+ window for it. Instead, the QQuickWindow instance is associated with the
+ render control, using the overload of the QQuickWindow constructor, and an
+ OpenGL framebuffer object by calling QQuickWindow::setRenderTarget().
+
+ Management of the context and framebuffer object is up to the application. The
+ context that will be used by Qt Quick must be created before calling
+ initialize(). The creation of the framebuffer object can be deferred, see
+ below. Qt 5.4 introduces the ability for QOpenGLContext to adopt existing
+ native contexts. Together with QQuickRenderControl this makes it possible to
+ create a QOpenGLContext that shares with an external rendering engine's
+ existing context. This new QOpenGLContext can then be used to render the Qt
+ Quick scene into a texture that is accessible by the other engine's context
+ too.
+
+ Loading and instantiation of the QML components happen by using a
+ QQmlEngine. Once the root object is created, it will need to be parented to
+ the QQuickWindow's contentItem().
- \internal
+ Applications will usually have to connect to 4 important signals:
+
+ \list
+
+ \li QQuickWindow::sceneGraphInitialized() Emitted at some point after calling
+ QQuickRenderControl::initialize(). Upon this signal, the application is
+ expected to create its framebuffer object and associate it with the
+ QQuickWindow.
+
+ \li QQuickWindow::sceneGraphInvalidated() When the scenegraph resources are
+ released, the framebuffer object can be destroyed too.
+
+ \li QQuickRenderControl::renderRequested() Indicates that the scene has to be
+ rendered by calling render(). After making the context current, applications
+ are expected to call render().
+
+ \li QQuickRenderControl::sceneChanged() Inidcates that the scene has changed
+ meaning that, before rendering, polishing and synchronizing is also necessary.
+
+ \endlist
+
+ To send events, for example mouse or keyboard events, to the scene, use
+ QCoreApplication::sendEvent() with the QQuickWindow instance as the receiver.
\inmodule QtQuick
*/
-QQuickRenderControl::QQuickRenderControl()
- : QObject(*(new QQuickRenderControlPrivate), 0)
+QSGContext *QQuickRenderControlPrivate::sg = 0;
+
+QQuickRenderControlPrivate::QQuickRenderControlPrivate()
+ : initialized(0),
+ window(0)
+{
+ if (!sg) {
+ qAddPostRoutine(cleanup);
+ sg = QSGContext::createDefaultContext();
+ }
+ rc = new QSGRenderContext(sg);
+}
+
+QQuickRenderControlPrivate::~QQuickRenderControlPrivate()
{
+ delete rc;
}
-QQuickRenderControl::~QQuickRenderControl()
+void QQuickRenderControlPrivate::cleanup()
+{
+ delete sg;
+ sg = 0;
+}
+
+QQuickRenderControl::QQuickRenderControl(QObject *parent)
+ : QObject(*(new QQuickRenderControlPrivate), parent)
{
}
-void QQuickRenderControl::windowDestroyed()
+/*!
+ Destroys the instance. Releases all scenegraph resources.
+
+ \sa invalidate()
+ */
+QQuickRenderControl::~QQuickRenderControl()
{
Q_D(QQuickRenderControl);
- if (d->window == 0) {
- d->rc->invalidate();
+
+ invalidate();
+
+ if (d->window)
+ QQuickWindowPrivate::get(d->window)->renderControl = 0;
+}
+
+void QQuickRenderControlPrivate::windowDestroyed()
+{
+ if (window == 0) {
+ rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
}
}
+/*!
+ Initializes the scene graph resources. The context \a gl has to
+ be the current context.
+ */
void QQuickRenderControl::initialize(QOpenGLContext *gl)
{
Q_D(QQuickRenderControl);
- if (!d->window)
+
+ if (!d->window) {
+ qWarning("QQuickRenderControl::initialize called with no associated window");
return;
+ }
+
+ if (QOpenGLContext::currentContext() != gl) {
+ qWarning("QQuickRenderControl::initialize called with incorrect current context");
+ return;
+ }
// It is the caller's responsiblity to make a context/surface current.
// It cannot be done here since the surface to use may not be the
@@ -121,11 +201,14 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// window/surface at all.
d->rc->initialize(gl);
+
+ d->initialized = true;
}
/*!
This function should be called as late as possible before
- sync(). In a threaded scenario, rendering can happen in parallel with this function.
+ sync(). In a threaded scenario, rendering can happen in parallel
+ with this function.
*/
void QQuickRenderControl::polishItems()
{
@@ -134,13 +217,20 @@ void QQuickRenderControl::polishItems()
return;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ cd->flushDelayedTouchEvent();
+ if (!d->window)
+ return;
cd->polishItems();
}
/*!
- Synchronize GUI and scenegraph. Returns true if the scene graph was changed.
+ This function is used to synchronize the QML scene with the rendering scene
+ graph.
+
+ If a dedicated render thread is used, the GUI thread should be blocked for the
+ duration of this call.
- This function is a synchronization point. Rendering can not happen in parallel.
+ \return \e true if the synchronization changed the scene graph.
*/
bool QQuickRenderControl::sync()
{
@@ -156,12 +246,31 @@ bool QQuickRenderControl::sync()
}
/*!
- Stop rendering and release resources. This function is typically
- called when the window is hidden. Requires a current context.
+ Stop rendering and release resources. Requires a current context.
+
+ This is the equivalent of the cleanup operations that happen with a
+ real QQuickWindow when the window becomes hidden.
+
+ This function is called from the destructor. Therefore there will
+ typically be no need to call it directly. Pay attention however to
+ the fact that this requires the context, that was passed to
+ initialize(), to be the current one at the time of destroying the
+ QQuickRenderControl instance.
+
+ Once invalidate() has been called, it is possible to reuse the
+ QQuickRenderControl instance by calling initialize() again.
+
+ \note This function does not take
+ QQuickWindow::persistentSceneGraph() or
+ QQuickWindow::persistentOpenGLContext() into account. This means
+ that context-specific resources are always released.
*/
void QQuickRenderControl::invalidate()
{
Q_D(QQuickRenderControl);
+ if (!d->initialized)
+ return;
+
if (!d->window)
return;
@@ -174,10 +283,12 @@ void QQuickRenderControl::invalidate()
// also essential to allow a subsequent initialize() to succeed.
d->rc->invalidate();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+
+ d->initialized = false;
}
/*!
- Render the scenegraph using the current context.
+ Renders the scenegraph using the current context.
*/
void QQuickRenderControl::render()
{
@@ -189,7 +300,6 @@ void QQuickRenderControl::render()
cd->renderSceneGraph(d->window->size());
}
-
/*!
\fn void QQuickRenderControl::renderRequested()
@@ -204,7 +314,11 @@ void QQuickRenderControl::render()
true, then render() needs to be called.
*/
+/*!
+ Grabs the contents of the scene and returns it as an image.
+ \note Requires the context to be current.
+ */
QImage QQuickRenderControl::grab()
{
Q_D(QQuickRenderControl);
@@ -216,47 +330,16 @@ QImage QQuickRenderControl::grab()
return grabContent;
}
-QSGContext *QQuickRenderControl::sceneGraphContext() const
-{
- Q_D(const QQuickRenderControl);
- return d->sg;
-}
-
-QSGRenderContext *QQuickRenderControl::renderContext(QSGContext *) const
-{
- Q_D(const QQuickRenderControl);
- return d->rc;
-}
-
-void QQuickRenderControl::setWindow(QQuickWindow *window)
-{
- Q_D(QQuickRenderControl);
- d->window = window;
-}
-
-/*!
- Returns the offscreen window.
- */
-
-QQuickWindow *QQuickRenderControl::window() const
+void QQuickRenderControlPrivate::update()
{
- Q_D(const QQuickRenderControl);
- return d->window;
+ Q_Q(QQuickRenderControl);
+ emit q->renderRequested();
}
-/*!
- Create an offscreen QQuickWindow for this render control,
- unless the render control already has a window().
-
- Returns the offscreen window if one is created, otherwise returns null.
- The caller takes ownership of the window, and is responsible for deleting it.
- */
-QQuickWindow *QQuickRenderControl::createOffscreenWindow()
+void QQuickRenderControlPrivate::maybeUpdate()
{
- Q_D(QQuickRenderControl);
- if (!d->window)
- return new QQuickWindow(this);
- return 0;
+ Q_Q(QQuickRenderControl);
+ emit q->sceneChanged();
}
/*!
@@ -276,7 +359,6 @@ QQuickWindow *QQuickRenderControl::createOffscreenWindow()
inside its window.
*/
-
QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
{
if (!win)
@@ -287,6 +369,4 @@ QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
return 0;
}
-
-
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
new file mode 100644
index 0000000000..c3e5380af3
--- /dev/null
+++ b/src/quick/items/qquickrendercontrol.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRENDERCONTROL_H
+#define QQUICKRENDERCONTROL_H
+
+#include <QtQuick/qtquickglobal.h>
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickWindow;
+class QOpenGLContext;
+class QQuickRenderControlPrivate;
+
+class Q_QUICK_EXPORT QQuickRenderControl : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickRenderControl(QObject *parent = 0);
+ ~QQuickRenderControl();
+
+ void initialize(QOpenGLContext *gl);
+ void invalidate();
+
+ void polishItems();
+ void render();
+ bool sync();
+
+ QImage grab();
+
+ static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
+ virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
+
+Q_SIGNALS:
+ void renderRequested();
+ void sceneChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QQuickRenderControl)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKRENDERCONTROL_H
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index d8d5b09a9c..18b1b370b3 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -42,54 +42,45 @@
#ifndef QQUICKRENDERCONTROL_P_H
#define QQUICKRENDERCONTROL_P_H
-#include <QtGui/QImage>
-#include <private/qtquickglobal_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.
+//
-QT_BEGIN_NAMESPACE
+#include "qquickrendercontrol.h"
+#include <QtQuick/private/qsgcontext_p.h>
-class QQuickWindow;
-class QSGContext;
-class QSGRenderContext;
-class QAnimationDriver;
-class QOpenGLContext;
-class QQuickRenderControlPrivate;
+QT_BEGIN_NAMESPACE
-class Q_QUICK_PRIVATE_EXPORT QQuickRenderControl : public QObject
+class QQuickRenderControlPrivate : public QObjectPrivate
{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQuickRenderControl)
public:
- QQuickRenderControl();
- ~QQuickRenderControl();
+ Q_DECLARE_PUBLIC(QQuickRenderControl)
- QQuickWindow *window() const;
- QQuickWindow *createOffscreenWindow();
- virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
- static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
+ QQuickRenderControlPrivate();
+ ~QQuickRenderControlPrivate();
- void windowDestroyed();
+ static QQuickRenderControlPrivate *get(QQuickRenderControl *renderControl) {
+ return renderControl->d_func();
+ }
- void initialize(QOpenGLContext *gl);
- void invalidate();
- void polishItems();
- void render();
- bool sync();
+ static void cleanup();
- QImage grab();
-
-Q_SIGNALS:
- void renderRequested();
- void sceneChanged();
+ void windowDestroyed();
-private:
- friend class QQuickWindowPrivate;
- friend class QQuickWindow;
- void setWindow(QQuickWindow *window);
- inline void update() { /*emit*/ renderRequested(); }
- inline void maybeUpdate() { /*emit*/ sceneChanged(); }
+ void update();
+ void maybeUpdate();
- QSGContext *sceneGraphContext() const;
- QSGRenderContext *renderContext(QSGContext *) const;
+ bool initialized;
+ QQuickWindow *window;
+ static QSGContext *sg;
+ QSGRenderContext *rc;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index e226d7ba49..2f7a8e7420 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -456,7 +456,7 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
int difference = 0;
QHash<int, QVector<QPointer<QQuickItem> > > moved;
- foreach (const QQmlChangeSet::Remove &remove, changeSet.removes()) {
+ foreach (const QQmlChangeSet::Change &remove, changeSet.removes()) {
int index = qMin(remove.index, d->deletables.count());
int count = qMin(remove.index + remove.count, d->deletables.count()) - index;
if (remove.isMove()) {
@@ -479,7 +479,7 @@ void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
}
d->createFrom = -1;
- foreach (const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
+ foreach (const QQmlChangeSet::Change &insert, changeSet.inserts()) {
int index = qMin(insert.index, d->deletables.count());
if (insert.isMove()) {
QVector<QPointer<QQuickItem> > items = moved.value(insert.moveId);
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 8bcd2e64db..148c33d2cd 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -565,7 +565,8 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
position (0, 0), the bottom-right (\l{Item::width}{width},
\l{Item::height}{height}).
\li attribute vec2 qt_MultiTexCoord0 - texture coordinate, the top-left
- coordinate is (0, 0), the bottom-right (1, 1).
+ coordinate is (0, 0), the bottom-right (1, 1). If \l supportsAtlasTextures
+ is true, coordinates will be based on position in the atlas instead.
\endlist
In addition, any property that can be mapped to an OpenGL Shading Language
@@ -594,7 +595,8 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
it is by default copied from the texture atlas into a stand-alone texture
so that the texture coordinates span from 0 to 1, and you get the expected
wrap modes. However, this will increase the memory usage. To avoid the
- texture copy, you can for each "uniform sampler2D <name>" declare a
+ texture copy, set \l supportsAtlasTextures for simple shaders using
+ qt_MultiTexCoord0, or for each "uniform sampler2D <name>" declare a
"uniform vec4 qt_SubRect_<name>" which will be assigned the texture's
normalized source rectangle. For stand-alone textures, the source rectangle
is [0, 1]x[0, 1]. For textures in an atlas, the source rectangle corresponds
@@ -649,6 +651,8 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\note Scene Graph textures have origin in the top-left corner rather than
bottom-left which is common in OpenGL.
+
+ For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
*/
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
@@ -665,6 +669,8 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
, m_dirtyParseLog(true)
, m_dirtyMesh(true)
, m_dirtyGeometry(true)
+ , m_customVertexShader(false)
+ , m_supportsAtlasTextures(false)
{
setFlag(QQuickItem::ItemHasContents);
}
@@ -718,6 +724,7 @@ void QQuickShaderEffect::setVertexShader(const QByteArray &code)
m_common.source.sourceCode[Key::VertexShader] = code;
m_dirtyProgram = true;
m_dirtyParseLog = true;
+ m_customVertexShader = true;
if (isComponentComplete())
m_common.updateShader(this, Key::VertexShader);
@@ -828,6 +835,31 @@ void QQuickShaderEffect::setCullMode(CullMode face)
emit cullModeChanged();
}
+/*!
+ \qmlproperty bool QtQuick::ShaderEffect::supportsAtlasTextures
+
+ Set this property true to indicate that the ShaderEffect is able to
+ use the default source texture without first removing it from an atlas.
+ In this case the range of qt_MultiTexCoord0 will based on the position of
+ the texture within the atlas, rather than (0,0) to (1,1).
+
+ Setting this to true may enable some optimizations.
+
+ The default value is false.
+
+ \since 5.4
+ \since QtQuick 2.4
+*/
+
+void QQuickShaderEffect::setSupportsAtlasTextures(bool supports)
+{
+ if (supports == m_supportsAtlasTextures)
+ return;
+ m_supportsAtlasTextures = supports;
+ updateGeometry();
+ emit supportsAtlasTexturesChanged();
+}
+
QString QQuickShaderEffect::parseLog()
{
if (m_dirtyParseLog) {
@@ -940,39 +972,6 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
}
- if (m_dirtyMesh) {
- node->setGeometry(0);
- m_dirtyMesh = false;
- m_dirtyGeometry = true;
- }
-
- if (m_dirtyGeometry) {
- node->setFlag(QSGNode::OwnsGeometry, false);
- QSGGeometry *geometry = node->geometry();
- QRectF rect(0, 0, width(), height());
- QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
-
- geometry = mesh->updateGeometry(geometry, m_common.attributes, rect);
- if (!geometry) {
- QString log = mesh->log();
- if (!log.isNull()) {
- m_log = parseLog();
- m_log += QLatin1String("*** Mesh ***\n");
- m_log += log;
- m_status = Error;
- emit logChanged();
- emit statusChanged();
- }
- delete node;
- return 0;
- }
-
- node->setGeometry(geometry);
- node->setFlag(QSGNode::OwnsGeometry, true);
-
- m_dirtyGeometry = false;
- }
-
QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(node->material());
// Update blending
@@ -1014,6 +1013,60 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}
+ int textureCount = material->textureProviders.size();
+ bool preventBatching = m_customVertexShader || textureCount > 1 || (textureCount > 0 && !m_supportsAtlasTextures);
+
+ QRectF srcRect(0, 0, 1, 1);
+ if (m_supportsAtlasTextures && textureCount != 0) {
+ if (QSGTextureProvider *provider = material->textureProviders.at(0)) {
+ if (provider->texture())
+ srcRect = provider->texture()->normalizedTextureSubRect();
+ }
+ }
+
+ if (bool(material->flags() & QSGMaterial::RequiresFullMatrix) != preventBatching) {
+ material->setFlag(QSGMaterial::RequiresFullMatrix, preventBatching);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (material->supportsAtlasTextures != m_supportsAtlasTextures) {
+ material->supportsAtlasTextures = m_supportsAtlasTextures;
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyMesh) {
+ node->setGeometry(0);
+ m_dirtyMesh = false;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyGeometry) {
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ QSGGeometry *geometry = node->geometry();
+ QRectF rect(0, 0, width(), height());
+ QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+
+ geometry = mesh->updateGeometry(geometry, m_common.attributes, srcRect, rect);
+ if (!geometry) {
+ QString log = mesh->log();
+ if (!log.isNull()) {
+ m_log = parseLog();
+ m_log += QLatin1String("*** Mesh ***\n");
+ m_log += log;
+ m_status = Error;
+ emit logChanged();
+ emit statusChanged();
+ }
+ delete node;
+ return 0;
+ }
+
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirtyGeometry = false;
+ }
+
return node;
}
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 8b613b4ef0..14d11a7814 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -99,6 +99,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(CullMode cullMode READ cullMode WRITE setCullMode NOTIFY cullModeChanged)
Q_PROPERTY(QString log READ log NOTIFY logChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
Q_ENUMS(CullMode)
Q_ENUMS(Status)
@@ -138,6 +139,9 @@ public:
QString log() const { return m_log; }
Status status() const { return m_status; }
+ bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
+ void setSupportsAtlasTextures(bool supports);
+
QString parseLog();
virtual bool event(QEvent *);
@@ -150,6 +154,7 @@ Q_SIGNALS:
void cullModeChanged();
void logChanged();
void statusChanged();
+ void supportsAtlasTexturesChanged();
protected:
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
@@ -187,6 +192,8 @@ private:
uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
+ uint m_customVertexShader : 1;
+ uint m_supportsAtlasTextures : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index bc97a424f4..cf2f8faf5e 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -70,7 +70,7 @@ QQuickGridMesh::QQuickGridMesh(QObject *parent)
connect(this, SIGNAL(resolutionChanged()), this, SIGNAL(geometryChanged()));
}
-QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &dstRect)
+QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &dstRect)
{
int vmesh = m_resolution.height();
int hmesh = m_resolution.width();
@@ -125,7 +125,6 @@ QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector
QSGGeometry::Point2D *vdata = static_cast<QSGGeometry::Point2D *>(geometry->vertexData());
- QRectF srcRect(0, 0, 1, 1);
for (int iy = 0; iy <= vmesh; ++iy) {
float fy = iy / float(vmesh);
float y = float(dstRect.top()) + fy * float(dstRect.height());
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index ea92490979..99dbacaa53 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -62,7 +62,7 @@ class QQuickShaderEffectMesh : public QObject
public:
QQuickShaderEffectMesh(QObject *parent = 0);
// If 'geometry' != 0, 'attributes' is the same as last time the function was called.
- virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect) = 0;
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) = 0;
// If updateGeometry() fails, the reason should appear in the log.
virtual QString log() const { return QString(); }
@@ -77,7 +77,7 @@ class QQuickGridMesh : public QQuickShaderEffectMesh
Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
public:
QQuickGridMesh(QObject *parent = 0);
- virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &rect);
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect);
virtual QString log() const { return m_log; }
void setResolution(const QSize &res);
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index a615cb6f91..df1fceae4c 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -41,11 +41,11 @@
#include <private/qquickshadereffectnode_p.h>
-#include "qquickshadereffectmesh_p.h"
#include "qquickshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
+#include <QtQuick/private/qsgtexture_p.h>
QT_BEGIN_NAMESPACE
@@ -66,7 +66,6 @@ protected:
const QQuickShaderEffectMaterialKey m_key;
QVector<const char *> m_attributeNames;
- const QVector<QByteArray> m_attributes;
QString m_log;
bool m_compiled;
@@ -76,7 +75,6 @@ protected:
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
- , m_attributes(attributes)
, m_compiled(false)
, m_initialized(false)
{
@@ -88,7 +86,7 @@ QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectM
void QQuickCustomMaterialShader::deactivate()
{
QSGMaterialShader::deactivate();
- glDisable(GL_CULL_FACE);
+ QOpenGLContext::currentContext()->functions()->glDisable(GL_CULL_FACE);
}
void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
@@ -136,17 +134,23 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
functions->glActiveTexture(GL_TEXTURE0 + idx);
if (QSGTextureProvider *provider = material->textureProviders.at(idx)) {
if (QSGTexture *texture = provider->texture()) {
+
+#ifndef QT_NO_DEBUG
+ if (!qsg_safeguard_texture(texture))
+ continue;
+#endif
+
if (loc >= 0) {
QRectF r = texture->normalizedTextureSubRect();
program()->setUniformValue(loc, r.x(), r.y(), r.width(), r.height());
- } else if (texture->isAtlasTexture()) {
+ } else if (texture->isAtlasTexture() && (idx != 0 || !material->supportsAtlasTextures)) {
texture = texture->removedFromAtlas();
}
texture->bind();
continue;
}
}
- glBindTexture(GL_TEXTURE_2D, 0);
+ functions->glBindTexture(GL_TEXTURE_2D, 0);
} else if (d.specialType == UniformData::Opacity) {
program()->setUniformValue(loc, state.opacity());
} else if (d.specialType == UniformData::Matrix) {
@@ -217,15 +221,15 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
if (oldEffect == 0 || material->cullMode != oldMaterial->cullMode) {
switch (material->cullMode) {
case QQuickShaderEffectMaterial::FrontFaceCulling:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_FRONT);
+ functions->glEnable(GL_CULL_FACE);
+ functions->glCullFace(GL_FRONT);
break;
case QQuickShaderEffectMaterial::BackFaceCulling:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
+ functions->glEnable(GL_CULL_FACE);
+ functions->glCullFace(GL_BACK);
break;
default:
- glDisable(GL_CULL_FACE);
+ functions->glDisable(GL_CULL_FACE);
break;
}
}
@@ -256,7 +260,7 @@ void QQuickCustomMaterialShader::compile()
char const *const *attr = attributeNames();
#ifndef QT_NO_DEBUG
int maxVertexAttribs = 0;
- glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+ QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
int attrCount = 0;
while (attrCount < maxVertexAttribs && attr[attrCount])
++attrCount;
@@ -325,6 +329,11 @@ bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMateria
return true;
}
+bool QQuickShaderEffectMaterialKey::operator != (const QQuickShaderEffectMaterialKey &other) const
+{
+ return !(*this == other);
+}
+
uint qHash(const QQuickShaderEffectMaterialKey &key)
{
uint hash = qHash((void *)key.className);
@@ -339,6 +348,7 @@ QHash<QQuickShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QQuickSha
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
: cullMode(NoCulling)
+ , supportsAtlasTextures(false)
, m_node(node)
, m_emittedLogChanged(false)
{
@@ -355,9 +365,40 @@ QSGMaterialShader *QQuickShaderEffectMaterial::createShader() const
return new QQuickCustomMaterialShader(m_source, attributes);
}
-int QQuickShaderEffectMaterial::compare(const QSGMaterial *other) const
+bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
{
- return this - static_cast<const QQuickShaderEffectMaterial *>(other);
+ if (specialType != other.specialType)
+ return false;
+ if (name != other.name)
+ return false;
+
+ if (specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(value));
+ QQuickItem *otherSource = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(other.value));
+ if (!source || !otherSource || !source->isTextureProvider() || !otherSource->isTextureProvider())
+ return false;
+ return source->textureProvider()->texture()->textureId() == otherSource->textureProvider()->texture()->textureId();
+ } else {
+ return value == other.value;
+ }
+}
+
+int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
+{
+ const QQuickShaderEffectMaterial *other = static_cast<const QQuickShaderEffectMaterial *>(o);
+ if (!supportsAtlasTextures || !other->supportsAtlasTextures)
+ return 1;
+ if (bool(flags() & QSGMaterial::RequiresFullMatrix) || bool(other->flags() & QSGMaterial::RequiresFullMatrix))
+ return 1;
+ if (cullMode != other->cullMode)
+ return 1;
+ if (m_source != other->m_source)
+ return 1;
+ for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ if (uniforms[shaderType] != other->uniforms[shaderType])
+ return 1;
+ }
+ return 0;
}
void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index 232dd86aa1..04faff5493 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -65,6 +65,7 @@ struct QQuickShaderEffectMaterialKey {
const char *className;
bool operator == (const QQuickShaderEffectMaterialKey &other) const;
+ bool operator != (const QQuickShaderEffectMaterialKey &other) const;
};
uint qHash(const QQuickShaderEffectMaterialKey &key);
@@ -82,6 +83,8 @@ public:
QByteArray name;
QVariant value;
SpecialType specialType;
+
+ bool operator == (const UniformData &other) const;
};
enum CullMode
@@ -100,6 +103,7 @@ public:
QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
QVector<QSGTextureProvider *> textureProviders;
CullMode cullMode;
+ bool supportsAtlasTextures;
void setProgramSource(const QQuickShaderEffectMaterialKey &source);
void updateTextures() const;
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 99d4979073..b727c1107c 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -50,6 +50,7 @@
#include "qopenglframebufferobject.h"
#include "qmath.h"
#include <QtQuick/private/qsgtexture_p.h>
+#include <QtCore/QRunnable>
QT_BEGIN_NAMESPACE
@@ -78,7 +79,7 @@ namespace
BindableFbo::~BindableFbo()
{
if (qmlFboFlushBeforeDetach())
- glFlush();
+ QOpenGLContext::currentContext()->functions()->glFlush();
if (m_depthStencil)
m_depthStencil->detach();
}
@@ -173,7 +174,7 @@ void QQuickShaderEffectTexture::invalidated()
m_debugOverlay = 0;
#endif
if (m_transparentTexture) {
- glDeleteTextures(1, &m_transparentTexture);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_transparentTexture);
m_transparentTexture = 0;
}
}
@@ -200,18 +201,18 @@ void QQuickShaderEffectTexture::bind()
if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
#endif
-
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (!m_fbo && m_format == GL_RGBA) {
if (m_transparentTexture == 0) {
- glGenTextures(1, &m_transparentTexture);
- glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+ funcs->glGenTextures(1, &m_transparentTexture);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
const uint zero = 0;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
} else {
- glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
}
} else {
- glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
updateBindOptions();
}
}
@@ -345,6 +346,7 @@ void QQuickShaderEffectTexture::grab()
m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
bool deleteFboLater = false;
if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
|| (!m_fbo->format().mipmap() && m_mipmap))
@@ -377,7 +379,7 @@ void QQuickShaderEffectTexture::grab()
deleteFboLater = true;
delete m_secondaryFbo;
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
- glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+ funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
updateBindOptions(true);
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
} else {
@@ -385,7 +387,7 @@ void QQuickShaderEffectTexture::grab()
delete m_secondaryFbo;
m_fbo = new QOpenGLFramebufferObject(m_size, format);
m_secondaryFbo = 0;
- glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
updateBindOptions(true);
m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo);
}
@@ -398,7 +400,7 @@ void QQuickShaderEffectTexture::grab()
Q_ASSERT(!m_multisampling);
m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format());
- glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+ funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
updateBindOptions(true);
}
@@ -418,7 +420,6 @@ void QQuickShaderEffectTexture::grab()
m_dirtyTexture = false;
- QOpenGLContext *ctx = m_context->openglContext();
m_renderer->setDeviceRect(m_size);
m_renderer->setViewportRect(m_size);
QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
@@ -436,7 +437,7 @@ void QQuickShaderEffectTexture::grab()
format.setMipmap(m_mipmap);
format.setSamples(0);
m_fbo = new QOpenGLFramebufferObject(m_size, format);
- glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
updateBindOptions(true);
}
@@ -453,7 +454,7 @@ void QQuickShaderEffectTexture::grab()
format.setInternalTextureFormat(m_format);
format.setMipmap(m_mipmap);
m_fbo = new QOpenGLFramebufferObject(m_size, format);
- glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+ funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
updateBindOptions(true);
}
qSwap(m_fbo, m_secondaryFbo);
@@ -463,8 +464,8 @@ void QQuickShaderEffectTexture::grab()
}
if (m_mipmap) {
- glBindTexture(GL_TEXTURE_2D, textureId());
- ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ funcs->glBindTexture(GL_TEXTURE_2D, textureId());
+ funcs->glGenerateMipmap(GL_TEXTURE_2D);
}
root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
@@ -485,6 +486,21 @@ QImage QQuickShaderEffectTexture::toImage() const
return QImage();
}
+class QQuickShaderEffectSourceCleanup : public QRunnable
+{
+public:
+ QQuickShaderEffectSourceCleanup(QQuickShaderEffectTexture *t, QQuickShaderEffectSourceTextureProvider *p)
+ : texture(t)
+ , provider(p)
+ {}
+ void run() Q_DECL_OVERRIDE {
+ delete texture;
+ delete provider;
+ }
+ QQuickShaderEffectTexture *texture;
+ QQuickShaderEffectSourceTextureProvider *provider;
+};
+
/*!
\qmltype ShaderEffectSource
\instantiates QQuickShaderEffectSource
@@ -586,15 +602,20 @@ QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
, m_grab(true)
{
setFlag(ItemHasContents);
+ connect(this, SIGNAL(sceneGraphInvalidated()), this, SLOT(invalidateSG()));
}
QQuickShaderEffectSource::~QQuickShaderEffectSource()
{
- if (m_texture)
- m_texture->deleteLater();
-
- if (m_provider)
- m_provider->deleteLater();
+ if (window()) {
+ window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
+ QQuickWindow::AfterSynchronizingStage);
+ } else {
+ // If we don't have a window, these should already have been
+ // released in invalidateSG or in releaseResrouces()
+ Q_ASSERT(!m_texture);
+ Q_ASSERT(!m_provider);
+ }
if (m_sourceItem) {
QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem);
@@ -710,9 +731,15 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
if (window())
d->derefWindow();
}
- m_sourceItem = item;
- if (item) {
+ if (window() == item->window()) {
+ m_sourceItem = item;
+ } else {
+ qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
+ m_sourceItem = 0;
+ }
+
+ if (m_sourceItem) {
QQuickItemPrivate *d = QQuickItemPrivate::get(item);
// 'item' needs a window to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
@@ -961,12 +988,10 @@ static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::W
void QQuickShaderEffectSource::releaseResources()
{
- if (m_texture) {
- m_texture->deleteLater();
+ if (m_texture || m_provider) {
+ window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
+ QQuickWindow::AfterSynchronizingStage);
m_texture = 0;
- }
- if (m_provider) {
- m_provider->deleteLater();
m_provider = 0;
}
}
@@ -1058,6 +1083,16 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
return node;
}
+void QQuickShaderEffectSource::invalidateSG()
+{
+ if (m_texture)
+ delete m_texture;
+ if (m_provider)
+ delete m_provider;
+ m_texture = 0;
+ m_provider = 0;
+}
+
void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeData &value)
{
if (change == QQuickItem::ItemSceneChange && m_sourceItem) {
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index efa963fe64..13b81cede5 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -235,6 +235,7 @@ Q_SIGNALS:
private Q_SLOTS:
void sourceItemDestroyed(QObject *item);
+ void invalidateSG();
protected:
virtual void releaseResources();
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index e5bb577344..95e6494ec7 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -47,6 +47,7 @@
#include <QPainter>
#include <QSet>
#include <QtGui/qopengl.h>
+#include <QOpenGLFunctions>
QT_BEGIN_NAMESPACE
@@ -388,7 +389,7 @@ QImage QQuickSpriteEngine::assembledImage()
m_imageStateCount = 0;
int maxSize = 0;
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+ QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
#ifdef SPRITE_IMAGE_DEBUG
qDebug() << "MAX TEXTURE SIZE" << maxSize;
#endif
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 71265689e9..a1a89d2f18 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -1456,6 +1456,7 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value)
d->implicitHeightValid = false;
d->updateLayout();
}
+ QQuickItem::itemChange(change, value);
}
/*!
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index b70e292026..37e94cddc0 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -881,6 +881,8 @@ void QQuickTextInput::setFocusOnPress(bool b)
Whether the TextInput should scroll when the text is longer than the width. By default this is
set to true.
+
+ \sa ensureVisible()
*/
bool QQuickTextInput::autoScroll() const
{
@@ -1197,7 +1199,7 @@ void QQuickTextInput::setInputMask(const QString &im)
bool QQuickTextInput::hasAcceptableInput() const
{
Q_D(const QQuickTextInput);
- return d->hasAcceptableInput(d->m_text) == QQuickTextInputPrivate::AcceptableInput;
+ return d->m_acceptableInput;
}
/*!
@@ -1721,33 +1723,24 @@ void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
}
-void QQuickTextInputPrivate::updateHorizontalScroll()
+void QQuickTextInputPrivate::ensureVisible(int position, int preeditCursor, int preeditLength)
{
Q_Q(QQuickTextInput);
-#ifndef QT_NO_IM
- QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
- const int preeditLength = m_textLayout.preeditAreaText().length();
-#else
- QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor);
-#endif
+ QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
const qreal width = qMax<qreal>(0, q->width());
qreal cix = 0;
qreal widthUsed = 0;
- if (currentLine.isValid()) {
-#ifndef QT_NO_IM
- cix = currentLine.cursorToX(m_cursor + preeditLength);
-#else
- cix = currentLine.cursorToX(m_cursor);
-#endif
+ if (textLine.isValid()) {
+ cix = textLine.cursorToX(position + preeditLength);
const qreal cursorWidth = cix >= 0 ? cix : width - cix;
- widthUsed = qMax(currentLine.naturalTextWidth(), cursorWidth);
+ widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
}
int previousScroll = hscroll;
- if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) {
+ if (widthUsed <= width) {
hscroll = 0;
} else {
- Q_ASSERT(currentLine.isValid());
+ Q_ASSERT(textLine.isValid());
if (cix - hscroll >= width) {
// text doesn't fit, cursor is to the right of br (scroll right)
hscroll = cix - width;
@@ -1767,7 +1760,7 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
if (preeditLength > 0) {
// check to ensure long pre-edit text doesn't push the cursor
// off to the left
- cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1));
+ cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
if (cix < hscroll)
hscroll = cix;
}
@@ -1777,6 +1770,20 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
textLayoutDirty = true;
}
+void QQuickTextInputPrivate::updateHorizontalScroll()
+{
+ if (autoScroll && m_echoMode != QQuickTextInput::NoEcho) {
+#ifndef QT_NO_IM
+ const int preeditLength = m_textLayout.preeditAreaText().length();
+ ensureVisible(m_cursor, m_preeditCursor, preeditLength);
+#else
+ ensureVisible(m_cursor);
+#endif
+ } else {
+ hscroll = 0;
+ }
+}
+
void QQuickTextInputPrivate::updateVerticalScroll()
{
Q_Q(QQuickTextInput);
@@ -1909,6 +1916,11 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
#ifndef QT_NO_IM
QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
{
+ return inputMethodQuery(property, QVariant());
+}
+
+QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
+{
Q_D(const QQuickTextInput);
switch (property) {
case Qt::ImEnabled:
@@ -1938,6 +1950,16 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
return QVariant(d->selectionEnd());
else
return QVariant(d->selectionStart());
+ case Qt::ImAbsolutePosition:
+ return QVariant(d->m_cursor);
+ case Qt::ImTextAfterCursor:
+ if (argument.isValid())
+ return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
+ return QVariant(d->m_text.mid(d->m_cursor));
+ case Qt::ImTextBeforeCursor:
+ if (argument.isValid())
+ return QVariant(d->m_text.left(d->m_cursor).right(argument.toInt()));
+ return QVariant(d->m_text.left(d->m_cursor));
default:
return QQuickItem::inputMethodQuery(property);
}
@@ -2063,9 +2085,8 @@ void QQuickTextInput::insert(int position, const QString &text)
{
Q_D(QQuickTextInput);
if (d->m_echoMode == QQuickTextInput::Password) {
- int delay = qGuiApp->styleHints()->passwordMaskDelay();
- if (delay > 0)
- d->m_passwordEchoTimer.start(delay, this);
+ if (d->m_passwordMaskDelay > 0)
+ d->m_passwordEchoTimer.start(d->m_passwordMaskDelay, this);
}
if (position < 0 || position > d->m_text.length())
return;
@@ -2245,6 +2266,34 @@ void QQuickTextInput::setPasswordCharacter(const QString &str)
}
/*!
+ \qmlproperty int QtQuick::TextInput::passwordMaskDelay
+ \since 5.4
+
+ Sets the delay before visible character is masked with password character, in milliseconds.
+
+ The reset method will be called by assigning undefined.
+*/
+int QQuickTextInput::passwordMaskDelay() const
+{
+ Q_D(const QQuickTextInput);
+ return d->m_passwordMaskDelay;
+}
+
+void QQuickTextInput::setPasswordMaskDelay(int delay)
+{
+ Q_D(QQuickTextInput);
+ if (d->m_passwordMaskDelay != delay) {
+ d->m_passwordMaskDelay = delay;
+ emit passwordMaskDelayChanged(delay);
+ }
+}
+
+void QQuickTextInput::resetPasswordMaskDelay()
+{
+ setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
+}
+
+/*!
\qmlproperty string QtQuick::TextInput::displayText
This is the text displayed in the TextInput.
@@ -2254,12 +2303,15 @@ void QQuickTextInput::setPasswordCharacter(const QString &str)
this property holds the text visible to the user, while
the \l text property holds the actual entered text.
+ \note Unlike the TextInput::text property, this contains
+ partial text input from an input method.
+
\readonly
*/
QString QQuickTextInput::displayText() const
{
Q_D(const QQuickTextInput);
- return d->m_textLayout.text();
+ return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
}
/*!
@@ -2540,7 +2592,7 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
&& !persistentSelection)
deselect();
- if (q->hasAcceptableInput() || fixup())
+ if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
emit q->editingFinished();
#ifndef QT_NO_IM
@@ -2607,14 +2659,16 @@ void QQuickTextInputPrivate::init()
}
}
-void QQuickTextInput::updateCursorRectangle()
+void QQuickTextInput::updateCursorRectangle(bool scroll)
{
Q_D(QQuickTextInput);
if (!isComponentComplete())
return;
- d->updateHorizontalScroll();
- d->updateVerticalScroll();
+ if (scroll) {
+ d->updateHorizontalScroll();
+ d->updateVerticalScroll();
+ }
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
update();
emit cursorRectangleChanged();
@@ -3364,6 +3418,27 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
}
}
#endif
+
+ if (m_maskData) {
+ if (m_text.length() != m_maxLength) {
+ m_acceptableInput = false;
+ } else {
+ for (int i = 0; i < m_maxLength; ++i) {
+ if (m_maskData[i].separator) {
+ if (m_text.at(i) != m_maskData[i].maskChar) {
+ m_acceptableInput = false;
+ break;
+ }
+ } else {
+ if (!isValidInput(m_text.at(i), m_maskData[i].maskChar)) {
+ m_acceptableInput = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (validateFromState >= 0 && wasValidInput && !m_validInput) {
if (m_transactions.count())
return false;
@@ -3484,9 +3559,8 @@ void QQuickTextInputPrivate::internalInsert(const QString &s)
{
Q_Q(QQuickTextInput);
if (m_echoMode == QQuickTextInput::Password) {
- int delay = qGuiApp->styleHints()->passwordMaskDelay();
- if (delay > 0)
- m_passwordEchoTimer.start(delay, q);
+ if (m_passwordMaskDelay > 0)
+ m_passwordEchoTimer.start(m_passwordMaskDelay, q);
}
Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
if (m_maskData) {
@@ -4149,7 +4223,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
Q_Q(QQuickTextInput);
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
- if (q->hasAcceptableInput() || fixup()) {
+ if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
emit q->accepted();
emit q->editingFinished();
}
@@ -4376,5 +4450,21 @@ void QQuickTextInputPrivate::deleteEndOfLine()
finishChange(priorState);
}
+/*!
+ \qmlmethod QtQuick::TextInput::ensureVisible(int position)
+ \since 5.4
+
+ Scrolls the contents of the text input so that the specified character
+ \a position is visible inside the boundaries of the text input.
+
+ \sa autoScroll
+*/
+void QQuickTextInput::ensureVisible(int position)
+{
+ Q_D(QQuickTextInput);
+ d->ensureVisible(position);
+ updateCursorRectangle(false);
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index 042859df17..032bfdb3d1 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -94,6 +94,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged)
Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged)
Q_PROPERTY(QString passwordCharacter READ passwordCharacter WRITE setPasswordCharacter NOTIFY passwordCharacterChanged)
+ Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay WRITE setPasswordMaskDelay RESET resetPasswordMaskDelay NOTIFY passwordMaskDelayChanged REVISION 3)
Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged)
Q_PROPERTY(bool autoScroll READ autoScroll WRITE setAutoScroll NOTIFY autoScrollChanged)
Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
@@ -225,6 +226,10 @@ public:
QString passwordCharacter() const;
void setPasswordCharacter(const QString &str);
+ int passwordMaskDelay() const;
+ void setPasswordMaskDelay(int delay);
+ void resetPasswordMaskDelay();
+
QString displayText() const;
QQmlComponent* cursorDelegate() const;
@@ -249,6 +254,7 @@ public:
#ifndef QT_NO_IM
QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+ Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
QRectF boundingRect() const;
@@ -296,6 +302,7 @@ Q_SIGNALS:
void inputMaskChanged(const QString &inputMask);
void echoModeChanged(EchoMode echoMode);
void passwordCharacterChanged();
+ Q_REVISION(3) void passwordMaskDelayChanged(int delay);
void displayTextChanged();
void activeFocusOnPressChanged(bool activeFocusOnPress);
void autoScrollChanged(bool autoScroll);
@@ -349,11 +356,12 @@ public Q_SLOTS:
void redo();
void insert(int position, const QString &text);
void remove(int start, int end);
+ Q_REVISION(3) void ensureVisible(int position);
private Q_SLOTS:
void selectionChanged();
void createCursor();
- void updateCursorRectangle();
+ void updateCursorRectangle(bool scroll = true);
void q_canPasteChanged();
void q_updateAlignment();
void triggerPreprocess();
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 21bd1bd6d7..facc6356a1 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -111,6 +111,7 @@ public:
, mouseSelectionMode(QQuickTextInput::SelectCharacters)
, m_layoutDirection(Qt::LayoutDirectionAuto)
, m_passwordCharacter(qApp->styleHints()->passwordMaskCharacter())
+ , m_passwordMaskDelay(qApp->styleHints()->passwordMaskDelay())
, focusOnPress(true)
, cursorVisible(false)
, cursorPending(false)
@@ -147,6 +148,7 @@ public:
void init();
void startCreatingCursor();
+ void ensureVisible(int position, int preeditCursor = 0, int preeditLength = 0);
void updateHorizontalScroll();
void updateVerticalScroll();
bool determineHorizontalAlignment();
@@ -250,6 +252,7 @@ public:
QChar m_blank;
QChar m_passwordCharacter;
+ int m_passwordMaskDelay;
bool focusOnPress:1;
bool cursorVisible:1;
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 72c66448b4..32fda331ee 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -58,16 +58,15 @@ QT_BEGIN_NAMESPACE
DEFINE_OBJECT_VTABLE(QQuickRootItemMarker);
-QQuickRootItemMarker::QQuickRootItemMarker(QQmlEngine *engine, QQuickWindow *window)
- : QV4::Object(QQmlEnginePrivate::getV4Engine(engine))
- , window(window)
+QQuickRootItemMarker *QQuickRootItemMarker::create(QQmlEngine *engine, QQuickWindow *window)
{
- setVTable(staticVTable());
+ QV4::ExecutionEngine *e = QQmlEnginePrivate::getV4Engine(engine);
+ return e->memoryManager->alloc<QQuickRootItemMarker>(e, window);
}
void QQuickRootItemMarker::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e)
{
- QQuickItem *root = static_cast<QQuickRootItemMarker*>(that)->window->contentItem();
+ QQuickItem *root = static_cast<QQuickRootItemMarker*>(that)->d()->window->contentItem();
if (root) {
QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root);
rootPrivate->markObjects(e);
@@ -91,7 +90,7 @@ void QQuickViewPrivate::init(QQmlEngine* e)
{
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine.data());
QV4::Scope scope(v4);
- QV4::Scoped<QQuickRootItemMarker> v(scope, new (v4->memoryManager) QQuickRootItemMarker(engine.data(), q));
+ QV4::Scoped<QQuickRootItemMarker> v(scope, QQuickRootItemMarker::create(engine.data(), q));
rootItemMarker = v;
}
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index dfc8c21d0b..eeb6003e5b 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -104,18 +104,22 @@ public:
struct QQuickRootItemMarker : public QV4::Object
{
- V4_OBJECT
+ struct Data : QV4::Object::Data {
+ Data(QV4::ExecutionEngine *engine, QQuickWindow *window)
+ : Object::Data(engine)
+ , window(window)
+ {
+ setVTable(staticVTable());
+ }
- QQuickRootItemMarker(QQmlEngine *engine, QQuickWindow *window);
+ QQuickWindow *window;
+ };
+ V4_OBJECT(QV4::Object)
- static void destroy(Managed *that)
- {
- static_cast<QQuickRootItemMarker*>(that)->~QQuickRootItemMarker();
- }
+ static QQuickRootItemMarker *create(QQmlEngine *engine, QQuickWindow *window);
static void markObjects(Managed *that, QV4::ExecutionEngine *e);
- QQuickWindow *window;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 3c2718dcaf..d3b0dc05d0 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -41,6 +41,7 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
+#include "qquickwindowattached_p.h"
#include "qquickitem.h"
#include "qquickitem_p.h"
@@ -66,6 +67,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qabstractanimation.h>
#include <QtCore/QLibraryInfo>
+#include <QtCore/QRunnable>
#include <QtQml/qqmlincubator.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
@@ -73,11 +75,18 @@
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlmemoryprofiler_p.h>
+#include <private/qopenglvertexarrayobject_p.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch");
+Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse");
+Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus");
+Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty");
+
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-bool QQuickWindowPrivate::defaultAlphaBuffer(0);
+bool QQuickWindowPrivate::defaultAlphaBuffer = false;
void QQuickWindowPrivate::updateFocusItemTransform()
{
@@ -103,9 +112,9 @@ public:
// Allow incubation for 1/3 of a frame.
m_incubation_time = qMax(1, int(1000 / QGuiApplication::primaryScreen()->refreshRate()) / 3);
- m_animation_driver = m_renderLoop->animationDriver();
- if (m_animation_driver) {
- connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped()));
+ QAnimationDriver *animationDriver = m_renderLoop->animationDriver();
+ if (animationDriver) {
+ connect(animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()));
connect(m_renderLoop, SIGNAL(timeToIncubate()), this, SLOT(incubate()));
}
}
@@ -151,7 +160,6 @@ protected:
private:
QSGRenderLoop *m_renderLoop;
int m_incubation_time;
- QAnimationDriver *m_animation_driver;
int m_timer;
};
@@ -189,16 +197,6 @@ thus the first item that has focus will get it (assuming the scope doesn't alrea
have a scope focused item), and the other items will have their focus cleared.
*/
-
-// #define FOCUS_DEBUG
-// #define MOUSE_DEBUG
-// #define TOUCH_DEBUG
-// #define DIRTY_DEBUG
-
-#ifdef FOCUS_DEBUG
-void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
-#endif
-
QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
: transformNode(0)
{
@@ -291,7 +289,7 @@ void QQuickWindow::update()
if (d->windowManager)
d->windowManager->update(this);
else if (d->renderControl)
- d->renderControl->update();
+ QQuickRenderControlPrivate::get(d->renderControl)->update();
}
void forcePolishHelper(QQuickItem *item)
@@ -335,6 +333,7 @@ void QQuickWindowPrivate::syncSceneGraph()
animationController->beforeNodeSync();
emit q->beforeSynchronizing();
+ runAndClearJobs(&beforeSynchronizingJobs);
if (!renderer) {
forceUpdate(contentItem);
@@ -350,14 +349,15 @@ void QQuickWindowPrivate::syncSceneGraph()
// Copy the current state of clearing from window into renderer.
renderer->setClearColor(clearColor);
- QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
+ QSGAbstractRenderer::ClearMode mode = QSGAbstractRenderer::ClearStencilBuffer | QSGAbstractRenderer::ClearDepthBuffer;
if (clearBeforeRendering)
- mode |= QSGRenderer::ClearColorBuffer;
+ mode |= QSGAbstractRenderer::ClearColorBuffer;
renderer->setClearMode(mode);
renderer->setCustomRenderMode(customRenderMode);
emit q->afterSynchronizing();
+ runAndClearJobs(&afterSynchronizingJobs);
context->endSync();
}
@@ -371,6 +371,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
animationController->advance();
emit q->beforeRendering();
+ runAndClearJobs(&beforeRenderingJobs);
int fboId = 0;
const qreal devicePixelRatio = q->devicePixelRatio();
renderer->setDeviceRect(QRect(QPoint(0, 0), size * devicePixelRatio));
@@ -385,6 +386,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
context->renderNextFrame(renderer, fboId);
emit q->afterRendering();
+ runAndClearJobs(&afterRenderingJobs);
}
QQuickWindowPrivate::QQuickWindowPrivate()
@@ -404,14 +406,17 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, renderer(0)
, windowManager(0)
, renderControl(0)
+ , touchRecursionGuard(0)
, clearColor(Qt::white)
, clearBeforeRendering(true)
, persistentGLContext(true)
, persistentSceneGraph(true)
, lastWheelEventAccepted(false)
, componentCompleted(true)
+ , lastFocusReason(Qt::OtherFocusReason)
, renderTarget(0)
, renderTargetId(0)
+ , vaoHelper(0)
, incubationController(0)
{
#ifndef QT_NO_DRAGANDDROP
@@ -440,7 +445,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
customRenderMode = qgetenv("QSG_VISUALIZE");
renderControl = control;
if (renderControl)
- renderControl->setWindow(q);
+ QQuickRenderControlPrivate::get(renderControl)->window = q;
if (!renderControl)
windowManager = QSGRenderLoop::instance();
@@ -449,26 +454,31 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
QSGContext *sg;
if (renderControl) {
- sg = renderControl->sceneGraphContext();
- context = renderControl->renderContext(sg);
+ QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl);
+ sg = renderControlPriv->sg;
+ context = renderControlPriv->rc;
} else {
windowManager->addWindow(q);
sg = windowManager->sceneGraphContext();
context = windowManager->createRenderContext(sg);
}
- q->setSurfaceType(QWindow::OpenGLSurface);
+ q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
animationController = new QQuickAnimatorController();
animationController->m_window = q;
+ delayedTouch = 0;
+
QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection);
QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection);
QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection);
QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged()));
QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(forcePolish()));
+
+ QObject::connect(q, SIGNAL(frameSwapped()), q, SLOT(runJobsAfterSwap()), Qt::DirectConnection);
}
/*!
@@ -545,7 +555,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// handler spins the event loop all subsequent moves and releases get lost.
touchMouseId = p.id();
itemForTouchPointId[touchMouseId] = item;
- QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
+ QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false));
// Send a single press and see if that's accepted
if (!mouseGrabberItem)
@@ -564,18 +574,21 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
}
if (mousePress->isAccepted() && checkIfDoubleClicked(event->timestamp())) {
- QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
+ QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false));
QCoreApplication::sendEvent(item, mouseDoubleClick.data());
event->setAccepted(mouseDoubleClick->isAccepted());
if (mouseDoubleClick->isAccepted()) {
+ touchMouseIdCandidates.clear();
return true;
} else {
touchMouseId = -1;
}
}
// The event was accepted, we are done.
- if (mousePress->isAccepted())
+ if (mousePress->isAccepted()) {
+ touchMouseIdCandidates.clear();
return true;
+ }
// The event was not accepted but touchMouseId was set.
if (touchMouseId != -1)
return false;
@@ -585,7 +598,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
} else if (p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
event->setAccepted(me->isAccepted());
if (me->isAccepted()) {
@@ -596,7 +609,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// no grabber, check if we care about mouse hover
// FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
// hover for touch???
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item, false));
if (lastMousePosition.isNull())
lastMousePosition = me->windowPos();
QPointF last = lastMousePosition;
@@ -615,7 +628,7 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e
// currently handled point was released
touchMouseId = -1;
if (mouseGrabberItem) {
- QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false));
QCoreApplication::sendEvent(item, me.data());
if (mouseGrabberItem) // might have ungrabbed due to event
mouseGrabberItem->ungrabMouse();
@@ -706,14 +719,12 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
Q_ASSERT(item);
Q_ASSERT(scope || item == contentItem);
-#ifdef FOCUS_DEBUG
- qWarning() << "QQuickWindowPrivate::setFocusInScope():";
- qWarning() << " scope:" << (QObject *)scope;
+ qCDebug(DBG_FOCUS) << "QQuickWindowPrivate::setFocusInScope():";
+ qCDebug(DBG_FOCUS) << " scope:" << (QObject *)scope;
if (scope)
- qWarning() << " scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
- qWarning() << " item:" << (QObject *)item;
- qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
-#endif
+ qCDebug(DBG_FOCUS) << " scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
+ qCDebug(DBG_FOCUS) << " item:" << (QObject *)item;
+ qCDebug(DBG_FOCUS) << " activeFocusItem:" << (QObject *)activeFocusItem;
QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
@@ -721,6 +732,8 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *newActiveFocusItem = 0;
+ lastFocusReason = reason;
+
QVarLengthArray<QQuickItem *, 20> changed;
// Does this change the active focus?
@@ -809,12 +822,10 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
Q_ASSERT(item);
Q_ASSERT(scope || item == contentItem);
-#ifdef FOCUS_DEBUG
- qWarning() << "QQuickWindowPrivate::clearFocusInScope():";
- qWarning() << " scope:" << (QObject *)scope;
- qWarning() << " item:" << (QObject *)item;
- qWarning() << " activeFocusItem:" << (QObject *)activeFocusItem;
-#endif
+ qCDebug(DBG_FOCUS) << "QQuickWindowPrivate::clearFocusInScope():";
+ qCDebug(DBG_FOCUS) << " scope:" << (QObject *)scope;
+ qCDebug(DBG_FOCUS) << " item:" << (QObject *)item;
+ qCDebug(DBG_FOCUS) << " activeFocusItem:" << (QObject *)activeFocusItem;
QQuickItemPrivate *scopePrivate = 0;
if (scope) {
@@ -827,6 +838,8 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
QQuickItem *oldActiveFocusItem = 0;
QQuickItem *newActiveFocusItem = 0;
+ lastFocusReason = reason;
+
QVarLengthArray<QQuickItem *, 20> changed;
Q_ASSERT(item == contentItem || item == scopePrivate->subFocusItem);
@@ -1040,8 +1053,18 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\note All classes with QSG prefix should be used solely on the scene graph's
rendering thread. See \l {Scene Graph and Rendering} for more information.
- \sa {Scene Graph - OpenGL Under QML}
+ \section2 Context and surface formats
+
+ While it is possible to specify a QSurfaceFormat for every QQuickWindow by
+ calling the member function setFormat(), windows may also be created from
+ QML by using the Window and ApplicationWindow elements. In this case there
+ is no C++ code involved in the creation of the window instance, yet
+ applications may still wish to set certain surface format values, for
+ example to request a given OpenGL version or profile. Such applications can
+ call the static function QSurfaceFormat::setDefaultFormat() at startup. The
+ specified format will be used for all Quick windows created afterwards.
+ \sa {Scene Graph - OpenGL Under QML}
*/
/*!
@@ -1087,7 +1110,7 @@ QQuickWindow::~QQuickWindow()
d->animationController->deleteLater();
if (d->renderControl) {
- d->renderControl->windowDestroyed();
+ QQuickRenderControlPrivate::get(d->renderControl)->windowDestroyed();
} else if (d->windowManager) {
d->windowManager->removeWindow(this);
d->windowManager->windowDestroyed(this);
@@ -1100,6 +1123,26 @@ QQuickWindow::~QQuickWindow()
delete d->dragGrabber; d->dragGrabber = 0;
#endif
delete d->contentItem; d->contentItem = 0;
+
+ d->renderJobMutex.lock();
+ qDeleteAll(d->beforeSynchronizingJobs);
+ d->beforeSynchronizingJobs.clear();
+ qDeleteAll(d->afterSynchronizingJobs);
+ d->afterSynchronizingJobs.clear();
+ qDeleteAll(d->beforeRenderingJobs);
+ d->beforeRenderingJobs.clear();
+ qDeleteAll(d->afterRenderingJobs);
+ d->afterRenderingJobs.clear();
+ qDeleteAll(d->afterSwapJobs);
+ d->afterSwapJobs.clear();
+ d->renderJobMutex.unlock();
+
+ // It is important that the pixmap cache is cleaned up during shutdown.
+ // Besides playing nice, this also solves a practical problem that
+ // QQuickTextureFactory implementations in other libraries need
+ // have their destructors loaded while they the library is still
+ // loaded into memory.
+ QQuickPixmap::purgeCache();
}
/*!
@@ -1126,8 +1169,9 @@ void QQuickWindow::releaseResources()
/*!
- Sets whether the OpenGL context can be released to \a
- persistent. The default value is true.
+ Sets whether the OpenGL context should be preserved, and cannot be
+ released until the last window is deleted, to \a persistent. The
+ default value is true.
The OpenGL context can be released to free up graphics resources
when the window is obscured, hidden or not rendering. When this
@@ -1484,10 +1528,7 @@ void QQuickWindow::mousePressEvent(QMouseEvent *event)
return;
}
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickWindow::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
-
+ qCDebug(DBG_MOUSE) << "QQuickWindow::mousePressEvent()" << event->localPos() << event->button() << event->buttons();
d->deliverMouseEvent(event);
}
@@ -1501,9 +1542,7 @@ void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
return;
}
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
+ qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
if (!d->mouseGrabberItem) {
QWindow::mouseReleaseEvent(event);
@@ -1525,9 +1564,7 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
return;
}
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickWindow::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
+ qCDebug(DBG_MOUSE) << "QQuickWindow::mouseDoubleClickEvent()" << event->localPos() << event->button() << event->buttons();
if (!d->mouseGrabberItem && (event->buttons() & event->button()) == event->buttons()) {
if (d->deliverInitialMousePressEvent(d->contentItem, event))
@@ -1566,9 +1603,7 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
return;
}
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
-#endif
+ qCDebug(DBG_MOUSE) << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
#ifndef QT_NO_CURSOR
d->updateCursor(event->windowPos());
@@ -1707,9 +1742,7 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
-#ifdef MOUSE_DEBUG
- qWarning() << "QQuickWindow::wheelEvent()" << event->pixelDelta() << event->angleDelta();
-#endif
+ qCDebug(DBG_MOUSE) << "QQuickWindow::wheelEvent()" << event->pixelDelta() << event->angleDelta();
//if the actual wheel event was accepted, accept the compatibility wheel event and return early
if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
@@ -1724,9 +1757,7 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
-#ifdef TOUCH_DEBUG
- qWarning("touchCancelEvent");
-#endif
+ qCDebug(DBG_TOUCH) << event;
Q_Q(QQuickWindow);
// A TouchCancel event will typically not contain any points.
// Deliver it to all items that have active touches.
@@ -1745,18 +1776,106 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
return true;
}
+static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet("QML_NO_TOUCH_COMPRESSION");
+
// check what kind of touch we have (begin/update) and
// call deliverTouchPoints to actually dispatch the points
-bool QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
-{
-#ifdef TOUCH_DEBUG
- if (event->type() == QEvent::TouchBegin)
- qWarning() << "touchBeginEvent";
- else if (event->type() == QEvent::TouchUpdate)
- qWarning() << "touchUpdateEvent points";
- else if (event->type() == QEvent::TouchEnd)
- qWarning("touchEndEvent");
-#endif
+void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
+{
+ qCDebug(DBG_TOUCH) << event;
+ Q_Q(QQuickWindow);
+
+ if (qquickwindow_no_touch_compression || touchRecursionGuard) {
+ reallyDeliverTouchEvent(event);
+ return;
+ }
+
+ Qt::TouchPointStates states = event->touchPointStates();
+ if (((states & (Qt::TouchPointMoved | Qt::TouchPointStationary)) != 0)
+ && ((states & (Qt::TouchPointPressed | Qt::TouchPointReleased)) == 0)) {
+ // we can only compress something that isn't a press or release
+ if (!delayedTouch) {
+ delayedTouch = new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints());
+ delayedTouch->setTimestamp(event->timestamp());
+ if (windowManager)
+ windowManager->maybeUpdate(q);
+ return;
+ } else {
+ // check if this looks like the last touch event
+ if (delayedTouch->type() == event->type() &&
+ delayedTouch->device() == event->device() &&
+ delayedTouch->modifiers() == event->modifiers() &&
+ delayedTouch->touchPoints().count() == event->touchPoints().count())
+ {
+ // possible match.. is it really the same?
+ bool mismatch = false;
+
+ QList<QTouchEvent::TouchPoint> tpts = event->touchPoints();
+ Qt::TouchPointStates states;
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ const QTouchEvent::TouchPoint &tp = tpts.at(i);
+ const QTouchEvent::TouchPoint &tp2 = delayedTouch->touchPoints().at(i);
+ if (tp.id() != tp2.id()) {
+ mismatch = true;
+ break;
+ }
+
+ if (tp2.state() == Qt::TouchPointMoved && tp.state() == Qt::TouchPointStationary)
+ tpts[i].setState(Qt::TouchPointMoved);
+
+ states |= tpts.at(i).state();
+ }
+
+ // same touch event? then merge if so
+ if (!mismatch) {
+ delayedTouch->setTouchPoints(tpts);
+ delayedTouch->setTimestamp(event->timestamp());
+ return;
+ }
+ }
+
+ // otherwise; we need to deliver the delayed event first, and
+ // then delay this one..
+ reallyDeliverTouchEvent(delayedTouch);
+ delete delayedTouch;
+ delayedTouch = new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints());
+ delayedTouch->setTimestamp(event->timestamp());
+ return;
+ }
+ } else {
+ if (delayedTouch) {
+ // deliver the delayed touch first
+ reallyDeliverTouchEvent(delayedTouch);
+ delete delayedTouch;
+ delayedTouch = 0;
+ }
+ reallyDeliverTouchEvent(event);
+ }
+}
+
+void QQuickWindowPrivate::flushDelayedTouchEvent()
+{
+ if (delayedTouch) {
+ reallyDeliverTouchEvent(delayedTouch);
+ delete delayedTouch;
+ delayedTouch = 0;
+
+ // Touch events which constantly start animations (such as a behavior tracking
+ // the mouse point) need animations to start.
+ QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
+ if (ut && ut->hasStartAnimationPending())
+ ut->startAnimations();
+ }
+}
+
+void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
+{
+ qCDebug(DBG_TOUCH) << " - delivering" << event;
+
+ // If users spin the eventloop as a result of touch delivery, we disable
+ // touch compression and send events directly. This is because we consider
+ // the usecase a bit evil, but we at least don't want to lose events.
+ ++touchRecursionGuard;
// List of all items that received an event before
// When we have TouchBegin this is and will stay empty
@@ -1787,7 +1906,8 @@ bool QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
// or some item accepted a point and should receive an update
if (newPoints.count() > 0 || updatedPoints.count() > 0) {
QSet<int> acceptedNewPoints;
- event->setAccepted(deliverTouchPoints(contentItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
+ QSet<QQuickItem *> hasFiltered;
+ event->setAccepted(deliverTouchPoints(contentItem, event, newPoints, &acceptedNewPoints, &updatedPoints, &hasFiltered));
} else
event->ignore();
@@ -1798,6 +1918,7 @@ bool QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
itemForTouchPointId.remove(touchPoints[i].id());
if (touchPoints[i].id() == touchMouseId)
touchMouseId = -1;
+ touchMouseIdCandidates.remove(touchPoints[i].id());
}
}
}
@@ -1806,11 +1927,13 @@ bool QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
Q_ASSERT(itemForTouchPointId.isEmpty());
}
- return event->isAccepted();
+ --touchRecursionGuard;
}
// This function recurses and sends the events to the individual items
-bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
+bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints,
+ QSet<int> *acceptedNewPoints, QHash<QQuickItem *,
+ QList<QTouchEvent::TouchPoint> > *updatedPoints, QSet<QQuickItem *> *hasFiltered)
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
@@ -1829,7 +1952,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
QQuickItem *child = children.at(ii);
if (!child->isEnabled() || !child->isVisible() || QQuickItemPrivate::get(child)->culled)
continue;
- if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
+ if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints, hasFiltered))
return true;
}
@@ -1879,7 +2002,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
// with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
transformTouchPoints(matchingPoints, itemPrivate->windowToItemTransform());
- deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
+ deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints, hasFiltered);
}
// record the fact that this item has been visited already
@@ -1893,7 +2016,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
// only the points that are relevant for this item. Thus the need for
// matchingPoints to already be that set of interesting points.
// They are all pre-transformed, too.
-bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
+bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem *> *hasFiltered)
{
QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
touchEvent.data()->setTarget(item);
@@ -1901,7 +2024,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
// First check whether the parent wants to be a filter,
// and if the parent accepts the event we are done.
- if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
+ if (sendFilteredTouchEvent(item->parentItem(), item, event, hasFiltered)) {
// If the touch was accepted (regardless by whom or in what form),
// update acceptedNewPoints
foreach (int id, matchingNewPoints)
@@ -1921,7 +2044,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
// send mouse event
- event->setAccepted(translateTouchToMouse(item, event));
+ event->setAccepted(translateTouchToMouse(item, touchEvent.data()));
if (event->isAccepted()) {
touchEventAccepted = true;
}
@@ -2077,9 +2200,27 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
return false;
-
QPointF p = item->mapFromScene(event->pos());
- if (item->contains(p)) {
+ bool itemContained = item->contains(p);
+
+ if (!itemContained && itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
+ return false;
+ }
+
+ QDragEnterEvent enterEvent(
+ event->pos(),
+ event->possibleActions(),
+ event->mimeData(),
+ event->mouseButtons(),
+ event->keyboardModifiers());
+ QQuickDropEventEx::copyActions(&enterEvent, *event);
+ QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
+ return true;
+ }
+
+ if (itemContained) {
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
QDragMoveEvent translatedEvent(
p.toPoint(),
@@ -2099,21 +2240,6 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
accepted = true;
}
}
- } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- return false;
- }
-
- QDragEnterEvent enterEvent(
- event->pos(),
- event->possibleActions(),
- event->mimeData(),
- event->mouseButtons(),
- event->keyboardModifiers());
- QQuickDropEventEx::copyActions(&enterEvent, *event);
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
- return true;
}
return accepted;
@@ -2168,73 +2294,92 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF
}
#endif
-bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
+bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem *> *hasFiltered)
{
if (!target)
return false;
+ bool filtered = false;
+
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents) {
+ if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
+ hasFiltered->insert(target);
QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
if (!targetEvent->touchPoints().isEmpty()) {
- QVector<int> touchIds;
- for (int i = 0; i < event->touchPoints().size(); ++i)
- touchIds.append(event->touchPoints().at(i).id());
if (target->childMouseEventFilter(item, targetEvent.data())) {
+ QVector<int> touchIds;
+ for (int i = 0; i < targetEvent->touchPoints().size(); ++i)
+ touchIds.append(targetEvent->touchPoints().at(i).id());
target->grabTouchPoints(touchIds);
if (mouseGrabberItem) {
mouseGrabberItem->ungrabMouse();
touchMouseId = -1;
}
- return true;
+ filtered = true;
}
- // Only offer a mouse event to the filter if we have one point
- if (targetEvent->touchPoints().count() == 1) {
+ for (int i = 0; i < targetEvent->touchPoints().size(); ++i) {
+ const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().at(i);
+
QEvent::Type t;
- const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
switch (tp.state()) {
case Qt::TouchPointPressed:
t = QEvent::MouseButtonPress;
+ if (touchMouseId == -1) {
+ // We don't want to later filter touches as a mouse event if they were pressed
+ // while a touchMouseId was already active.
+ // Remember this touch as a potential to become the touchMouseId.
+ touchMouseIdCandidates.insert(tp.id());
+ }
break;
case Qt::TouchPointReleased:
t = QEvent::MouseButtonRelease;
break;
+ case Qt::TouchPointStationary:
+ continue;
default:
- // move or stationary
t = QEvent::MouseMove;
break;
}
- // targetEvent is already transformed wrt local position, velocity, etc.
- QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
- if (target->childMouseEventFilter(item, mouseEvent.data())) {
- itemForTouchPointId[tp.id()] = target;
- touchMouseId = tp.id();
- target->grabMouse();
- return true;
+ // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
+ if ((touchMouseIdCandidates.contains(tp.id()) && touchMouseId == -1) || touchMouseId == tp.id()) {
+ // targetEvent is already transformed wrt local position, velocity, etc.
+ QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event, item, false));
+ if (target->childMouseEventFilter(item, mouseEvent.data())) {
+ if (t != QEvent::MouseButtonRelease) {
+ itemForTouchPointId[tp.id()] = target;
+ touchMouseId = tp.id();
+ target->grabMouse();
+ }
+ touchMouseIdCandidates.clear();
+ filtered = true;
+ }
+ // Only one event can be filtered as a mouse event.
+ break;
}
}
}
}
- return sendFilteredTouchEvent(target->parentItem(), item, event);
+ return sendFilteredTouchEvent(target->parentItem(), item, event, hasFiltered) || filtered;
}
-bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
+bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event, QSet<QQuickItem *> *hasFiltered)
{
if (!target)
return false;
+ bool filtered = false;
+
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
- if (targetPrivate->filtersChildMouseEvents)
+ if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
+ hasFiltered->insert(target);
if (target->childMouseEventFilter(item, event))
- return true;
-
- if (sendFilteredMouseEvent(target->parentItem(), item, event))
- return true;
+ filtered = true;
+ }
- return false;
+ return sendFilteredMouseEvent(target->parentItem(), item, event, hasFiltered) || filtered;
}
bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold)
@@ -2375,18 +2520,22 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
- case QEvent::MouseMove:
- // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- // accept because qml items by default accept and have to explicitly opt out of accepting
- e->accept();
- QCoreApplication::sendEvent(item, e);
+ case QEvent::MouseMove: {
+ // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
+ QSet<QQuickItem *> hasFiltered;
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
+ // accept because qml items by default accept and have to explicitly opt out of accepting
+ e->accept();
+ QCoreApplication::sendEvent(item, e);
+ }
}
break;
- case QEvent::UngrabMouse:
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- e->accept();
- item->mouseUngrabEvent();
+ case QEvent::UngrabMouse: {
+ QSet<QQuickItem *> hasFiltered;
+ if (!d->sendFilteredMouseEvent(item->parentItem(), item, e, &hasFiltered)) {
+ e->accept();
+ item->mouseUngrabEvent();
+ }
}
break;
#ifndef QT_NO_WHEELEVENT
@@ -2408,8 +2557,10 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
break;
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
+ case QEvent::TouchEnd: {
+ QSet<QQuickItem*> hasFiltered;
+ d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e), &hasFiltered);
+ }
break;
default:
break;
@@ -2463,9 +2614,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown()
void QQuickWindowPrivate::updateDirtyNodes()
{
-#ifdef DIRTY_DEBUG
- qWarning() << "QQuickWindowPrivate::updateDirtyNodes():";
-#endif
+ qCDebug(DBG_DIRTY) << "QQuickWindowPrivate::updateDirtyNodes():";
cleanupNodes();
@@ -2478,9 +2627,7 @@ void QQuickWindowPrivate::updateDirtyNodes()
QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
itemPriv->removeFromDirtyList();
-#ifdef DIRTY_DEBUG
- qWarning() << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
-#endif
+ qCDebug(DBG_DIRTY) << " QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
updateDirtyNode(item);
}
}
@@ -2727,7 +2874,7 @@ void QQuickWindow::maybeUpdate()
{
Q_D(QQuickWindow);
if (d->renderControl)
- d->renderControl->maybeUpdate();
+ QQuickRenderControlPrivate::get(d->renderControl)->maybeUpdate();
else if (d->windowManager)
d->windowManager->maybeUpdate(this);
}
@@ -2736,13 +2883,21 @@ void QQuickWindow::cleanupSceneGraph()
{
Q_D(QQuickWindow);
+ delete d->vaoHelper;
+ d->vaoHelper = 0;
+
if (!d->renderer)
return;
delete d->renderer->rootNode();
delete d->renderer;
-
d->renderer = 0;
+
+ d->runAndClearJobs(&d->beforeSynchronizingJobs);
+ d->runAndClearJobs(&d->afterSynchronizingJobs);
+ d->runAndClearJobs(&d->beforeRenderingJobs);
+ d->runAndClearJobs(&d->afterRenderingJobs);
+ d->runAndClearJobs(&d->afterSwapJobs);
}
void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
@@ -2794,6 +2949,11 @@ QOpenGLContext *QQuickWindow::openglContext() const
has been invalidated and all user resources tied to that context
should be released.
+ The OpenGL context of this window will be bound when this function
+ is called. The only exception is if the native OpenGL has been
+ destroyed outside Qt's control, for instance through
+ EGL_CONTEXT_LOST.
+
This signal will be emitted from the scene graph rendering thread.
*/
@@ -2817,7 +2977,7 @@ QOpenGLContext *QQuickWindow::openglContext() const
\internal
\since 5.1
- \inmodule QtQuick.Window
+ \inmodule QtQuick
\brief Notification that a \l QQuickWindow is about to be closed
*/
@@ -2988,7 +3148,7 @@ QImage QQuickWindow::grabWindow()
QOpenGLContext context;
context.setFormat(requestedFormat());
- context.setShareContext(QOpenGLContextPrivate::globalShareContext());
+ context.setShareContext(qt_gl_global_share_context());
context.create();
context.makeCurrent(this);
d->context->initialize(&context);
@@ -3280,7 +3440,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
{
Q_D(const QQuickWindow);
- if (d->context && d->context->openglContext()) {
+ if (d->context) {
if (options & TextureCanUseAtlas)
return d->context->createTexture(image);
else
@@ -3380,10 +3540,10 @@ bool QQuickWindow::hasDefaultAlphaBuffer()
\brief \a useAlpha specifies whether to use alpha transparency on newly created windows.
\since 5.1
- In any application which expects to create translucent windows, it's
- necessary to set this to true before creating the first QQuickWindow,
- because all windows will share the same \l QOpenGLContext. The default
- value is false.
+ In any application which expects to create translucent windows, it's necessary to set
+ this to true before creating the first QQuickWindow. The default value is false.
+
+ \sa hasDefaultAlphaBuffer()
*/
void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
{
@@ -3414,38 +3574,48 @@ void QQuickWindow::resetOpenGLState()
if (!openglContext())
return;
- QOpenGLFunctions *gl = openglContext()->functions();
+ Q_D(QQuickWindow);
+
+ QOpenGLContext *ctx = openglContext();
+ QOpenGLFunctions *gl = ctx->functions();
gl->glBindBuffer(GL_ARRAY_BUFFER, 0);
gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- int maxAttribs;
- glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
- for (int i=0; i<maxAttribs; ++i) {
- gl->glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
- gl->glDisableVertexAttribArray(i);
+ if (!d->vaoHelper)
+ d->vaoHelper = new QOpenGLVertexArrayObjectHelper(ctx);
+ if (d->vaoHelper->isValid())
+ d->vaoHelper->glBindVertexArray(0);
+
+ if (ctx->isOpenGLES() || (gl->openGLFeatures() & QOpenGLFunctions::FixedFunctionPipeline)) {
+ int maxAttribs;
+ gl->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs);
+ for (int i=0; i<maxAttribs; ++i) {
+ gl->glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
+ gl->glDisableVertexAttribArray(i);
+ }
}
gl->glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, 0);
+ gl->glBindTexture(GL_TEXTURE_2D, 0);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_SCISSOR_TEST);
+ gl->glDisable(GL_DEPTH_TEST);
+ gl->glDisable(GL_STENCIL_TEST);
+ gl->glDisable(GL_SCISSOR_TEST);
- glColorMask(true, true, true, true);
- glClearColor(0, 0, 0, 0);
+ gl->glColorMask(true, true, true, true);
+ gl->glClearColor(0, 0, 0, 0);
- glDepthMask(true);
- glDepthFunc(GL_LESS);
+ gl->glDepthMask(true);
+ gl->glDepthFunc(GL_LESS);
gl->glClearDepthf(1);
- glStencilMask(0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_ALWAYS, 0, 0xff);
+ gl->glStencilMask(0xff);
+ gl->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ gl->glStencilFunc(GL_ALWAYS, 0, 0xff);
- glDisable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ZERO);
+ gl->glDisable(GL_BLEND);
+ gl->glBlendFunc(GL_ONE, GL_ZERO);
gl->glUseProgram(0);
@@ -3453,6 +3623,87 @@ void QQuickWindow::resetOpenGLState()
}
/*!
+ \brief QQuickWindow::glslVersion
+ \since 5.4
+ \return The OpenGL Shading Language version for this window.
+
+ QML components that need to be usable on different platforms and environments may need
+ to deal with different OpenGL versions if they include ShaderEffect items. The source
+ code for a given shader may not be compatible with an OpenGL context that targets a
+ different OpenGL version or profile, hence it might be necessary to provide multiple
+ versions of the shader. This property helps in deciding which shader source should be
+ chosen.
+
+ The value corresponds to GLSL version declarations, for example an OpenGL 4.2 core
+ profile context will result in the value \e{420 core}, while an OpenGL ES 3.0 context
+ gives \e{300 es}. For OpenGL (ES) 2 the value will be an empty string since the
+ corresponding shading language does not use version declarations.
+
+ \note The value does not necessarily indicate that the shader source must target that
+ specific version. For example, compatibility profiles and ES 3.x all allow using
+ OpenGL 2 style shaders. The most important for reusable components is to check for
+ core profiles since these do not accept shaders with the old syntax.
+
+ \sa setFormat(), glslIsCoreProfile()
+ */
+QString QQuickWindow::glslVersion() const
+{
+ QString ver;
+ QOpenGLContext *ctx = openglContext();
+ if (ctx) {
+ const QSurfaceFormat fmt = ctx->format();
+ if (fmt.renderableType() == QSurfaceFormat::OpenGLES
+ && fmt.majorVersion() >= 3) {
+ ver += QLatin1Char(fmt.majorVersion() + '0');
+ ver += QLatin1Char(fmt.minorVersion() + '0');
+ ver += QLatin1String("0 es");
+ } else if (fmt.renderableType() == QSurfaceFormat::OpenGL
+ && fmt.majorVersion() >= 3) {
+ if (fmt.version() == qMakePair(3, 0)) {
+ ver = QStringLiteral("130");
+ } else if (fmt.version() == qMakePair(3, 1)) {
+ ver = QStringLiteral("140");
+ } else if (fmt.version() == qMakePair(3, 2)) {
+ ver = QStringLiteral("150");
+ } else {
+ ver += QLatin1Char(fmt.majorVersion() + '0');
+ ver += QLatin1Char(fmt.minorVersion() + '0');
+ ver += QLatin1Char('0');
+ }
+ if (fmt.version() >= qMakePair(3, 2)) {
+ if (fmt.profile() == QSurfaceFormat::CoreProfile)
+ ver += QStringLiteral(" core");
+ else if (fmt.profile() == QSurfaceFormat::CompatibilityProfile)
+ ver += QStringLiteral(" compatibility");
+ }
+ }
+ }
+ return ver;
+}
+
+/*!
+ \brief QQuickWindow::glslIsCoreProfile
+ \since 5.4
+ \return True if the window is rendering using OpenGL core profile.
+
+ This is convenience function to check if the window's OpenGL context is a core profile
+ context. It is more efficient to perform the check via this function than parsing the
+ string returned from glslVersion().
+
+ Resusable QML components will typically use this function in bindings in order to
+ choose between core and non core profile compatible shader sources.
+
+ To retrieve more information about the shading language, use glslVersion().
+
+ \sa glslVersion(), setFormat()
+ */
+bool QQuickWindow::glslIsCoreProfile() const
+{
+ QOpenGLContext *ctx = openglContext();
+ return ctx ? ctx->format().profile() == QSurfaceFormat::CoreProfile : false;
+}
+
+/*!
\qmlproperty string Window::title
The window's title in the windowing system.
@@ -3557,6 +3808,18 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
+ \qmlattachedproperty QWindow::Visibility Window::visibility
+ \since 5.4
+
+ This attached property holds whether whether the window is currently shown
+ in the windowing system as normal, minimized, maximized, fullscreen or
+ hidden. The Window attached property can be attached to any Item. If the
+ item is not shown in any window, the value will be \l {QWindow::}{Hidden}.
+
+ \sa visible, visibility
+*/
+
+/*!
\qmlproperty Qt::ScreenOrientation Window::contentOrientation
This is a hint to the window manager in case it needs to display
@@ -3603,6 +3866,15 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
+ \qmlattachedproperty Item Window::activeFocusItem
+ \since 5.4
+
+ This attached property holds the item which currently has active focus or
+ \c null if there is no item with active focus. The Window attached property
+ can be attached to any Item.
+*/
+
+/*!
\qmlproperty Window::active
\since 5.1
@@ -3612,6 +3884,26 @@ void QQuickWindow::resetOpenGLState()
*/
/*!
+ \qmlattachedproperty bool Window::active
+ \since 5.4
+
+ This attached property tells whether the window is active. The Window
+ attached property can be attached to any Item.
+
+ Here is an example which changes a label to show the active state of the
+ window in which it is shown:
+
+ \qml
+ import QtQuick 2.4
+ import QtQuick.Window 2.2
+
+ Text {
+ text: Window.active ? "active" : "inactive"
+ }
+ \endqml
+*/
+
+/*!
\qmlmethod QtQuick::Window::requestActivate()
\since 5.1
@@ -3630,6 +3922,91 @@ void QQuickWindow::resetOpenGLState()
flashing or bouncing the taskbar entry.
*/
+/*!
+ \enum QQuickWindow::RenderJobSchedule
+ \since 5.4
+
+ \value ScheduleBeforeSynchronizing Before synchronization.
+ \value ScheduleAfterSynchronizing After synchronization.
+ \value ScheduleBeforeRendering Before rendering.
+ \value ScheduleAfterRendering After rendering.
+ \value ScheduleAfterSwap After the frame is swapped.
+
+ \sa {Scene Graph and Rendering}
+ */
+
+/*!
+ \since 5.4
+
+ Schedule \a job to run when the rendering of this window reaches
+ the given \a stage.
+
+ This is a convenience to the equivalent signals in QQuickWindow for
+ "one shot" tasks.
+
+ The window takes ownership over \a job and will delete it when the
+ job is completed.
+
+ If rendering is shut down before \a job has a chance to run, the
+ job will be run and then deleted as part of the scene graph cleanup.
+ If the window is never shown and no rendering happens before the QQuickWindow
+ is destroyed, all pending jobs will be destroyed without their run()
+ method being called.
+
+ If the rendering is happening on a different thread, then the job
+ will happen on the rendering thread.
+
+ \note This function does not trigger rendering; the job
+ will be stored run until rendering is triggered elsewhere.
+ To force the job to run earlier, call QQuickWindow::update();
+
+ \sa beforeRendering(), afterRendering(), beforeSynchronizing(),
+ afterSynchronizing(), frameSwapped(), sceneGraphInvalidated()
+ */
+
+void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
+{
+ Q_D(QQuickWindow);
+
+ d->renderJobMutex.lock();
+ if (stage == BeforeSynchronizingStage)
+ d->beforeSynchronizingJobs << job;
+ else if (stage == AfterSynchronizingStage)
+ d->afterSynchronizingJobs << job;
+ else if (stage == BeforeRenderingStage)
+ d->beforeRenderingJobs << job;
+ else if (stage == AfterRenderingStage)
+ d->afterRenderingJobs << job;
+ else if (stage == AfterSwapStage)
+ d->afterSwapJobs << job;
+ d->renderJobMutex.unlock();
+}
+
+QQuickWindowAttached *QQuickWindow::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickWindowAttached(object);
+}
+
+void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
+{
+ renderJobMutex.lock();
+ QList<QRunnable *> jobList = *jobs;
+ jobs->clear();
+ renderJobMutex.unlock();
+
+ foreach (QRunnable *r, jobList) {
+ r->run();
+ delete r;
+ }
+}
+
+void QQuickWindow::runJobsAfterSwap()
+{
+ Q_D(QQuickWindow);
+ d->runAndClearJobs(&d->afterSwapJobs);
+}
+
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 0d1aaf64f0..7757168aa3 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -47,13 +47,16 @@
#include <QtGui/qopengl.h>
#include <QtGui/qwindow.h>
#include <QtGui/qevent.h>
+#include <qqml.h>
QT_BEGIN_NAMESPACE
+class QRunnable;
class QQuickItem;
class QSGTexture;
class QInputMethodEvent;
class QQuickWindowPrivate;
+class QQuickWindowAttached;
class QOpenGLFramebufferObject;
class QQmlIncubationController;
class QInputMethodEvent;
@@ -67,6 +70,8 @@ class Q_QUICK_EXPORT QQuickWindow : public QWindow
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT)
Q_PROPERTY(QQuickItem* activeFocusItem READ activeFocusItem NOTIFY activeFocusItemChanged REVISION 1)
+ Q_PROPERTY(QString glslVersion READ glslVersion CONSTANT REVISION 2)
+ Q_PROPERTY(bool glslIsCoreProfile READ glslIsCoreProfile CONSTANT REVISION 2)
Q_CLASSINFO("DefaultProperty", "data")
Q_DECLARE_PRIVATE(QQuickWindow)
public:
@@ -77,6 +82,14 @@ public:
TextureCanUseAtlas = 0x0008
};
+ enum RenderStage {
+ BeforeSynchronizingStage,
+ AfterSynchronizingStage,
+ BeforeRenderingStage,
+ AfterRenderingStage,
+ AfterSwapStage
+ };
+
Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption)
enum SceneGraphError {
@@ -85,6 +98,7 @@ public:
Q_ENUMS(SceneGraphError)
QQuickWindow(QWindow *parent = 0);
+ explicit QQuickWindow(QQuickRenderControl *renderControl);
virtual ~QQuickWindow();
@@ -136,6 +150,13 @@ public:
QOpenGLContext *openglContext() const;
+ QString glslVersion() const;
+ bool glslIsCoreProfile() const;
+
+ void scheduleRenderJob(QRunnable *job, RenderStage schedule);
+
+ static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@@ -187,19 +208,20 @@ private Q_SLOTS:
void cleanupSceneGraph();
void forcePolish();
void setTransientParent_helper(QQuickWindow *window);
+ void runJobsAfterSwap();
private:
friend class QQuickItem;
friend class QQuickWidget;
friend class QQuickRenderControl;
friend class QQuickAnimatorController;
- explicit QQuickWindow(QQuickRenderControl*);
Q_DISABLE_COPY(QQuickWindow)
};
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
+QML_DECLARE_TYPEINFO(QQuickWindow, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKWINDOW_H
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 421651b483..c8f156ed37 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -94,6 +94,8 @@ class QTouchEvent;
class QQuickWindowRenderLoop;
class QQuickWindowIncubationController;
+class QOpenGLVertexArrayObjectHelper;
+
class Q_QUICK_PRIVATE_EXPORT QQuickWindowPrivate : public QWindowPrivate
{
public:
@@ -135,19 +137,21 @@ public:
static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
bool deliverMouseEvent(QMouseEvent *);
- bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *);
+ bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *, QSet<QQuickItem *> *);
#ifndef QT_NO_WHEELEVENT
bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
#endif
bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
- QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *);
- bool deliverTouchEvent(QTouchEvent *);
+ QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *, QSet<QQuickItem*> *filtered);
+ void deliverTouchEvent(QTouchEvent *);
+ void reallyDeliverTouchEvent(QTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *);
+ void flushDelayedTouchEvent();
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
- bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints);
+ bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent);
QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
- bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event);
+ bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
bool clearHover();
@@ -210,6 +214,8 @@ public:
QSGRenderLoop *windowManager;
QQuickRenderControl *renderControl;
QQuickAnimatorController *animationController;
+ QTouchEvent *delayedTouch;
+ int touchRecursionGuard;
QColor clearColor;
@@ -223,12 +229,17 @@ public:
uint lastWheelEventAccepted : 1;
bool componentCompleted : 1;
+ Qt::FocusReason lastFocusReason;
+
QOpenGLFramebufferObject *renderTarget;
uint renderTargetId;
QSize renderTargetSize;
+ QOpenGLVertexArrayObjectHelper *vaoHelper;
+
// Keeps track of which touch point (int) was last accepted by which item
QHash<int, QQuickItem *> itemForTouchPointId;
+ QSet<int> touchMouseIdCandidates;
mutable QQuickWindowIncubationController *incubationController;
@@ -247,6 +258,15 @@ public:
QString *untranslatedMessage,
bool isEs);
+ QMutex renderJobMutex;
+ QList<QRunnable *> beforeSynchronizingJobs;
+ QList<QRunnable *> afterSynchronizingJobs;
+ QList<QRunnable *> beforeRenderingJobs;
+ QList<QRunnable *> afterRenderingJobs;
+ QList<QRunnable *> afterSwapJobs;
+
+ void runAndClearJobs(QList<QRunnable *> *jobs);
+
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
diff --git a/src/quick/items/qquickwindowattached.cpp b/src/quick/items/qquickwindowattached.cpp
new file mode 100644
index 0000000000..666b21f6cd
--- /dev/null
+++ b/src/quick/items/qquickwindowattached.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickwindow.h"
+#include "qquickitem.h"
+#include "qquickwindowattached_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// QDoc comments must go in qquickwindow.cpp to avoid overwriting the Window docs
+
+QQuickWindowAttached::QQuickWindowAttached(QObject* attachee)
+ : QObject(attachee)
+ , m_window(NULL)
+{
+ m_attachee = qobject_cast<QQuickItem*>(attachee);
+ if (m_attachee && m_attachee->window()) // It might not be in a window yet
+ windowChanged(m_attachee->window());
+ if (m_attachee)
+ connect(m_attachee, &QQuickItem::windowChanged, this, &QQuickWindowAttached::windowChanged);
+}
+
+QWindow::Visibility QQuickWindowAttached::visibility() const
+{
+ return (m_window ? m_window->visibility() : QWindow::Hidden);
+}
+
+bool QQuickWindowAttached::isActive() const
+{
+ return (m_window ? m_window->isActive() : false);
+}
+
+QQuickItem *QQuickWindowAttached::activeFocusItem() const
+{
+ return (m_window ? m_window->activeFocusItem() : Q_NULLPTR);
+}
+
+void QQuickWindowAttached::windowChanged(QQuickWindow *window)
+{
+ if (window != m_window) {
+ QQuickWindow* oldWindow = m_window;
+ m_window = window;
+
+ if (oldWindow)
+ oldWindow->disconnect(this);
+
+ if (!window)
+ return; // No values to get, therefore nothing to emit
+
+ if (!oldWindow || window->visibility() != oldWindow->visibility())
+ emit visibilityChanged();
+ if (!oldWindow || window->isActive() != oldWindow->isActive())
+ emit activeChanged();
+ if (!oldWindow || window->activeFocusItem() != oldWindow->activeFocusItem())
+ emit activeFocusItemChanged();
+
+ // QQuickWindowQmlImpl::visibilityChanged also exists, and window might even
+ // be QQuickWindowQmlImpl, but that's not what we are connecting to.
+ // So this is actual window state rather than a buffered or as-requested one.
+ // If we used the metaobject connect syntax there would be a warning:
+ // QMetaObjectPrivate::indexOfSignalRelative - QMetaObject::indexOfSignal:
+ // signal visibilityChanged(QWindow::Visibility) from QQuickWindow redefined in QQuickWindowQmlImpl
+ connect(window, &QQuickWindow::visibilityChanged,
+ this, &QQuickWindowAttached::visibilityChanged);
+ connect(window, &QQuickWindow::activeChanged,
+ this, &QQuickWindowAttached::activeChanged);
+ connect(window, &QQuickWindow::activeFocusItemChanged,
+ this, &QQuickWindowAttached::activeFocusItemChanged);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindowattached_p.h b/src/quick/items/qquickwindowattached_p.h
new file mode 100644
index 0000000000..007ff007f7
--- /dev/null
+++ b/src/quick/items/qquickwindowattached_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOW_ATTACHED_P_H
+#define QQUICKWINDOW_ATTACHED_P_H
+
+#include <qqml.h>
+#include <QWindow>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickWindow;
+
+class Q_AUTOTEST_EXPORT QQuickWindowAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QWindow::Visibility visibility READ visibility NOTIFY visibilityChanged)
+ Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
+ Q_PROPERTY(QQuickItem* activeFocusItem READ activeFocusItem NOTIFY activeFocusItemChanged)
+
+public:
+ QQuickWindowAttached(QObject* attachee);
+
+ QWindow::Visibility visibility() const;
+ bool isActive() const;
+ QQuickItem* activeFocusItem() const;
+
+Q_SIGNALS:
+
+ void visibilityChanged();
+ void activeChanged();
+ void activeFocusItemChanged();
+
+protected Q_SLOTS:
+ void windowChanged(QQuickWindow*);
+
+private:
+ QQuickWindow* m_window;
+ QQuickItem* m_attachee;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index 91388ea30f..f472d5b867 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qquickwindowmodule_p.h"
+#include "qquickwindowattached_p.h"
#include "qquickscreen_p.h"
#include "qquickview_p.h"
#include <QtQuick/QQuickWindow>
@@ -102,7 +103,7 @@ protected:
{
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(e);
QV4::Scope scope(v4);
- QV4::ScopedObject v(scope, new (v4->memoryManager) QQuickRootItemMarker(e, this));
+ QV4::ScopedObject v(scope, QQuickRootItemMarker::create(e, this));
rootItemMarker = v;
}
}
@@ -173,6 +174,10 @@ void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
+ // Since Window is both an attached property and a createable type,
+ // the attached property declaration must come first so that it can
+ // be overridden below.
+ qmlRegisterUncreatableType<QQuickWindow>(uri, 2, 2, "Window", QQuickWindow::tr("Window is available via attached properties"));
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
qmlRegisterRevision<QWindow,2>(uri, 2, 2);
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index 9d2a0b0f75..fe24c2512a 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -44,6 +44,7 @@
#include <private/qquickutilmodule_p.h>
#include <private/qquickvaluetypes_p.h>
#include <private/qquickitemsmodule_p.h>
+#include <private/qquickaccessiblefactory_p.h>
#include <private/qqmlenginedebugservice_p.h>
#include <private/qqmldebugstatesdelegate_p.h>
@@ -190,6 +191,10 @@ void QQmlQtQuick2Module::defineModule()
QQuickValueTypes::registerValueTypes();
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::installFactory(&qQuickAccessibleFactory);
+#endif
+
if (QQmlDebugService::isDebuggingEnabled()) {
QQmlEngineDebugService::instance()->setStatesDelegate(
new QQmlQtQuick2DebugStatesDelegate);
diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h
index f67a08c218..cd4cb61ebb 100644
--- a/src/quick/qtquickglobal_p.h
+++ b/src/quick/qtquickglobal_p.h
@@ -42,6 +42,8 @@
#ifndef QTQUICKGLOBAL_P_H
#define QTQUICKGLOBAL_P_H
+#include <QtCore/qloggingcategory.h>
+
//
// W A R N I N G
// -------------
@@ -61,6 +63,11 @@ QT_BEGIN_NAMESPACE
void QQuick_initializeProviders();
+Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH)
+Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE)
+Q_DECLARE_LOGGING_CATEGORY(DBG_FOCUS)
+Q_DECLARE_LOGGING_CATEGORY(DBG_DIRTY)
+
QT_END_NAMESPACE
#endif // QTQUICKGLOBAL_P_H
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index 38e743cc5c..6e08662e61 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -29,6 +29,9 @@ include(util/util.pri)
include(scenegraph/scenegraph.pri)
include(items/items.pri)
include(designer/designer.pri)
+contains(QT_CONFIG, accessibility) {
+ include(accessible/accessible.pri)
+}
HEADERS += \
qtquickglobal.h \
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
new file mode 100644
index 0000000000..9409822c8f
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgabstractrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGAbstractRenderer
+ \brief QSGAbstractRenderer gives access to the scene graph nodes and rendering of a QSGEngine.
+ \inmodule QtQuick
+ \since 5.4
+
+ A QSGAbstractRenderer created by a QSGEngine allows you to set your QSGNode
+ tree through setRootNode() and control the rendering viewport through
+ setDeviceRect(), setViewportRect() and setProjectionMatrixToRect().
+ You can finally trigger the rendering to the desired framebuffer through
+ renderScene().
+
+ The QSGAbstractRenderer is only available when used with a QSGEngine
+ and isn't exposed when used internally by QQuickWindow.
+
+ \sa QSGEngine, QSGNode
+ */
+
+/*!
+ \enum QSGAbstractRenderer::ClearModeBit
+
+ Used with setClearMode() to indicate which buffer should
+ be cleared before the scene render.
+
+ \value ClearColorBuffer Clear the color buffer using clearColor().
+ \value ClearDepthBuffer Clear the depth buffer.
+ \value ClearStencilBuffer Clear the stencil buffer.
+
+ \sa setClearMode(), setClearColor()
+ */
+
+/*!
+ \fn void QSGAbstractRenderer::renderScene(GLuint fboId = 0)
+
+ Render the scene to the specified \a fboId
+
+ If \a fboId isn't specified, the scene graph will be rendered
+ to the default framebuffer. You will have to call
+ QOpenGLContext::swapBuffers() yourself afterward.
+
+ The framebuffer specified by \a fboId will be bound automatically.
+
+ \sa QOpenGLContext::swapBuffers(), QOpenGLFramebufferObject::handle()
+ */
+
+/*!
+ \fn void QSGAbstractRenderer::sceneGraphChanged()
+
+ This signal is emitted on the first modification of a node in
+ the tree after the last scene render.
+ */
+
+/*!
+ \internal
+ */
+QSGAbstractRendererPrivate::QSGAbstractRendererPrivate()
+ : m_root_node(0)
+ , m_clear_color(Qt::transparent)
+ , m_clear_mode(QSGAbstractRenderer::ClearColorBuffer | QSGAbstractRenderer::ClearDepthBuffer)
+{
+}
+
+/*!
+ \internal
+ */
+QSGAbstractRenderer::QSGAbstractRenderer(QObject *parent)
+ : QObject(*new QSGAbstractRendererPrivate, parent)
+{
+}
+
+/*!
+ \internal
+ */
+QSGAbstractRenderer::~QSGAbstractRenderer()
+{
+}
+
+/*!
+ Sets the \a node as the root of the QSGNode scene
+ that you want to render. You need to provide a \a node
+ before trying to render the scene.
+
+ \note This doesn't take ownership of \a node.
+
+ \sa rootNode()
+*/
+void QSGAbstractRenderer::setRootNode(QSGRootNode *node)
+{
+ Q_D(QSGAbstractRenderer);
+ if (d->m_root_node == node)
+ return;
+ if (d->m_root_node) {
+ d->m_root_node->m_renderers.removeOne(this);
+ nodeChanged(d->m_root_node, QSGNode::DirtyNodeRemoved);
+ }
+ d->m_root_node = node;
+ if (d->m_root_node) {
+ Q_ASSERT(!d->m_root_node->m_renderers.contains(this));
+ d->m_root_node->m_renderers << this;
+ nodeChanged(d->m_root_node, QSGNode::DirtyNodeAdded);
+ }
+}
+
+/*!
+ Returns the root of the QSGNode scene.
+
+ \sa setRootNode()
+*/
+QSGRootNode *QSGAbstractRenderer::rootNode() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_root_node;
+}
+
+
+/*!
+ \fn void QSGAbstractRenderer::setDeviceRect(const QSize &size)
+ \overload
+
+ Sets the \a size of the surface being rendered to.
+
+ \sa deviceRect()
+ */
+
+/*!
+ Sets \a rect as the geometry of the surface being rendered to.
+
+ \sa deviceRect()
+ */
+void QSGAbstractRenderer::setDeviceRect(const QRect &rect)
+{
+ Q_D(QSGAbstractRenderer);
+ d->m_device_rect = rect;
+}
+
+/*!
+ Returns the device rect of the surface being rendered to.
+
+ \sa setDeviceRect()
+ */
+QRect QSGAbstractRenderer::deviceRect() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_device_rect;
+}
+
+/*!
+ \fn void QSGAbstractRenderer::setViewportRect(const QSize &size)
+ \overload
+
+ Sets the \a size of the viewport to render
+ on the surface.
+
+ \sa viewportRect()
+ */
+
+/*!
+ Sets \a rect as the geometry of the viewport to render
+ on the surface.
+
+ \sa viewportRect()
+ */
+void QSGAbstractRenderer::setViewportRect(const QRect &rect)
+{
+ Q_D(QSGAbstractRenderer);
+ d->m_viewport_rect = rect;
+}
+
+/*!
+ Returns the rect of the viewport to render.
+
+ \sa setViewportRect()
+ */
+QRect QSGAbstractRenderer::viewportRect() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_viewport_rect;
+}
+
+/*!
+ Convenience method that calls setProjectionMatrix() with an
+ orthographic matrix generated from \a rect.
+
+ \sa setProjectionMatrix(), projectionMatrix()
+ */
+void QSGAbstractRenderer::setProjectionMatrixToRect(const QRectF &rect)
+{
+ QMatrix4x4 matrix;
+ matrix.ortho(rect.x(),
+ rect.x() + rect.width(),
+ rect.y() + rect.height(),
+ rect.y(),
+ 1,
+ -1);
+ setProjectionMatrix(matrix);
+}
+
+/*!
+ Use \a matrix to project the QSGNode coordinates onto surface pixels.
+
+ \sa projectionMatrix(), setProjectionMatrixToRect()
+ */
+void QSGAbstractRenderer::setProjectionMatrix(const QMatrix4x4 &matrix)
+{
+ Q_D(QSGAbstractRenderer);
+ d->m_projection_matrix = matrix;
+}
+
+/*!
+ Returns the projection matrix
+
+ \sa setProjectionMatrix(), setProjectionMatrixToRect()
+ */
+QMatrix4x4 QSGAbstractRenderer::projectionMatrix() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_projection_matrix;
+}
+
+/*!
+ Use \a color to clear the framebuffer when clearMode() is
+ set to QSGAbstractRenderer::ClearColorBuffer.
+
+ \sa clearColor(), setClearMode()
+ */
+void QSGAbstractRenderer::setClearColor(const QColor &color)
+{
+ Q_D(QSGAbstractRenderer);
+ d->m_clear_color = color;
+}
+
+/*!
+ Returns the color that clears the framebuffer at the beginning
+ of the rendering.
+
+ \sa setClearColor(), clearMode()
+ */
+QColor QSGAbstractRenderer::clearColor() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_clear_color;
+}
+
+/*!
+ Defines which attachment of the framebuffer should be cleared
+ before each scene render with the \a mode flag.
+
+ \sa clearMode(), setClearColor()
+ */
+void QSGAbstractRenderer::setClearMode(ClearMode mode)
+{
+ Q_D(QSGAbstractRenderer);
+ d->m_clear_mode = mode;
+}
+
+/*!
+ Flags defining which attachment of the framebuffer will be cleared
+ before each scene render.
+
+ \sa setClearMode(), clearColor()
+ */
+QSGAbstractRenderer::ClearMode QSGAbstractRenderer::clearMode() const
+{
+ Q_D(const QSGAbstractRenderer);
+ return d->m_clear_mode;
+}
+
+/*!
+ \fn void QSGAbstractRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
+ \internal
+ */
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
new file mode 100644
index 0000000000..671d62e931
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGABSTRACTRENDERER_H
+#define QSGABSTRACTRENDERER_H
+
+#include "qsgnode.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGAbstractRendererPrivate;
+
+class Q_QUICK_EXPORT QSGAbstractRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ enum ClearModeBit
+ {
+ ClearColorBuffer = 0x0001,
+ ClearDepthBuffer = 0x0002,
+ ClearStencilBuffer = 0x0004
+ };
+ Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
+
+ virtual ~QSGAbstractRenderer();
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const;
+ void setDeviceRect(const QRect &rect);
+ inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
+ QRect deviceRect() const;
+
+ void setViewportRect(const QRect &rect);
+ inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
+ QRect viewportRect() const;
+
+ void setProjectionMatrixToRect(const QRectF &rect);
+ void setProjectionMatrix(const QMatrix4x4 &matrix);
+ QMatrix4x4 projectionMatrix() const;
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const;
+
+ void setClearMode(ClearMode mode);
+ ClearMode clearMode() const;
+
+ virtual void renderScene(GLuint fboId = 0) = 0;
+
+Q_SIGNALS:
+ void sceneGraphChanged();
+
+protected:
+ QSGAbstractRenderer(QObject *parent = 0);
+ virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) = 0;
+
+private:
+ Q_DECLARE_PRIVATE(QSGAbstractRenderer)
+ friend class QSGRootNode;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGAbstractRenderer::ClearMode)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h
new file mode 100644
index 0000000000..c60a488cc8
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGABSTRACTRENDERER_P_H
+#define QSGABSTRACTRENDERER_P_H
+
+#include "qsgabstractrenderer.h"
+
+#include "qsgnode.h"
+#include <qcolor.h>
+
+#include <QtCore/private/qobject_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGAbstractRendererPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGAbstractRenderer)
+public:
+ static const QSGAbstractRendererPrivate *get(const QSGAbstractRenderer *q) { return q->d_func(); }
+
+ QSGAbstractRendererPrivate();
+ void updateProjectionMatrix();
+
+ QSGRootNode *m_root_node;
+ QColor m_clear_color;
+ QSGAbstractRenderer::ClearMode m_clear_mode;
+
+ QRect m_device_rect;
+ QRect m_viewport_rect;
+
+ QMatrix4x4 m_projection_matrix;
+ uint m_mirrored : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 5c83528b82..4119dfb530 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -53,8 +53,10 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLVertexArrayObject>
+#include <QtGui/QOpenGLFunctions_1_0>
#include <private/qquickprofiler_p.h>
+#include "qsgmaterialshader_p.h"
#include <algorithm>
@@ -79,10 +81,7 @@ const bool debug_noalpha = qgetenv("QSG_RENDERER_DEBUG").contains("noalpha");
const bool debug_noopaque = qgetenv("QSG_RENDERER_DEBUG").contains("noopaque");
const bool debug_noclip = qgetenv("QSG_RENDERER_DEBUG").contains("noclip");
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer qsg_renderer_timer;
-#endif
#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
#define SHADOWNODE_TRAVERSE(NODE) for (QList<Node *>::const_iterator child = NODE->children.constBegin(); child != NODE->children.constEnd(); ++child)
@@ -133,10 +132,8 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material)
if (shader)
return shader;
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing || QQuickProfiler::enabled)
+ if (QSG_LOG_TIME_COMPILATION().isDebugEnabled() || QQuickProfiler::enabled)
qsg_renderer_timer.start();
-#endif
QSGMaterialShader *s = material->createShader();
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@@ -164,13 +161,10 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material)
Q_ASSERT(shader->pos_order >= 0);
Q_ASSERT(shader->id_zRange >= 0);
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- qDebug(" - compiling material: %dms", (int) qsg_renderer_timer.elapsed());
+ qCDebug(QSG_LOG_TIME_COMPILATION, "shader compiled in %dms", (int) qsg_renderer_timer.elapsed());
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphContextFrame, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphContextFrame, (
qsg_renderer_timer.nsecsElapsed()));
-#endif
rewrittenShaders[type] = shader;
return shader;
@@ -183,10 +177,8 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate
if (shader)
return shader;
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing || QQuickProfiler::enabled)
+ if (QSG_LOG_TIME_COMPILATION().isDebugEnabled() || QQuickProfiler::enabled)
qsg_renderer_timer.start();
-#endif
QSGMaterialShader *s = static_cast<QSGMaterialShader *>(material->createShader());
context->compile(s, material);
@@ -200,14 +192,10 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate
stockShaders[type] = shader;
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- qDebug(" - compiling material: %dms", (int) qsg_renderer_timer.elapsed());
+ qCDebug(QSG_LOG_TIME_COMPILATION, "shader compiled in %dms (no rewrite)", (int) qsg_renderer_timer.elapsed());
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphContextFrame, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphContextFrame, (
qsg_renderer_timer.nsecsElapsed()));
-#endif
-
return shader;
}
@@ -606,11 +594,6 @@ void Element::computeBounds()
BatchCompatibility Batch::isMaterialCompatible(Element *e) const
{
- // If material has changed between opaque and translucent, it is not compatible
- QSGMaterial *m = e->node->activeMaterial();
- if (isOpaque != ((m->flags() & QSGMaterial::Blending) == 0))
- return BatchBreaksOnBlending;
-
Element *n = first;
// Skip to the first node other than e which has not been removed
while (n && (n == e || n->removed))
@@ -621,6 +604,7 @@ BatchCompatibility Batch::isMaterialCompatible(Element *e) const
if (!n)
return BatchIsCompatible;
+ QSGMaterial *m = e->node->activeMaterial();
QSGMaterial *nm = n->node->activeMaterial();
return (nm->type() == m->type() && nm->compare(m) == 0)
? BatchIsCompatible
@@ -766,11 +750,14 @@ Renderer::Renderer(QSGRenderContext *ctx)
, m_renderOrderRebuildUpper(-1)
, m_currentMaterial(0)
, m_currentShader(0)
+ , m_currentStencilValue(0)
+ , m_clipMatrixId(0)
, m_currentClip(0)
, m_currentClipType(NoClip)
, m_vao(0)
, m_visualizeMode(VisualizeNothing)
{
+ initializeOpenGLFunctions();
setNodeUpdater(new Updater(this));
m_shaderManager = ctx->findChild<ShaderManager *>(QStringLiteral("__qt_ShaderManager"), Qt::FindDirectChildrenOnly);
@@ -838,10 +825,12 @@ static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs)
Renderer::~Renderer()
{
- // Clean up batches and buffers
- for (int i=0; i<m_opaqueBatches.size(); ++i) qsg_wipeBatch(m_opaqueBatches.at(i), this);
- for (int i=0; i<m_alphaBatches.size(); ++i) qsg_wipeBatch(m_alphaBatches.at(i), this);
- for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
+ if (QOpenGLContext::currentContext()) {
+ // Clean up batches and buffers
+ for (int i=0; i<m_opaqueBatches.size(); ++i) qsg_wipeBatch(m_opaqueBatches.at(i), this);
+ for (int i=0; i<m_alphaBatches.size(); ++i) qsg_wipeBatch(m_alphaBatches.at(i), this);
+ for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
+ }
// The shadowtree
qDeleteAll(m_nodes.values());
@@ -1185,11 +1174,12 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
if (state & QSGNode::DirtyMaterial && node->type() == QSGNode::GeometryNodeType) {
Element *e = shadowNode->element();
if (e) {
- if (e->batch) {
- BatchCompatibility compat = e->batch->isMaterialCompatible(e);
- if (compat == BatchBreaksOnBlending)
- m_rebuild |= Renderer::FullRebuild;
- else if (compat == BatchBreaksOnCompare)
+ bool blended = hasMaterialWithBlending(static_cast<QSGGeometryNode *>(node));
+ if (e->isMaterialBlended != blended) {
+ m_rebuild |= Renderer::FullRebuild;
+ e->isMaterialBlended = blended;
+ } else if (e->batch) {
+ if (e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare)
invalidateBatchAndOverlappingRenderOrders(e->batch);
} else {
m_rebuild |= Renderer::BuildBatches;
@@ -1464,7 +1454,7 @@ void Renderer::prepareOpaqueBatches()
{
for (int i=m_opaqueRenderList.size() - 1; i >= 0; --i) {
Element *ei = m_opaqueRenderList.at(i);
- if (!ei || ei->batch)
+ if (!ei || ei->batch || ei->node->geometry()->vertexCount() == 0)
continue;
Batch *batch = newBatch();
batch->first = ei;
@@ -1486,7 +1476,7 @@ void Renderer::prepareOpaqueBatches()
continue;
if (ej->root != ei->root)
break;
- if (ej->batch)
+ if (ej->batch || ej->node->geometry()->vertexCount() == 0)
continue;
QSGGeometryNode *gnj = ej->node;
@@ -1557,6 +1547,9 @@ void Renderer::prepareAlphaBatches()
continue;
}
+ if (ei->node->geometry()->vertexCount() == 0)
+ continue;
+
Batch *batch = newBatch();
batch->first = ei;
batch->root = ei->root;
@@ -1583,6 +1576,8 @@ void Renderer::prepareAlphaBatches()
continue;
QSGGeometryNode *gnj = ej->node;
+ if (gnj->geometry()->vertexCount() == 0)
+ continue;
if (gni->clipList() == gnj->clipList()
&& gni->geometry()->drawingMode() == gnj->geometry()->drawingMode()
@@ -1920,6 +1915,132 @@ void Renderer::uploadBatch(Batch *b)
b->uploadedThisFrame = true;
}
+/*!
+ * Convenience function to set up the stencil buffer for clipping based on \a clip.
+ *
+ * If the clip is a pixel aligned rectangle, this function will use glScissor instead
+ * of stencil.
+ */
+Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip)
+{
+ if (!clip) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ return NoClip;
+ }
+
+ ClipType clipType = NoClip;
+
+ glDisable(GL_SCISSOR_TEST);
+
+ m_currentStencilValue = 0;
+ m_currentScissorRect = QRect();
+ while (clip) {
+ QMatrix4x4 m = m_current_projection_matrix;
+ if (clip->matrix())
+ m *= *clip->matrix();
+
+ // TODO: Check for multisampling and pixel grid alignment.
+ bool isRectangleWithNoPerspective = clip->isRectangular()
+ && qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1));
+ bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0));
+ bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1));
+
+ if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
+ QRectF bbox = clip->clipRect();
+ qreal invW = 1 / m(3, 3);
+ qreal fx1, fy1, fx2, fy2;
+ if (noRotate) {
+ fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+ } else {
+ Q_ASSERT(isRotate90);
+ fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW;
+ fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW;
+ fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW;
+ fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW;
+ }
+
+ if (fx1 > fx2)
+ qSwap(fx1, fx2);
+ if (fy1 > fy2)
+ qSwap(fy1, fy2);
+
+ QRect deviceRect = this->deviceRect();
+
+ GLint ix1 = qRound((fx1 + 1) * deviceRect.width() * qreal(0.5));
+ GLint iy1 = qRound((fy1 + 1) * deviceRect.height() * qreal(0.5));
+ GLint ix2 = qRound((fx2 + 1) * deviceRect.width() * qreal(0.5));
+ GLint iy2 = qRound((fy2 + 1) * deviceRect.height() * qreal(0.5));
+
+ if (!(clipType & ScissorClip)) {
+ m_currentScissorRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ glEnable(GL_SCISSOR_TEST);
+ clipType |= ScissorClip;
+ } else {
+ m_currentScissorRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ }
+ glScissor(m_currentScissorRect.x(), m_currentScissorRect.y(),
+ m_currentScissorRect.width(), m_currentScissorRect.height());
+ } else {
+ if (!(clipType & StencilClip)) {
+ if (!m_clipProgram.isLinked()) {
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ &m_clipProgram,
+ QStringLiteral(":/scenegraph/shaders/stencilclip.vert"),
+ QStringLiteral(":/scenegraph/shaders/stencilclip.frag"));
+ m_clipProgram.bindAttributeLocation("vCoord", 0);
+ m_clipProgram.link();
+ m_clipMatrixId = m_clipProgram.uniformLocation("matrix");
+ }
+
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ m_clipProgram.bind();
+ m_clipProgram.enableAttributeArray(0);
+
+ clipType |= StencilClip;
+ }
+
+ glStencilFunc(GL_EQUAL, m_currentStencilValue, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
+
+ const QSGGeometry *g = clip->geometry();
+ Q_ASSERT(g->attributeCount() > 0);
+ const QSGGeometry::Attribute *a = g->attributes();
+ glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->sizeOfVertex(), g->vertexData());
+
+ m_clipProgram.setUniformValue(m_clipMatrixId, m);
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+
+ ++m_currentStencilValue;
+ }
+
+ clip = clip->clipList();
+ }
+
+ if (clipType & StencilClip) {
+ m_clipProgram.disableAttributeArray(0);
+ glStencilFunc(GL_EQUAL, m_currentStencilValue, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
+ bindable()->reactivate();
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+
+ return clipType;
+}
+
void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch)
{
if (clipList != m_currentClip && Q_LIKELY(!debug_noclip)) {
@@ -2067,6 +2188,19 @@ void Renderer::renderMergedBatch(const Batch *batch)
program->updateState(state(dirty), material, m_currentMaterial);
+#ifndef QT_NO_DEBUG
+ if (qsg_test_and_clear_material_failure()) {
+ qDebug() << "QSGMaterial::updateState triggered an error (merged), batch will be skipped:";
+ Element *ee = e;
+ while (ee) {
+ qDebug() << " -" << ee->node;
+ ee = ee->nextInBatch;
+ }
+ QSGNodeDumper::dump(rootNode());
+ qFatal("Aborting: scene graph is invalid...");
+ }
+#endif
+
m_currentMaterial = material;
QSGGeometry* g = gn->geometry();
@@ -2174,6 +2308,16 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
program->updateState(state(dirty), material, m_currentMaterial);
+#ifndef QT_NO_DEBUG
+ if (qsg_test_and_clear_material_failure()) {
+ qDebug() << "QSGMaterial::updateState() triggered an error (unmerged), batch will be skipped:";
+ qDebug() << " - offending node is" << e->node;
+ QSGNodeDumper::dump(rootNode());
+ qFatal("Aborting: scene graph is invalid...");
+ return;
+ }
+#endif
+
// We don't need to bother with asking each node for its material as they
// are all identical (compare==0) since they are in the same batch.
m_currentMaterial = material;
@@ -2193,8 +2337,11 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES)
glLineWidth(g->lineWidth());
#if !defined(QT_OPENGL_ES_2)
- else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS)
- glPointSize(g->lineWidth());
+ else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS) {
+ QOpenGLFunctions_1_0 *gl1funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_1_0>();
+ gl1funcs->initializeOpenGLFunctions();
+ gl1funcs->glPointSize(g->lineWidth());
+ }
#endif
if (g->indexCount())
@@ -2225,11 +2372,7 @@ void Renderer::renderBatches()
glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF());
if (m_useDepthBuffer) {
-#if defined(QT_OPENGL_ES)
- glClearDepthf(1);
-#else
- glClearDepth(1);
-#endif
+ glClearDepthf(1); // calls glClearDepth() under the hood for desktop OpenGL
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(true);
@@ -2286,6 +2429,7 @@ void Renderer::renderBatches()
updateStencilClip(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glDepthMask(true);
}
void Renderer::deleteRemovedElements()
@@ -2470,16 +2614,19 @@ void Renderer::renderRenderNode(Batch *batch)
state.projectionMatrix = &pm;
state.scissorEnabled = m_currentClipType & ScissorClip;
state.stencilEnabled = m_currentClipType & StencilClip;
- state.scissorRect = m_current_scissor_rect;
- state.stencilValue = m_current_stencil_value;
+ state.scissorRect = m_currentScissorRect;
+ state.stencilValue = m_currentStencilValue;
QSGNode *xform = e->renderNode->parent();
QMatrix4x4 matrix;
- while (xform != rootNode()) {
+ QSGNode *root = rootNode();
+ if (e->root) {
+ matrix = qsg_matrixForRoot(e->root);
+ root = e->root->sgNode;
+ }
+ while (xform != root) {
if (xform->type() == QSGNode::TransformNodeType) {
- matrix = static_cast<QSGTransformNode *>(xform)->combinedMatrix();
- if (e->root)
- matrix = qsg_matrixForRoot(e->root) * matrix;
+ matrix = matrix * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
break;
}
xform = xform->parent();
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 44b7b8740d..574c6df810 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -67,6 +67,12 @@ class Updater;
class Renderer;
class ShaderManager;
+inline bool hasMaterialWithBlending(QSGGeometryNode *n)
+{
+ return (n->opaqueMaterial() ? n->opaqueMaterial()->flags() & QSGMaterial::Blending
+ : n->material()->flags() & QSGMaterial::Blending);
+}
+
struct Pt {
float x, y;
@@ -163,6 +169,7 @@ struct Element {
, removed(false)
, orphaned(false)
, isRenderNode(false)
+ , isMaterialBlended(n ? hasMaterialWithBlending(n) : false)
{
}
@@ -187,6 +194,7 @@ struct Element {
uint removed : 1;
uint orphaned : 1;
uint isRenderNode : 1;
+ uint isMaterialBlended : 1;
};
struct RenderNodeElement : public Element {
@@ -233,7 +241,6 @@ struct DrawSet
enum BatchCompatibility
{
- BatchBreaksOnBlending,
BatchBreaksOnCompare,
BatchIsCompatible
};
@@ -399,7 +406,7 @@ public:
QSGRenderContext *context;
};
-class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer
+class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer, public QOpenGLFunctions
{
public:
Renderer(QSGRenderContext *);
@@ -419,6 +426,14 @@ protected:
void render();
private:
+ enum ClipTypeBit
+ {
+ NoClip = 0x00,
+ ScissorClip = 0x01,
+ StencilClip = 0x02
+ };
+ Q_DECLARE_FLAGS(ClipType, ClipTypeBit)
+
enum RebuildFlag {
BuildRenderListsForTaggedRoots = 0x0001,
BuildRenderLists = 0x0002,
@@ -450,6 +465,7 @@ private:
void renderBatches();
void renderMergedBatch(const Batch *batch);
void renderUnmergedBatch(const Batch *batch);
+ ClipType updateStencilClip(const QSGClipNode *clip);
void updateClip(const QSGClipNode *clipList, const Batch *batch);
const QMatrix4x4 &matrixForRoot(Node *node);
void renderRenderNode(Batch *batch);
@@ -511,6 +527,11 @@ private:
QSGMaterial *m_currentMaterial;
QSGMaterialShader *m_currentProgram;
ShaderManager::Shader *m_currentShader;
+
+ QRect m_currentScissorRect;
+ int m_currentStencilValue;
+ QOpenGLShaderProgram m_clipProgram;
+ int m_clipMatrixId;
const QSGClipNode *m_currentClip;
ClipType m_currentClipType;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 22fe29959e..376aeb2423 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -46,6 +46,21 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_DEBUG
+bool qsg_material_failure = false;
+bool qsg_test_and_clear_material_failure()
+{
+ bool fail = qsg_material_failure;
+ qsg_material_failure = false;
+ return fail;
+}
+
+void qsg_set_material_failure()
+{
+ qsg_material_failure = true;
+}
+#endif
+
const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const
{
QStringList files = m_sourceFiles[type];
@@ -346,7 +361,8 @@ void QSGMaterialShader::compile()
char const *const *attr = attributeNames();
#ifndef QT_NO_DEBUG
int maxVertexAttribs = 0;
- glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
for (int i = 0; attr[i]; ++i) {
if (i >= maxVertexAttribs) {
qFatal("List of attribute names is either too long or not null-terminated.\n"
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
index fc8a35c41d..43b224f9f9 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
@@ -56,6 +56,11 @@ public:
mutable QHash<QOpenGLShader::ShaderType, QByteArray> m_sources;
};
+#ifndef QT_NO_DEBUG
+Q_QUICK_PRIVATE_EXPORT bool qsg_test_and_clear_material_failure();
+Q_QUICK_PRIVATE_EXPORT void qsg_set_material_failure();
+#endif
+
QT_END_NAMESPACE
#endif // QSGMATERIALSHADER_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index b0a4f20149..0950148c98 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -135,6 +135,7 @@ static void qt_print_node_count()
\value OwnsOpaqueMaterial Only valid for QSGGeometryNode. The node has
ownership over the opaque material and will delete it when the node is
destroyed or a material is assigned.
+ \value InternalReserved Reserved for internal use.
*/
/*!
@@ -668,12 +669,15 @@ void QSGNode::markDirty(DirtyState bits)
}
}
-#ifdef QSG_RUNTIME_DESCRIPTION
void qsgnode_set_description(QSGNode *node, const QString &description)
{
+#ifdef QSG_RUNTIME_DESCRIPTION
QSGNodePrivate::setDescription(node, description);
-}
+#else
+ Q_UNUSED(node);
+ Q_UNUSED(description);
#endif
+}
/*!
\class QSGBasicGeometryNode
@@ -1005,7 +1009,6 @@ void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
*/
QSGMaterial *QSGGeometryNode::activeMaterial() const
{
- Q_ASSERT_X(dirtyState() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
if (m_opaque_material && m_opacity > 0.999)
return m_opaque_material;
return m_material;
@@ -1491,7 +1494,6 @@ QDebug operator<<(QDebug d, const QSGGeometryNode *n)
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
- d << "dirty=" << hex << (int) n->dirtyState() << dec;
return d;
}
@@ -1512,7 +1514,7 @@ QDebug operator<<(QDebug d, const QSGClipNode *n)
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
- d << "dirty=" << hex << (int) n->dirtyState() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
return d;
}
@@ -1534,7 +1536,7 @@ QDebug operator<<(QDebug d, const QSGTransformNode *n)
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
- d << "dirty=" << hex << (int) n->dirtyState() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
d << ')';
return d;
}
@@ -1553,7 +1555,6 @@ QDebug operator<<(QDebug d, const QSGOpacityNode *n)
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
- d << "dirty=" << hex << (int) n->dirtyState() << dec;
d << ')';
return d;
}
@@ -1565,8 +1566,7 @@ QDebug operator<<(QDebug d, const QSGRootNode *n)
d << "RootNode(null)";
return d;
}
- d << "RootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyState() << dec
- << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << "RootNode" << hex << (void *) n << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
d << QSGNodePrivate::description(n);
#endif
@@ -1600,7 +1600,6 @@ QDebug operator<<(QDebug d, const QSGNode *n)
break;
case QSGNode::RenderNodeType:
d << "RenderNode(" << hex << (void *) n << dec
- << "dirty=" << hex << (int) n->dirtyState()
<< "flags=" << (int) n->flags() << dec
<< (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
@@ -1610,7 +1609,6 @@ QDebug operator<<(QDebug d, const QSGNode *n)
break;
default:
d << "Node(" << hex << (void *) n << dec
- << "dirty=" << hex << (int) n->dirtyState()
<< "flags=" << (int) n->flags() << dec
<< (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
#ifdef QSG_RUNTIME_DESCRIPTION
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index f85184db90..3dc2a865bd 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -49,8 +49,11 @@
QT_BEGIN_NAMESPACE
-// #define QSG_RUNTIME_DESCRIPTION
+#ifndef QT_NO_DEBUG
+#define QSG_RUNTIME_DESCRIPTION
+#endif
+class QSGAbstractRenderer;
class QSGRenderer;
class QSGNode;
@@ -92,9 +95,14 @@ public:
// QSGBasicGeometryNode
OwnsGeometry = 0x00010000,
OwnsMaterial = 0x00020000,
- OwnsOpaqueMaterial = 0x00040000
+ OwnsOpaqueMaterial = 0x00040000,
// Uppermost 8 bits are reserved for internal use.
+#ifndef qdoc
+ IsVisitableNode = 0x01000000
+#else
+ InternalReserved = 0x01000000
+#endif
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -142,9 +150,9 @@ public:
inline NodeType type() const { return m_type; }
- void clearDirty() { m_dirtyState = 0; }
+ QT_DEPRECATED void clearDirty() { }
void markDirty(DirtyState bits);
- DirtyState dirtyState() const { return m_dirtyState; }
+ QT_DEPRECATED DirtyState dirtyState() const { return 0; }
virtual bool isSubtreeBlocked() const;
@@ -183,9 +191,7 @@ protected:
QScopedPointer<QSGNodePrivate> d_ptr;
};
-#ifdef QSG_RUNTIME_DESCRIPTION
void Q_QUICK_EXPORT qsgnode_set_description(QSGNode *node, const QString &description);
-#endif
class Q_QUICK_EXPORT QSGBasicGeometryNode : public QSGNode
{
@@ -298,11 +304,11 @@ public:
private:
void notifyNodeChange(QSGNode *node, DirtyState state);
- friend class QSGRenderer;
+ friend class QSGAbstractRenderer;
friend class QSGNode;
friend class QSGGeometryNode;
- QList<QSGRenderer *> m_renderers;
+ QList<QSGAbstractRenderer *> m_renderers;
};
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index 51cc844612..e290eb30c1 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -113,9 +113,6 @@ bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
{
- if (t->dirtyState() & QSGNode::DirtyMatrix)
- ++m_force_update;
-
#ifdef QSG_UPDATER_DEBUG
qDebug() << "enter transform:" << t << "force=" << m_force_update;
#endif
@@ -143,9 +140,6 @@ void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
qDebug() << "leave transform:" << t;
#endif
- if (t->dirtyState() & QSGNode::DirtyMatrix)
- --m_force_update;
-
if (!t->matrix().isIdentity()) {
m_combined_matrix_stack.pop_back();
}
@@ -217,9 +211,6 @@ void QSGNodeUpdater::leaveRenderNode(QSGRenderNode *r)
void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
{
- if (o->dirtyState() & QSGNode::DirtyOpacity)
- ++m_force_update;
-
qreal opacity = m_opacity_stack.last() * o->opacity();
o->setCombinedOpacity(opacity);
m_opacity_stack.add(opacity);
@@ -252,15 +243,11 @@ void QSGNodeUpdater::visitNode(QSGNode *n)
qDebug() << "enter:" << n;
#endif
- if (!n->dirtyState() && !m_force_update)
+ if (!m_force_update)
return;
if (n->isSubtreeBlocked())
return;
- bool forceUpdate = n->dirtyState() & (QSGNode::DirtyNodeAdded | QSGNode::DirtyForceUpdate);
- if (forceUpdate)
- ++m_force_update;
-
switch (n->type()) {
case QSGNode::TransformNodeType: {
QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
@@ -296,11 +283,6 @@ void QSGNodeUpdater::visitNode(QSGNode *n)
visitChildren(n);
break;
}
-
- if (forceUpdate)
- --m_force_update;
-
- n->clearDirty();
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index a4e122ec91..3c9042fee5 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -40,59 +40,33 @@
****************************************************************************/
#include "qsgrenderer_p.h"
-#include "qsgnode.h"
-#include "qsgmaterial.h"
#include "qsgnodeupdater_p.h"
-#include "qsggeometry_p.h"
-#include <private/qsgadaptationlayer_p.h>
-#include <private/qsgshadersourcebuilder_p.h>
-
-#include <QOpenGLShaderProgram>
#include <qopenglframebufferobject.h>
-#include <QtGui/qguiapplication.h>
-
-#include <qdatetime.h>
#include <private/qquickprofiler_p.h>
QT_BEGIN_NAMESPACE
-//#define RENDERER_DEBUG
-//#define QT_GL_NO_SCISSOR_TEST
-
static bool qsg_sanity_check = qgetenv("QSG_SANITY_CHECK").toInt();
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer frameTimer;
static qint64 preprocessTime;
static qint64 updatePassTime;
-#endif
-void QSGBindable::clear(QSGRenderer::ClearMode mode) const
+void QSGBindable::clear(QSGAbstractRenderer::ClearMode mode) const
{
GLuint bits = 0;
- if (mode & QSGRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
- if (mode & QSGRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
- if (mode & QSGRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
- glClear(bits);
+ if (mode & QSGAbstractRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
+ if (mode & QSGAbstractRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
+ if (mode & QSGAbstractRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
+ QOpenGLContext::currentContext()->functions()->glClear(bits);
}
// Reactivate the color buffer after switching to the stencil.
void QSGBindable::reactivate() const
{
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-}
-
-QSGBindableFbo::QSGBindableFbo(QOpenGLFramebufferObject *fbo) : m_fbo(fbo)
-{
-}
-
-
-void QSGBindableFbo::bind() const
-{
- m_fbo->bind();
+ QOpenGLContext::currentContext()->functions()->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
QSGBindableFboId::QSGBindableFboId(GLuint id)
@@ -103,9 +77,7 @@ QSGBindableFboId::QSGBindableFboId(GLuint id)
void QSGBindableFboId::bind() const
{
- QOpenGLContext *context = QOpenGLContext::currentContext();
- context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_id);
- QOpenGLContextPrivate::get(context)->current_fbo = m_id;
+ QOpenGLContext::currentContext()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_id);
}
/*!
@@ -137,24 +109,15 @@ void QSGBindableFboId::bind() const
QSGRenderer::QSGRenderer(QSGRenderContext *context)
- : QObject()
- , m_clear_color(Qt::transparent)
- , m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
- , m_current_opacity(1)
+ : m_current_opacity(1)
, m_current_determinant(1)
, m_device_pixel_ratio(1)
- , m_current_stencil_value(0)
, m_context(context)
- , m_root_node(0)
, m_node_updater(0)
, m_bindable(0)
, m_changed_emitted(false)
- , m_mirrored(false)
, m_is_rendering(false)
- , m_vertex_buffer_bound(false)
- , m_index_buffer_bound(false)
{
- initializeOpenGLFunctions();
}
@@ -192,66 +155,55 @@ void QSGRenderer::setNodeUpdater(QSGNodeUpdater *updater)
m_node_updater = updater;
}
-
-void QSGRenderer::setRootNode(QSGRootNode *node)
+bool QSGRenderer::isMirrored() const
{
- if (m_root_node == node)
- return;
- if (m_root_node) {
- m_root_node->m_renderers.removeOne(this);
- nodeChanged(m_root_node, QSGNode::DirtyNodeRemoved);
- }
- m_root_node = node;
- if (m_root_node) {
- Q_ASSERT(!m_root_node->m_renderers.contains(this));
- m_root_node->m_renderers << this;
- nodeChanged(m_root_node, QSGNode::DirtyNodeAdded);
- }
+ QMatrix4x4 matrix = projectionMatrix();
+ // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
+ return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
}
-
-void QSGRenderer::renderScene()
+void QSGRenderer::renderScene(GLuint fboId)
{
- class B : public QSGBindable
- {
- public:
- void bind() const { QOpenGLFramebufferObject::bindDefault(); }
- } b;
- renderScene(b);
+ if (fboId) {
+ QSGBindableFboId bindable(fboId);
+ renderScene(bindable);
+ } else {
+ class B : public QSGBindable
+ {
+ public:
+ void bind() const { QOpenGLFramebufferObject::bindDefault(); }
+ } bindable;
+ renderScene(bindable);
+ }
}
-
void QSGRenderer::renderScene(const QSGBindable &bindable)
{
- if (!m_root_node)
+ if (!rootNode())
return;
m_is_rendering = true;
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
frameTimer.start();
qint64 bindTime = 0;
qint64 renderTime = 0;
-#endif
m_bindable = &bindable;
preprocess();
bindable.bind();
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
bindTime = frameTimer.nsecsElapsed();
-#endif
// Sanity check that attribute registers are disabled
if (qsg_sanity_check) {
GLint count = 0;
- glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
+ QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
GLint enabled;
for (int i=0; i<count; ++i) {
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
+ QOpenGLContext::currentContext()->functions()->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
if (enabled) {
qWarning("QSGRenderer: attribute %d is enabled, this can lead to memory corruption and crashes.", i);
}
@@ -259,72 +211,27 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
}
render();
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
renderTime = frameTimer.nsecsElapsed();
-#endif
- glDisable(GL_SCISSOR_TEST);
m_is_rendering = false;
m_changed_emitted = false;
m_bindable = 0;
- if (m_vertex_buffer_bound) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- m_vertex_buffer_bound = false;
- }
-
- if (m_index_buffer_bound) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- m_index_buffer_bound = false;
- }
-
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug(" - Breakdown of render time: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d",
- int(preprocessTime / 1000000),
- int((updatePassTime - preprocessTime) / 1000000),
- int((bindTime - updatePassTime) / 1000000),
- int((renderTime - bindTime) / 1000000),
- int(renderTime / 1000000));
- }
+ qCDebug(QSG_LOG_TIME_RENDERER,
+ "time in renderer: total=%dms, preprocess=%d, updates=%d, binding=%d, rendering=%d",
+ int(renderTime / 1000000),
+ int(preprocessTime / 1000000),
+ int((updatePassTime - preprocessTime) / 1000000),
+ int((bindTime - updatePassTime) / 1000000),
+ int((renderTime - bindTime) / 1000000));
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRendererFrame, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRendererFrame, (
preprocessTime,
updatePassTime - preprocessTime,
bindTime - updatePassTime,
renderTime - bindTime));
-#endif
-}
-
-void QSGRenderer::setProjectionMatrixToDeviceRect()
-{
- setProjectionMatrixToRect(m_device_rect);
-}
-
-void QSGRenderer::setProjectionMatrixToRect(const QRectF &rect)
-{
- QMatrix4x4 matrix;
- matrix.ortho(rect.x(),
- rect.x() + rect.width(),
- rect.y() + rect.height(),
- rect.y(),
- 1,
- -1);
- setProjectionMatrix(matrix);
-}
-
-void QSGRenderer::setProjectionMatrix(const QMatrix4x4 &matrix)
-{
- m_projection_matrix = matrix;
- // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
- m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
-}
-
-void QSGRenderer::setClearColor(const QColor &color)
-{
- m_clear_color = color;
}
/*!
@@ -355,13 +262,10 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
}
}
-void QSGRenderer::materialChanged(QSGGeometryNode *, QSGMaterial *, QSGMaterial *)
-{
-}
-
void QSGRenderer::preprocess()
{
- Q_ASSERT(m_root_node);
+ QSGRootNode *root = rootNode();
+ Q_ASSERT(root);
// We need to take a copy here, in case any of the preprocess calls deletes a node that
// is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
@@ -371,24 +275,19 @@ void QSGRenderer::preprocess()
for (QSet<QSGNode *>::const_iterator it = items.constBegin();
it != items.constEnd(); ++it) {
QSGNode *n = *it;
- if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
+ if (!nodeUpdater()->isNodeBlocked(n, root)) {
n->preprocess();
}
}
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled()|| QQuickProfiler::enabled;
if (profileFrames)
preprocessTime = frameTimer.nsecsElapsed();
-#endif
- nodeUpdater()->updateStates(m_root_node);
+ nodeUpdater()->updateStates(root);
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
updatePassTime = frameTimer.nsecsElapsed();
-#endif
-
}
void QSGRenderer::addNodesToPreprocess(QSGNode *node)
@@ -409,320 +308,6 @@ void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
/*!
- Convenience function to set up the stencil buffer for clipping based on \a clip.
-
- If the clip is a pixel aligned rectangle, this function will use glScissor instead
- of stencil.
- */
-
-QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
-{
- if (!clip) {
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_SCISSOR_TEST);
- return NoClip;
- }
-
- ClipType clipType = NoClip;
-
- glDisable(GL_SCISSOR_TEST);
-
- m_current_stencil_value = 0;
- m_current_scissor_rect = QRect();
- while (clip) {
- QMatrix4x4 m = m_current_projection_matrix;
- if (clip->matrix())
- m *= *clip->matrix();
-
- // TODO: Check for multisampling and pixel grid alignment.
- bool isRectangleWithNoPerspective = clip->isRectangular()
- && qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1));
- bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0));
- bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1));
-
- if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
- QRectF bbox = clip->clipRect();
- qreal invW = 1 / m(3, 3);
- qreal fx1, fy1, fx2, fy2;
- if (noRotate) {
- fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
- fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
- fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
- fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
- } else {
- Q_ASSERT(isRotate90);
- fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW;
- fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW;
- fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW;
- fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW;
- }
-
- if (fx1 > fx2)
- qSwap(fx1, fx2);
- if (fy1 > fy2)
- qSwap(fy1, fy2);
-
- GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5));
- GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5));
- GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5));
- GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5));
-
- if (!(clipType & ScissorClip)) {
- m_current_scissor_rect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
- glEnable(GL_SCISSOR_TEST);
- clipType |= ScissorClip;
- } else {
- m_current_scissor_rect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
- }
- glScissor(m_current_scissor_rect.x(), m_current_scissor_rect.y(),
- m_current_scissor_rect.width(), m_current_scissor_rect.height());
- } else {
- if (!(clipType & StencilClip)) {
- if (!m_clip_program.isLinked()) {
- QSGShaderSourceBuilder::initializeProgramFromFiles(
- &m_clip_program,
- QStringLiteral(":/scenegraph/shaders/stencilclip.vert"),
- QStringLiteral(":/scenegraph/shaders/stencilclip.frag"));
- m_clip_program.bindAttributeLocation("vCoord", 0);
- m_clip_program.link();
- m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
- }
-
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
- glEnable(GL_STENCIL_TEST);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glDepthMask(GL_FALSE);
-
- if (m_vertex_buffer_bound) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- m_vertex_buffer_bound = false;
- }
- if (m_index_buffer_bound) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- m_index_buffer_bound = false;
- }
-
- m_clip_program.bind();
- m_clip_program.enableAttributeArray(0);
-
- clipType |= StencilClip;
- }
-
- glStencilFunc(GL_EQUAL, m_current_stencil_value, 0xff); // stencil test, ref, test mask
- glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
-
- const QSGGeometry *g = clip->geometry();
- Q_ASSERT(g->attributeCount() > 0);
- const QSGGeometry::Attribute *a = g->attributes();
- glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->sizeOfVertex(), g->vertexData());
-
- m_clip_program.setUniformValue(m_clip_matrix_id, m);
- if (g->indexCount()) {
- glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
- } else {
- glDrawArrays(g->drawingMode(), 0, g->vertexCount());
- }
-
- ++m_current_stencil_value;
- }
-
- clip = clip->clipList();
- }
-
- if (clipType & StencilClip) {
- m_clip_program.disableAttributeArray(0);
- glStencilFunc(GL_EQUAL, m_current_stencil_value, 0xff); // stencil test, ref, test mask
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
- bindable()->reactivate();
- } else {
- glDisable(GL_STENCIL_TEST);
- }
-
- return clipType;
-}
-
-
-
-static inline int size_of_type(GLenum type)
-{
- static int sizes[] = {
- sizeof(char),
- sizeof(unsigned char),
- sizeof(short),
- sizeof(unsigned short),
- sizeof(int),
- sizeof(unsigned int),
- sizeof(float),
- 2,
- 3,
- 4,
- sizeof(double)
- };
- Q_ASSERT(type >= GL_BYTE && type <= 0x140A); // the value of GL_DOUBLE
- return sizes[type - GL_BYTE];
-}
-
-
-class QSGRendererVBOGeometryData : public QSGGeometryData
-{
-public:
- QSGRendererVBOGeometryData()
- : vertexBuffer(0)
- , indexBuffer(0)
- {
- }
-
- ~QSGRendererVBOGeometryData()
- {
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (!ctx)
- return;
- QOpenGLFunctions *func = ctx->functions();
- if (vertexBuffer)
- func->glDeleteBuffers(1, &vertexBuffer);
- if (indexBuffer)
- func->glDeleteBuffers(1, &indexBuffer);
- }
-
- GLuint vertexBuffer;
- GLuint indexBuffer;
-
- static QSGRendererVBOGeometryData *get(const QSGGeometry *g) {
- QSGRendererVBOGeometryData *gd = static_cast<QSGRendererVBOGeometryData *>(QSGGeometryData::data(g));
- if (!gd) {
- gd = new QSGRendererVBOGeometryData;
- QSGGeometryData::install(g, gd);
- }
- return gd;
- }
-
-};
-
-static inline GLenum qt_drawTypeForPattern(QSGGeometry::DataPattern p)
-{
- Q_ASSERT(p > 0 && p <= 3);
- static GLenum drawTypes[] = { 0,
- GL_STREAM_DRAW,
- GL_DYNAMIC_DRAW,
- GL_STATIC_DRAW
- };
- return drawTypes[p];
-}
-
-
-/*!
- Issues the GL draw call for the geometry \a g using the material \a shader.
-
- The function assumes that attributes have been bound and set up prior
- to making this call.
-
- \internal
- */
-
-void QSGRenderer::draw(const QSGMaterialShader *shader, const QSGGeometry *g)
-{
- const void *vertexData;
- int vertexByteSize = g->vertexCount() * g->sizeOfVertex();
- if (g->vertexDataPattern() != QSGGeometry::AlwaysUploadPattern && vertexByteSize > 1024) {
-
- // The base pointer for a VBO is 0
- vertexData = 0;
-
- bool updateData = QSGGeometryData::hasDirtyVertexData(g);
- QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g);
- if (!gd->vertexBuffer) {
- glGenBuffers(1, &gd->vertexBuffer);
- updateData = true;
- }
-
- glBindBuffer(GL_ARRAY_BUFFER, gd->vertexBuffer);
- m_vertex_buffer_bound = true;
-
- if (updateData) {
- glBufferData(GL_ARRAY_BUFFER, vertexByteSize, g->vertexData(),
- qt_drawTypeForPattern(g->vertexDataPattern()));
- QSGGeometryData::clearDirtyVertexData(g);
- }
-
- } else {
- if (m_vertex_buffer_bound) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- m_vertex_buffer_bound = false;
- }
- vertexData = g->vertexData();
- }
-
- // Bind the vertices to attributes...
- char const *const *attrNames = shader->attributeNames();
- int offset = 0;
- for (int j = 0; attrNames[j]; ++j) {
- if (!*attrNames[j])
- continue;
- Q_ASSERT_X(j < g->attributeCount(), "QSGRenderer::bindGeometry()", "Geometry lacks attribute required by material");
- const QSGGeometry::Attribute &a = g->attributes()[j];
- Q_ASSERT_X(j == a.position, "QSGRenderer::bindGeometry()", "Geometry does not have continuous attribute positions");
-
-#if defined(QT_OPENGL_ES_2)
- GLboolean normalize = a.type != GL_FLOAT;
-#else
- GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE;
-#endif
- glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->sizeOfVertex(), (char *) vertexData + offset);
- offset += a.tupleSize * size_of_type(a.type);
- }
-
- // Set up the indices...
- const void *indexData;
- if (g->indexDataPattern() != QSGGeometry::AlwaysUploadPattern && g->indexCount() > 512) {
-
- // Base pointer for a VBO is 0
- indexData = 0;
-
- bool updateData = QSGGeometryData::hasDirtyIndexData(g);
- QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g);
- if (!gd->indexBuffer) {
- glGenBuffers(1, &gd->indexBuffer);
- updateData = true;
- }
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gd->indexBuffer);
- m_index_buffer_bound = true;
-
- if (updateData) {
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- g->indexCount() * g->sizeOfIndex(),
- g->indexData(),
- qt_drawTypeForPattern(g->indexDataPattern()));
- QSGGeometryData::clearDirtyIndexData(g);
- }
-
- } else {
- if (m_index_buffer_bound) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- m_index_buffer_bound = false;
- }
- indexData = g->indexData();
- }
-
- // Set the line width if applicable
- if (g->drawingMode() == GL_LINES || g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP) {
- glLineWidth(g->lineWidth());
- }
-
- // draw the stuff...
- if (g->indexCount()) {
- glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), indexData);
- } else {
- glDrawArrays(g->drawingMode(), 0, g->vertexCount());
- }
-
- // We leave buffers bound for now... They will be reset by bind on next draw() or
- // set back to 0 if next draw is not using VBOs
-
-}
-
-/*!
\class QSGNodeDumper
\brief The QSGNodeDumper class provides a way of dumping a scene grahp to the console.
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index eddd38a68f..f02cc83161 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -42,62 +42,28 @@
#ifndef QSGRENDERER_P_H
#define QSGRENDERER_P_H
-#include <qset.h>
-#include <qhash.h>
-
-#include <qcolor.h>
-#include <qopenglfunctions.h>
-#include <qopenglshaderprogram.h>
-
+#include "qsgabstractrenderer.h"
+#include "qsgabstractrenderer_p.h"
#include "qsgnode.h"
#include "qsgmaterial.h"
-#include <QtQuick/qsgtexture.h>
#include <QtQuick/private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
-class QSGMaterialShader;
-struct QSGMaterialType;
-class QOpenGLFramebufferObject;
-class TextureReference;
class QSGBindable;
class QSGNodeUpdater;
-class Q_QUICK_PRIVATE_EXPORT QSGRenderer : public QObject, public QOpenGLFunctions
+Q_QUICK_PRIVATE_EXPORT bool qsg_test_and_clear_fatal_render_error();
+Q_QUICK_PRIVATE_EXPORT void qsg_set_fatal_renderer_error();
+
+class Q_QUICK_PRIVATE_EXPORT QSGRenderer : public QSGAbstractRenderer
{
- Q_OBJECT
public:
- enum ClipTypeBit
- {
- NoClip = 0x00,
- ScissorClip = 0x01,
- StencilClip = 0x02
- };
- Q_DECLARE_FLAGS(ClipType, ClipTypeBit)
-
- enum ClearModeBit
- {
- ClearColorBuffer = 0x0001,
- ClearDepthBuffer = 0x0002,
- ClearStencilBuffer = 0x0004
- };
- Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
QSGRenderer(QSGRenderContext *context);
virtual ~QSGRenderer();
- void setRootNode(QSGRootNode *node);
- QSGRootNode *rootNode() const { return m_root_node; }
-
- void setDeviceRect(const QRect &rect) { m_device_rect = rect; }
- inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
- QRect deviceRect() const { return m_device_rect; }
-
- void setViewportRect(const QRect &rect) { m_viewport_rect = rect; }
- inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
- QRect viewportRect() const { return m_viewport_rect; }
-
// Accessed by QSGMaterialShader::RenderState.
QMatrix4x4 currentProjectionMatrix() const { return m_current_projection_matrix; }
QMatrix4x4 currentModelViewMatrix() const { return m_current_model_view_matrix; }
@@ -107,43 +73,24 @@ public:
void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; }
qreal devicePixelRatio() const { return m_device_pixel_ratio; }
-
- void setProjectionMatrixToDeviceRect();
- virtual void setProjectionMatrixToRect(const QRectF &rect);
- void setProjectionMatrix(const QMatrix4x4 &matrix);
- QMatrix4x4 projectionMatrix() const { return m_projection_matrix; }
- bool isMirrored() const { return m_mirrored; }
-
- void setClearColor(const QColor &color);
- QColor clearColor() const { return m_clear_color; }
-
QSGRenderContext *context() const { return m_context; }
- void renderScene();
+ bool isMirrored() const;
void renderScene(const QSGBindable &bindable);
- virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
- virtual void materialChanged(QSGGeometryNode *node, QSGMaterial *from, QSGMaterial *to);
+ virtual void renderScene(GLuint fboId = 0) Q_DECL_OVERRIDE;
+ virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) Q_DECL_OVERRIDE;
QSGNodeUpdater *nodeUpdater() const;
void setNodeUpdater(QSGNodeUpdater *updater);
inline QSGMaterialShader::RenderState state(QSGMaterialShader::RenderState::DirtyStates dirty) const;
- void setClearMode(ClearMode mode) { m_clear_mode = mode; }
- ClearMode clearMode() const { return m_clear_mode; }
-
virtual void setCustomRenderMode(const QByteArray &) { };
void clearChangedFlag() { m_changed_emitted = false; }
-Q_SIGNALS:
- void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
-
protected:
- void draw(const QSGMaterialShader *material, const QSGGeometry *g);
-
virtual void render() = 0;
- QSGRenderer::ClipType updateStencilClip(const QSGClipNode *clip);
const QSGBindable *bindable() const { return m_bindable; }
@@ -152,63 +99,34 @@ protected:
void addNodesToPreprocess(QSGNode *node);
void removeNodesToPreprocess(QSGNode *node);
- void markNodeDirtyState(QSGNode *node, QSGNode::DirtyState state) { node->m_dirtyState |= state; }
-
- QColor m_clear_color;
- ClearMode m_clear_mode;
QMatrix4x4 m_current_projection_matrix;
QMatrix4x4 m_current_model_view_matrix;
qreal m_current_opacity;
qreal m_current_determinant;
qreal m_device_pixel_ratio;
- QRect m_current_scissor_rect;
- int m_current_stencil_value;
QSGRenderContext *m_context;
private:
- QSGRootNode *m_root_node;
QSGNodeUpdater *m_node_updater;
- QRect m_device_rect;
- QRect m_viewport_rect;
-
QSet<QSGNode *> m_nodes_to_preprocess;
- QMatrix4x4 m_projection_matrix;
- QOpenGLShaderProgram m_clip_program;
- int m_clip_matrix_id;
-
const QSGBindable *m_bindable;
uint m_changed_emitted : 1;
- uint m_mirrored : 1;
uint m_is_rendering : 1;
-
- uint m_vertex_buffer_bound : 1;
- uint m_index_buffer_bound : 1;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
-
class Q_QUICK_PRIVATE_EXPORT QSGBindable
{
public:
virtual ~QSGBindable() { }
virtual void bind() const = 0;
- virtual void clear(QSGRenderer::ClearMode mode) const;
+ virtual void clear(QSGAbstractRenderer::ClearMode mode) const;
virtual void reactivate() const;
};
-class QSGBindableFbo : public QSGBindable
-{
-public:
- QSGBindableFbo(QOpenGLFramebufferObject *fbo);
- virtual void bind() const;
-private:
- QOpenGLFramebufferObject *m_fbo;
-};
-
class QSGBindableFboId : public QSGBindable
{
public:
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 17f4ba1243..ee077dbaf1 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -44,6 +44,7 @@
#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>
#include <QtGui/qguiapplication.h>
#include <qdir.h>
@@ -53,10 +54,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer qsg_render_timer;
-#endif
QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
@@ -163,11 +161,9 @@ void QSGDistanceFieldGlyphCache::update()
if (m_pendingGlyphs.isEmpty())
return;
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
qsg_render_timer.start();
-#endif
QList<QDistanceField> distanceFields;
for (int i = 0; i < m_pendingGlyphs.size(); ++i) {
@@ -176,31 +172,28 @@ void QSGDistanceFieldGlyphCache::update()
m_doubleGlyphResolution));
}
-#ifndef QSG_NO_RENDER_TIMING
qint64 renderTime = 0;
int count = m_pendingGlyphs.size();
if (profileFrames)
renderTime = qsg_render_timer.nsecsElapsed();
-#endif
m_pendingGlyphs.reset();
storeGlyphs(distanceFields);
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug(" - glyphs: count=%d, render=%d, store=%d, total=%d",
- count,
- int(renderTime/1000000),
- (int) qsg_render_timer.elapsed() - int(renderTime/1000000),
- (int) qsg_render_timer.elapsed());
-
+ if (QSG_LOG_TIME_GLYPH().isDebugEnabled()) {
+ quint64 now = qsg_render_timer.elapsed();
+ qCDebug(QSG_LOG_TIME_GLYPH,
+ "distancefield: %d glyphs prepared in %dms, rendering=%d, upload=%d",
+ count,
+ (int) now,
+ int(renderTime / 1000000),
+ int((now - (renderTime / 1000000))));
}
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphAdaptationLayerFrame, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphAdaptationLayerFrame, (
count,
renderTime,
qsg_render_timer.nsecsElapsed() - renderTime));
-#endif
}
void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &glyphs)
@@ -298,4 +291,52 @@ void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, con
}
}
+void QSGNodeVisitorEx::visitChildren(QSGNode *node)
+{
+ for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) {
+ switch (child->type()) {
+ case QSGNode::ClipNodeType: {
+ QSGClipNode *c = static_cast<QSGClipNode*>(child);
+ visit(c);
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::TransformNodeType: {
+ QSGTransformNode *c = static_cast<QSGTransformNode*>(child);
+ visit(c);
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::OpacityNodeType: {
+ QSGOpacityNode *c = static_cast<QSGOpacityNode*>(child);
+ visit(c);
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::GeometryNodeType: {
+ if (child->flags() & QSGNode::IsVisitableNode) {
+ QSGVisitableNode *v = static_cast<QSGVisitableNode*>(child);
+ v->accept(this);
+ } else {
+ QSGGeometryNode *c = static_cast<QSGGeometryNode*>(child);
+ visit(c);
+ visitChildren(c);
+ endVisit(c);
+ }
+ break;
+ }
+ case QSGNode::BasicNodeType: {
+ visitChildren(child);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index f2d7dc07ca..cc998a9cef 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -67,8 +67,44 @@ class TextureReference;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldGlyphNode;
class QOpenGLContext;
+class QSGImageNode;
+class QSGRectangleNode;
+class QSGGlyphNode;
+class QSGNinePatchNode;
-class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGGeometryNode
+class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx
+{
+public:
+ virtual void visit(QSGTransformNode *) = 0;
+ virtual void endVisit(QSGTransformNode *) = 0;
+ virtual void visit(QSGClipNode *) = 0;
+ virtual void endVisit(QSGClipNode *) = 0;
+ virtual void visit(QSGGeometryNode *) = 0;
+ virtual void endVisit(QSGGeometryNode *) = 0;
+ virtual void visit(QSGOpacityNode *) = 0;
+ virtual void endVisit(QSGOpacityNode *) = 0;
+ virtual void visit(QSGImageNode *) = 0;
+ virtual void endVisit(QSGImageNode *) = 0;
+ virtual void visit(QSGRectangleNode *) = 0;
+ virtual void endVisit(QSGRectangleNode *) = 0;
+ virtual void visit(QSGGlyphNode *) = 0;
+ virtual void endVisit(QSGGlyphNode *) = 0;
+ virtual void visit(QSGNinePatchNode *) = 0;
+ virtual void endVisit(QSGNinePatchNode *) = 0;
+
+ void visitChildren(QSGNode *node);
+};
+
+
+class Q_QUICK_PRIVATE_EXPORT QSGVisitableNode : public QSGGeometryNode
+{
+public:
+ QSGVisitableNode() { setFlag(IsVisitableNode); }
+
+ virtual void accept(QSGNodeVisitorEx *) = 0;
+};
+
+class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGVisitableNode
{
public:
virtual void setRect(const QRectF &rect) = 0;
@@ -81,10 +117,12 @@ public:
virtual void setAligned(bool aligned) = 0;
virtual void update() = 0;
+
+ virtual void accept(QSGNodeVisitorEx *visitor) { visitor->visit(this); visitor->visitChildren(this); visitor->endVisit(this); }
};
-class Q_QUICK_PRIVATE_EXPORT QSGImageNode : public QSGGeometryNode
+class Q_QUICK_PRIVATE_EXPORT QSGImageNode : public QSGVisitableNode
{
public:
virtual void setTargetRect(const QRectF &rect) = 0;
@@ -103,10 +141,24 @@ public:
virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
virtual void update() = 0;
+
+ virtual void accept(QSGNodeVisitorEx *visitor) { visitor->visit(this); visitor->visitChildren(this); visitor->endVisit(this); }
};
+class Q_QUICK_PRIVATE_EXPORT QSGNinePatchNode : public QSGVisitableNode
+{
+public:
+ virtual void setTexture(QSGTexture *texture) = 0;
+ virtual void setBounds(const QRectF &bounds) = 0;
+ virtual void setDevicePixelRatio(qreal ratio) = 0;
+ virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0;
+
+ virtual void update() = 0;
+
+ virtual void accept(QSGNodeVisitorEx *visitor) { visitor->visit(this); visitor->visitChildren(this); visitor->endVisit(this); }
+};
-class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGGeometryNode
+class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
{
public:
enum AntialiasingMode
@@ -134,6 +186,7 @@ public:
void setOwnerElement(QQuickItem *ownerElement) { m_ownerElement = ownerElement; }
QQuickItem *ownerElement() const { return m_ownerElement; }
+ virtual void accept(QSGNodeVisitorEx *visitor) { visitor->visit(this); visitor->visitChildren(this); visitor->endVisit(this); }
protected:
QRectF m_bounding_rect;
QQuickItem *m_ownerElement;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 124316a92f..4ea0cca553 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -50,6 +50,7 @@
#include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h>
#include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h>
#include <QtQuick/private/qsgatlastexture_p.h>
+#include <QtQuick/private/qsgrenderloop_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
@@ -93,6 +94,30 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
QT_BEGIN_NAMESPACE
+// Used for very high-level info about the renderering and gl context
+// Includes GL_VERSION, type of render loop, atlas size, etc.
+Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.info")
+
+// Used to debug the renderloop logic. Primarily useful for platform integrators
+// and when investigating the render loop logic.
+Q_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP, "qt.scenegraph.renderloop")
+
+
+// GLSL shader compilation
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION, "qt.scenegraph.time.compilation")
+
+// polish, animations, sync, render and swap in the render loop
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop")
+
+// Texture uploads and swizzling
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_TEXTURE, "qt.scenegraph.time.texture")
+
+// Glyph preparation (only for distance fields atm)
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
+
+// Timing inside the renderer base class
+Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
+
class QSGContextPrivate : public QObjectPrivate
{
public:
@@ -161,6 +186,15 @@ QSGContext::QSGContext(QObject *parent) :
d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
else if (mode == "gray")
d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
+
+ // Adds compatibility with Qt 5.3 and earlier's QSG_RENDER_TIMING
+ if (qEnvironmentVariableIsSet("QSG_RENDER_TIMING")) {
+ ((QLoggingCategory &) QSG_LOG_TIME_GLYPH()).setEnabled(QtDebugMsg, true);
+ ((QLoggingCategory &) QSG_LOG_TIME_TEXTURE()).setEnabled(QtDebugMsg, true);
+ ((QLoggingCategory &) QSG_LOG_TIME_RENDERER()).setEnabled(QtDebugMsg, true);
+ ((QLoggingCategory &) QSG_LOG_TIME_RENDERLOOP()).setEnabled(QtDebugMsg, true);
+ ((QLoggingCategory &) QSG_LOG_TIME_COMPILATION()).setEnabled(QtDebugMsg, true);
+ }
}
@@ -204,19 +238,20 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
}
static bool dumped = false;
- if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) {
+ if (!dumped && QSG_LOG_INFO().isDebugEnabled()) {
dumped = true;
QSurfaceFormat format = renderContext->openglContext()->format();
- qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize();
- qDebug() << "Depth Buffer: " << format.depthBufferSize();
- qDebug() << "Stencil Buffer: " << format.stencilBufferSize();
- qDebug() << "Samples: " << format.samples();
- qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR);
- qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER);
- qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ qCDebug(QSG_LOG_INFO) << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Depth Buffer: " << format.depthBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Stencil Buffer: " << format.stencilBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Samples: " << format.samples();
+ qCDebug(QSG_LOG_INFO) << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR);
+ qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER);
+ qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION);
QSet<QByteArray> exts = renderContext->openglContext()->extensions();
QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e;
- qDebug() << "GL_EXTENSIONS: " << all.constData();
+ qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData();
}
d->mutex.unlock();
@@ -264,9 +299,18 @@ QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc, bool preferNativ
}
}
+/*!
+ * Factory function for scene graph backends of the QStyle stylable elements. Returns a
+ * null pointer if the backend doesn't provide its own node type.
+ */
+QSGNinePatchNode *QSGContext::createNinePatchNode()
+{
+ return 0;
+}
+
QSurfaceFormat QSGContext::defaultSurfaceFormat() const
{
- QSurfaceFormat format;
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER");
format.setDepthBufferSize(useDepth ? 24 : 0);
@@ -328,6 +372,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context)
, m_distanceFieldCacheManager(0)
, m_brokenIBOs(false)
, m_serializedRender(false)
+ , m_attachToGLContext(true)
{
}
@@ -349,12 +394,7 @@ void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
if (m_serializedRender)
qsg_framerender_mutex.lock();
- if (fboId) {
- QSGBindableFboId bindable(fboId);
- renderer->renderScene(bindable);
- } else {
- renderer->renderScene();
- }
+ renderer->renderScene(fboId);
if (m_serializedRender)
qsg_framerender_mutex.unlock();
@@ -406,6 +446,12 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw
return cache;
}
+void QSGRenderContext::setAttachToGLContext(bool attach)
+{
+ Q_ASSERT(!isValid());
+ m_attachToGLContext = attach;
+}
+
#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context)
@@ -438,14 +484,18 @@ void QSGRenderContext::initialize(QOpenGLContext *context)
Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
m_gl = context;
- m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+ if (m_attachToGLContext) {
+ Q_ASSERT(!context->property(QSG_RENDERCONTEXT_PROPERTY).isValid());
+ context->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+ }
m_sg->renderContextInitialized(this);
#ifdef Q_OS_LINUX
- const char *vendor = (const char *) glGetString(GL_VENDOR);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ const char *vendor = (const char *) funcs->glGetString(GL_VENDOR);
if (strstr(vendor, "nouveau"))
m_brokenIBOs = true;
- const char *renderer = (const char *) glGetString(GL_RENDERER);
+ const char *renderer = (const char *) funcs->glGetString(GL_RENDERER);
if (strstr(renderer, "llvmpipe"))
m_serializedRender = true;
if (strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16"))
@@ -505,7 +555,8 @@ void QSGRenderContext::invalidate()
delete m_distanceFieldCacheManager;
m_distanceFieldCacheManager = 0;
- m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
+ if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
m_gl = 0;
m_sg->renderContextInvalidated(this);
@@ -555,6 +606,8 @@ QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager()
QSGTexture *QSGRenderContext::createTexture(const QImage &image) const
{
+ if (!openglContext())
+ return 0;
QSGTexture *t = m_atlasManager->create(image);
if (t)
return t;
@@ -642,6 +695,7 @@ void QSGRenderContext::compile(QSGMaterialShader *shader, QSGMaterial *material,
void QSGRenderContext::initialize(QSGMaterialShader *shader)
{
+ shader->program()->bind();
shader->initialize();
}
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index ac372b9718..da0de12a42 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -64,6 +64,7 @@ class QSGContextPrivate;
class QSGRectangleNode;
class QSGImageNode;
class QSGGlyphNode;
+class QSGNinePatchNode;
class QSGRenderer;
class QSGDistanceFieldGlyphCache;
class QQuickWindow;
@@ -79,6 +80,14 @@ class QQuickTextureFactory;
class QSGDistanceFieldGlyphCacheManager;
class QSGContext;
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_TEXTURE)
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH)
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER)
+
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP)
class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject
{
@@ -89,6 +98,7 @@ public:
QOpenGLContext *openglContext() const { return m_gl; }
QSGContext *sceneGraphContext() const { return m_sg; }
+ bool isValid() const { return m_gl; }
virtual void initialize(QOpenGLContext *context);
virtual void invalidate();
@@ -109,6 +119,7 @@ public:
virtual void compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0);
virtual void initialize(QSGMaterialShader *shader);
+ void setAttachToGLContext(bool attach);
void registerFontengineForCleanup(QFontEngine *engine);
static QSGRenderContext *from(QOpenGLContext *context);
@@ -138,6 +149,7 @@ protected:
bool m_brokenIBOs;
bool m_serializedRender;
+ bool m_attachToGLContext;
};
@@ -163,6 +175,8 @@ public:
virtual QSGRectangleNode *createRectangleNode();
virtual QSGImageNode *createImageNode();
virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode);
+ virtual QSGNinePatchNode *createNinePatchNode();
+ QSGNinePatchNode *createQStyleNode() { return createNinePatchNode(); }
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
virtual QSize minimumFBOSize() const;
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 48b405467b..5257cfda3d 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -63,8 +63,9 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistance
, m_blitProgram(0)
, m_blitBuffer(QOpenGLBuffer::VertexBuffer)
, m_fboGuard(0)
+ , m_funcs(c->functions())
#if !defined(QT_OPENGL_ES_2)
- , m_funcs(0)
+ , m_coreFuncs(0)
#endif
{
m_blitBuffer.create();
@@ -80,7 +81,7 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistance
QSGDefaultDistanceFieldGlyphCache::~QSGDefaultDistanceFieldGlyphCache()
{
for (int i = 0; i < m_textures.count(); ++i)
- glDeleteTextures(1, &m_textures[i].texture);
+ m_funcs->glDeleteTextures(1, &m_textures[i].texture);
if (m_fboGuard != 0)
m_fboGuard->free();
@@ -144,10 +145,10 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
QHash<TextureInfo *, QVector<glyph_t> > glyphTextures;
GLint alignment = 4; // default value
- glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+ m_funcs->glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
// Distance field data is always tightly packed
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (int i = 0; i < glyphs.size(); ++i) {
QDistanceField glyph = glyphs.at(i);
@@ -156,7 +157,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
TextureInfo *texInfo = m_glyphsTexture.value(glyphIndex);
resizeTexture(texInfo, texInfo->allocatedArea.width(), texInfo->allocatedArea.height());
- glBindTexture(GL_TEXTURE_2D, texInfo->texture);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, texInfo->texture);
glyphTextures[texInfo].append(glyphIndex);
@@ -181,21 +182,21 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
#endif
if (useTextureUploadWorkaround()) {
for (int i = 0; i < glyph.height(); ++i) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- c.x, c.y + i, glyph.width(),1,
- format, GL_UNSIGNED_BYTE,
- glyph.scanLine(i));
+ m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y + i, glyph.width(),1,
+ format, GL_UNSIGNED_BYTE,
+ glyph.scanLine(i));
}
} else {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- c.x, c.y, glyph.width(), glyph.height(),
- format, GL_UNSIGNED_BYTE,
- glyph.constBits());
+ m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y, glyph.width(), glyph.height(),
+ format, GL_UNSIGNED_BYTE,
+ glyph.constBits());
}
}
// restore to previous alignment
- glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+ m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
QHash<TextureInfo *, QVector<glyph_t> >::const_iterator i;
for (i = glyphTextures.constBegin(); i != glyphTextures.constEnd(); ++i) {
@@ -221,18 +222,18 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
if (useTextureResizeWorkaround() && texInfo->image.isNull())
texInfo->image = QDistanceField(width, height);
- while (glGetError() != GL_NO_ERROR) { }
+ while (m_funcs->glGetError() != GL_NO_ERROR) { }
- glGenTextures(1, &texInfo->texture);
- glBindTexture(GL_TEXTURE_2D, texInfo->texture);
+ m_funcs->glGenTextures(1, &texInfo->texture);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
if (!QOpenGLContext::currentContext()->isOpenGLES())
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
#else
@@ -240,14 +241,14 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
const GLenum format = GL_ALPHA;
#endif
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
+ m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
texInfo->size = QSize(width, height);
- GLuint error = glGetError();
+ GLuint error = m_funcs->glGetError();
if (error != GL_NO_ERROR) {
- glBindTexture(GL_TEXTURE_2D, 0);
- glDeleteTextures(1, &texInfo->texture);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, 0);
+ m_funcs->glDeleteTextures(1, &texInfo->texture);
texInfo->texture = 0;
}
@@ -281,42 +282,42 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
// For an OpenGL Core Profile we can use http://www.opengl.org/wiki/Framebuffer#Blitting
// to efficiently copy the contents of the old texture to the new texture
// TODO: Use ARB_copy_image if available of if we have >=4.3 context
- if (!m_funcs) {
- m_funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
- Q_ASSERT(m_funcs);
- m_funcs->initializeOpenGLFunctions();
+ if (!m_coreFuncs) {
+ m_coreFuncs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
+ Q_ASSERT(m_coreFuncs);
+ m_coreFuncs->initializeOpenGLFunctions();
}
// Create a framebuffer object to which we can attach our old and new textures (to
// the first two color buffer attachment points)
if (!m_fboGuard) {
GLuint fbo;
- m_funcs->glGenFramebuffers(1, &fbo);
+ m_coreFuncs->glGenFramebuffers(1, &fbo);
m_fboGuard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
}
// Bind the FBO to both the GL_READ_FRAMEBUFFER? and GL_DRAW_FRAMEBUFFER targets
- m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
+ m_coreFuncs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
// Bind the old texture to GL_COLOR_ATTACHMENT0
- m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ m_coreFuncs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, oldTexture, 0);
// Bind the new texture to GL_COLOR_ATTACHMENT1
- m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
+ m_coreFuncs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, texInfo->texture, 0);
// Set the source and destination buffers
- m_funcs->glReadBuffer(GL_COLOR_ATTACHMENT0);
- m_funcs->glDrawBuffer(GL_COLOR_ATTACHMENT1);
+ m_coreFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0);
+ m_coreFuncs->glDrawBuffer(GL_COLOR_ATTACHMENT1);
// Do the blit
- m_funcs->glBlitFramebuffer(0, 0, oldWidth, oldHeight,
+ m_coreFuncs->glBlitFramebuffer(0, 0, oldWidth, oldHeight,
0, 0, oldWidth, oldHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Reset the default framebuffer
- m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ m_coreFuncs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
return;
} else if (useTextureResizeWorkaround()) {
@@ -324,8 +325,8 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
if (useTextureResizeWorkaround()) {
#endif
GLint alignment = 4; // default value
- glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ m_funcs->glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+ m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#if !defined(QT_OPENGL_ES_2)
const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
@@ -335,22 +336,22 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
if (useTextureUploadWorkaround()) {
for (int i = 0; i < texInfo->image.height(); ++i) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, i, oldWidth, 1,
- format, GL_UNSIGNED_BYTE,
- texInfo->image.scanLine(i));
+ m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, i, oldWidth, 1,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.scanLine(i));
}
} else {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, 0, oldWidth, oldHeight,
- format, GL_UNSIGNED_BYTE,
- texInfo->image.constBits());
+ m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0, oldWidth, oldHeight,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.constBits());
}
- glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
+ m_funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
texInfo->image = texInfo->image.copy(0, 0, width, height);
- glDeleteTextures(1, &oldTexture);
+ m_funcs->glDeleteTextures(1, &oldTexture);
return;
}
@@ -361,30 +362,30 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
if (!m_fboGuard) {
GLuint fbo;
- ctx->functions()->glGenFramebuffers(1, &fbo);
+ m_funcs->glGenFramebuffers(1, &fbo);
m_fboGuard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
}
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
GLuint tmp_texture;
- glGenTextures(1, &tmp_texture);
- glBindTexture(GL_TEXTURE_2D, tmp_texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ m_funcs->glGenTextures(1, &tmp_texture);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
if (!ctx->isOpenGLES())
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ m_funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, 0);
- ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, tmp_texture, 0);
+ m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, 0);
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, tmp_texture, 0);
- ctx->functions()->glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, oldTexture);
+ m_funcs->glActiveTexture(GL_TEXTURE0);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, oldTexture);
// save current render states
GLboolean stencilTestEnabled;
@@ -393,19 +394,19 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
GLboolean blendEnabled;
GLint viewport[4];
GLint oldProgram;
- glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
- glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
- glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
- glGetBooleanv(GL_BLEND, &blendEnabled);
- glGetIntegerv(GL_VIEWPORT, &viewport[0]);
- glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram);
+ m_funcs->glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
+ m_funcs->glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
+ m_funcs->glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
+ m_funcs->glGetBooleanv(GL_BLEND, &blendEnabled);
+ m_funcs->glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+ m_funcs->glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram);
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_BLEND);
+ m_funcs->glDisable(GL_STENCIL_TEST);
+ m_funcs->glDisable(GL_DEPTH_TEST);
+ m_funcs->glDisable(GL_SCISSOR_TEST);
+ m_funcs->glDisable(GL_BLEND);
- glViewport(0, 0, oldWidth, oldHeight);
+ m_funcs->glViewport(0, 0, oldWidth, oldHeight);
const bool vaoInit = m_vao.isCreated();
if (isCoreProfile()) {
@@ -425,35 +426,35 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
m_blitProgram->setUniformValue("imageTexture", GLuint(0));
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ m_funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glBindTexture(GL_TEXTURE_2D, texInfo->texture);
+ m_funcs->glBindTexture(GL_TEXTURE_2D, texInfo->texture);
if (useTextureUploadWorkaround()) {
for (int i = 0; i < oldHeight; ++i)
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, 0, i, oldWidth, 1);
+ m_funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, 0, i, oldWidth, 1);
} else {
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ m_funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
}
- ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_RENDERBUFFER, 0);
- glDeleteTextures(1, &tmp_texture);
- glDeleteTextures(1, &oldTexture);
+ m_funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, 0);
+ m_funcs->glDeleteTextures(1, &tmp_texture);
+ m_funcs->glDeleteTextures(1, &oldTexture);
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
// restore render states
if (stencilTestEnabled)
- glEnable(GL_STENCIL_TEST);
+ m_funcs->glEnable(GL_STENCIL_TEST);
if (depthTestEnabled)
- glEnable(GL_DEPTH_TEST);
+ m_funcs->glEnable(GL_DEPTH_TEST);
if (scissorTestEnabled)
- glEnable(GL_SCISSOR_TEST);
+ m_funcs->glEnable(GL_SCISSOR_TEST);
if (blendEnabled)
- glEnable(GL_BLEND);
- glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
- ctx->functions()->glUseProgram(oldProgram);
+ m_funcs->glEnable(GL_BLEND);
+ m_funcs->glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+ m_funcs->glUseProgram(oldProgram);
m_blitProgram->disableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
@@ -479,7 +480,7 @@ bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
static bool set = false;
static bool useWorkaround = false;
if (!set) {
- useWorkaround = qstrcmp(reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
+ useWorkaround = qstrcmp(reinterpret_cast<const char*>(m_funcs->glGetString(GL_RENDERER)),
"Mali-400 MP") == 0;
set = true;
}
@@ -489,7 +490,7 @@ bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
{
if (!m_maxTextureSize)
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ m_funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
return m_maxTextureSize;
}
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index e1be2105cd..b04b03acdf 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -139,8 +139,9 @@ private:
QOpenGLVertexArrayObject m_vao;
QOpenGLSharedResourceGuard *m_fboGuard;
+ QOpenGLFunctions *m_funcs;
#if !defined(QT_OPENGL_ES_2)
- QOpenGLFunctions_3_2_Core *m_funcs;
+ QOpenGLFunctions_3_2_Core *m_coreFuncs;
#endif
};
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 86befa0b3b..c3234be158 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -125,13 +125,14 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf
|| oldMaterial->texture()->textureId() != material->texture()->textureId()) {
program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
1.0 / material->cacheTextureHeight()));
- glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
// Set the mag/min filters to be nearest. We only need to do this when the texture
// has been recreated.
if (updated) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
@@ -215,16 +216,18 @@ void QSG24BitTextMaskShader::initialize()
void QSG24BitTextMaskShader::activate()
{
- glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
if (m_useSRGB)
- glEnable(GL_FRAMEBUFFER_SRGB);
+ funcs->glEnable(GL_FRAMEBUFFER_SRGB);
}
void QSG24BitTextMaskShader::deactivate()
{
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
if (m_useSRGB)
- glDisable(GL_FRAMEBUFFER_SRGB);
+ funcs->glDisable(GL_FRAMEBUFFER_SRGB);
}
static inline qreal qt_sRGB_to_linear_RGB(qreal f)
@@ -250,7 +253,7 @@ void QSG24BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *
QVector4D color = material->color();
if (m_useSRGB)
color = qt_sRGB_to_linear_RGB(color);
- state.context()->functions()->glBlendColor(color.x(), color.y(), color.z(), color.w());
+ QOpenGLContext::currentContext()->functions()->glBlendColor(color.x(), color.y(), color.z(), color.w());
color = qsg_premultiply(color, state.opacity());
program()->setUniformValue(m_color_id, color.w());
}
@@ -313,13 +316,14 @@ void QSGStyledTextShader::updateState(const RenderState &state,
|| oldMaterial->texture()->textureId() != material->texture()->textureId()) {
program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
1.0 / material->cacheTextureHeight()));
- glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
// Set the mag/min filters to be linear. We only need to do this when the texture
// has been recreated.
if (updated) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 12a431246c..33cb8edf16 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -178,15 +178,16 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
updateTextureScale(QVector2D(1.0 / material->textureSize().width(),
1.0 / material->textureSize().height()));
- glBindTexture(GL_TEXTURE_2D, material->texture()->textureId);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId);
if (updated) {
// Set the mag/min filters to be linear. We only need to do this when the texture
// has been recreated.
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
}
@@ -511,13 +512,13 @@ void QSGHiQSubPixelDistanceFieldTextMaterialShader::initialize()
void QSGHiQSubPixelDistanceFieldTextMaterialShader::activate()
{
QSGDistanceFieldTextMaterialShader::activate();
- glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+ QOpenGLContext::currentContext()->functions()->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
}
void QSGHiQSubPixelDistanceFieldTextMaterialShader::deactivate()
{
QSGDistanceFieldTextMaterialShader::deactivate();
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ QOpenGLContext::currentContext()->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 05302cfe33..0f43ecffd7 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -65,7 +65,6 @@
QT_BEGIN_NAMESPACE
-DEFINE_BOOL_CONFIG_OPTION(qsg_render_timing, QSG_RENDER_TIMING)
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -87,6 +86,11 @@ QSGRenderLoop::~QSGRenderLoop()
{
}
+QSurface::SurfaceType QSGRenderLoop::windowSurfaceType() const
+{
+ return QSurface::OpenGLSurface;
+}
+
void QSGRenderLoop::cleanup()
{
if (!s_instance)
@@ -167,14 +171,16 @@ bool QSGRenderLoop::useConsistentTiming()
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
- s_instance = QSGContext::createWindowManager();
- bool info = qEnvironmentVariableIsSet("QSG_INFO");
+ // For compatibility with 5.3 and earlier's QSG_INFO environment variables
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ ((QLoggingCategory &) QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
+
+ s_instance = QSGContext::createWindowManager();
if (useConsistentTiming()) {
QUnifiedTimer::instance(true)->setConsistentTiming(true);
- if (info)
- qDebug() << "QSG: using fixed animation steps";
+ qCDebug(QSG_LOG_INFO, "using fixed animation steps");
}
if (!s_instance) {
@@ -208,15 +214,15 @@ QSGRenderLoop *QSGRenderLoop::instance()
switch (loopType) {
case ThreadedRenderLoop:
- if (info) qDebug() << "QSG: threaded render loop";
+ qCDebug(QSG_LOG_INFO, "threaded render loop");
s_instance = new QSGThreadedRenderLoop();
break;
case WindowsRenderLoop:
- if (info) qDebug() << "QSG: windows render loop";
+ qCDebug(QSG_LOG_INFO, "windows render loop");
s_instance = new QSGWindowsRenderLoop();
break;
default:
- if (info) qDebug() << "QSG: basic render loop";
+ qCDebug(QSG_LOG_INFO, "QSG: basic render loop");
s_instance = new QSGGuiThreadRenderLoop();
break;
}
@@ -333,8 +339,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!gl) {
gl = new QOpenGLContext();
gl->setFormat(window->requestedFormat());
- if (QOpenGLContextPrivate::globalShareContext())
- gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
+ if (qt_gl_global_share_context())
+ gl->setShareContext(qt_gl_global_share_context());
if (!gl->create()) {
const bool isEs = gl->isOpenGLES();
delete gl;
@@ -356,16 +362,27 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!current)
return;
- cd->polishItems();
-
- emit window->afterAnimating();
-
- qint64 renderTime = 0, syncTime = 0;
+ if (!data.grabOnly) {
+ cd->flushDelayedTouchEvent();
+ // Event delivery/processing triggered the window to be deleted or stop rendering.
+ if (!m_windows.contains(window))
+ return;
+ }
QElapsedTimer renderTimer;
- bool profileFrames = qsg_render_timing() || QQuickProfiler::enabled;
+ qint64 renderTime = 0, syncTime = 0, polishTime = 0;
+ bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
renderTimer.start();
+ cd->polishItems();
+
+ if (profileFrames) {
+ polishTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishFrame, (polishTime));
+ }
+
+ emit window->afterAnimating();
+
cd->syncSceneGraph();
if (profileFrames)
@@ -374,7 +391,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
cd->renderSceneGraph(window->size());
if (profileFrames)
- renderTime = renderTimer.nsecsElapsed() - syncTime;
+ renderTime = renderTimer.nsecsElapsed();
if (data.grabOnly) {
grabContent = qt_gl_read_framebuffer(window->size() * window->devicePixelRatio(), false, false);
@@ -387,24 +404,26 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
}
qint64 swapTime = 0;
- if (profileFrames) {
- swapTime = renderTimer.nsecsElapsed() - renderTime - syncTime;
- }
+ if (profileFrames)
+ swapTime = renderTimer.nsecsElapsed();
- if (qsg_render_timing()) {
+ if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
static QTime lastFrameTime = QTime::currentTime();
- qDebug() << "- Breakdown of frame time; sync:" << syncTime/1000000
- << "ms render:" << renderTime/1000000 << "ms swap:" << swapTime/1000000
- << "ms total:" << (swapTime + renderTime + syncTime)/1000000
- << "ms time since last frame:" << (lastFrameTime.msecsTo(QTime::currentTime()))
- << "ms";
+ qCDebug(QSG_LOG_TIME_RENDERLOOP,
+ "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
+ int(swapTime / 1000000),
+ int(polishTime / 1000000),
+ int((syncTime - polishTime) / 1000000),
+ int((renderTime - syncTime) / 1000000),
+ int((swapTime - renderTime) / 10000000),
+ int(lastFrameTime.msecsTo(QTime::currentTime())));
lastFrameTime = QTime::currentTime();
}
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, (
- syncTime,
- renderTime,
- swapTime));
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, (
+ syncTime - polishTime,
+ renderTime - syncTime,
+ swapTime - renderTime));
// Might have been set during syncSceneGraph()
if (data.updatePending)
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 8d5312b188..b398a64234 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -43,6 +43,7 @@
#define QSGRenderLoop_P_H
#include <QtGui/QImage>
+#include <QtGui/QSurface>
#include <private/qtquickglobal_p.h>
#include <QtCore/QSet>
@@ -83,6 +84,8 @@ public:
void removeWindow(QQuickWindow *win) { m_windows.remove(win); }
QSet<QQuickWindow *> windows() const { return m_windows; }
+ virtual QSurface::SurfaceType windowSurfaceType() const;
+
// ### make this less of a singleton
static QSGRenderLoop *instance();
static void setInstance(QSGRenderLoop *instance);
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 296050ec2f..84ae3f818b 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -50,6 +51,8 @@
#include <QtGui/QScreen>
#include <QtGui/QOffscreenSurface>
+#include <qpa/qwindowsysteminterface.h>
+
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
@@ -108,18 +111,7 @@
QT_BEGIN_NAMESPACE
-
-// #define QSG_RENDER_LOOP_DEBUG
-
-#if defined (QSG_RENDER_LOOP_DEBUG)
-QElapsedTimer qsgrl_timer;
-# define QSG_RT_DEBUG(MSG) qDebug("(%6d) line=%4d - win=%10p): Render: %s", (int) qsgrl_timer.elapsed(), __LINE__, window, MSG);
-# define QSG_GUI_DEBUG(WIN, MSG) qDebug("(%6d) line=%4d - win=%10p): Gui: %s", (int) qsgrl_timer.elapsed(), __LINE__, WIN, MSG);
-#else
-# define QSG_RT_DEBUG(MSG)
-# define QSG_GUI_DEBUG(WIN,MSG)
-#endif
-
+#define QSG_RT_PAD " (RT)"
static int get_env_int(const char *name, int defaultValue)
{
@@ -141,48 +133,35 @@ static inline int qsgrl_animation_interval() {
}
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer threadTimer;
static qint64 syncTime;
static qint64 renderTime;
static qint64 sinceLastTime;
-#endif
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
// RL: Render Loop
// RT: Render Thread
-// Passed from the RL to the RT when a window is rendeirng on screen
-// and should be added to the render loop.
-const QEvent::Type WM_Expose = QEvent::Type(QEvent::User + 1);
-
// Passed from the RL to the RT when a window is removed obscured and
// should be removed from the render loop.
-const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 2);
-
-// Passed from the RL to itself to initiate a polishAndSync() call.
-//const QEvent::Type WM_LockAndSync = QEvent::Type(QEvent::User + 3); // not used for now
+const QEvent::Type WM_Obscure = QEvent::Type(QEvent::User + 1);
// Passed from the RL to RT when GUI has been locked, waiting for sync
// (updatePaintNode())
-const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 4);
+const QEvent::Type WM_RequestSync = QEvent::Type(QEvent::User + 2);
// Passed by the RT to itself to trigger another render pass. This is
// typically a result of QQuickWindow::update().
-const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 5);
+const QEvent::Type WM_RequestRepaint = QEvent::Type(QEvent::User + 3);
// Passed by the RL to the RT to free up maybe release SG and GL contexts
// if no windows are rendering.
-const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 7);
+const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4);
// Passed by the RL to the RT when a QQuickWindow::grabWindow() is
// called.
-const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 9);
-
-// Passed by RL to RT when polish fails and we need to reset the expose sycle.
-const QEvent::Type WM_ResetExposeCycle = QEvent::Type(QEvent::User + 10);
+const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5);
template <typename T> T *windowFor(const QList<T> list, QQuickWindow *window)
{
@@ -215,11 +194,12 @@ public:
QOffscreenSurface *fallbackSurface;
};
-class WMExposeEvent : public WMWindowEvent
+class WMSyncEvent : public WMWindowEvent
{
public:
- WMExposeEvent(QQuickWindow *c) : WMWindowEvent(c, WM_Expose), size(c->size()) { }
+ WMSyncEvent(QQuickWindow *c, bool inExpose) : WMWindowEvent(c, WM_RequestSync), size(c->size()), syncInExpose(inExpose) { }
QSize size;
+ bool syncInExpose;
};
@@ -285,7 +265,6 @@ public:
, pendingUpdate(0)
, sleeping(false)
, syncResultedInChanges(false)
- , exposeCycle(NoExpose)
, active(false)
, window(0)
, stopEventProcessing(false)
@@ -309,7 +288,7 @@ public:
void run();
void syncAndRender();
- void sync();
+ void sync(bool inExpose);
void requestRepaint()
{
@@ -325,20 +304,15 @@ public:
public slots:
void sceneGraphChanged() {
- QSG_RT_DEBUG("sceneGraphChanged()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "sceneGraphChanged";
syncResultedInChanges = true;
}
public:
enum UpdateRequest {
SyncRequest = 0x01,
- RepaintRequest = 0x02
- };
-
- enum ExposeCycle {
- NoExpose,
- ExposePendingSync,
- ExposePendingSwap
+ RepaintRequest = 0x02,
+ ExposeRequest = 0x04 | RepaintRequest | SyncRequest
};
QSGThreadedRenderLoop *wm;
@@ -350,7 +324,6 @@ public:
uint pendingUpdate;
bool sleeping;
bool syncResultedInChanges;
- ExposeCycle exposeCycle;
volatile bool active;
@@ -373,30 +346,16 @@ bool QSGRenderThread::event(QEvent *e)
{
switch ((int) e->type()) {
- case WM_Expose: {
- QSG_RT_DEBUG("WM_Expose");
- WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
- Q_ASSERT(!window || window == se->window);
- windowSize = se->size;
- window = se->window;
- Q_ASSERT(exposeCycle == NoExpose);
- exposeCycle = ExposePendingSync;
- return true; }
-
- case WM_ResetExposeCycle:
- QSG_RT_DEBUG("WM_ResetExposeCycle");
- exposeCycle = NoExpose;
- return true;
-
case WM_Obscure: {
- QSG_RT_DEBUG("WM_Obscure");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Obscure";
Q_ASSERT(!window || window == static_cast<WMWindowEvent *>(e)->window);
mutex.lock();
if (window) {
QQuickWindowPrivate::get(window)->fireAboutToStop();
- QSG_RT_DEBUG(" - removed window...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window removed";
+ gl->doneCurrent();
window = 0;
}
waitCondition.wakeOne();
@@ -404,63 +363,68 @@ bool QSGRenderThread::event(QEvent *e)
return true; }
- case WM_RequestSync:
- QSG_RT_DEBUG("WM_RequestSync");
+ case WM_RequestSync: {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestSync";
+ WMSyncEvent *se = static_cast<WMSyncEvent *>(e);
if (sleeping)
stopEventProcessing = true;
- if (window)
- pendingUpdate |= SyncRequest;
- if (exposeCycle == ExposePendingSync) {
- pendingUpdate |= RepaintRequest;
- exposeCycle = ExposePendingSwap;
+ window = se->window;
+ windowSize = se->size;
+
+ pendingUpdate |= SyncRequest;
+ if (se->syncInExpose) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- triggered from expose";
+ pendingUpdate |= ExposeRequest;
}
- return true;
+ return true; }
case WM_TryRelease: {
- QSG_RT_DEBUG("WM_TryRelease");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_TryRelease";
mutex.lock();
- wm->m_locked = true;
+ wm->m_lockedForSync = true;
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (!window || wme->inDestructor) {
- QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- setting exit flag and invalidating OpenGL";
invalidateOpenGL(wme->window, wme->inDestructor, wme->fallbackSurface);
active = gl;
+ Q_ASSERT_X(!wme->inDestructor || !active, "QSGRenderThread::invalidateOpenGL()", "Thread's active state is not set to false when shutting down");
if (sleeping)
stopEventProcessing = true;
} else {
- QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- not releasing because window is still active";
}
waitCondition.wakeOne();
- wm->m_locked = false;
+ wm->m_lockedForSync = false;
mutex.unlock();
return true;
}
case WM_Grab: {
- QSG_RT_DEBUG("WM_Grab");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Grab";
WMGrabEvent *ce = static_cast<WMGrabEvent *>(e);
Q_ASSERT(ce->window == window);
mutex.lock();
if (window) {
gl->makeCurrent(window);
- QSG_RT_DEBUG(" - syncing scene graph");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync scene graph";
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->syncSceneGraph();
- QSG_RT_DEBUG(" - rendering scene graph");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering scene graph";
QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize);
- QSG_RT_DEBUG(" - grabbing result...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result";
*ce->image = qt_gl_read_framebuffer(windowSize * window->devicePixelRatio(), false, false);
}
- QSG_RT_DEBUG(" - waking gui to handle grab result");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result";
waitCondition.wakeOne();
mutex.unlock();
return true;
}
case WM_RequestRepaint:
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestPaint";
// When GUI posts this event, it is followed by a polishAndSync, so we mustn't
// exit the event loop yet.
pendingUpdate |= RepaintRequest;
@@ -474,13 +438,13 @@ bool QSGRenderThread::event(QEvent *e)
void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *fallback)
{
- QSG_RT_DEBUG("invalidateOpenGL()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "invalidateOpenGL()";
if (!gl)
return;
if (!window) {
- qWarning("QSGThreadedRenderLoop:QSGRenderThread: no window to make current...");
+ qCWarning(QSG_LOG_RENDERLOOP()) << "QSGThreadedRenderLoop:QSGRenderThread: no window to make current...";
return;
}
@@ -489,11 +453,8 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
bool current = gl->makeCurrent(fallback ? static_cast<QSurface *>(fallback) : static_cast<QSurface *>(window));
- if (!current) {
-#ifndef QT_NO_DEBUG
- qWarning() << "Scene Graph failed to acquire GL context during cleanup";
-#endif
- return;
+ if (Q_UNLIKELY(!current)) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- cleanup without an OpenGL context";
}
// The canvas nodes must be cleaned up regardless if we are in the destructor..
@@ -501,23 +462,25 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
dd->cleanupNodesOnShutdown();
} else {
- QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
- gl->doneCurrent();
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- persistent SG, avoiding cleanup";
+ if (current)
+ gl->doneCurrent();
return;
}
sgrc->invalidate();
QCoreApplication::processEvents();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- gl->doneCurrent();
- QSG_RT_DEBUG(" - invalidated scenegraph..");
+ if (current)
+ gl->doneCurrent();
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- invalidating scene graph";
if (wipeGL) {
delete gl;
gl = 0;
- QSG_RT_DEBUG(" - invalidated OpenGL");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- invalidated OpenGL";
} else {
- QSG_RT_DEBUG(" - persistent GL, avoiding cleanup");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- persistent GL, avoiding cleanup";
}
}
@@ -525,12 +488,12 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
Enters the mutex lock to make sure GUI is blocking and performs
sync, then wakes GUI.
*/
-void QSGRenderThread::sync()
+void QSGRenderThread::sync(bool inExpose)
{
- QSG_RT_DEBUG("sync()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "sync()";
mutex.lock();
- Q_ASSERT_X(wm->m_locked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
+ Q_ASSERT_X(wm->m_lockedForSync, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
bool current = false;
if (windowSize.width() > 0 && windowSize.height() > 0)
@@ -544,7 +507,7 @@ void QSGRenderThread::sync()
d->renderer->clearChangedFlag();
d->syncSceneGraph();
if (!hadRenderer && d->renderer) {
- QSG_RT_DEBUG(" - renderer was created, hooking up changed signal");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- renderer was created";
syncResultedInChanges = true;
connect(d->renderer, SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()), Qt::DirectConnection);
}
@@ -554,52 +517,51 @@ void QSGRenderThread::sync()
// and the delete is a safe operation.
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
} else {
- QSG_RT_DEBUG(" - window has bad size, waiting...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window has bad size, sync aborted";
}
- waitCondition.wakeOne();
- mutex.unlock();
+ if (!inExpose) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync complete, waking Gui";
+ waitCondition.wakeOne();
+ mutex.unlock();
+ }
}
-
void QSGRenderThread::syncAndRender()
{
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames) {
sinceLastTime = threadTimer.nsecsElapsed();
threadTimer.start();
}
-#endif
+
QElapsedTimer waitTimer;
waitTimer.start();
- QSG_RT_DEBUG("syncAndRender()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "syncAndRender()";
syncResultedInChanges = false;
- bool repaintRequested = pendingUpdate & RepaintRequest;
- bool syncRequested = pendingUpdate & SyncRequest;
+ uint pending = pendingUpdate;
pendingUpdate = 0;
- if (syncRequested) {
- QSG_RT_DEBUG(" - update pending, doing sync");
- sync();
+ if (pending & SyncRequest) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- updatePending, doing sync";
+ sync(pending == ExposeRequest);
}
- if (!syncResultedInChanges && !(repaintRequested)) {
- QSG_RT_DEBUG(" - no changes, rendering aborted");
+ if (!syncResultedInChanges && ((pending & RepaintRequest) == 0)) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted";
int waitTime = vsyncDelta - (int) waitTimer.elapsed();
if (waitTime > 0)
msleep(waitTime);
return;
}
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
syncTime = threadTimer.nsecsElapsed();
-#endif
- QSG_RT_DEBUG(" - rendering starting");
+
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering started";
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
@@ -614,45 +576,39 @@ void QSGRenderThread::syncAndRender()
current = gl->makeCurrent(window);
if (current) {
d->renderSceneGraph(windowSize);
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
renderTime = threadTimer.nsecsElapsed();
-#endif
gl->swapBuffers(window);
d->fireFrameSwapped();
} else {
- QSG_RT_DEBUG(" - Window not yet ready, skipping render...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window not ready, skipping render";
}
- QSG_RT_DEBUG(" - rendering done");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering done";
// Though it would be more correct to put this block directly after
// fireFrameSwapped in the if (current) branch above, we don't do
// that to avoid blocking the GUI thread in the case where it
// has started rendering with a bad window, causing makeCurrent to
// fail or if the window has a bad size.
- mutex.lock();
- if (exposeCycle == ExposePendingSwap) {
- QSG_RT_DEBUG(" - waking GUI after expose");
- exposeCycle = NoExpose;
+ if (pending == ExposeRequest) {
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- wake Gui after initial expose";
waitCondition.wakeOne();
+ mutex.unlock();
}
- mutex.unlock();
-
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- qDebug("Render Thread: window=%p, framedelta=%d, sync=%d, first render=%d, after final swap=%d",
- window,
- int(sinceLastTime/1000000),
- int(syncTime/1000000),
- int((renderTime - syncTime)/1000000),
- int(threadTimer.elapsed() - renderTime/1000000));
-
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, (
+
+ qCDebug(QSG_LOG_TIME_RENDERLOOP,
+ "Frame rendered with 'threaded' renderloop in %dms, sync=%d, render=%d, swap=%d - (on render thread)",
+ int(threadTimer.elapsed()),
+ int((syncTime/1000000)),
+ int((renderTime - syncTime) / 1000000),
+ int(threadTimer.elapsed() - renderTime / 1000000));
+
+
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, (
syncTime,
renderTime - syncTime,
threadTimer.nsecsElapsed() - renderTime));
-#endif
}
@@ -666,30 +622,30 @@ void QSGRenderThread::postEvent(QEvent *e)
void QSGRenderThread::processEvents()
{
- QSG_RT_DEBUG("processEvents()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- begin processEvents()";
while (eventQueue.hasMoreEvents()) {
QEvent *e = eventQueue.takeEvent(false);
event(e);
delete e;
}
- QSG_RT_DEBUG(" - done with processEvents()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- done processEvents()";
}
void QSGRenderThread::processEventsAndWaitForMore()
{
- QSG_RT_DEBUG("processEventsAndWaitForMore()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- begin processEventsAndWaitForMore()";
stopEventProcessing = false;
while (!stopEventProcessing) {
QEvent *e = eventQueue.takeEvent(true);
event(e);
delete e;
}
- QSG_RT_DEBUG(" - done with processEventsAndWaitForMore()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "--- done processEventsAndWaitForMore()";
}
void QSGRenderThread::run()
{
- QSG_RT_DEBUG("run()");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()";
animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0);
animatorDriver->install();
QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
@@ -708,7 +664,7 @@ void QSGRenderThread::run()
QCoreApplication::processEvents();
if (active && (pendingUpdate == 0 || !window)) {
- QSG_RT_DEBUG("enter event loop (going to sleep)");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "done drawing, sleep...";
sleeping = true;
processEventsAndWaitForMore();
sleeping = false;
@@ -717,7 +673,7 @@ void QSGRenderThread::run()
Q_ASSERT_X(!gl, "QSGRenderThread::run()", "The OpenGL context should be cleaned up before exiting the render thread...");
- QSG_RT_DEBUG("run() completed...");
+ qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run() completed";
delete animatorDriver;
animatorDriver = 0;
@@ -742,7 +698,6 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped()));
m_animation_driver->install();
- QSG_GUI_DEBUG((void *) 0, "QSGThreadedRenderLoop() created");
}
QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const
@@ -753,7 +708,7 @@ QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) con
void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w)
{
if (w->timerId == 0) {
- QSG_GUI_DEBUG(w->window, " - posting update");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- posting update";
w->timerId = startTimer(m_exhaust_delay, Qt::PreciseTimer);
}
}
@@ -785,7 +740,7 @@ bool QSGThreadedRenderLoop::interleaveIncubation() const
void QSGThreadedRenderLoop::animationStarted()
{
- QSG_GUI_DEBUG((void *) 0, "animationStarted()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- animationStarted()";
startOrStopAnimationTimer();
for (int i=0; i<m_windows.size(); ++i)
@@ -794,7 +749,7 @@ void QSGThreadedRenderLoop::animationStarted()
void QSGThreadedRenderLoop::animationStopped()
{
- QSG_GUI_DEBUG((void *) 0, "animationStopped()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- animationStopped()";
startOrStopAnimationTimer();
}
@@ -824,54 +779,19 @@ void QSGThreadedRenderLoop::startOrStopAnimationTimer()
}
/*
- Adds this window to the list of tracked windows in this window
- manager. show() does not trigger rendering to start, that happens
- in expose.
- */
-
-void QSGThreadedRenderLoop::show(QQuickWindow *window)
-{
- QSG_GUI_DEBUG(window, "show()");
-
- if (Window *w = windowFor(m_windows, window)) {
- /* Safeguard ourselves against misbehaving platform plugins.
- *
- * When being shown, the window should not be exposed as the
- * platform plugin is only told to show after we send the show
- * event. If we are already shown at this time and we don't have
- * an active rendering thread we don't trust the plugin to send
- * us another expose event, so make this explicit call to
- * handleExposure.
- *
- * REF: QTCREATORBUG-10699
- */
- if (window->isExposed() && (!w->thread || !w->thread->window))
- handleExposure(w);
- return;
- }
-
- QSG_GUI_DEBUG(window, " - now tracking new window");
-
- Window win;
- win.window = window;
- win.actualWindowFormat = window->format();
- win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
- win.timerId = 0;
- win.updateDuringSync = false;
- m_windows << win;
-}
-
-
-
-/*
Removes this window from the list of tracked windowes in this
window manager. hide() will trigger obscure, which in turn will
stop rendering.
+
+ This function will be called during QWindow::close() which will
+ also destroy the QPlatformWindow so it is important that this
+ triggers handleObscurity() and that rendering for that window
+ is fully done and over with by the time this function exits.
*/
void QSGThreadedRenderLoop::hide(QQuickWindow *window)
{
- QSG_GUI_DEBUG(window, "hide()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "hide()" << window;
if (window->isExposed())
handleObscurity(windowFor(m_windows, window));
@@ -887,39 +807,41 @@ void QSGThreadedRenderLoop::hide(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
{
- QSG_GUI_DEBUG(window, "windowDestroyed()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "begin windowDestroyed()" << window;
+
+ Window *w = windowFor(m_windows, window);
+ if (!w)
+ return;
+
+ handleObscurity(w);
+ releaseResources(w, true);
- if (window->isVisible())
- hide(window);
- releaseResources(window, true);
+ QSGRenderThread *thread = w->thread;
+ while (thread->isRunning())
+ QThread::yieldCurrentThread();
+ Q_ASSERT(thread->thread() == QThread::currentThread());
+ delete thread;
for (int i=0; i<m_windows.size(); ++i) {
if (m_windows.at(i).window == window) {
- QSGRenderThread *thread = m_windows.at(i).thread;
- while (thread->isRunning())
- QThread::yieldCurrentThread();
- Q_ASSERT(thread->thread() == QThread::currentThread());
- delete thread;
m_windows.removeAt(i);
break;
}
}
- QSG_GUI_DEBUG(window, " - done with windowDestroyed()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "done windowDestroyed()" << window;
}
void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
{
- QSG_GUI_DEBUG(window, "exposureChanged()");
- Window *w = windowFor(m_windows, window);
- if (!w)
- return;
-
+ qCDebug(QSG_LOG_RENDERLOOP) << "exposureChanged()" << window;
if (window->isExposed()) {
- handleExposure(w);
+ handleExposure(window);
} else {
- handleObscurity(w);
+ Window *w = windowFor(m_windows, window);
+ if (w)
+ handleObscurity(w);
}
}
@@ -927,9 +849,26 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
Will post an event to the render thread that this window should
start to render.
*/
-void QSGThreadedRenderLoop::handleExposure(Window *w)
+void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
{
- QSG_GUI_DEBUG(w->window, "handleExposure");
+ qCDebug(QSG_LOG_RENDERLOOP) << "handleExposure()" << window;
+
+ Window *w = windowFor(m_windows, window);
+ if (!w) {
+ qCDebug(QSG_LOG_RENDERLOOP) << "- adding window to list";
+ Window win;
+ win.window = window;
+ win.actualWindowFormat = window->format();
+ win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
+ win.timerId = 0;
+ win.updateDuringSync = false;
+ m_windows << win;
+ w = &m_windows.last();
+ }
+
+ // set this early as we'll be rendering shortly anyway and this avoids
+ // specialcasing exposure in polishAndSync.
+ w->thread->window = window;
if (w->window->width() <= 0 || w->window->height() <= 0
|| !w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
@@ -946,12 +885,12 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
// Start render thread if it is not running
if (!w->thread->isRunning()) {
- QSG_GUI_DEBUG(w->window, " - starting render thread...");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- starting render thread";
if (!w->thread->gl) {
w->thread->gl = new QOpenGLContext();
- if (QOpenGLContextPrivate::globalShareContext())
- w->thread->gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
+ if (qt_gl_global_share_context())
+ w->thread->gl->setShareContext(qt_gl_global_share_context());
w->thread->gl->setFormat(w->window->requestedFormat());
if (!w->thread->gl->create()) {
const bool isEs = w->thread->gl->isOpenGLES();
@@ -964,7 +903,7 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
QQuickWindowPrivate::get(w->window)->fireOpenGLContextCreated(w->thread->gl);
w->thread->gl->moveToThread(w->thread);
- QSG_GUI_DEBUG(w->window, " - OpenGL context created...");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- OpenGL context created";
}
QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
@@ -979,24 +918,11 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
w->thread->start();
} else {
- QSG_GUI_DEBUG(w->window, " - render thread already running");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- render thread already running";
}
- w->thread->postEvent(new WMExposeEvent(w->window));
- bool synced = polishAndSync(w);
-
- if (synced) {
- w->thread->mutex.lock();
- if (w->thread->exposeCycle != QSGRenderThread::NoExpose) {
- QSG_GUI_DEBUG(w->window, " - waiting for swap to complete...");
- w->thread->waitCondition.wait(&w->thread->mutex);
- }
- Q_ASSERT(w->thread->exposeCycle == QSGRenderThread::NoExpose);
- w->thread->mutex.unlock();
- } else {
- w->thread->postEvent(new QEvent(WM_ResetExposeCycle));
- }
- QSG_GUI_DEBUG(w->window, " - handleExposure completed...");
+ polishAndSync(w, true);
+ qCDebug(QSG_LOG_RENDERLOOP) << "- done with handleExposure()";
startOrStopAnimationTimer();
}
@@ -1010,14 +936,13 @@ void QSGThreadedRenderLoop::handleExposure(Window *w)
*/
void QSGThreadedRenderLoop::handleObscurity(Window *w)
{
- QSG_GUI_DEBUG(w->window, "handleObscurity");
+ qCDebug(QSG_LOG_RENDERLOOP) << "handleObscurity()" << w->window;
if (w->thread->isRunning()) {
w->thread->mutex.lock();
w->thread->postEvent(new WMWindowEvent(w->window, WM_Obscure));
w->thread->waitCondition.wait(&w->thread->mutex);
w->thread->mutex.unlock();
}
-
startOrStopAnimationTimer();
}
@@ -1038,19 +963,21 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w)
if (!QCoreApplication::instance())
return;
- Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
- "QQuickItem::update()",
- "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
+ QThread *current = QThread::currentThread();
+ if (current != QCoreApplication::instance()->thread() && (current != w->thread || !m_lockedForSync)) {
+ qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()";
+ return;
+ }
- QSG_GUI_DEBUG(w->window, "maybeUpdate...");
if (!w || !w->thread->isRunning()) {
return;
}
+ qCDebug(QSG_LOG_RENDERLOOP) << "update from item" << w->window;
// Call this function from the Gui thread later as startTimer cannot be
// called from the render thread.
if (QThread::currentThread() == w->thread) {
- QSG_GUI_DEBUG(w->window, " - on render thread, will update later..");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- on render thread";
w->updateDuringSync = true;
return;
}
@@ -1070,32 +997,35 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
return;
if (w->thread == QThread::currentThread()) {
- QSG_RT_DEBUG("QQuickWindow::update called on render thread");
+ qCDebug(QSG_LOG_RENDERLOOP) << "update on window - on render thread" << w->window;
w->thread->requestRepaint();
return;
}
- QSG_GUI_DEBUG(w->window, "update called");
+ qCDebug(QSG_LOG_RENDERLOOP) << "update on window" << w->window;
w->thread->postEvent(new QEvent(WM_RequestRepaint));
maybeUpdate(w);
}
+void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window)
+{
+ Window *w = windowFor(m_windows, window);
+ if (w)
+ releaseResources(w, false);
+}
/*!
* Release resources will post an event to the render thread to
* free up the SG and GL resources and exists the render thread.
*/
-void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestructor)
+void QSGThreadedRenderLoop::releaseResources(Window *w, bool inDestructor)
{
- QSG_GUI_DEBUG(window, "releaseResources requested...");
-
- Window *w = windowFor(m_windows, window);
- if (!w)
- return;
+ qCDebug(QSG_LOG_RENDERLOOP) << "releaseResources()" << (inDestructor ? "in destructor" : "in api-call") << w->window;
w->thread->mutex.lock();
if (w->thread->isRunning() && w->thread->active) {
+ QQuickWindow *window = w->window;
// The platform window might have been destroyed before
// hide/release/windowDestroyed is called, so we need to have a
@@ -1105,16 +1035,15 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestru
// create it here and pass it on to QSGRenderThread::invalidateGL()
QOffscreenSurface *fallback = 0;
if (!window->handle()) {
- QSG_GUI_DEBUG(w->window, " - using fallback surface");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- using fallback surface";
fallback = new QOffscreenSurface();
fallback->setFormat(w->actualWindowFormat);
fallback->create();
}
- QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- posting release request to render thread";
w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor, fallback));
w->thread->waitCondition.wait(&w->thread->mutex);
-
delete fallback;
}
w->thread->mutex.unlock();
@@ -1124,67 +1053,71 @@ void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestru
/* Calls polish on all items, then requests synchronization with the render thread
* and blocks until that is complete. Returns false if it aborted; otherwise true.
*/
-bool QSGThreadedRenderLoop::polishAndSync(Window *w)
+void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
{
- QSG_GUI_DEBUG(w->window, "polishAndSync()");
+ qCDebug(QSG_LOG_RENDERLOOP) << "polishAndSync" << (inExpose ? "(in expose)" : "(normal)") << w->window;
+
+ QQuickWindow *window = w->window;
+ if (!w->thread || !w->thread->window) {
+ qCDebug(QSG_LOG_RENDERLOOP) << "- not exposed, abort";
+ killTimer(w->timerId);
+ w->timerId = 0;
+ return;
+ }
- if (!w->window->isExposed() || !w->window->isVisible() || w->window->size().isEmpty()) {
- QSG_GUI_DEBUG(w->window, " - not exposed, aborting...");
+ // Flush pending touch events.
+ QQuickWindowPrivate::get(window)->flushDelayedTouchEvent();
+ // The delivery of the event might have caused the window to stop rendering
+ w = windowFor(m_windows, window);
+ if (!w || !w->thread || !w->thread->window) {
+ qCDebug(QSG_LOG_RENDERLOOP) << "- removed after event flushing, abort";
killTimer(w->timerId);
w->timerId = 0;
- return false;
+ return;
}
-#ifndef QSG_NO_RENDER_TIMING
QElapsedTimer timer;
qint64 polishTime = 0;
qint64 waitTime = 0;
qint64 syncTime = 0;
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
timer.start();
-#endif
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w->window);
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->polishItems();
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
polishTime = timer.nsecsElapsed();
-#endif
w->updateDuringSync = false;
- emit w->window->afterAnimating();
+ emit window->afterAnimating();
- QSG_GUI_DEBUG(w->window, " - lock for sync...");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- lock for sync";
w->thread->mutex.lock();
- m_locked = true;
- w->thread->postEvent(new QEvent(WM_RequestSync));
+ m_lockedForSync = true;
+ w->thread->postEvent(new WMSyncEvent(window, inExpose));
- QSG_GUI_DEBUG(w->window, " - wait for sync...");
-#ifndef QSG_NO_RENDER_TIMING
+ qCDebug(QSG_LOG_RENDERLOOP) << "- wait for sync";
if (profileFrames)
waitTime = timer.nsecsElapsed();
-#endif
w->thread->waitCondition.wait(&w->thread->mutex);
- m_locked = false;
+ m_lockedForSync = false;
w->thread->mutex.unlock();
- QSG_GUI_DEBUG(w->window, " - unlocked after sync...");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- unlock after sync";
-#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
syncTime = timer.nsecsElapsed();
-#endif
killTimer(w->timerId);
w->timerId = 0;
if (m_animation_timer == 0 && m_animation_driver->isRunning()) {
- QSG_GUI_DEBUG(w->window, " - animations advancing");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- advancing animations";
m_animation_driver->advance();
- QSG_GUI_DEBUG(w->window, " - animations done");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- animations done..";
// We need to trigger another sync to keep animations running...
maybePostPolishRequest(w);
emit timeToIncubate();
@@ -1192,24 +1125,30 @@ bool QSGThreadedRenderLoop::polishAndSync(Window *w)
maybePostPolishRequest(w);
}
+ qCDebug(QSG_LOG_TIME_RENDERLOOP()).nospace()
+ << "Frame prepared with 'threaded' renderloop"
+ << ", polish=" << (polishTime / 1000000)
+ << ", lock=" << (waitTime - polishTime) / 1000000
+ << ", blockedForSync=" << (syncTime - waitTime) / 1000000
+ << ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000
+ << " - (on Gui thread) " << window;
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- qDebug(" - Gui Thread: window=%p, polish=%d, lock=%d, block/sync=%d -- animations=%d",
- w->window,
- int(polishTime/1000000),
- int((waitTime - polishTime)/1000000),
- int((syncTime - waitTime)/1000000),
- int((timer.nsecsElapsed() - syncTime)/1000000));
-
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphPolishAndSync, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishAndSync, (
polishTime,
waitTime - polishTime,
syncTime - waitTime,
timer.nsecsElapsed() - syncTime));
-#endif
+}
- return true;
+QSGThreadedRenderLoop::Window *QSGThreadedRenderLoop::windowForTimer(int timerId) const
+{
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).timerId == timerId) {
+ return const_cast<Window *>(&m_windows.at(i));
+ break;
+ }
+ }
+ return 0;
}
bool QSGThreadedRenderLoop::event(QEvent *e)
@@ -1219,18 +1158,12 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
case QEvent::Timer: {
QTimerEvent *te = static_cast<QTimerEvent *>(e);
if (te->timerId() == m_animation_timer) {
- QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> non-visual animation");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- ticking non-visual timer";
m_animation_driver->advance();
emit timeToIncubate();
} else {
- QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> Polish & Sync");
- Window *w = 0;
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).timerId == te->timerId()) {
- w = const_cast<Window *>(&m_windows.at(i));
- break;
- }
- }
+ qCDebug(QSG_LOG_RENDERLOOP) << "- polish and sync timer";
+ Window *w = windowForTimer(te->timerId());
if (w)
polishAndSync(w);
else
@@ -1260,7 +1193,7 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
QImage QSGThreadedRenderLoop::grab(QQuickWindow *window)
{
- QSG_GUI_DEBUG(window, "grab");
+ qCDebug(QSG_LOG_RENDERLOOP) << "grab()" << window;
Window *w = windowFor(m_windows, window);
Q_ASSERT(w);
@@ -1271,21 +1204,20 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window)
if (!window->handle())
window->create();
- QSG_GUI_DEBUG(w->window, " - polishing items...");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- polishing items";
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->polishItems();
QImage result;
w->thread->mutex.lock();
- m_locked = true;
- QSG_GUI_DEBUG(w->window, " - locking, posting grab event");
+ m_lockedForSync = true;
+ qCDebug(QSG_LOG_RENDERLOOP) << "- posting grab event";
w->thread->postEvent(new WMGrabEvent(window, &result));
w->thread->waitCondition.wait(&w->thread->mutex);
- QSG_GUI_DEBUG(w->window, " - locking, grab done, unlocking");
- m_locked = false;
+ m_lockedForSync = false;
w->thread->mutex.unlock();
- QSG_GUI_DEBUG(w->window, " - grab complete");
+ qCDebug(QSG_LOG_RENDERLOOP) << "- grab complete";
return result;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 82ab2cdaa0..b86b3c73a4 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -58,8 +58,8 @@ class QSGThreadedRenderLoop : public QSGRenderLoop
public:
QSGThreadedRenderLoop();
- void show(QQuickWindow *window);
- void hide(QQuickWindow *window);
+ void show(QQuickWindow *) {}
+ void hide(QQuickWindow *);
void windowDestroyed(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
@@ -73,7 +73,7 @@ public:
QAnimationDriver *animationDriver() const;
- void releaseResources(QQuickWindow *window) { releaseResources(window, false); }
+ void releaseResources(QQuickWindow *window);
bool event(QEvent *);
@@ -94,8 +94,9 @@ private:
friend class QSGRenderThread;
- void releaseResources(QQuickWindow *window, bool inDestructor);
+ void releaseResources(Window *window, bool inDestructor);
bool checkAndResetForceUpdate(QQuickWindow *window);
+ Window *windowForTimer(int timerId) const;
bool anyoneShowing() const;
void initialize();
@@ -103,10 +104,10 @@ private:
void startOrStopAnimationTimer();
void maybePostPolishRequest(Window *w);
void waitForReleaseComplete();
- bool polishAndSync(Window *w);
+ void polishAndSync(Window *w, bool inExpose = false);
void maybeUpdate(Window *window);
- void handleExposure(Window *w);
+ void handleExposure(QQuickWindow *w);
void handleObscurity(Window *w);
@@ -117,7 +118,7 @@ private:
int m_animation_timer;
int m_exhaust_delay;
- bool m_locked;
+ bool m_lockedForSync;
};
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index e20f9cdb9e..671b341046 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -58,22 +58,13 @@ QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-// #define QSG_RENDER_LOOP_DEBUG
+#define RLDEBUG(x) qCDebug(QSG_LOG_RENDERLOOP) << x;
-#ifdef QSG_RENDER_LOOP_DEBUG
-static QElapsedTimer qsg_debug_timer;
-# define RLDEBUG(x) qDebug("(%6d) %s : %4d - %s", (int) qsg_debug_timer.elapsed(), __FILE__, __LINE__, x)
-#else
-# define RLDEBUG(x)
-#endif
-
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer qsg_render_timer;
-#define QSG_RENDER_TIMING_SAMPLE(sampleName) qint64 sampleName = 0; if (qsg_render_timing || QQuickProfiler::enabled) sampleName = qsg_render_timer.nsecsElapsed()
-#else
-#define QSG_RENDER_TIMING_SAMPLE(sampleName)
-#endif
+#define QSG_RENDER_TIMING_SAMPLE(sampleName) \
+ qint64 sampleName = 0; \
+ if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::enabled) \
+ sampleName = qsg_render_timer.nsecsElapsed()
QSGWindowsRenderLoop::QSGWindowsRenderLoop()
@@ -82,10 +73,6 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
, m_updateTimer(0)
, m_animationTimer(0)
{
-#ifdef QSG_RENDER_LOOP_DEBUG
- qsg_debug_timer.start();
-#endif
-
m_rc = m_sg->createRenderContext();
m_animationDriver = m_sg->createAnimationDriver(m_sg);
@@ -100,9 +87,7 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
RLDEBUG("Windows Render Loop created");
-#ifndef QSG_NO_RENDER_TIMIMG
qsg_render_timer.start();
-#endif
}
QSGWindowsRenderLoop::~QSGWindowsRenderLoop()
@@ -174,13 +159,11 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
// By preparing the GL context here, it is feasible (if the app
// is quick enough) to have a perfect first frame.
if (!m_gl) {
- QSG_RENDER_TIMING_SAMPLE(time_start);
-
RLDEBUG(" - creating GL context");
m_gl = new QOpenGLContext();
m_gl->setFormat(window->requestedFormat());
- if (QOpenGLContextPrivate::globalShareContext())
- m_gl->setShareContext(QOpenGLContextPrivate::globalShareContext());
+ if (qt_gl_global_share_context())
+ m_gl->setShareContext(qt_gl_global_share_context());
bool created = m_gl->create();
if (!created) {
const bool isEs = m_gl->isOpenGLES();
@@ -192,27 +175,11 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
QQuickWindowPrivate::get(window)->fireOpenGLContextCreated(m_gl);
- QSG_RENDER_TIMING_SAMPLE(time_created);
RLDEBUG(" - making current");
bool current = m_gl->makeCurrent(window);
RLDEBUG(" - initializing SG");
- QSG_RENDER_TIMING_SAMPLE(time_current);
if (current)
m_rc->initialize(m_gl);
-
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug("WindowsRenderLoop: GL=%d ms, makeCurrent=%d ms, SG=%d ms",
- int((time_created - time_start)/1000000),
- int((time_current - time_created)/1000000),
- int((qsg_render_timer.nsecsElapsed() - time_current)/1000000));
- }
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphWindowsRenderShow, (
- time_created - time_start,
- time_current - time_created,
- qsg_render_timer.nsecsElapsed() - time_current));
-#endif
-
}
WindowData data;
@@ -405,14 +372,12 @@ void QSGWindowsRenderLoop::render()
m_animationDriver->advance();
RLDEBUG("animations advanced");
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug("WindowsRenderLoop: animations=%d ms",
- int((qsg_render_timer.nsecsElapsed() - time_start)/1000000));
- }
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphWindowsAnimations, (
+ qCDebug(QSG_LOG_TIME_RENDERLOOP,
+ "animations ticked in %dms",
+ int((qsg_render_timer.nsecsElapsed() - time_start)/1000000));
+
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphWindowsAnimations, (
qsg_render_timer.nsecsElapsed() - time_start));
-#endif
// It is not given that animations triggered another maybeUpdate()
// and thus another render pass, so to keep things running,
@@ -442,12 +407,19 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
if (!m_gl->makeCurrent(window))
return;
+ d->flushDelayedTouchEvent();
+ // Event delivery or processing has caused the window to stop rendering.
+ if (!windowData(window))
+ return;
+
QSG_RENDER_TIMING_SAMPLE(time_start);
RLDEBUG(" - polishing");
d->polishItems();
QSG_RENDER_TIMING_SAMPLE(time_polished);
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishFrame, (time_polished - time_start));
+
emit window->afterAnimating();
RLDEBUG(" - syncing");
@@ -465,24 +437,18 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
RLDEBUG(" - frameDone");
d->fireFrameSwapped();
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug("WindowsRenderLoop(t=%d): window=%p, polish=%d ms, sync=%d ms, render=%d ms, swap=%d ms",
- int(qsg_render_timer.elapsed()),
- window,
- int((time_polished - time_start)/1000000),
- int((time_synced - time_polished)/1000000),
- int((time_rendered - time_synced)/1000000),
- int((time_swapped - time_rendered)/1000000));
- }
+ qCDebug(QSG_LOG_TIME_RENDERLOOP()).nospace()
+ << "Frame rendered with 'windows' renderloop in: " << time_swapped << "ms"
+ << ", polish=" << (time_polished - time_start) / 1000000
+ << ", sync=" << (time_synced - time_polished) / 1000000
+ << ", render=" << (time_rendered - time_synced) / 1000000
+ << ", swap=" << (time_swapped - time_rendered) / 1000000
+ << " - " << window;
- Q_QUICK_SG_PROFILE2(QQuickProfiler::SceneGraphWindowsPolishFrame,
- QQuickProfiler::SceneGraphRenderLoopFrame, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, (
time_synced - time_polished,
time_rendered - time_synced,
- time_swapped - time_rendered,
- time_polished - time_start));
-#endif
+ time_swapped - time_rendered));
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 570d6b92b5..d08fce0336 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -10,12 +10,15 @@ HEADERS += \
$$PWD/coreapi/qsgnode.h \
$$PWD/coreapi/qsgnode_p.h \
$$PWD/coreapi/qsgnodeupdater_p.h \
+ $$PWD/coreapi/qsgabstractrenderer.h \
+ $$PWD/coreapi/qsgabstractrenderer_p.h \
$$PWD/coreapi/qsgrenderer_p.h \
$$PWD/coreapi/qsgrendernode_p.h \
$$PWD/coreapi/qsggeometry_p.h \
$$PWD/coreapi/qsgmaterialshader_p.h
SOURCES += \
+ $$PWD/coreapi/qsgabstractrenderer.cpp \
$$PWD/coreapi/qsgbatchrenderer.cpp \
$$PWD/coreapi/qsggeometry.cpp \
$$PWD/coreapi/qsgmaterial.cpp \
@@ -30,6 +33,8 @@ HEADERS += \
$$PWD/util/qsgareaallocator_p.h \
$$PWD/util/qsgatlastexture_p.h \
$$PWD/util/qsgdepthstencilbuffer_p.h \
+ $$PWD/util/qsgengine.h \
+ $$PWD/util/qsgengine_p.h \
$$PWD/util/qsgflatcolormaterial.h \
$$PWD/util/qsgsimplematerial.h \
$$PWD/util/qsgsimplerectnode.h \
@@ -48,6 +53,7 @@ SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
$$PWD/util/qsgatlastexture.cpp \
$$PWD/util/qsgdepthstencilbuffer.cpp \
+ $$PWD/util/qsgengine.cpp \
$$PWD/util/qsgflatcolormaterial.cpp \
$$PWD/util/qsgsimplerectnode.cpp \
$$PWD/util/qsgsimpletexturenode.cpp \
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 782beca1de..c92d79dc2a 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -43,11 +43,13 @@
#include <QtCore/QVarLengthArray>
#include <QtCore/QElapsedTimer>
+#include <QtCore/QtMath>
#include <QtGui/QOpenGLContext>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
#include <QtGui/QSurface>
+#include <QtGui/QWindow>
#include <QtGui/qpa/qplatformnativeinterface.h>
#include <private/qsgtexture_p.h>
@@ -61,26 +63,11 @@ QT_BEGIN_NAMESPACE
#endif
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
static QElapsedTimer qsg_renderer_timer;
-#endif
namespace QSGAtlasTexture
{
-static inline int qsg_powerOfTwo(int v)
-{
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- ++v;
- return v;
-}
-
static int qsg_envInt(const char *name, int defaultValue)
{
QByteArray content = qgetenv(name);
@@ -98,16 +85,24 @@ Manager::Manager()
QSurface *surface = gl->surface();
QSize surfaceSize = surface->size();
int max;
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+ gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
+
+ int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfaceSize.width() - 1))));
+ int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfaceSize.height() - 1))));
- int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qMax(512, qsg_powerOfTwo(surfaceSize.width()))));
- int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qMax(512, qsg_powerOfTwo(surfaceSize.height()))));
+ if (surface->surfaceClass() == QSurface::Window) {
+ QWindow *window = static_cast<QWindow *>(surface);
+ // Coverwindows, optimize for memory rather than speed
+ if ((window->type() & Qt::CoverWindow) == Qt::CoverWindow) {
+ w /= 2;
+ h /= 2;
+ }
+ }
m_atlas_size_limit = qsg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
m_atlas_size = QSize(w, h);
- if (qEnvironmentVariableIsSet("QSG_INFO"))
- qDebug() << "QSG: texture atlas dimensions:" << w << "x" << h;
+ qCDebug(QSG_LOG_INFO, "texture atlas dimensions: %dx%d", w, h);
}
@@ -161,7 +156,7 @@ Atlas::Atlas(const QSize &size)
static bool wrongfullyReportsBgra8888Support = false;
#endif // ANDROID
- const char *ext = (const char *) glGetString(GL_EXTENSIONS);
+ const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS);
if (!wrongfullyReportsBgra8888Support
&& (strstr(ext, "GL_EXT_bgra")
|| strstr(ext, "GL_EXT_texture_format_BGRA8888")
@@ -191,11 +186,9 @@ Atlas::~Atlas()
void Atlas::invalidate()
{
- Q_ASSERT(QOpenGLContext::currentContext());
- if (m_texture_id) {
- glDeleteTextures(1, &m_texture_id);
- m_texture_id = 0;
- }
+ if (m_texture_id && QOpenGLContext::currentContext())
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
+ m_texture_id = 0;
}
Texture *Atlas::create(const QImage &image)
@@ -215,7 +208,7 @@ int Atlas::textureId() const
{
if (!m_texture_id) {
Q_ASSERT(QOpenGLContext::currentContext());
- glGenTextures(1, &const_cast<Atlas *>(this)->m_texture_id);
+ QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<Atlas *>(this)->m_texture_id);
}
return m_texture_id;
@@ -266,11 +259,14 @@ void Atlas::upload(Texture *texture)
if (m_externalFormat == GL_RGBA)
swizzleBGRAToRGBA(&tmp);
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), r.width(), r.height(), m_externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
+ QOpenGLContext::currentContext()->functions()->glTexSubImage2D(GL_TEXTURE_2D, 0,
+ r.x(), r.y(), r.width(), r.height(),
+ m_externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
}
void Atlas::uploadBgra(Texture *texture)
{
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
const QRect &r = texture->atlasSubRect();
QImage image = texture->image();
@@ -299,48 +295,48 @@ void Atlas::uploadBgra(Texture *texture)
dst[0] = src[0];
memcpy(dst + 1, src, iw * sizeof(quint32));
dst[1 + iw] = src[iw-1];
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), iw + 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, dst);
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), iw + 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, dst);
// bottom row, padded corners
const quint32 *lastRow = src + bpl * (ih - 1);
dst[0] = lastRow[0];
memcpy(dst + 1, lastRow, iw * sizeof(quint32));
dst[1 + iw] = lastRow[iw-1];
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y() + ih + 1, iw + 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, dst);
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y() + ih + 1, iw + 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, dst);
// left column
for (int i=0; i<ih; ++i)
dst[i] = src[i * bpl];
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst);
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst);
// right column
for (int i=0; i<ih; ++i)
dst[i] = src[i * bpl + iw - 1];
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + iw + 1, r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst);
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + iw + 1, r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst);
// Inner part of the image....
- glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src);
-
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src);
}
void Atlas::bind(QSGTexture::Filtering filtering)
{
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (!m_allocated) {
m_allocated = true;
- while (glGetError() != GL_NO_ERROR) ;
+ while (funcs->glGetError() != GL_NO_ERROR) ;
- glGenTextures(1, &m_texture_id);
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ funcs->glGenTextures(1, &m_texture_id);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if !defined(QT_OPENGL_ES_2)
if (!QOpenGLContext::currentContext()->isOpenGLES())
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
- glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0);
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0);
#if 0
QImage pink(m_size.width(), m_size.height(), QImage::Format_ARGB32_Premultiplied);
@@ -357,21 +353,21 @@ void Atlas::bind(QSGTexture::Filtering filtering)
p.fillRect(0, 0, m_size.width(), m_size.height(), blueGrad);
p.end();
- glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, pink.constBits());
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, pink.constBits());
#endif
- GLenum errorCode = glGetError();
+ GLenum errorCode = funcs->glGetError();
if (errorCode == GL_OUT_OF_MEMORY) {
qDebug("QSGTextureAtlas: texture atlas allocation failed, out of memory");
- glDeleteTextures(1, &m_texture_id);
+ funcs->glDeleteTextures(1, &m_texture_id);
m_texture_id = 0;
} else if (errorCode != GL_NO_ERROR) {
qDebug("QSGTextureAtlas: texture atlas allocation failed, code=%x", errorCode);
- glDeleteTextures(1, &m_texture_id);
+ funcs->glDeleteTextures(1, &m_texture_id);
m_texture_id = 0;
}
} else {
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
}
if (m_texture_id == 0)
@@ -380,11 +376,9 @@ void Atlas::bind(QSGTexture::Filtering filtering)
// Upload all pending images..
for (int i=0; i<m_pending_uploads.size(); ++i) {
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
qsg_renderer_timer.start();
-#endif
if (m_externalFormat == GL_BGRA &&
!m_use_bgra_fallback) {
@@ -393,26 +387,21 @@ void Atlas::bind(QSGTexture::Filtering filtering)
upload(m_pending_uploads.at(i));
}
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug(" - AtlasTexture(%dx%d), uploaded in %d ms",
- m_pending_uploads.at(i)->image().width(),
- m_pending_uploads.at(i)->image().height(),
- (int) (qsg_renderer_timer.elapsed()));
- }
+ qCDebug(QSG_LOG_TIME_TEXTURE).nospace() << "atlastexture uploaded in: " << qsg_renderer_timer.elapsed()
+ << "ms (" << m_pending_uploads.at(i)->image().width() << "x"
+ << m_pending_uploads.at(i)->image().height() << ")";
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphTexturePrepare, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTexturePrepare, (
0, // bind (not relevant)
0, // convert (not relevant)
0, // swizzle (not relevant)
qsg_renderer_timer.nsecsElapsed(), // (upload all of the above)
0)); // mipmap (not used ever...)
-#endif
}
GLenum f = filtering == QSGTexture::Nearest ? GL_NEAREST : GL_LINEAR;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, f);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, f);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, f);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, f);
m_pending_uploads.clear();
}
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
new file mode 100644
index 0000000000..127f624d8b
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgengine_p.h"
+
+#include <QtQuick/qsgtexture.h>
+#include <private/qsgcontext_p.h>
+#include <private/qsgrenderer_p.h>
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \class QSGEngine
+ \brief The QSGEngine class allows low level rendering of a scene graph.
+ \inmodule QtQuick
+ \since 5.4
+
+ A QSGEngine can be used to render a tree of QSGNode directly on a QWindow
+ or QOpenGLFramebufferObject without any integration with QML, QQuickWindow
+ or QQuickItem and the convenience that they provide.
+
+ This means that you must handle event propagation, animation timing,
+ and node lifetime yourself.
+
+ \note This class is for very low level access to an independent scene graph.
+ Most of the time you will instead want to subclass QQuickItem and insert
+ your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode().
+
+ \sa QSGAbstractRenderer
+ */
+
+/*!
+ \enum QSGEngine::CreateTextureOption
+
+ The CreateTextureOption enums are used to customize how a texture is wrapped.
+
+ \value TextureHasAlphaChannel The texture has an alpha channel and should
+ be drawn using blending.
+
+ \value TextureOwnsGLTexture The texture object owns the texture id and
+ will delete the GL texture when the texture object is deleted.
+
+ \value TextureCanUseAtlas The image can be uploaded into a texture atlas.
+ */
+
+QSGEnginePrivate::QSGEnginePrivate()
+ : sgContext(QSGContext::createDefaultContext())
+ , sgRenderContext(new QSGRenderContext(sgContext.data()))
+{
+}
+
+/*!
+ Constructs a new QSGEngine with its \a parent
+ */
+QSGEngine::QSGEngine(QObject *parent)
+ : QObject(*(new QSGEnginePrivate), parent)
+{
+}
+
+/*!
+ Destroys the engine
+ */
+QSGEngine::~QSGEngine()
+{
+}
+
+/*!
+ Initialize the engine with \a context.
+
+ \warning You have to make sure that you call
+ QOpenGLContext::makeCurrent() on \a context before calling this.
+ */
+void QSGEngine::initialize(QOpenGLContext *context)
+{
+ Q_D(QSGEngine);
+ if (QOpenGLContext::currentContext() != context) {
+ qWarning("WARNING: The context must be current before calling QSGEngine::initialize.");
+ return;
+ }
+
+ if (!d->sgRenderContext->isValid()) {
+ d->sgRenderContext->setAttachToGLContext(false);
+ d->sgRenderContext->initialize(context);
+ connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
+ }
+}
+
+/*!
+ Invalidate the engine releasing its resources
+
+ You will have to call initialize() and createRenderer() if you
+ want to use it again.
+ */
+void QSGEngine::invalidate()
+{
+ Q_D(QSGEngine);
+ d->sgRenderContext->invalidate();
+}
+
+/*!
+ Returns a renderer that can be used to render a QSGNode tree
+
+ You call initialize() first with the QOpenGLContext that you
+ want to use with this renderer. This will return a null
+ renderer otherwise.
+ */
+QSGAbstractRenderer *QSGEngine::createRenderer() const
+{
+ Q_D(const QSGEngine);
+ if (!d->sgRenderContext->isValid())
+ return 0;
+
+ QSGRenderer *renderer = d->sgRenderContext->createRenderer();
+ renderer->setCustomRenderMode(qgetenv("QSG_VISUALIZE"));
+ return renderer;
+}
+
+/*!
+ Creates a texture using the data of \a image
+
+ Valid \a options are TextureCanUseAtlas
+
+ The caller takes ownership of the texture and the
+ texture should only be used with this engine.
+
+ \sa createTextureFromId(), QSGSimpleTextureNode::setOwnsTexture(), QQuickWindow::createTextureFromImage()
+ */
+QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
+{
+ Q_D(const QSGEngine);
+ if (!d->sgRenderContext->isValid())
+ return 0;
+
+ if (options & TextureCanUseAtlas)
+ return d->sgRenderContext->createTexture(image);
+ else
+ return d->sgRenderContext->createTextureNoAtlas(image);
+}
+
+/*!
+ Creates a texture object that wraps the GL texture \a id uploaded with \a size
+
+ Valid \a options are TextureHasAlphaChannel and TextureOwnsGLTexture
+
+ The caller takes ownership of the texture object and the
+ texture should only be used with this engine.
+
+ \sa createTextureFromImage(), QSGSimpleTextureNode::setOwnsTexture(), QQuickWindow::createTextureFromId()
+ */
+QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
+{
+ Q_D(const QSGEngine);
+ if (d->sgRenderContext->isValid()) {
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+ }
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
new file mode 100644
index 0000000000..7aae882a70
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGENGINE_H
+#define QSGENGINE_H
+
+#include <QtCore/QObject>
+#include <QtQuick/qtquickglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+class QSGAbstractRenderer;
+class QSGEnginePrivate;
+class QSGTexture;
+
+class Q_QUICK_EXPORT QSGEngine : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGEngine)
+public:
+ enum CreateTextureOption {
+ TextureHasAlphaChannel = 0x0001,
+ TextureOwnsGLTexture = 0x0004,
+ TextureCanUseAtlas = 0x0008
+ };
+ Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption)
+
+ QSGEngine(QObject *parent = 0);
+ ~QSGEngine();
+
+ void initialize(QOpenGLContext *context);
+ void invalidate();
+
+ QSGAbstractRenderer *createRenderer() const;
+ QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption(0)) const;
+ QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGENGINE_H
diff --git a/src/quick/scenegraph/util/qsgengine_p.h b/src/quick/scenegraph/util/qsgengine_p.h
new file mode 100644
index 0000000000..a7e1599fd5
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgengine_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGENGINE_P_H
+#define QSGENGINE_P_H
+
+#include "qsgengine.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGContext;
+class QSGRenderContext;
+
+class QSGEnginePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSGEngine)
+
+public:
+ QSGEnginePrivate();
+
+ QScopedPointer<QSGContext> sgContext;
+ QScopedPointer<QSGRenderContext> sgRenderContext;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGENGINE_P_H
diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp
index 8ccb9d2ffb..c9bb5daed1 100644
--- a/src/quick/scenegraph/util/qsgpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgpainternode.cpp
@@ -53,19 +53,7 @@
QT_BEGIN_NAMESPACE
-#define QT_MINIMUM_DYNAMIC_FBO_SIZE 64
-
-static inline int qt_next_power_of_two(int v)
-{
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- ++v;
- return v;
-}
+#define QT_MINIMUM_DYNAMIC_FBO_SIZE 64U
QSGPainterTexture::QSGPainterTexture()
: QSGPlainTexture()
@@ -322,8 +310,8 @@ void QSGPainterNode::updateFBOSize()
int fboWidth;
int fboHeight;
if (m_fastFBOResizing) {
- fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.width()));
- fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.height()));
+ fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_size.width() - 1));
+ fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_size.height() - 1));
} else {
QSize minimumFBOSize = m_context->sceneGraphContext()->minimumFBOSize();
fboWidth = qMax(minimumFBOSize.width(), m_size.width());
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 4512577f23..bbf115fa2a 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -52,10 +52,12 @@ public:
: QSGGeometryNodePrivate()
, m_texCoordMode(QSGSimpleTextureNode::NoTransform)
, isAtlasTexture(false)
+ , ownsTexture(false)
{}
QSGSimpleTextureNode::TextureCoordinatesTransformMode m_texCoordMode;
uint isAtlasTexture : 1;
+ uint ownsTexture : 1;
};
static void qsgsimpletexturenode_update(QSGGeometry *g,
@@ -113,6 +115,16 @@ QSGSimpleTextureNode::QSGSimpleTextureNode()
}
/*!
+ Destroys the texture node
+ */
+QSGSimpleTextureNode::~QSGSimpleTextureNode()
+{
+ Q_D(QSGSimpleTextureNode);
+ if (d->ownsTexture)
+ delete m_material.texture();
+}
+
+/*!
Sets the filtering to be used for this texture node to \a filtering.
For smooth scaling, use QSGTexture::Linear; for normal scaling, use
@@ -170,6 +182,10 @@ QRectF QSGSimpleTextureNode::rect() const
/*!
Sets the texture of this texture node to \a texture.
+ Use setOwnsTexture() to set whether the node should take
+ ownership of the texture. By default, the node does not
+ take ownership.
+
\warning A texture node must have a texture before being added
to the scenegraph to be rendered.
*/
@@ -246,4 +262,26 @@ QSGSimpleTextureNode::TextureCoordinatesTransformMode QSGSimpleTextureNode::text
return d->m_texCoordMode;
}
+/*!
+ Sets whether the node takes ownership of the texture to \a owns.
+
+ By default, the node does not take ownership of the texture.
+
+ \sa setTexture()
+ */
+void QSGSimpleTextureNode::setOwnsTexture(bool owns)
+{
+ Q_D(QSGSimpleTextureNode);
+ d->ownsTexture = owns;
+}
+
+/*!
+ Returns \c true if the node takes ownership of the texture; otherwise returns \c false.
+ */
+bool QSGSimpleTextureNode::ownsTexture() const
+{
+ Q_D(const QSGSimpleTextureNode);
+ return d->ownsTexture;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.h b/src/quick/scenegraph/util/qsgsimpletexturenode.h
index 0c0b58442c..d971f00326 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.h
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.h
@@ -54,6 +54,7 @@ class Q_QUICK_EXPORT QSGSimpleTextureNode : public QSGGeometryNode
{
public:
QSGSimpleTextureNode();
+ ~QSGSimpleTextureNode();
void setRect(const QRectF &rect);
inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); }
@@ -75,6 +76,9 @@ public:
void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode);
TextureCoordinatesTransformMode textureCoordinatesTransform() const;
+ void setOwnsTexture(bool owns);
+ bool ownsTexture() const;
+
private:
QSGGeometry m_geometry;
QSGOpaqueTextureMaterial m_opaque_material;
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index cd0b64fe49..02dd2efae3 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -47,6 +47,10 @@
#include <private/qqmlglobal_p.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+
+#include <private/qsgmaterialshader_p.h>
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__)
#define CAN_BACKTRACE_EXECINFO
@@ -65,14 +69,12 @@
#include <QHash>
#endif
+static QElapsedTimer qsg_renderer_timer;
+
#ifndef QT_NO_DEBUG
static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
#endif
-#ifndef QSG_NO_RENDER_TIMING
-static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
-static QElapsedTimer qsg_renderer_timer;
-#endif
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
@@ -273,6 +275,23 @@ static void qt_debug_remove_texture(QSGTexture* texture)
\internal
*/
+#ifndef QT_NO_DEBUG
+Q_GLOBAL_STATIC(QSet<QSGTexture *>, qsg_valid_texture_set)
+Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
+
+bool qsg_safeguard_texture(QSGTexture *texture)
+{
+ QMutexLocker locker(qsg_valid_texture_mutex());
+ if (!qsg_valid_texture_set()->contains(texture)) {
+ qWarning() << "Invalid texture accessed:" << (void *) texture;
+ qsg_set_material_failure();
+ QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0);
+ return false;
+ }
+ return true;
+}
+#endif
+
/*!
Constructs the QSGTexture base class.
*/
@@ -282,6 +301,9 @@ QSGTexture::QSGTexture()
#ifndef QT_NO_DEBUG
if (qsg_leak_check)
qt_debug_add_texture(this);
+
+ QMutexLocker locker(qsg_valid_texture_mutex());
+ qsg_valid_texture_set()->insert(this);
#endif
}
@@ -293,6 +315,9 @@ QSGTexture::~QSGTexture()
#ifndef QT_NO_DEBUG
if (qsg_leak_check)
qt_debug_remove_texture(this);
+
+ QMutexLocker locker(qsg_valid_texture_mutex());
+ qsg_valid_texture_set()->remove(this);
#endif
}
@@ -496,6 +521,7 @@ QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
void QSGTexture::updateBindOptions(bool force)
{
Q_D(QSGTexture);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
force |= isAtlasTexture();
if (force || d->filteringChanged) {
@@ -509,8 +535,8 @@ void QSGTexture::updateBindOptions(bool force)
else if (d->mipmapMode == Linear)
minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR;
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
d->filteringChanged = false;
}
@@ -524,8 +550,8 @@ void QSGTexture::updateBindOptions(bool force)
qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
}
#endif
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
d->wrapChanged = false;
}
}
@@ -546,7 +572,7 @@ QSGPlainTexture::QSGPlainTexture()
QSGPlainTexture::~QSGPlainTexture()
{
if (m_texture_id && m_owns_texture)
- glDeleteTextures(1, &m_texture_id);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
}
void qsg_swizzleBGRAToRGBA(QImage *image)
@@ -579,7 +605,7 @@ int QSGPlainTexture::textureId() const
return 0;
} else if (m_texture_id == 0){
// Generate a texture id for use later and return it.
- glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id);
+ QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id);
return m_texture_id;
}
}
@@ -589,7 +615,7 @@ int QSGPlainTexture::textureId() const
void QSGPlainTexture::setTextureId(int id)
{
if (m_texture_id && m_owns_texture)
- glDeleteTextures(1, &m_texture_id);
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
m_texture_id = id;
m_dirty_texture = false;
@@ -600,11 +626,12 @@ void QSGPlainTexture::setTextureId(int id)
void QSGPlainTexture::bind()
{
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QOpenGLFunctions *funcs = context->functions();
if (!m_dirty_texture) {
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
if (mipmapFiltering() != QSGTexture::None && !m_mipmaps_generated) {
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ funcs->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
updateBindOptions(m_dirty_bind_options);
@@ -614,25 +641,19 @@ void QSGPlainTexture::bind()
m_dirty_texture = false;
-#ifndef QSG_NO_RENDER_TIMING
- bool profileFrames = qsg_render_timing || QQuickProfiler::enabled;
+ bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled() || QQuickProfiler::enabled;
if (profileFrames)
qsg_renderer_timer.start();
-#endif
if (m_image.isNull()) {
if (m_texture_id && m_owns_texture) {
- glDeleteTextures(1, &m_texture_id);
-#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing) {
- qDebug(" - texture deleted in %dms (size: %dx%d)",
- (int) qsg_renderer_timer.elapsed(),
- m_texture_size.width(),
- m_texture_size.height());
- }
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphTextureDeletion, (
+ funcs->glDeleteTextures(1, &m_texture_id);
+ qCDebug(QSG_LOG_TIME_TEXTURE, "plain texture deleted in %dms - %dx%d",
+ (int) qsg_renderer_timer.elapsed(),
+ m_texture_size.width(),
+ m_texture_size.height());
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTextureDeletion, (
qsg_renderer_timer.nsecsElapsed()));
-#endif
}
m_texture_id = 0;
m_texture_size = QSize();
@@ -642,14 +663,12 @@ void QSGPlainTexture::bind()
}
if (m_texture_id == 0)
- glGenTextures(1, &m_texture_id);
- glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ funcs->glGenTextures(1, &m_texture_id);
+ funcs->glBindTexture(GL_TEXTURE_2D, m_texture_id);
-#ifndef QSG_NO_RENDER_TIMING
qint64 bindTime = 0;
if (profileFrames)
bindTime = qsg_renderer_timer.nsecsElapsed();
-#endif
// ### TODO: check for out-of-memory situations...
int w = m_image.width();
@@ -661,11 +680,9 @@ void QSGPlainTexture::bind()
if (tmp.width() * 4 != tmp.bytesPerLine())
tmp = tmp.copy();
-#ifndef QSG_NO_RENDER_TIMING
qint64 convertTime = 0;
if (profileFrames)
convertTime = qsg_renderer_timer.nsecsElapsed();
-#endif
updateBindOptions(m_dirty_bind_options);
@@ -683,7 +700,6 @@ void QSGPlainTexture::bind()
static bool wrongfullyReportsBgra8888Support = false;
#endif
- QOpenGLContext *context = QOpenGLContext::currentContext();
if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) {
externalFormat = GL_BGRA;
#ifdef QT_OPENGL_ES
@@ -706,53 +722,44 @@ void QSGPlainTexture::bind()
qsg_swizzleBGRAToRGBA(&tmp);
}
-#ifndef QSG_NO_RENDER_TIMING
qint64 swizzleTime = 0;
if (profileFrames)
swizzleTime = qsg_renderer_timer.nsecsElapsed();
-#endif
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
-#ifndef QSG_NO_RENDER_TIMING
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
+
qint64 uploadTime = 0;
if (profileFrames)
uploadTime = qsg_renderer_timer.nsecsElapsed();
-#endif
-
if (mipmapFiltering() != QSGTexture::None) {
- context->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ funcs->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
-#ifndef QSG_NO_RENDER_TIMING
qint64 mipmapTime = 0;
- if (qsg_render_timing) {
+ if (profileFrames) {
mipmapTime = qsg_renderer_timer.nsecsElapsed();
-
- qDebug(" - plaintexture(%dx%d) bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d, total=%d",
- m_texture_size.width(), m_texture_size.height(),
- int(bindTime/1000000),
- int((convertTime - bindTime)/1000000),
- int((swizzleTime - convertTime)/1000000),
- externalFormat == GL_BGRA ? "BGRA" : "RGBA",
- internalFormat == GL_BGRA ? "BGRA" : "RGBA",
- int((uploadTime - swizzleTime)/1000000),
- int((mipmapTime - uploadTime)/1000000),
- (int) qsg_renderer_timer.elapsed());
-
+ qCDebug(QSG_LOG_TIME_TEXTURE,
+ "plain texture uploaded in: %dms (%dx%d), bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d",
+ int(mipmapTime / 1000000),
+ m_texture_size.width(), m_texture_size.height(),
+ int(bindTime / 1000000),
+ int((convertTime - bindTime)/1000000),
+ int((swizzleTime - convertTime)/1000000),
+ (externalFormat == GL_BGRA ? "BGRA" : "RGBA"),
+ (internalFormat == GL_BGRA ? "BGRA" : "RGBA"),
+ int((uploadTime - swizzleTime)/1000000),
+ int((mipmapTime - uploadTime)/1000000));
}
- Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphTexturePrepare, (
+ Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTexturePrepare, (
bindTime,
convertTime - bindTime,
swizzleTime - convertTime,
uploadTime - swizzleTime,
qsg_renderer_timer.nsecsElapsed() - uploadTime));
-#endif
-
-
m_texture_size = QSize(w, h);
m_texture_rect = QRectF(0, 0, 1, 1);
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index bc81569f84..8b726e9eb8 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -113,6 +113,8 @@ protected:
uint m_retain_image: 1;
};
+Q_QUICK_PRIVATE_EXPORT bool qsg_safeguard_texture(QSGTexture *);
+
QT_END_NAMESPACE
#endif // QSGTEXTURE_P_H
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index afa535d322..87fcb6a186 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgtexturematerial_p.h"
+#include "qsgtexture_p.h"
#include <QtGui/qopenglshaderprogram.h>
#include <QtGui/qopenglfunctions.h>
@@ -80,6 +81,11 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
QSGTexture *t = tx->texture();
+#ifndef QT_NO_DEBUG
+ if (!qsg_safeguard_texture(t))
+ return;
+#endif
+
t->setFiltering(tx->filtering());
t->setHorizontalWrapMode(tx->horizontalWrapMode());
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 9f81f28b7a..9639129583 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -360,7 +360,7 @@ void QQuickXAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->dx = m_value;
@@ -377,7 +377,7 @@ void QQuickYAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->dy = m_value;
@@ -435,7 +435,7 @@ void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller || !m_opacityNode)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_opacityNode->setOpacity(m_value);
@@ -451,7 +451,7 @@ void QQuickScaleAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
m_helper->scale = m_value;
@@ -471,7 +471,7 @@ void QQuickRotationAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
float t = m_easing.valueForProgress(time / (qreal) m_duration);
switch (m_direction) {
@@ -551,7 +551,7 @@ void QQuickUniformAnimatorJob::updateCurrentTime(int time)
{
if (!m_controller)
return;
- Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ Q_ASSERT(!m_controller->m_window->openglContext() || m_controller->m_window->openglContext()->thread() == QThread::currentThread());
if (!m_node || m_uniformIndex == -1 || m_uniformType == -1)
return;
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index fb7c900252..159d855ef0 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -50,34 +50,21 @@
QT_BEGIN_NAMESPACE
-class QQuickApplicationPrivate : public QQmlApplicationPrivate
-{
- Q_DECLARE_PUBLIC(QQuickApplication)
-public:
- QQuickApplicationPrivate()
- : isActive(QGuiApplication::focusWindow() != 0),
- direction(QGuiApplication::layoutDirection())
- {
- }
-
-private:
- bool isActive;
- Qt::LayoutDirection direction;
-};
-
/*
This object and its properties are documented as part of the Qt object,
in qqmlengine.cpp
*/
QQuickApplication::QQuickApplication(QObject *parent)
- : QQmlApplication(*new QQuickApplicationPrivate(), parent)
+ : QQmlApplication(parent)
{
if (qApp) {
- qApp->installEventFilter(this);
-
+ connect(qApp, SIGNAL(layoutDirectionChanged(Qt::LayoutDirection)),
+ this, SIGNAL(layoutDirectionChanged()));
connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
this, SIGNAL(stateChanged(Qt::ApplicationState)));
+ connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+ this, SIGNAL(activeChanged()));
}
}
@@ -87,14 +74,12 @@ QQuickApplication::~QQuickApplication()
bool QQuickApplication::active() const
{
- Q_D(const QQuickApplication);
- return d->isActive;
+ return QGuiApplication::applicationState() == Qt::ApplicationActive;
}
Qt::LayoutDirection QQuickApplication::layoutDirection() const
{
- Q_D(const QQuickApplication);
- return d->direction;
+ return QGuiApplication::layoutDirection();
}
bool QQuickApplication::supportsMultipleWindows() const
@@ -107,30 +92,4 @@ Qt::ApplicationState QQuickApplication::state() const
return QGuiApplication::applicationState();
}
-bool QQuickApplication::eventFilter(QObject *, QEvent *event)
-{
- Q_D(QQuickApplication);
- if ((event->type() == QEvent::ApplicationActivate) ||
- (event->type() == QEvent::ApplicationDeactivate) ||
- (event->type() == QEvent::ApplicationStateChange)) {
- bool wasActive = d->isActive;
- if (event->type() == QEvent::ApplicationStateChange) {
- QApplicationStateChangeEvent * e= static_cast<QApplicationStateChangeEvent*>(event);
- d->isActive = e->applicationState() == Qt::ApplicationActive;
- } else {
- d->isActive = (event->type() == QEvent::ApplicationActivate);
- }
- if (d->isActive != wasActive) {
- emit activeChanged();
- }
- } else if (event->type() == QEvent::ApplicationLayoutDirectionChange) {
- Qt::LayoutDirection newDirection = QGuiApplication::layoutDirection();
- if (d->direction != newDirection) {
- d->direction = newDirection;
- emit layoutDirectionChanged();
- }
- }
- return false;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h
index 780fb1ffa6..996ed67c8f 100644
--- a/src/quick/util/qquickapplication_p.h
+++ b/src/quick/util/qquickapplication_p.h
@@ -50,7 +50,6 @@
QT_BEGIN_NAMESPACE
-class QQuickApplicationPrivate;
class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication
{
Q_OBJECT
@@ -73,10 +72,7 @@ Q_SIGNALS:
void stateChanged(Qt::ApplicationState state);
private:
- bool eventFilter(QObject *, QEvent *event);
-
Q_DISABLE_COPY(QQuickApplication)
- Q_DECLARE_PRIVATE(QQuickApplication)
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickfontmetrics.cpp b/src/quick/util/qquickfontmetrics.cpp
new file mode 100644
index 0000000000..47e4fc1c7e
--- /dev/null
+++ b/src/quick/util/qquickfontmetrics.cpp
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfontmetrics_p.h"
+
+#include <QFont>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FontMetrics
+ \instantiates QQuickFontMetrics
+ \inqmlmodule QtQuick
+ \ingroup qtquick-text-utility
+ \brief Provides metrics for a given font
+
+ FontMetrics calculates the size of characters and strings for a given font.
+
+ It provides a subset of the C++ \l QFontMetricsF API, with the added
+ ability to change the font that is used for calculations via the \l font
+ property.
+
+ \code
+ FontMetrics {
+ id: fontMetrics
+ font.family: "Arial"
+ }
+
+ Rectangle {
+ width: fontMetrics.height * 4
+ height: fontMetrics.height * 2
+ }
+ \endcode
+
+ \sa QFontMetricsF, TextMetrics
+*/
+QQuickFontMetrics::QQuickFontMetrics(QObject *parent) :
+ QObject(parent),
+ m_metrics(m_font)
+{
+}
+
+QQuickFontMetrics::~QQuickFontMetrics()
+{
+}
+
+/*!
+ \qmlproperty font QtQuick::FontMetrics::font
+
+ This property holds the font used for the metrics calculations.
+*/
+QFont QQuickFontMetrics::font() const
+{
+ return m_font;
+}
+
+void QQuickFontMetrics::setFont(const QFont &font)
+{
+ if (m_font != font) {
+ m_font = font;
+ m_metrics = QFontMetricsF(m_font);
+ emit fontChanged(m_font);
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::ascent
+
+ This property holds the ascent of the font.
+
+ \sa {QFontMetricsF::ascent()}, descent, height
+*/
+qreal QQuickFontMetrics::ascent() const
+{
+ return m_metrics.ascent();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::descent
+
+ This property holds the descent of the font.
+
+ \sa {QFontMetricsF::descent()}, ascent, height
+*/
+qreal QQuickFontMetrics::descent() const
+{
+ return m_metrics.descent();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::height
+
+ This property holds the height of the font.
+
+ \sa {QFontMetricsF::height()}
+*/
+qreal QQuickFontMetrics::height() const
+{
+ return m_metrics.height();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::leading
+
+ This property holds the leading of the font.
+
+ \sa {QFontMetricsF::leading()}
+*/
+qreal QQuickFontMetrics::leading() const
+{
+ return m_metrics.leading();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::lineSpacing
+
+ This property holds the distance from one base line to the next.
+
+ \sa {QFontMetricsF::lineSpacing()}
+*/
+qreal QQuickFontMetrics::lineSpacing() const
+{
+ return m_metrics.lineSpacing();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::minimumLeftBearing
+
+ This property holds the minimum left bearing of the font.
+
+ \sa {QFontMetricsF::minLeftBearing()}
+*/
+qreal QQuickFontMetrics::minimumLeftBearing() const
+{
+ return m_metrics.minLeftBearing();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::minimumRightBearing
+
+ This property holds the minimum right bearing of the font.
+
+ \sa {QFontMetricsF::minRightBearing()}
+*/
+qreal QQuickFontMetrics::minimumRightBearing() const
+{
+ return m_metrics.minRightBearing();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::maximumCharacterWidth
+
+ This property holds the width of the widest character in the font.
+
+ \sa {QFontMetricsF::maxWidth()}
+*/
+qreal QQuickFontMetrics::maximumCharacterWidth() const
+{
+ return m_metrics.maxWidth();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::xHeight
+
+ This property holds the 'x' height of the font.
+
+ \sa {QFontMetricsF::xHeight()}
+*/
+qreal QQuickFontMetrics::xHeight() const
+{
+ return m_metrics.xHeight();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::averageCharacterWidth
+
+ This property holds the average width of glyphs in the font.
+
+ \sa {QFontMetricsF::averageCharWidth()}
+*/
+qreal QQuickFontMetrics::averageCharacterWidth() const
+{
+ return m_metrics.averageCharWidth();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::underlinePosition
+
+ This property holds the distance from the base line to where an underscore
+ should be drawn.
+
+ \sa {QFontMetricsF::underlinePos()}, overlinePosition, strikeOutPosition
+*/
+qreal QQuickFontMetrics::underlinePosition() const
+{
+ return m_metrics.underlinePos();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::overlinePosition
+
+ This property holds the distance from the base line to where an overline
+ should be drawn.
+
+ \sa {QFontMetricsF::overlinePos()}, underlinePosition, strikeOutPosition
+*/
+qreal QQuickFontMetrics::overlinePosition() const
+{
+ return m_metrics.overlinePos();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::strikeOutPosition
+
+ This property holds the distance from the base line to where the strikeout
+ line should be drawn.
+
+ \sa {QFontMetricsF::strikeOutPos()}, overlinePosition, underlinePosition
+*/
+qreal QQuickFontMetrics::strikeOutPosition() const
+{
+ return m_metrics.strikeOutPos();
+}
+
+/*!
+ \qmlproperty real QtQuick::FontMetrics::lineWidth
+
+ This property holds the width of the underline and strikeout lines,
+ adjusted for the point size of the font.
+
+ \sa {QFontMetricsF::lineWidth()}
+*/
+qreal QQuickFontMetrics::lineWidth() const
+{
+ return m_metrics.lineWidth();
+}
+
+/*!
+ \qmlmethod qreal QtQuick::FontMetrics::advanceWidth(string text)
+
+ This method returns the advance in pixels of the characters in \a text.
+ This is the distance from the position of the string to where the next
+ string should be drawn.
+
+ This method is offered as an imperative alternative to the
+ \l {QQuickTextMetrics::advanceWidth}{advanceWidth} property of
+ \l {QQuickTextMetrics::advanceWidth}{TextMetrics}.
+
+ \sa {QFontMetricsF::width()}, height()
+*/
+qreal QQuickFontMetrics::advanceWidth(const QString &text) const
+{
+ return m_metrics.width(text);
+}
+
+/*!
+ \qmlmethod rect QtQuick::FontMetrics::boundingRect(string text)
+
+ This method returns the bounding rectangle of the characters in the string
+ specified by \a text.
+
+ This method is offered as an imperative alternative to the
+ \l {QQuickTextMetrics::boundingRect}{boundingRect} property of
+ \l {QQuickTextMetrics::boundingRect}{TextMetrics}.
+
+ \sa {QFontMetricsF::boundingRect()}, tightBoundingRect()
+*/
+QRectF QQuickFontMetrics::boundingRect(const QString &text) const
+{
+ return m_metrics.boundingRect(text);
+}
+
+/*!
+ \qmlmethod rect QtQuick::FontMetrics::tightBoundingRect(string text)
+
+ This method returns a tight bounding rectangle around the characters in the
+ string specified by \a text.
+
+ This method is offered as an imperative alternative to the
+ \l {QQuickTextMetrics::tightBoundingRect}{tightBoundingRect} property of
+ \l {QQuickTextMetrics::tightBoundingRect}{TextMetrics}.
+
+ \sa {QFontMetricsF::tightBoundingRect()}, boundingRect()
+*/
+QRectF QQuickFontMetrics::tightBoundingRect(const QString &text) const
+{
+ return m_metrics.tightBoundingRect(text);
+}
+
+/*!
+ \qmlmethod string QtQuick::FontMetrics::elidedText(string text, enum mode,
+ qreal width, int flags)
+
+ This method returns a returns an elided version of the string (i.e., a
+ string with "..." in it) if the string \a text is wider than \a width.
+ Otherwise, returns the original string.
+
+ The \a flags argument is optional and currently only supports
+ \l {Qt::TextShowMnemonic}.
+
+ This method is offered as an imperative alternative to the
+ \l {QQuickTextMetrics::elidedText}{elidedText} property of
+ \l {QQuickTextMetrics::elidedText}{TextMetrics}.
+
+ \sa {QFontMetricsF::elidedText()}
+*/
+QString QQuickFontMetrics::elidedText(const QString &text, Qt::TextElideMode mode, qreal width, int flags) const
+{
+ return m_metrics.elidedText(text, mode, width, flags);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qquickfontmetrics_p.h b/src/quick/util/qquickfontmetrics_p.h
new file mode 100644
index 0000000000..4017fd4061
--- /dev/null
+++ b/src/quick/util/qquickfontmetrics_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFONTMETRICS_H
+#define QQUICKFONTMETRICS_H
+
+#include <qqml.h>
+
+#include <QtGui/QFontMetricsF>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QFont;
+
+class Q_AUTOTEST_EXPORT QQuickFontMetrics : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(qreal ascent READ ascent NOTIFY fontChanged)
+ Q_PROPERTY(qreal descent READ descent NOTIFY fontChanged)
+ Q_PROPERTY(qreal height READ height NOTIFY fontChanged)
+ Q_PROPERTY(qreal leading READ leading NOTIFY fontChanged)
+ Q_PROPERTY(qreal lineSpacing READ lineSpacing NOTIFY fontChanged)
+ Q_PROPERTY(qreal minimumLeftBearing READ minimumLeftBearing NOTIFY fontChanged)
+ Q_PROPERTY(qreal minimumRightBearing READ minimumRightBearing NOTIFY fontChanged)
+ Q_PROPERTY(qreal maximumCharacterWidth READ maximumCharacterWidth NOTIFY fontChanged)
+ Q_PROPERTY(qreal xHeight READ xHeight NOTIFY fontChanged)
+ Q_PROPERTY(qreal averageCharacterWidth READ averageCharacterWidth NOTIFY fontChanged)
+ Q_PROPERTY(qreal underlinePosition READ underlinePosition NOTIFY fontChanged)
+ Q_PROPERTY(qreal overlinePosition READ overlinePosition NOTIFY fontChanged)
+ Q_PROPERTY(qreal strikeOutPosition READ strikeOutPosition NOTIFY fontChanged)
+ Q_PROPERTY(qreal lineWidth READ lineWidth NOTIFY fontChanged)
+public:
+ explicit QQuickFontMetrics(QObject *parent = 0);
+ ~QQuickFontMetrics();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ qreal ascent() const;
+ qreal descent() const;
+ qreal height() const;
+ qreal leading() const;
+ qreal lineSpacing() const;
+ qreal minimumLeftBearing() const;
+ qreal minimumRightBearing() const;
+ qreal maximumCharacterWidth() const;
+
+ qreal xHeight() const;
+ qreal averageCharacterWidth() const;
+
+ qreal underlinePosition() const;
+ qreal overlinePosition() const;
+ qreal strikeOutPosition() const;
+ qreal lineWidth() const;
+
+ Q_INVOKABLE qreal advanceWidth(const QString &text) const;
+ Q_INVOKABLE QRectF boundingRect(const QString &text) const;
+ Q_INVOKABLE QRectF tightBoundingRect(const QString &text) const;
+ Q_INVOKABLE QString elidedText(const QString &text, Qt::TextElideMode mode, qreal width, int flags = 0) const;
+
+Q_SIGNALS:
+ void fontChanged(const QFont &font);
+
+private:
+ QFont m_font;
+ QFontMetricsF m_metrics;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFontMetrics)
+
+#endif // QQUICKFONTMETRICS_H
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 4428452aa0..b92613a718 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -286,17 +286,17 @@ public:
QV4::ScopedString s(scope);
- QV4::ScopedValue vbold(scope, obj->get((s = v4->newString(QStringLiteral("bold")))));
- QV4::ScopedValue vcap(scope, obj->get((s = v4->newString(QStringLiteral("capitalization")))));
- QV4::ScopedValue vfam(scope, obj->get((s = v4->newString(QStringLiteral("family")))));
- QV4::ScopedValue vital(scope, obj->get((s = v4->newString(QStringLiteral("italic")))));
- QV4::ScopedValue vlspac(scope, obj->get((s = v4->newString(QStringLiteral("letterSpacing")))));
- QV4::ScopedValue vpixsz(scope, obj->get((s = v4->newString(QStringLiteral("pixelSize")))));
- QV4::ScopedValue vpntsz(scope, obj->get((s = v4->newString(QStringLiteral("pointSize")))));
- QV4::ScopedValue vstrk(scope, obj->get((s = v4->newString(QStringLiteral("strikeout")))));
- QV4::ScopedValue vundl(scope, obj->get((s = v4->newString(QStringLiteral("underline")))));
- QV4::ScopedValue vweight(scope, obj->get((s = v4->newString(QStringLiteral("weight")))));
- QV4::ScopedValue vwspac(scope, obj->get((s = v4->newString(QStringLiteral("wordSpacing")))));
+ QV4::ScopedValue vbold(scope, obj->get((s = v4->newString(QStringLiteral("bold"))).getPointer()));
+ QV4::ScopedValue vcap(scope, obj->get((s = v4->newString(QStringLiteral("capitalization"))).getPointer()));
+ QV4::ScopedValue vfam(scope, obj->get((s = v4->newString(QStringLiteral("family"))).getPointer()));
+ QV4::ScopedValue vital(scope, obj->get((s = v4->newString(QStringLiteral("italic"))).getPointer()));
+ QV4::ScopedValue vlspac(scope, obj->get((s = v4->newString(QStringLiteral("letterSpacing"))).getPointer()));
+ QV4::ScopedValue vpixsz(scope, obj->get((s = v4->newString(QStringLiteral("pixelSize"))).getPointer()));
+ QV4::ScopedValue vpntsz(scope, obj->get((s = v4->newString(QStringLiteral("pointSize"))).getPointer()));
+ QV4::ScopedValue vstrk(scope, obj->get((s = v4->newString(QStringLiteral("strikeout"))).getPointer()));
+ QV4::ScopedValue vundl(scope, obj->get((s = v4->newString(QStringLiteral("underline"))).getPointer()));
+ QV4::ScopedValue vweight(scope, obj->get((s = v4->newString(QStringLiteral("weight"))).getPointer()));
+ QV4::ScopedValue vwspac(scope, obj->get((s = v4->newString(QStringLiteral("wordSpacing"))).getPointer()));
// pull out the values, set ok to true if at least one valid field is given.
if (vbold->isBoolean()) {
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index a5a56949e6..95b3ac5b21 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -508,6 +508,7 @@ void QQuickPixmapReader::processJobs()
replies.remove(reply);
reply->close();
}
+ Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
// deleteLater, since not owned by this thread
job->deleteLater();
}
@@ -664,7 +665,11 @@ void QQuickPixmapReader::cancel(QQuickPixmapReply *reply)
// XXX
if (threadObject) threadObject->processJobs();
} else {
- jobs.removeAll(reply);
+ // If loading was started (reply removed from jobs) but the reply was never processed
+ // (otherwise it would have deleted itself) we need to profile an error.
+ if (jobs.removeAll(reply) == 0) {
+ Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
+ }
delete reply;
}
mutex.unlock();
@@ -898,7 +903,9 @@ bool QQuickPixmapReply::event(QEvent *event)
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
Q_QUICK_PROFILE(pixmapLoadingFinished(data->url,
- data->requestSize.width() > 0 ? data->requestSize : data->implicitSize));
+ data->textureFactory != 0 && data->textureFactory->textureSize().isValid() ?
+ data->textureFactory->textureSize() :
+ (data->requestSize.isValid() ? data->requestSize : data->implicitSize)));
} else {
Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
data->errorString = de->errorString;
@@ -907,6 +914,8 @@ bool QQuickPixmapReply::event(QEvent *event)
data->reply = 0;
emit finished();
+ } else {
+ Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
}
delete this;
@@ -975,10 +984,10 @@ void QQuickPixmapData::removeFromCache()
{
if (inCache) {
QQuickPixmapKey key = { &url, &requestSize };
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
- url, pixmapStore()->m_cache.count()));
pixmapStore()->m_cache.remove(key);
inCache = false;
+ Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
+ url, pixmapStore()->m_cache.count()));
}
}
@@ -1075,6 +1084,12 @@ QQuickPixmap::QQuickPixmap(QQmlEngine *engine, const QUrl &url, const QSize &siz
load(engine, url, size);
}
+QQuickPixmap::QQuickPixmap(const QUrl &url, const QImage &image)
+{
+ d = new QQuickPixmapData(this, url, new QQuickDefaultTextureFactory(image), image.size(), QSize());
+ d->addToCache();
+}
+
QQuickPixmap::~QQuickPixmap()
{
if (d) {
@@ -1167,6 +1182,17 @@ void QQuickPixmap::setImage(const QImage &p)
d = new QQuickPixmapData(this, textureFactoryForImage(p));
}
+void QQuickPixmap::setPixmap(const QQuickPixmap &other)
+{
+ clear();
+
+ if (other.d) {
+ d = other.d;
+ d->addref();
+ d->declarativePixmaps.insert(this);
+ }
+}
+
int QQuickPixmap::width() const
{
if (d && d->textureFactory)
@@ -1242,8 +1268,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
- Q_QUICK_PROFILE(pixmapLoadingFinished(url,
- d->requestSize.width() > 0 ? d->requestSize : d->implicitSize));
+ Q_QUICK_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
d->addToCache();
return;
@@ -1291,6 +1316,14 @@ void QQuickPixmap::clear(QObject *obj)
}
}
+bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize)
+{
+ QQuickPixmapKey key = { &url, &requestSize };
+ QQuickPixmapStore *store = pixmapStore();
+
+ return store->m_cache.contains(key);
+}
+
bool QQuickPixmap::connectFinished(QObject *object, const char *method)
{
if (!d || !d->reply) {
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index aa1761e896..76bbf6d341 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -78,6 +78,7 @@ public:
QQuickPixmap();
QQuickPixmap(QQmlEngine *, const QUrl &);
QQuickPixmap(QQmlEngine *, const QUrl &, const QSize &);
+ QQuickPixmap(const QUrl &, const QImage &image);
~QQuickPixmap();
enum Status { Null, Ready, Error, Loading };
@@ -100,6 +101,7 @@ public:
const QSize &requestSize() const;
QImage image() const;
void setImage(const QImage &);
+ void setPixmap(const QQuickPixmap &other);
QQuickTextureFactory *textureFactory() const;
@@ -121,6 +123,7 @@ public:
bool connectDownloadProgress(QObject *, int);
static void purgeCache();
+ static bool isCached(const QUrl &url, const QSize &requestSize);
private:
Q_DISABLE_COPY(QQuickPixmap)
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index 4418f6dd9c..3fd9b15f08 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -88,7 +88,7 @@ void QQuickProfilerData::toByteArrays(QList<QByteArray> &messages) const
// RendererFrame: preprocessTime, updateTime, bindingTime, renderTime
case QQuickProfiler::SceneGraphRendererFrame: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break;
// AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime
- case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << (int)subtime_1 << subtime_2 << subtime_3; break;
+ case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << subtime_1 << subtime_2 << subtime_3; break;
// ContextFrame: compiling material time
case QQuickProfiler::SceneGraphContextFrame: ds << subtime_1; break;
// RenderLoop: syncTime, renderTime, swapTime
@@ -103,8 +103,8 @@ void QQuickProfilerData::toByteArrays(QList<QByteArray> &messages) const
case QQuickProfiler::SceneGraphWindowsRenderShow: ds << subtime_1 << subtime_2 << subtime_3; break;
// WindowsAnimations: update time
case QQuickProfiler::SceneGraphWindowsAnimations: ds << subtime_1; break;
- // WindowsRenderWindow: polish time; always comes packed after a RenderLoop
- case QQuickProfiler::SceneGraphWindowsPolishFrame: ds << subtime_4; break;
+ // non-threaded rendering: polish time
+ case QQuickProfiler::SceneGraphPolishFrame: ds << subtime_1; break;
default:break;
}
break;
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index 03cef951b5..d5927a1f1f 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -71,10 +71,8 @@ QT_BEGIN_NAMESPACE
#define Q_QUICK_PROFILE(Method)\
Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::Method)
-#define Q_QUICK_SG_PROFILE2(Type1, Type2, Params)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::sceneGraphFrame<Type1, Type2> Params))
-
-#define Q_QUICK_SG_PROFILE1(Type, Params) Q_QUICK_SG_PROFILE2(Type, Type, Params)
+#define Q_QUICK_SG_PROFILE(Type, Params)\
+ Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::sceneGraphFrame<Type> Params))
// This struct is somewhat dangerous to use:
@@ -170,12 +168,12 @@ public:
}
}
- template<SceneGraphFrameType FrameType1, SceneGraphFrameType FrameType2>
+ template<SceneGraphFrameType FrameType>
static void sceneGraphFrame(qint64 value1, qint64 value2 = -1, qint64 value3 = -1,
qint64 value4 = -1, qint64 value5 = -1)
{
s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << SceneGraphFrame,
- 1 << FrameType1 | 1 << FrameType2, value1, value2, value3, value4, value5));
+ 1 << FrameType, value1, value2, value3, value4, value5));
}
template<PixmapEventType PixmapState>
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 0289f46429..d7167793ed 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -204,7 +204,7 @@ public:
isExplicit(false) {}
QPointer<QObject> object;
- QByteArray data;
+ QList<const QV4::CompiledData::Binding *> bindings;
QQmlRefPointer<QQmlCompiledData> cdata;
bool decoded : 1;
@@ -212,6 +212,7 @@ public:
bool isExplicit : 1;
void decode();
+ void decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
class ExpressionChange {
public:
@@ -237,10 +238,8 @@ public:
QQmlProperty property(const QString &);
};
-void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::CompiledData::Binding*> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
+void QQuickPropertyChangesParser::verifyList(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
{
- QString propName = pre + qmlUnit->header.stringAt(binding->propertyNameIndex);
-
if (binding->type == QV4::CompiledData::Binding::Type_Object) {
error(qmlUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
return;
@@ -248,133 +247,105 @@ void QQuickPropertyChangesParser::compileList(QList<QPair<QString, const QV4::Co
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
|| binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- QString pre = propName + QLatin1Char('.');
const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
- compileList(list, pre, qmlUnit, subBinding);
+ verifyList(qmlUnit, subBinding);
}
- return;
}
-
- list << qMakePair(propName, binding);
}
-QByteArray QQuickPropertyChangesParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+void QQuickPropertyChangesPrivate::decode()
{
- QList<QPair<QString, const QV4::CompiledData::Binding *> > data;
- for (int ii = 0; ii < props.count(); ++ii)
- compileList(data, QString(), qmlUnit, props.at(ii));
-
- QByteArray rv;
- QDataStream ds(&rv, QIODevice::WriteOnly);
-
- ds << data.count();
- for (int ii = 0; ii < data.count(); ++ii) {
- const QV4::CompiledData::Binding *binding = data.at(ii).second;
- ds << data.at(ii).first << int(binding->type);
- QVariant var;
- switch (binding->type) {
- case QV4::CompiledData::Binding::Type_Script:
- ds << bindingIdentifier(binding);
- // Fall through as we also need the expression string.
- // Signal handlers still need to be constructed by string ;(
- case QV4::CompiledData::Binding::Type_String:
- var = binding->valueAsString(&qmlUnit->header);
- break;
- case QV4::CompiledData::Binding::Type_Number:
- var = binding->valueAsNumber();
- break;
- case QV4::CompiledData::Binding::Type_Boolean:
- var = binding->valueAsBoolean();
- break;
- case QV4::CompiledData::Binding::Type_Translation:
- case QV4::CompiledData::Binding::Type_TranslationById:
- ds << binding->value.translationData.commentIndex << binding->value.translationData.number;
- var = binding->stringIndex;
- default:
- break;
- }
- ds << var;
- }
+ if (decoded)
+ return;
+
+ foreach (const QV4::CompiledData::Binding *binding, bindings)
+ decodeBinding(QString(), cdata->qmlUnit, binding);
+
+ bindings.clear();
- return rv;
+ decoded = true;
}
-void QQuickPropertyChangesPrivate::decode()
+void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding)
{
Q_Q(QQuickPropertyChanges);
- if (decoded)
- return;
- QDataStream ds(&data, QIODevice::ReadOnly);
+ QString propertyName = propertyPrefix + qmlUnit->header.stringAt(binding->propertyNameIndex);
- int count;
- ds >> count;
- for (int ii = 0; ii < count; ++ii) {
- QString name;
- int type;
- QVariant data;
- QQmlBinding::Identifier id = QQmlBinding::Invalid;
- QV4::CompiledData::TranslationData tsd;
- ds >> name;
- ds >> type;
-
- if (type == QV4::CompiledData::Binding::Type_Script) {
- ds >> id;
- } else if (type == QV4::CompiledData::Binding::Type_Translation
- || type == QV4::CompiledData::Binding::Type_TranslationById) {
- quint32 commentIndex;
- qint32 number;
- ds >> commentIndex >> number;
- tsd.commentIndex = commentIndex;
- tsd.number = number;
+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
+ || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ QString pre = propertyName + QLatin1Char('.');
+ const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
+ decodeBinding(pre, qmlUnit, subBinding);
}
+ return;
+ }
- ds >> data;
-
- QQmlProperty prop = property(name); //### better way to check for signal property?
- if (prop.type() & QQmlProperty::SignalProperty) {
- QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
- handler->property = prop;
- handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
- QQmlContextData::get(qmlContext(q)), object, cdata->functionForBindingId(id)));
- signalReplacements << handler;
- } else if (type == QV4::CompiledData::Binding::Type_Script) { // binding
- QString expression = data.toString();
- QUrl url = QUrl();
- int line = -1;
- int column = -1;
-
- QQmlData *ddata = QQmlData::get(q);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
- url = ddata->outerContext->url;
- line = ddata->lineNumber;
- column = ddata->columnNumber;
- }
+ QQmlProperty prop = property(propertyName); //### better way to check for signal property?
- expressions << ExpressionChange(name, id, expression, url, line, column);
- } else {
- if (type == QV4::CompiledData::Binding::Type_Translation
- || type == QV4::CompiledData::Binding::Type_TranslationById) {
- QV4::CompiledData::Binding tmpBinding;
- tmpBinding.type = type;
- tmpBinding.stringIndex = data.toInt();
- tmpBinding.value.translationData = tsd;
- data = tmpBinding.valueAsString(&cdata->qmlUnit->header);
- }
- properties << qMakePair(name, data);
+ if (prop.type() & QQmlProperty::SignalProperty) {
+ QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
+ handler->property = prop;
+ handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
+ QQmlContextData::get(qmlContext(q)), object, cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
+ signalReplacements << handler;
+ return;
+ }
+
+ if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ QString expression = binding->valueAsString(&qmlUnit->header);
+ QUrl url = QUrl();
+ int line = -1;
+ int column = -1;
+
+ QQmlData *ddata = QQmlData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ url = ddata->outerContext->url;
+ line = ddata->lineNumber;
+ column = ddata->columnNumber;
}
+
+ expressions << ExpressionChange(propertyName, binding->value.compiledScriptIndex, expression, url, line, column);
+ return;
}
- decoded = true;
- data.clear();
+
+ QVariant var;
+ switch (binding->type) {
+ case QV4::CompiledData::Binding::Type_Script:
+ Q_UNREACHABLE();
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ case QV4::CompiledData::Binding::Type_String:
+ var = binding->valueAsString(&qmlUnit->header);
+ break;
+ case QV4::CompiledData::Binding::Type_Number:
+ var = binding->valueAsNumber();
+ break;
+ case QV4::CompiledData::Binding::Type_Boolean:
+ var = binding->valueAsBoolean();
+ break;
+ default:
+ break;
+ }
+
+ properties << qMakePair(propertyName, var);
}
-void QQuickPropertyChangesParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata)
+void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props)
+{
+ for (int ii = 0; ii < props.count(); ++ii)
+ verifyList(qmlUnit, props.at(ii));
+}
+
+void QQuickPropertyChangesParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQuickPropertyChangesPrivate *p =
- static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(object));
- p->data = data;
+ static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj));
+ p->bindings = bindings;
p->cdata = cdata;
p->decoded = false;
}
@@ -483,9 +454,17 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
a.specifiedObject = d->object;
a.specifiedProperty = property;
- QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
+ QQmlContextData *context = QQmlContextData::get(qmlContext(this));
+
+ QQmlBinding *newBinding = 0;
+ if (e.id != QQmlBinding::Invalid) {
+ QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
+ QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(context, object(), d->cdata->compilationUnit->runtimeFunctions[e.id]));
+ newBinding = new QQmlBinding(function, object(), context);
+ }
+// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
if (!newBinding)
- newBinding = new QQmlBinding(e.expression, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column);
+ newBinding = new QQmlBinding(e.expression, object(), context, e.url.toString(), e.line, e.column);
if (d->isExplicit) {
// in this case, we don't want to assign a binding, per se,
diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h
index 3eed151d11..971aade7f2 100644
--- a/src/quick/util/qquickpropertychanges_p.h
+++ b/src/quick/util/qquickpropertychanges_p.h
@@ -92,10 +92,10 @@ public:
QQuickPropertyChangesParser()
: QQmlCustomParser(AcceptsAttachedProperties) {}
- void compileList(QList<QPair<QString, const QV4::CompiledData::Binding *> > &list, const QString &pre, const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
+ void verifyList(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding);
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
- virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *);
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
+ virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
};
diff --git a/src/quick/util/qquicksystempalette.cpp b/src/quick/util/qquicksystempalette.cpp
index 515bf28c2f..a249a353c4 100644
--- a/src/quick/util/qquicksystempalette.cpp
+++ b/src/quick/util/qquicksystempalette.cpp
@@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE
class QQuickSystemPalettePrivate : public QObjectPrivate
{
public:
- QPalette palette;
QPalette::ColorGroup group;
};
@@ -85,9 +84,8 @@ QQuickSystemPalette::QQuickSystemPalette(QObject *parent)
: QObject(*(new QQuickSystemPalettePrivate), parent)
{
Q_D(QQuickSystemPalette);
- d->palette = QGuiApplication::palette();
d->group = QPalette::Active;
- qApp->installEventFilter(this);
+ connect(qApp, SIGNAL(paletteChanged(QPalette)), this, SIGNAL(paletteChanged()));
}
QQuickSystemPalette::~QQuickSystemPalette()
@@ -103,7 +101,7 @@ QQuickSystemPalette::~QQuickSystemPalette()
QColor QQuickSystemPalette::window() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Window);
+ return QGuiApplication::palette().color(d->group, QPalette::Window);
}
/*!
@@ -115,7 +113,7 @@ QColor QQuickSystemPalette::window() const
QColor QQuickSystemPalette::windowText() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::WindowText);
+ return QGuiApplication::palette().color(d->group, QPalette::WindowText);
}
/*!
@@ -127,7 +125,7 @@ QColor QQuickSystemPalette::windowText() const
QColor QQuickSystemPalette::base() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Base);
+ return QGuiApplication::palette().color(d->group, QPalette::Base);
}
/*!
@@ -139,7 +137,7 @@ QColor QQuickSystemPalette::base() const
QColor QQuickSystemPalette::text() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Text);
+ return QGuiApplication::palette().color(d->group, QPalette::Text);
}
/*!
@@ -151,7 +149,7 @@ QColor QQuickSystemPalette::text() const
QColor QQuickSystemPalette::alternateBase() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::AlternateBase);
+ return QGuiApplication::palette().color(d->group, QPalette::AlternateBase);
}
/*!
@@ -163,7 +161,7 @@ QColor QQuickSystemPalette::alternateBase() const
QColor QQuickSystemPalette::button() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Button);
+ return QGuiApplication::palette().color(d->group, QPalette::Button);
}
/*!
@@ -175,7 +173,7 @@ QColor QQuickSystemPalette::button() const
QColor QQuickSystemPalette::buttonText() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::ButtonText);
+ return QGuiApplication::palette().color(d->group, QPalette::ButtonText);
}
/*!
@@ -187,7 +185,7 @@ QColor QQuickSystemPalette::buttonText() const
QColor QQuickSystemPalette::light() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Light);
+ return QGuiApplication::palette().color(d->group, QPalette::Light);
}
/*!
@@ -199,7 +197,7 @@ QColor QQuickSystemPalette::light() const
QColor QQuickSystemPalette::midlight() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Midlight);
+ return QGuiApplication::palette().color(d->group, QPalette::Midlight);
}
/*!
@@ -211,7 +209,7 @@ QColor QQuickSystemPalette::midlight() const
QColor QQuickSystemPalette::dark() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Dark);
+ return QGuiApplication::palette().color(d->group, QPalette::Dark);
}
/*!
@@ -223,7 +221,7 @@ QColor QQuickSystemPalette::dark() const
QColor QQuickSystemPalette::mid() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Mid);
+ return QGuiApplication::palette().color(d->group, QPalette::Mid);
}
/*!
@@ -235,7 +233,7 @@ QColor QQuickSystemPalette::mid() const
QColor QQuickSystemPalette::shadow() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Shadow);
+ return QGuiApplication::palette().color(d->group, QPalette::Shadow);
}
/*!
@@ -247,7 +245,7 @@ QColor QQuickSystemPalette::shadow() const
QColor QQuickSystemPalette::highlight() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::Highlight);
+ return QGuiApplication::palette().color(d->group, QPalette::Highlight);
}
/*!
@@ -259,7 +257,7 @@ QColor QQuickSystemPalette::highlight() const
QColor QQuickSystemPalette::highlightedText() const
{
Q_D(const QQuickSystemPalette);
- return d->palette.color(d->group, QPalette::HighlightedText);
+ return QGuiApplication::palette().color(d->group, QPalette::HighlightedText);
}
/*!
@@ -288,26 +286,4 @@ void QQuickSystemPalette::setColorGroup(QQuickSystemPalette::ColorGroup colorGro
emit paletteChanged();
}
-bool QQuickSystemPalette::eventFilter(QObject *watched, QEvent *event)
-{
- if (watched == qApp) {
- if (event->type() == QEvent::ApplicationPaletteChange) {
- QGuiApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
- return false;
- }
- }
- return QObject::eventFilter(watched, event);
-}
-
-bool QQuickSystemPalette::event(QEvent *event)
-{
- Q_D(QQuickSystemPalette);
- if (event->type() == QEvent::ApplicationPaletteChange) {
- d->palette = QGuiApplication::palette();
- emit paletteChanged();
- return true;
- }
- return QObject::event(event);
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/util/qquicksystempalette_p.h b/src/quick/util/qquicksystempalette_p.h
index b06a4a2ef3..d27fca7d9b 100644
--- a/src/quick/util/qquicksystempalette_p.h
+++ b/src/quick/util/qquicksystempalette_p.h
@@ -102,11 +102,6 @@ public:
Q_SIGNALS:
void paletteChanged();
-
-private:
- bool eventFilter(QObject *watched, QEvent *event);
- bool event(QEvent *event);
-
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquicktextmetrics.cpp b/src/quick/util/qquicktextmetrics.cpp
new file mode 100644
index 0000000000..09af99b82b
--- /dev/null
+++ b/src/quick/util/qquicktextmetrics.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktextmetrics_p.h"
+
+#include <QFont>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype TextMetrics
+ \instantiates QQuickTextMetrics
+ \inqmlmodule QtQuick
+ \ingroup qtquick-text-utility
+ \brief Provides metrics for a given font and text
+
+ TextMetrics calculates various properties of a given string of text for a
+ particular font.
+
+ It provides a declarative API for the functions in \l QFontMetricsF which
+ take arguments.
+
+ \code
+ TextMetrics {
+ id: textMetrics
+ font.family: "Arial"
+ elide: Text.ElideMiddle
+ elideWidth: 100
+ text: "Hello World"
+ }
+
+ MyItem {
+ text: textMetrics.elidedText
+ }
+ \endcode
+
+ \sa QFontMetricsF, FontMetrics
+*/
+QQuickTextMetrics::QQuickTextMetrics(QObject *parent) :
+ QObject(parent),
+ m_metrics(m_font),
+ m_elide(Qt::ElideNone),
+ m_elideWidth(0)
+{
+}
+
+QQuickTextMetrics::~QQuickTextMetrics()
+{
+}
+
+/*!
+ \qmlproperty font QtQuick::TextMetrics::font
+
+ This property holds the font used for the metrics calculations.
+*/
+QFont QQuickTextMetrics::font() const
+{
+ return m_font;
+}
+
+void QQuickTextMetrics::setFont(const QFont &font)
+{
+ if (m_font != font) {
+ m_font = font;
+ m_metrics = QFontMetricsF(m_font);
+ emit fontChanged();
+ emit metricsChanged();
+ }
+}
+
+/*!
+ \qmlproperty string QtQuick::TextMetrics::text
+
+ This property holds the text used for the metrics calculations.
+*/
+QString QQuickTextMetrics::text() const
+{
+ return m_text;
+}
+
+void QQuickTextMetrics::setText(const QString &text)
+{
+ if (m_text != text) {
+ m_text = text;
+ emit textChanged();
+ emit metricsChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::TextMetrics::elide
+
+ This property holds the elide mode of the text. This determines the
+ position in which the string is elided. The possible values are:
+
+ \list
+ \li \c Qt::ElideNone - No eliding; this is the default value.
+ \li \c Qt::ElideLeft - For example: "...World"
+ \li \c Qt::ElideMiddle - For example: "He...ld"
+ \li \c Qt::ElideRight - For example: "Hello..."
+ \endlist
+
+ \sa elideWidth, elidedText
+*/
+Qt::TextElideMode QQuickTextMetrics::elide() const
+{
+ return m_elide;
+}
+
+void QQuickTextMetrics::setElide(Qt::TextElideMode elide)
+{
+ if (m_elide != elide) {
+ m_elide = elide;
+ emit elideChanged();
+ emit metricsChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick::TextMetrics::elideWidth
+
+ This property holds the largest width the text can have (in pixels) before
+ eliding will occur.
+
+ \sa elide, elidedText
+*/
+qreal QQuickTextMetrics::elideWidth() const
+{
+ return m_elideWidth;
+}
+
+void QQuickTextMetrics::setElideWidth(qreal elideWidth)
+{
+ if (m_elideWidth != elideWidth) {
+ m_elideWidth = elideWidth;
+ emit elideWidthChanged();
+ emit metricsChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick::TextMetrics::advanceWidth
+
+ This property holds the advance in pixels of the characters in \l text.
+ This is the distance from the position of the string to where the next
+ string should be drawn.
+
+ \sa {QFontMetricsF::width()}
+*/
+qreal QQuickTextMetrics::advanceWidth() const
+{
+ return m_metrics.width(m_text);
+}
+
+/*!
+ \qmlproperty rect QtQuick::TextMetrics::boundingRect
+
+ This property holds the bounding rectangle of the characters in the string
+ specified by \l text.
+
+ \sa {QFontMetricsF::boundingRect()}, tightBoundingRect
+*/
+QRectF QQuickTextMetrics::boundingRect() const
+{
+ return m_metrics.boundingRect(m_text);
+}
+
+/*!
+ \qmlproperty real QtQuick::TextMetrics::width
+
+ This property holds the width of the bounding rectangle of the characters
+ in the string specified by \l text. It is equivalent to:
+
+ \code
+ textMetrics.boundingRect.width
+ \endcode
+
+ \sa boundingRect
+*/
+qreal QQuickTextMetrics::width() const
+{
+ return boundingRect().width();
+}
+
+/*!
+ \qmlproperty real QtQuick::TextMetrics::height
+
+ This property holds the height of the bounding rectangle of the characters
+ in the string specified by \l text. It is equivalent to:
+
+ \code
+ textMetrics.boundingRect.height
+ \endcode
+
+ \sa boundingRect
+*/
+qreal QQuickTextMetrics::height() const
+{
+ return boundingRect().height();
+}
+
+/*!
+ \qmlproperty rect QtQuick::TextMetrics::tightBoundingRect
+
+ This property holds a tight bounding rectangle around the characters in the
+ string specified by \l text.
+
+ \sa {QFontMetricsF::tightBoundingRect()}, boundingRect
+*/
+QRectF QQuickTextMetrics::tightBoundingRect() const
+{
+ return m_metrics.tightBoundingRect(m_text);
+}
+
+/*!
+ \qmlmethod string QtQuick::TextMetrics::elidedText
+
+ This property holds an elided version of the string (i.e., a string with
+ "..." in it) if the string \l text is wider than \l elideWidth. If the
+ text is not wider than \l elideWidth, or \l elide is set to
+ \c Qt::ElideNone, this property will be equal to the original string.
+
+ \sa {QFontMetricsF::elidedText()}
+*/
+QString QQuickTextMetrics::elidedText() const
+{
+ return m_metrics.elidedText(m_text, m_elide, m_elideWidth);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qquicktextmetrics_p.h b/src/quick/util/qquicktextmetrics_p.h
new file mode 100644
index 0000000000..ec993229e5
--- /dev/null
+++ b/src/quick/util/qquicktextmetrics_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTMETRICS_H
+#define QQUICKTEXTMETRICS_H
+
+#include <qqml.h>
+
+#include <QtGui/QFontMetricsF>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QFont;
+
+class Q_AUTOTEST_EXPORT QQuickTextMetrics : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(qreal advanceWidth READ advanceWidth NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(qreal width READ width NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(qreal height READ height NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(QRectF tightBoundingRect READ tightBoundingRect NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(QString elidedText READ elidedText NOTIFY metricsChanged FINAL)
+ Q_PROPERTY(Qt::TextElideMode elide READ elide WRITE setElide NOTIFY elideChanged FINAL)
+ Q_PROPERTY(qreal elideWidth READ elideWidth WRITE setElideWidth NOTIFY elideWidthChanged FINAL)
+
+public:
+ explicit QQuickTextMetrics(QObject *parent = 0);
+ ~QQuickTextMetrics();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ Qt::TextElideMode elide() const;
+ void setElide(Qt::TextElideMode elide);
+
+ qreal elideWidth() const;
+ void setElideWidth(qreal elideWidth);
+
+ qreal advanceWidth() const;
+ QRectF boundingRect() const;
+ qreal width() const;
+ qreal height() const;
+ QRectF tightBoundingRect() const;
+ QString elidedText() const;
+
+Q_SIGNALS:
+ void fontChanged();
+ void textChanged();
+ void elideChanged();
+ void elideWidthChanged();
+ void metricsChanged();
+
+private:
+ QString m_text;
+ QFont m_font;
+ QFontMetricsF m_metrics;
+ Qt::TextElideMode m_elide;
+ qreal m_elideWidth;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTextMetrics)
+
+#endif // QQUICKTEXTMETRICS_H
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index a6e907713a..8ea903b010 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -45,6 +45,7 @@
#include "qquickbehavior_p.h"
#include "qquicksmoothedanimation_p.h"
#include "qquickfontloader_p.h"
+#include "qquickfontmetrics_p.h"
#include "qquickpropertychanges_p.h"
#include "qquickspringanimation_p.h"
#include "qquickstategroup_p.h"
@@ -52,6 +53,7 @@
#include "qquickstate_p.h"
#include "qquickstate_p_p.h"
#include "qquicksystempalette_p.h"
+#include "qquicktextmetrics_p.h"
#include "qquicktransition_p.h"
#include "qquickanimator_p.h"
#include <qqmlinfo.h>
@@ -106,4 +108,7 @@ void QQuickUtilModule::defineModule()
qRegisterMetaType<QKeySequence::StandardKey>();
qmlRegisterUncreatableType<QKeySequence, 2>("QtQuick", 2, 2, "StandardKey", QStringLiteral("Cannot create an instance of StandardKey."));
+
+ qmlRegisterType<QQuickFontMetrics>("QtQuick", 2, 4, "FontMetrics");
+ qmlRegisterType<QQuickTextMetrics>("QtQuick", 2, 4, "TextMetrics");
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index ce409bd10d..76cf1996bc 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -26,7 +26,9 @@ SOURCES += \
$$PWD/qquickanimator.cpp \
$$PWD/qquickanimatorjob.cpp \
$$PWD/qquickanimatorcontroller.cpp \
- $$PWD/qquickprofiler.cpp
+ $$PWD/qquickprofiler.cpp \
+ $$PWD/qquickfontmetrics.cpp \
+ $$PWD/qquicktextmetrics.cpp
HEADERS += \
$$PWD/qquickapplication_p.h\
@@ -60,4 +62,6 @@ HEADERS += \
$$PWD/qquickanimator_p_p.h \
$$PWD/qquickanimatorjob_p.h \
$$PWD/qquickanimatorcontroller_p.h \
- $$PWD/qquickprofiler_p.h
+ $$PWD/qquickprofiler_p.h \
+ $$PWD/qquickfontmetrics_p.h \
+ $$PWD/qquicktextmetrics_p.h
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 8a61e371e7..2541359fdd 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -72,7 +72,7 @@ class QQuickWidgetRenderControl : public QQuickRenderControl
{
public:
QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {}
- QWindow *renderWindow(QPoint *offset) {
+ QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE {
if (offset)
*offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint());
return m_quickWidget->window()->windowHandle();
@@ -86,7 +86,7 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
Q_Q(QQuickWidget);
renderControl = new QQuickWidgetRenderControl(q);
- offscreenWindow = renderControl->createOffscreenWindow();
+ offscreenWindow = new QQuickWindow(renderControl);
offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
// Do not call create() on offscreenWindow.
@@ -162,8 +162,8 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
// context and offscreenSurface are current at this stage, if the context was created.
Q_ASSERT(!context || (QOpenGLContext::currentContext() == context && context->surface() == offscreenSurface));
+ delete renderControl; // always delete the rendercontrol first
delete offscreenWindow;
- delete renderControl;
delete resolvedFbo;
delete fbo;
@@ -227,7 +227,7 @@ void QQuickWidgetPrivate::renderSceneGraph()
renderControl->polishItems();
renderControl->sync();
renderControl->render();
- glFlush();
+ context->functions()->glFlush();
if (resolvedFbo) {
QRect rect(QPoint(0, 0), fbo->size());
@@ -238,6 +238,15 @@ void QQuickWidgetPrivate::renderSceneGraph()
q->update();
}
+QImage QQuickWidgetPrivate::grabFramebuffer()
+{
+ if (!context)
+ return QImage();
+
+ context->makeCurrent(offscreenSurface);
+ return renderControl->grab();
+}
+
/*!
\module QtQuickWidgets
\title Qt Quick Widgets C++ Classes
@@ -631,8 +640,8 @@ void QQuickWidgetPrivate::createContext()
context = new QOpenGLContext;
context->setFormat(offscreenWindow->requestedFormat());
- if (QOpenGLContextPrivate::globalShareContext())
- context->setShareContext(QOpenGLContextPrivate::globalShareContext());
+ if (qt_gl_global_share_context())
+ context->setShareContext(qt_gl_global_share_context());
if (!context->create()) {
const bool isEs = context->isOpenGLES();
delete context;
@@ -869,26 +878,15 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
d->fakeHidden = true;
return;
}
- if (d->fakeHidden) {
+ if (d->fakeHidden && d->context) {
//restart rendering
d->fakeHidden = false;
d->renderControl->sync();
}
- if (d->context) {
- // Bail out in the special case of receiving a resize after
- // scenegraph invalidation during application exit.
- if (!d->fbo && !d->offscreenWindow->openglContext())
- return;
- if (!d->fbo || d->fbo->size() != size() * devicePixelRatio())
- createFramebufferObject();
- } else {
- // This will result in a scenegraphInitialized() signal which
- // is connected to createFramebufferObject().
- d->createContext();
- }
-
- d->offscreenWindow->resizeEvent(e);
+ d->createContext();
+ createFramebufferObject();
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
d->offscreenWindow->setGeometry(0, 0, e->size().width(), e->size().height());
QOpenGLContext *context = d->offscreenWindow->openglContext();
@@ -898,8 +896,15 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
}
context->makeCurrent(d->offscreenSurface);
+
+ if (d->fakeHidden) {
+ d->fakeHidden = false;
+ d->renderControl->sync();
+ }
+
d->renderControl->render();
- glFlush();
+
+ context->functions()->glFlush();
context->doneCurrent();
}
@@ -909,7 +914,7 @@ void QQuickWidget::keyPressEvent(QKeyEvent *e)
Q_D(QQuickWidget);
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
- d->offscreenWindow->keyPressEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
/*! \reimp */
@@ -918,7 +923,7 @@ void QQuickWidget::keyReleaseEvent(QKeyEvent *e)
Q_D(QQuickWidget);
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
- d->offscreenWindow->keyReleaseEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
/*! \reimp */
@@ -932,7 +937,7 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
// the windowPos in e is ignored and is replaced by localPos. This is necessary
// because QQuickWindow thinks of itself as a top-level window always.
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mouseMoveEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -945,10 +950,10 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
// See QTBUG-25831
QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->screenPos(), e->button(),
e->buttons(), e->modifiers());
- d->offscreenWindow->mousePressEvent(&pressEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(),
e->modifiers());
- d->offscreenWindow->mouseDoubleClickEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -974,7 +979,7 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mousePressEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
/*! \reimp */
@@ -984,7 +989,7 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
- d->offscreenWindow->mouseReleaseEvent(&mappedEvent);
+ QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
#ifndef QT_NO_WHEELEVENT
@@ -995,7 +1000,7 @@ void QQuickWidget::wheelEvent(QWheelEvent *e)
Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
// Wheel events only have local and global positions, no need to map.
- d->offscreenWindow->wheelEvent(e);
+ QCoreApplication::sendEvent(d->offscreenWindow, e);
}
#endif
@@ -1038,7 +1043,8 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::TouchUpdate:
case QEvent::TouchCancel:
// Touch events only have local and global positions, no need to map.
- return d->offscreenWindow->event(e);
+ return QCoreApplication::sendEvent(d->offscreenWindow, e);
+
case QEvent::WindowChangeInternal:
d->handleWindowChange();
break;
@@ -1099,4 +1105,14 @@ QSurfaceFormat QQuickWidget::format() const
return d->offscreenWindow->format();
}
+/*!
+ Renders a frame and reads it back into an image.
+
+ \note This is a potentially expensive operation.
+ */
+QImage QQuickWidget::grabFramebuffer() const
+{
+ return const_cast<QQuickWidgetPrivate *>(d_func())->grabFramebuffer();
+}
+
QT_END_NAMESPACE
diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h
index 4287933063..6c3d63a419 100644
--- a/src/quickwidgets/qquickwidget.h
+++ b/src/quickwidgets/qquickwidget.h
@@ -47,6 +47,7 @@
#include <QtCore/qurl.h>
#include <QtQml/qqmldebug.h>
#include <QtQuickWidgets/qtquickwidgetsglobal.h>
+#include <QtGui/qimage.h>
QT_BEGIN_NAMESPACE
@@ -64,6 +65,7 @@ class Q_QUICKWIDGETS_EXPORT QQuickWidget : public QWidget
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true)
Q_ENUMS(ResizeMode Status)
+
public:
explicit QQuickWidget(QWidget *parent = 0);
QQuickWidget(QQmlEngine* engine, QWidget *parent);
@@ -92,6 +94,8 @@ public:
void setFormat(const QSurfaceFormat &format);
QSurfaceFormat format() const;
+ QImage grabFramebuffer() const;
+
public Q_SLOTS:
void setSource(const QUrl&);
void setContent(const QUrl& url, QQmlComponent *component, QObject *item);
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index 8a8d98f45e..755acb969d 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -89,6 +89,7 @@ public:
void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs);
GLuint textureId() const Q_DECL_OVERRIDE;
+ QImage grabFramebuffer() Q_DECL_OVERRIDE;
void init(QQmlEngine* e = 0);
void handleWindowChange();