aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/common/common.pri35
-rw-r--r--src/qml/common/qqmlapiversion_p.h56
-rw-r--r--src/qml/common/qqmljsdiagnosticmessage_p.h92
-rw-r--r--src/qml/common/qqmljsfixedpoolarray_p.h140
-rw-r--r--src/qml/common/qqmljsmemorypool_p.h (renamed from src/qml/parser/qqmljsmemorypool_p.h)81
-rw-r--r--src/qml/common/qv4alloca_p.h (renamed from src/qml/jsruntime/qv4alloca_p.h)0
-rw-r--r--src/qml/common/qv4calldata_p.h (renamed from src/qml/jit/qv4jithelpers_p.h)89
-rw-r--r--src/qml/common/qv4compileddata_p.h (renamed from src/qml/compiler/qv4compileddata_p.h)563
-rw-r--r--src/qml/common/qv4staticvalue_p.h559
-rw-r--r--src/qml/common/qv4stringtoarrayindex_p.h96
-rw-r--r--src/qml/compiler/compiler.pri26
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp582
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h139
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp4
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h64
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp7
-rw-r--r--src/qml/compiler/qv4bytecodehandler_p.h3
-rw-r--r--src/qml/compiler/qv4codegen.cpp546
-rw-r--r--src/qml/compiler/qv4codegen_p.h301
-rw-r--r--src/qml/compiler/qv4compiler.cpp79
-rw-r--r--src/qml/compiler/qv4compiler_p.h11
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp26
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h14
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h11
-rw-r--r--src/qml/compiler/qv4compilerglobal_p.h (renamed from src/qml/qmldirparser/qqmlsourcecoordinate_p.h)28
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp62
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h101
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp107
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h64
-rw-r--r--src/qml/compiler/qv4util_p.h (renamed from src/qml/jsruntime/qv4util_p.h)1
-rw-r--r--src/qml/configure.json94
-rw-r--r--src/qml/debugger/debugger.pri2
-rw-r--r--src/qml/debugger/qqmlconfigurabledebugservice_p.h4
-rw-r--r--src/qml/debugger/qqmlmemoryprofiler.cpp144
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h15
-rw-r--r--src/qml/doc/qtqml.qdocconf10
-rw-r--r--src/qml/doc/snippets/delegatemodel/delegatemodel.qml75
-rw-r--r--src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/main.cpp72
-rw-r--r--src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml76
-rw-r--r--src/qml/doc/snippets/delegatemodel/delegatemodelgroup.qml92
-rw-r--r--src/qml/doc/snippets/package/Delegate.qml88
-rw-r--r--src/qml/doc/snippets/package/view.qml103
-rw-r--r--src/qml/doc/snippets/qml/events.qml8
-rw-r--r--src/qml/doc/snippets/qml/listmodel/listelements.qml87
-rw-r--r--src/qml/doc/snippets/qml/listmodel/listmodel-modify.qml106
-rw-r--r--src/qml/doc/snippets/qml/listmodel/listmodel-nested.qml112
-rw-r--r--src/qml/doc/snippets/qml/listmodel/listmodel-simple.qml89
-rw-r--r--src/qml/doc/snippets/qml/listmodel/listmodel.qml69
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml2
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp10
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml2
-rw-r--r--src/qml/doc/snippets/qml/statemachine/guardcondition.qml2
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc33
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc140
-rw-r--r--src/qml/jit/jit.pri2
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp4
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h11
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp64
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h4
-rw-r--r--src/qml/jit/qv4baselinejit.cpp298
-rw-r--r--src/qml/jit/qv4baselinejit_p.h63
-rw-r--r--src/qml/jit/qv4jithelpers.cpp174
-rw-r--r--src/qml/jsapi/qjsengine.cpp40
-rw-r--r--src/qml/jsapi/qjsengine.h3
-rw-r--r--src/qml/jsapi/qjsengine_p.h4
-rw-r--r--src/qml/jsapi/qjsvalue.cpp9
-rw-r--r--src/qml/jsruntime/jsruntime.pri47
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp61
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp15
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp (renamed from src/qml/compiler/qv4compilationunitmapper.cpp)2
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_p.h (renamed from src/qml/compiler/qv4compilationunitmapper_p.h)0
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_unix.cpp (renamed from src/qml/compiler/qv4compilationunitmapper_unix.cpp)4
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_win.cpp (renamed from src/qml/compiler/qv4compilationunitmapper_win.cpp)4
-rw-r--r--src/qml/jsruntime/qv4context.cpp24
-rw-r--r--src/qml/jsruntime/qv4context_p.h5
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp23
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp520
-rw-r--r--src/qml/jsruntime/qv4engine_p.h177
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h14
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp4
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp (renamed from src/qml/compiler/qv4compileddata.cpp)607
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h333
-rw-r--r--src/qml/jsruntime/qv4function.cpp53
-rw-r--r--src/qml/jsruntime/qv4function_p.h61
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h14
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4global_p.h77
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp22
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp21
-rw-r--r--src/qml/jsruntime/qv4include.cpp30
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp101
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp12
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h33
-rw-r--r--src/qml/jsruntime/qv4managed_p.h1
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4math_p.h40
-rw-r--r--src/qml/jsruntime/qv4module.cpp4
-rw-r--r--src/qml/jsruntime/qv4module_p.h4
-rw-r--r--src/qml/jsruntime/qv4object.cpp29
-rw-r--r--src/qml/jsruntime/qv4object_p.h22
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h2
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp2
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h20
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h6
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp42
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h1
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp77
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h2
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp45
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h15
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp557
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h6
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h587
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp16
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen_p.h6
-rw-r--r--src/qml/jsruntime/qv4script.cpp38
-rw-r--r--src/qml/jsruntime/qv4script_p.h10
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp25
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp427
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h54
-rw-r--r--src/qml/jsruntime/qv4string.cpp11
-rw-r--r--src/qml/jsruntime/qv4string_p.h47
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp17
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp46
-rw-r--r--src/qml/jsruntime/qv4value.cpp29
-rw-r--r--src/qml/jsruntime/qv4value_p.h568
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp341
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h1
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h6
-rw-r--r--src/qml/memory/memory.pri6
-rw-r--r--src/qml/memory/qv4heap_p.h4
-rw-r--r--src/qml/memory/qv4mm.cpp32
-rw-r--r--src/qml/memory/qv4writebarrier_p.h2
-rw-r--r--src/qml/parser/parser.pri2
-rw-r--r--src/qml/parser/qqmljs.g426
-rw-r--r--src/qml/parser/qqmljsast.cpp88
-rw-r--r--src/qml/parser/qqmljsast_p.h266
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h7
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h11
-rw-r--r--src/qml/parser/qqmljsengine_p.h25
-rw-r--r--src/qml/parser/qqmljslexer.cpp123
-rw-r--r--src/qml/parser/qqmljslexer_p.h10
-rw-r--r--src/qml/qml.pro35
-rw-r--r--src/qml/qml/ftw/ftw.pri7
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp78
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h851
-rw-r--r--src/qml/qml/ftw/qlinkedstringhash_p.h238
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h80
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h29
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h807
-rw-r--r--src/qml/qml/qml.pri63
-rw-r--r--src/qml/qml/qqml.cpp161
-rw-r--r--src/qml/qml/qqml.h58
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp36
-rw-r--r--src/qml/qml/qqmlapplicationengine.h1
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h6
-rw-r--r--src/qml/qml/qqmlbinding.cpp13
-rw-r--r--src/qml/qml/qqmlbinding_p.h3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp4
-rw-r--r--src/qml/qml/qqmlcomponent.cpp84
-rw-r--r--src/qml/qml/qqmlcomponent.h9
-rw-r--r--src/qml/qml/qqmlcomponent_p.h6
-rw-r--r--src/qml/qml/qqmlcontext.cpp48
-rw-r--r--src/qml/qml/qqmlcontext_p.h8
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp9
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h11
-rw-r--r--src/qml/qml/qqmldata_p.h8
-rw-r--r--src/qml/qml/qqmldatablob.cpp639
-rw-r--r--src/qml/qml/qqmldatablob_p.h259
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp2
-rw-r--r--src/qml/qml/qqmldirdata.cpp95
-rw-r--r--src/qml/qml/qqmldirdata_p.h86
-rw-r--r--src/qml/qml/qqmlengine.cpp279
-rw-r--r--src/qml/qml/qqmlengine.h9
-rw-r--r--src/qml/qml/qqmlengine_p.h46
-rw-r--r--src/qml/qml/qqmlenumdata_p.h (renamed from src/qml/types/qqmlmodelsmodule_p.h)17
-rw-r--r--src/qml/qml/qqmlenumvalue_p.h68
-rw-r--r--src/qml/qml/qqmlerror.cpp (renamed from src/qml/qmldirparser/qqmlerror.cpp)48
-rw-r--r--src/qml/qml/qqmlerror.h (renamed from src/qml/qmldirparser/qqmlerror.h)2
-rw-r--r--src/qml/qml/qqmlexpression.cpp10
-rw-r--r--src/qml/qml/qqmlglobal.cpp69
-rw-r--r--src/qml/qml/qqmlglobal_p.h23
-rw-r--r--src/qml/qml/qqmlimport.cpp252
-rw-r--r--src/qml/qml/qqmlimport_p.h7
-rw-r--r--src/qml/qml/qqmlincubator.cpp3
-rw-r--r--src/qml/qml/qqmlincubator_p.h2
-rw-r--r--src/qml/qml/qqmlinfo.cpp6
-rw-r--r--src/qml/qml/qqmlinfo.h1
-rw-r--r--src/qml/qml/qqmlirloader.cpp206
-rw-r--r--src/qml/qml/qqmlirloader_p.h82
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp9
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h6
-rw-r--r--src/qml/qml/qqmllist_p.h2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp1
-rw-r--r--src/qml/qml/qqmllocale.cpp2
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h2
-rw-r--r--src/qml/qml/qqmlmetaobject.cpp327
-rw-r--r--src/qml/qml/qqmlmetaobject_p.h187
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2299
-rw-r--r--src/qml/qml/qqmlmetatype_p.h284
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp226
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h148
-rw-r--r--src/qml/qml/qqmlnotifier.cpp4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp99
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h17
-rw-r--r--src/qml/qml/qqmlobjectorgadget.cpp60
-rw-r--r--src/qml/qml/qqmlobjectorgadget_p.h (renamed from src/qml/util/qqmllistaccessor_p.h)42
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp1
-rw-r--r--src/qml/qml/qqmlprivate.h11
-rw-r--r--src/qml/qml/qqmlproperty.cpp12
-rw-r--r--src/qml/qml/qqmlproperty_p.h5
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp427
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h643
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp (renamed from src/qml/compiler/qqmlpropertycachecreator.cpp)33
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h (renamed from src/qml/compiler/qqmlpropertycachecreator_p.h)329
-rw-r--r--src/qml/qml/qqmlpropertycachemethodarguments_p.h (renamed from src/qml/jsruntime/qv4serialize_p.h)31
-rw-r--r--src/qml/qml/qqmlpropertycachevector_p.h (renamed from src/qml/debugger/qqmlmemoryprofiler_p.h)106
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h411
-rw-r--r--src/qml/qml/qqmlpropertyresolver.cpp92
-rw-r--r--src/qml/qml/qqmlpropertyresolver_p.h87
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp (renamed from src/qml/compiler/qqmlpropertyvalidator.cpp)175
-rw-r--r--src/qml/qml/qqmlpropertyvalidator_p.h (renamed from src/qml/compiler/qqmlpropertyvalidator_p.h)36
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp263
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h97
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp166
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h (renamed from src/qml/types/qquickworkerscript_p.h)92
-rw-r--r--src/qml/qml/qqmlsourcecoordinate_p.h95
-rw-r--r--src/qml/qml/qqmlstaticmetaobject.cpp51
-rw-r--r--src/qml/qml/qqmlstaticmetaobject_p.h68
-rw-r--r--src/qml/qml/qqmltype.cpp885
-rw-r--r--src/qml/qml/qqmltype_p.h196
-rw-r--r--src/qml/qml/qqmltype_p_p.h170
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp (renamed from src/qml/compiler/qqmltypecompiler.cpp)259
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h (renamed from src/qml/compiler/qqmltypecompiler_p.h)40
-rw-r--r--src/qml/qml/qqmltypedata.cpp846
-rw-r--r--src/qml/qml/qqmltypedata_p.h163
-rw-r--r--src/qml/qml/qqmltypeloader.cpp2289
-rw-r--r--src/qml/qml/qqmltypeloader_p.h436
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp74
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h86
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp121
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h (renamed from src/qml/types/qquickpackage_p.h)60
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp198
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h110
-rw-r--r--src/qml/qml/qqmltypemodule.cpp174
-rw-r--r--src/qml/qml/qqmltypemodule_p.h102
-rw-r--r--src/qml/qml/qqmltypemodule_p_p.h89
-rw-r--r--src/qml/qml/qqmltypemoduleversion.cpp95
-rw-r--r--src/qml/qml/qqmltypemoduleversion_p.h87
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h3
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp244
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h6
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp61
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h3
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp385
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h6
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp24
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp67
-rw-r--r--src/qml/qml/v8/qv8engine.cpp331
-rw-r--r--src/qml/qml/v8/qv8engine_p.h243
-rw-r--r--src/qml/qml/v8/v8.pri2
-rw-r--r--src/qml/qmldirparser/qmldirparser.pri7
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp36
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h12
-rw-r--r--src/qml/qtqmlcompilerglobal.h58
-rw-r--r--src/qml/qtqmlcompilerglobal_p.h59
-rw-r--r--src/qml/qtqmlglobal.h4
-rw-r--r--src/qml/qtqmlglobal_p.h3
-rw-r--r--src/qml/types/qqmlbind.cpp196
-rw-r--r--src/qml/types/qqmlbind_p.h27
-rw-r--r--src/qml/types/qqmlconnections.cpp81
-rw-r--r--src/qml/types/qqmlconnections_p.h12
-rw-r--r--src/qml/types/qqmldelegatecomponent.cpp321
-rw-r--r--src/qml/types/qqmldelegatecomponent_p.h155
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp3557
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h249
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h450
-rw-r--r--src/qml/types/qqmlinstantiator.cpp509
-rw-r--r--src/qml/types/qqmlinstantiator_p.h119
-rw-r--r--src/qml/types/qqmlinstantiator_p_p.h98
-rw-r--r--src/qml/types/qqmlitemmodels.qdoc110
-rw-r--r--src/qml/types/qqmlitemselectionmodel.qdoc239
-rw-r--r--src/qml/types/qqmllistmodel.cpp2900
-rw-r--r--src/qml/types/qqmllistmodel_p.h208
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h428
-rw-r--r--src/qml/types/qqmllistmodelworkeragent.cpp177
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h140
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp82
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp431
-rw-r--r--src/qml/types/qqmlobjectmodel_p.h193
-rw-r--r--src/qml/types/qqmltableinstancemodel.cpp547
-rw-r--r--src/qml/types/qqmltableinstancemodel_p.h162
-rw-r--r--src/qml/types/qquickpackage.cpp198
-rw-r--r--src/qml/types/qquickworkerscript.cpp675
-rw-r--r--src/qml/types/types.pri45
-rw-r--r--src/qml/util/qqmladaptormodel.cpp1044
-rw-r--r--src/qml/util/qqmladaptormodel_p.h179
-rw-r--r--src/qml/util/qqmlchangeset.cpp583
-rw-r--r--src/qml/util/qqmlchangeset_p.h161
-rw-r--r--src/qml/util/qqmllistaccessor.cpp160
-rw-r--r--src/qml/util/qqmllistcompositor.cpp1482
-rw-r--r--src/qml/util/qqmllistcompositor_p.h372
-rw-r--r--src/qml/util/util.pri14
318 files changed, 17365 insertions, 31240 deletions
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
new file mode 100644
index 0000000000..bcc3ea0fa0
--- /dev/null
+++ b/src/qml/common/common.pri
@@ -0,0 +1,35 @@
+!build_pass {
+ # Create a header containing a hash that describes this library. For a
+ # released version of Qt, we'll use the .tag file that is updated by git
+ # archive with the commit hash. For unreleased versions, we'll ask git
+ # describe. Note that it won't update unless qmake is run again, even if
+ # the commit change also changed something in this library.
+ tagFile = $$PWD/../../.tag
+ tag =
+ exists($$tagFile) {
+ tag = $$cat($$tagFile, singleline)
+ QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
+ }
+ !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
+ QML_COMPILE_HASH = $$tag
+ } else:exists($$PWD/../../.git) {
+ commit = $$system(git rev-parse HEAD)
+ QML_COMPILE_HASH = $$commit
+ }
+ compile_hash_contents = \
+ "// Generated file, DO NOT EDIT" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
+ write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
+}
+
+HEADERS += \
+ $$PWD/qqmlapiversion_p.h \
+ $$PWD/qqmljsdiagnosticmessage_p.h \
+ $$PWD/qqmljsfixedpoolarray_p.h \
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qv4alloca_p.h \
+ $$PWD/qv4calldata_p.h \
+ $$PWD/qv4compileddata_p.h \
+ $$PWD/qv4staticvalue_p.h \
+ $$PWD/qv4stringtoarrayindex_p.h
diff --git a/src/qml/common/qqmlapiversion_p.h b/src/qml/common/qqmlapiversion_p.h
new file mode 100644
index 0000000000..eca05558d8
--- /dev/null
+++ b/src/qml/common/qqmlapiversion_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLAPIVERSION_P_H
+#define QQMLAPIVERSION_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.
+//
+
+#define Q_QML_PRIVATE_API_VERSION 5
+
+#endif // QQMLAPIVERSION_P_H
diff --git a/src/qml/common/qqmljsdiagnosticmessage_p.h b/src/qml/common/qqmljsdiagnosticmessage_p.h
new file mode 100644
index 0000000000..763332ba76
--- /dev/null
+++ b/src/qml/common/qqmljsdiagnosticmessage_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSDIAGNOSTICMESSAGE_P_H
+#define QQMLJSDIAGNOSTICMESSAGE_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/qlogging.h>
+#include <QtCore/qstring.h>
+
+// Include the API version here, to avoid complications when querying it for the
+// QQmlSourceLocation -> line/column change.
+#include <private/qqmlapiversion_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+struct DiagnosticMessage
+{
+ QString message;
+ QtMsgType type = QtCriticalMsg;
+ quint32 line = 0;
+ quint32 column = 0;
+
+ bool isError() const
+ {
+ return type == QtCriticalMsg;
+ }
+
+ bool isWarning() const
+ {
+ return type == QtWarningMsg;
+ }
+
+ bool isValid() const
+ {
+ return !message.isEmpty();
+ }
+};
+} // namespace QQmlJS
+
+Q_DECLARE_TYPEINFO(QQmlJS::DiagnosticMessage, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSDIAGNOSTICMESSAGE_P_H
diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h
new file mode 100644
index 0000000000..b65b994d6c
--- /dev/null
+++ b/src/qml/common/qqmljsfixedpoolarray_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSFIXEDPOOLARRAY_P_H
+#define QQMLJSFIXEDPOOLARRAY_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/qglobal.h>
+#include <private/qqmljsmemorypool_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+template <typename T>
+class FixedPoolArray
+{
+ T *data;
+ int count = 0;
+
+public:
+ FixedPoolArray()
+ : data(nullptr)
+ {}
+
+ FixedPoolArray(MemoryPool *pool, int size)
+ { allocate(pool, size); }
+
+ void allocate(MemoryPool *pool, int size)
+ {
+ count = size;
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ }
+
+ void allocate(MemoryPool *pool, const QVector<T> &vector)
+ {
+ count = vector.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+
+ if (QTypeInfo<T>::isComplex) {
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(vector.at(i));
+ } else {
+ memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
+ }
+ }
+
+ template <typename Container>
+ void allocate(MemoryPool *pool, const Container &container)
+ {
+ count = container.count();
+ data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
+ typename Container::ConstIterator it = container.constBegin();
+ for (int i = 0; i < count; ++i)
+ new (data + i) T(*it++);
+ }
+
+ int size() const
+ { return count; }
+
+ const T &at(int index) const {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &at(int index) {
+ Q_ASSERT(index >= 0 && index < count);
+ return data[index];
+ }
+
+ T &operator[](int index) {
+ return at(index);
+ }
+
+
+ int indexOf(const T &value) const {
+ for (int i = 0; i < count; ++i)
+ if (data[i] == value)
+ return i;
+ return -1;
+ }
+
+ const T *begin() const { return data; }
+ const T *end() const { return data + count; }
+
+ T *begin() { return data; }
+ T *end() { return data + count; }
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSFIXEDPOOLARRAY_P_H
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/common/qqmljsmemorypool_p.h
index e7b1f46414..0cf7ea84e6 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/common/qqmljsmemorypool_p.h
@@ -51,8 +51,6 @@
// We mean it.
//
-#include "qqmljsglobal_p.h"
-
#include <QtCore/qglobal.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qdebug.h>
@@ -65,7 +63,7 @@ namespace QQmlJS {
class Managed;
-class QML_PARSER_EXPORT MemoryPool : public QSharedData
+class MemoryPool : public QSharedData
{
MemoryPool(const MemoryPool &other);
void operator =(const MemoryPool &other);
@@ -162,7 +160,7 @@ private:
};
};
-class QML_PARSER_EXPORT Managed
+class Managed
{
Q_DISABLE_COPY(Managed)
public:
@@ -174,81 +172,6 @@ public:
void operator delete(void *, MemoryPool *) {}
};
-template <typename T>
-class FixedPoolArray
-{
- T *data;
- int count = 0;
-
-public:
- FixedPoolArray()
- : data(nullptr)
- {}
-
- FixedPoolArray(MemoryPool *pool, int size)
- { allocate(pool, size); }
-
- void allocate(MemoryPool *pool, int size)
- {
- count = size;
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
- }
-
- void allocate(MemoryPool *pool, const QVector<T> &vector)
- {
- count = vector.count();
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
-
- if (QTypeInfo<T>::isComplex) {
- for (int i = 0; i < count; ++i)
- new (data + i) T(vector.at(i));
- } else {
- memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
- }
- }
-
- template <typename Container>
- void allocate(MemoryPool *pool, const Container &container)
- {
- count = container.count();
- data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
- typename Container::ConstIterator it = container.constBegin();
- for (int i = 0; i < count; ++i)
- new (data + i) T(*it++);
- }
-
- int size() const
- { return count; }
-
- const T &at(int index) const {
- Q_ASSERT(index >= 0 && index < count);
- return data[index];
- }
-
- T &at(int index) {
- Q_ASSERT(index >= 0 && index < count);
- return data[index];
- }
-
- T &operator[](int index) {
- return at(index);
- }
-
-
- int indexOf(const T &value) const {
- for (int i = 0; i < count; ++i)
- if (data[i] == value)
- return i;
- return -1;
- }
-
- const T *begin() const { return data; }
- const T *end() const { return data + count; }
-
- T *begin() { return data; }
- T *end() { return data + count; }
-};
-
} // namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index 65c3e4d65a..65c3e4d65a 100644
--- a/src/qml/jsruntime/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/common/qv4calldata_p.h
index d9abfc071e..5a5280cb86 100644
--- a/src/qml/jit/qv4jithelpers_p.h
+++ b/src/qml/common/qv4calldata_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef TEMPLATE_H
-#define TEMPLATE_H
+#ifndef QV4CALLDATA_P_H
+#define QV4CALLDATA_P_H
//
// W A R N I N G
@@ -51,42 +51,73 @@
// We mean it.
//
-#include <private/qv4global_p.h>
-
-//QT_REQUIRE_CONFIG(qml_jit);
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-#ifdef V4_ENABLE_JIT
+struct CallData
+{
+ enum Offsets {
+ Function = 0,
+ Context = 1,
+ Accumulator = 2,
+ This = 3,
+ NewTarget = 4,
+ Argc = 5,
+
+ LastOffset = Argc,
+ OffsetCount = LastOffset + 1
+ };
+
+ StaticValue function;
+ StaticValue context;
+ StaticValue accumulator;
+ StaticValue thisObject;
+ StaticValue newTarget;
+ StaticValue _argc;
+
+ int argc() const {
+ Q_ASSERT(_argc.isInteger());
+ return _argc.int_32();
+ }
+
+ void setArgc(int argc) {
+ Q_ASSERT(argc >= 0);
+ _argc.setInt_32(argc);
+ }
+
+ inline ReturnedValue argument(int i) const {
+ return i < argc() ? args[i].asReturnedValue()
+ : StaticValue::undefinedValue().asReturnedValue();
+ }
+
+ StaticValue args[1];
-namespace JIT {
-namespace Helpers {
+ static Q_DECL_CONSTEXPR int HeaderSize()
+ {
+ return offsetof(CallData, args) / sizeof(QV4::StaticValue);
+ }
-void convertThisToObject(ExecutionEngine *engine, Value *t);
-ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index);
-ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index);
-ReturnedValue toObject(ExecutionEngine *engine, const Value &obj);
-ReturnedValue exp(const Value &base, const Value &exp);
-ReturnedValue getLookup(Function *f, ExecutionEngine *engine, const Value &base, int index);
-void setLookupStrict(Function *f, int index, Value &base, const Value &value);
-void setLookupSloppy(Function *f, int index, Value &base, const Value &value);
-void pushBlockContext(Value *stack, int index);
-void cloneBlockContext(Value *contextSlot);
-void pushScriptContext(Value *stack, ExecutionEngine *engine, int index);
-void popScriptContext(Value *stack, ExecutionEngine *engine);
-ReturnedValue deleteProperty(QV4::Function *function, const QV4::Value &base, const QV4::Value &index);
-ReturnedValue deleteName(Function *function, int name);
-void throwOnNullOrUndefined(ExecutionEngine *engine, const Value &v);
+ template<typename Value>
+ Value *argValues();
-} // Helpers namespace
-} // JIT namespace
+ template<typename Value>
+ const Value *argValues() const;
+};
-#endif // V4_ENABLE_JIT
+Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
+Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(StaticValue));
+Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(StaticValue));
-} // QV4 namespace
+} // namespace QV4
QT_END_NAMESPACE
-#endif // TEMPLATE_H
+#endif // QV4CALLDATA_P_H
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 9050cfba94..c3ddce5884 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -50,36 +50,35 @@
// We mean it.
//
+#include <functional>
+
#include <QtCore/qstring.h>
-#include <QVector>
-#include <QStringList>
-#include <QHash>
-#include <QUrl>
-
-#include <private/qv4value_p.h>
-#include <private/qv4executableallocator_p.h>
-#include <private/qqmlrefcount_p.h>
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qv4identifier_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qendian_p.h>
-#include <private/qqmljsastfwd_p.h>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmltypenamecache_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include "private/qintrusivelist_p.h"
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
+
+#if QT_CONFIG(temporaryfile)
+#include <QtCore/qsavefile.h>
#endif
+#include <private/qendian_p.h>
+#include <private/qv4staticvalue_p.h>
+#include <functional>
+
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x21
+//
+// IMPORTANT:
+//
+// Also change the comment behind the number to describe the latest change. This has the added
+// benefit that if another patch changes the version too, it will result in a merge conflict, and
+// not get removed silently.
+#define QV4_DATA_STRUCTURE_VERSION 0x24 // Collect function parameter types
class QIODevice;
-class QQmlPropertyCache;
-class QQmlPropertyData;
class QQmlTypeNameCache;
-class QQmlScriptData;
class QQmlType;
class QQmlEngine;
@@ -88,14 +87,14 @@ struct Document;
}
namespace QV4 {
-
namespace Heap {
struct Module;
+struct String;
+struct InternalClass;
};
struct Function;
class EvalISelFactory;
-class CompilationUnitMapper;
namespace CompiledData {
@@ -128,8 +127,6 @@ struct Location
Location() : _dummy(0) { }
- Location &operator=(const QQmlJS::AST::SourceLocation &astLocation);
-
inline bool operator<(const Location &other) const {
return line < other.line ||
(line == other.line && column < other.column);
@@ -259,6 +256,29 @@ struct Block
};
static_assert(sizeof(Block) == 12, "Block structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+enum class BuiltinType : unsigned int {
+ Var = 0, Variant, Int, Bool, Real, String, Url, Color,
+ Font, Time, Date, DateTime, Rect, Point, Size,
+ Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin
+};
+
+struct ParameterType
+{
+ union {
+ quint32 _dummy;
+ quint32_le_bitfield<0, 1> indexIsBuiltinType;
+ quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
+ };
+};
+static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
+struct Parameter
+{
+ quint32_le nameIndex;
+ ParameterType type;
+};
+static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
// for unaligned access. The ordering of the fields is also from largest to smallest.
struct Function
@@ -277,6 +297,7 @@ struct Function
quint16_le length;
quint16_le nFormals;
quint32_le formalsOffset; // Can't turn this into a calculated offset because of the mutation in CompilationUnit::createUnitData.
+ ParameterType returnType;
quint32_le localsOffset;
quint16_le nLocals;
quint16_le nLineNumbers;
@@ -291,10 +312,6 @@ struct Function
quint32_le nLabelInfos;
size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
- typedef quint16_le TraceInfoCount;
- TraceInfoCount nTraceInfos;
- static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
-
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
@@ -302,13 +319,13 @@ struct Function
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
- const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); }
+ const Parameter *formalsTable() const { return reinterpret_cast<const Parameter *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
// --- QQmlPropertyCacheCreator interface
- const quint32_le *formalsBegin() const { return formalsTable(); }
- const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
+ const Parameter *formalsBegin() const { return formalsTable(); }
+ const Parameter *formalsEnd() const { return formalsTable() + nFormals; }
// ---
const quint32_le *labelInfoTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + labelInfosOffset()); }
@@ -316,7 +333,7 @@ struct Function
const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
- int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ int trailingData = nFormals * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ nLines*sizeof(CodeOffsetToLine);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
@@ -327,7 +344,7 @@ struct Function
return (a + 7) & ~size_t(7);
}
};
-static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Function) == 56, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Method {
enum Type {
@@ -415,7 +432,7 @@ static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have th
// Qml data structures
-struct Q_QML_EXPORT TranslationData
+struct TranslationData
{
quint32_le stringIndex;
quint32_le commentIndex;
@@ -424,7 +441,7 @@ struct Q_QML_EXPORT TranslationData
};
static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-struct Q_QML_PRIVATE_EXPORT Binding
+struct Binding
{
quint32_le propertyNameIndex;
@@ -521,22 +538,52 @@ struct Q_QML_PRIVATE_EXPORT Binding
bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
- static QString escapedString(const QString &string);
+ //reverse of Lexer::singleEscape()
+ static QString escapedString(const QString &string)
+ {
+ QString tmp = QLatin1String("\"");
+ for (int i = 0; i < string.length(); ++i) {
+ const QChar &c = string.at(i);
+ switch (c.unicode()) {
+ case 0x08:
+ tmp += QLatin1String("\\b");
+ break;
+ case 0x09:
+ tmp += QLatin1String("\\t");
+ break;
+ case 0x0A:
+ tmp += QLatin1String("\\n");
+ break;
+ case 0x0B:
+ tmp += QLatin1String("\\v");
+ break;
+ case 0x0C:
+ tmp += QLatin1String("\\f");
+ break;
+ case 0x0D:
+ tmp += QLatin1String("\\r");
+ break;
+ case 0x22:
+ tmp += QLatin1String("\\\"");
+ break;
+ case 0x27:
+ tmp += QLatin1String("\\\'");
+ break;
+ case 0x5C:
+ tmp += QLatin1String("\\\\");
+ break;
+ default:
+ tmp += c;
+ break;
+ }
+ }
+ tmp += QLatin1Char('\"');
+ return tmp;
+ }
bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
-#ifndef V4_BOOTSTRAP
- QString valueAsString(const CompilationUnit *unit) const;
- QString valueAsScriptString(const CompilationUnit *unit) const;
-#endif
- double valueAsNumber(const Value *constantTable) const
- {
- if (type != Type_Number)
- return 0.0;
- return constantTable[value.constantValueIndex].doubleValue();
- }
-
bool valueAsBoolean() const
{
if (type == Type_Boolean)
@@ -580,15 +627,6 @@ struct Enum
};
static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-struct Parameter
-{
- quint32_le nameIndex;
- quint32_le type;
- quint32_le customTypeNameIndex;
- Location location;
-};
-static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
struct Signal
{
quint32_le nameIndex;
@@ -616,24 +654,33 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected
struct Property
{
- enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
- Font, Time, Date, DateTime, Rect, Point, Size,
- Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
- Custom, CustomList };
-
- enum Flags : unsigned int {
- IsReadOnly = 0x1
- };
-
quint32_le nameIndex;
union {
- quint32_le_bitfield<0, 31> type;
- quint32_le_bitfield<31, 1> flags; // readonly
+ quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex;
+ quint32_le_bitfield<29, 1> isBuiltinType;
+ quint32_le_bitfield<30, 1> isList;
+ quint32_le_bitfield<31, 1> isReadOnly;
};
- quint32_le customTypeNameIndex; // If type >= Custom
+
Location location;
+
+ void setBuiltinType(BuiltinType t)
+ {
+ builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
+ isBuiltinType = true;
+ }
+ BuiltinType builtinType() const {
+ if (isBuiltinType)
+ return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
+ return BuiltinType::InvalidBuiltin;
+ }
+ void setCustomType(int nameIndex)
+ {
+ builtinTypeOrTypeNameIndex = nameIndex;
+ isBuiltinType = false;
+ }
};
-static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Alias {
enum Flags : unsigned int {
@@ -830,7 +877,6 @@ static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expect
enum { QmlCompileHashSpace = 48 };
static const char magic_str[] = "qv4cdata";
-extern const char qml_compile_hash[QmlCompileHashSpace + 1];
struct Unit
{
@@ -845,8 +891,6 @@ struct Unit
char libraryVersionHash[QmlCompileHashSpace];
char md5Checksum[16]; // checksum of all bytes following this field.
- void generateChecksum();
-
char dependencyMD5Checksum[16];
enum : unsigned int {
@@ -894,8 +938,6 @@ struct Unit
quint32_le offsetToQmlUnit;
- bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
-
/* QML specific fields */
const QmlUnit *qmlUnit() const {
@@ -1029,8 +1071,8 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto prop = obj->propertiesBegin();
auto propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
- if (prop->type >= QV4::CompiledData::Property::Custom) {
- TypeReference &r = this->add(prop->customTypeNameIndex, prop->location);
+ if (!prop->isBuiltinType) {
+ TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
r.errorWhenNotFound = true;
}
}
@@ -1051,142 +1093,144 @@ struct TypeReferenceMap : QHash<int, TypeReference>
}
};
-#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference;
-// map from name index
-// While this could be a hash, a map is chosen here to provide a stable
-// order, which is used to calculating a check-sum on dependent meta-objects.
-struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
+using DependentTypesHasher = std::function<QByteArray()>;
+
+// This is how this hooks into the existing structures:
+
+struct CompilationUnitBase
{
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
-};
+ Q_DISABLE_COPY(CompilationUnitBase)
-using DependentTypesHasher = std::function<bool(QCryptographicHash *)>;
-#else
-struct DependentTypesHasher {};
-#endif
+ CompilationUnitBase() = default;
+ ~CompilationUnitBase() = default;
-// index is per-object binding index
-typedef QVector<QQmlPropertyData*> BindingPropertyData;
+ CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); }
-// This is how this hooks into the existing structures:
+ CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept
+ {
+ if (this != &other) {
+ runtimeStrings = other.runtimeStrings;
+ other.runtimeStrings = nullptr;
+ constants = other.constants;
+ other.constants = nullptr;
+ runtimeRegularExpressions = other.runtimeRegularExpressions;
+ other.runtimeRegularExpressions = nullptr;
+ runtimeClasses = other.runtimeClasses;
+ other.runtimeClasses = nullptr;
+ imports = other.imports;
+ other.imports = nullptr;
+ }
+ return *this;
+ }
-struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
-{
// pointers either to data->constants() or little-endian memory copy.
- QV4::Heap::String **runtimeStrings = nullptr; // Array
- const Value* constants = nullptr;
- QV4::Value *runtimeRegularExpressions = nullptr;
- QV4::Heap::InternalClass **runtimeClasses = nullptr;
- const Value** imports = nullptr;
+ Heap::String **runtimeStrings = nullptr; // Array
+ const StaticValue* constants = nullptr;
+ QV4::StaticValue *runtimeRegularExpressions = nullptr;
+ Heap::InternalClass **runtimeClasses = nullptr;
+ const StaticValue** imports = nullptr;
};
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const Value *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const Value *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
+Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
-struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase
+struct CompilationUnit : public CompilationUnitBase
{
+ Q_DISABLE_COPY(CompilationUnit)
+
const Unit *data = nullptr;
const QmlUnit *qmlData = nullptr;
+ QStringList dynamicStrings;
public:
- CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString());
- ~CompilationUnit();
+ using CompiledObject = CompiledData::Object;
- void addref()
+ CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
+ const QString &finalUrlString = QString())
{
- Q_ASSERT(refCount.load() > 0);
- refCount.ref();
+ setUnitData(unitData, nullptr, fileName, finalUrlString);
}
- void release()
- {
- Q_ASSERT(refCount.load() > 0);
- if (!refCount.deref())
- destroy();
- }
- int count() const
+ ~CompilationUnit()
{
- return refCount.load();
- }
-
- const Unit *unitData() const { return data; }
- void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
- const QString &fileName = QString(), const QString &finalUrlString = QString());
+ if (data) {
+ if (data->qmlUnit() != qmlData)
+ free(const_cast<QmlUnit *>(qmlData));
+ qmlData = nullptr;
-#ifndef V4_BOOTSTRAP
- QIntrusiveListNode nextCompilationUnit;
- ExecutionEngine *engine = nullptr;
- QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
+ if (!(data->flags & QV4::CompiledData::Unit::StaticData))
+ free(const_cast<Unit *>(data));
+ }
+ data = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+ constants = nullptr;
+#endif
- // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
- // warnings about that code. They include any potential URL interceptions and thus represent the
- // "physical" location of the code.
- //
- // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
- // They are _not_ intercepted and thus represent the "logical" name for the code.
+ delete [] imports;
+ imports = nullptr;
+ }
- QString fileName() const { return m_fileName; }
- QString finalUrlString() const { return m_finalUrlString; }
- QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QUrl finalUrl() const
+ CompilationUnit(CompilationUnit &&other) noexcept
{
- if (m_finalUrl.isNull)
- m_finalUrl = QUrl(finalUrlString());
- return m_finalUrl;
+ *this = std::move(other);
}
- QV4::Lookup *runtimeLookups = nullptr;
- QVector<QV4::Function *> runtimeFunctions;
- QVector<QV4::Heap::InternalClass *> runtimeBlocks;
- mutable QVector<QV4::Heap::Object *> templateObjects;
- mutable QQmlNullableValue<QUrl> m_url;
- mutable QQmlNullableValue<QUrl> m_finalUrl;
-
- // QML specific fields
- QQmlPropertyCacheVector propertyCaches;
- QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
-
- // index is object index. This allows fast access to the
- // property data when initializing bindings, avoiding expensive
- // lookups by string (property name).
- QVector<BindingPropertyData> bindingPropertyDataPerObject;
-
- // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
- // this is initialized on-demand by QQmlContextData
- QHash<int, IdentifierHash> namedObjectsPerComponentCache;
- inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
-
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
-
- int totalBindingsCount = 0; // Number of bindings used in this type
- int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount = 0; // Number of objects explicitly instantiated
-
- QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
- ResolvedTypeReferenceMap resolvedTypes;
- ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
+ CompilationUnit &operator=(CompilationUnit &&other) noexcept
+ {
+ if (this != &other) {
+ data = other.data;
+ other.data = nullptr;
+ qmlData = other.qmlData;
+ other.qmlData = nullptr;
+ dynamicStrings = std::move(other.dynamicStrings);
+ other.dynamicStrings.clear();
+ m_fileName = std::move(other.m_fileName);
+ other.m_fileName.clear();
+ m_finalUrlString = std::move(other.m_finalUrlString);
+ other.m_finalUrlString.clear();
+ m_module = other.m_module;
+ other.m_module = nullptr;
+ CompilationUnitBase::operator=(std::move(other));
+ }
+ return *this;
+ }
- bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const;
+ const Unit *unitData() const { return data; }
- int metaTypeId = -1;
- int listMetaTypeId = -1;
- bool isRegisteredWithEngine = false;
+ void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
+ const QString &fileName = QString(), const QString &finalUrlString = QString())
+ {
+ data = unitData;
+ qmlData = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+#endif
+ constants = nullptr;
+ m_fileName.clear();
+ m_finalUrlString.clear();
+ if (!data)
+ return;
+
+ qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize];
+ const quint64_le *littleEndianConstants = data->constants();
+ for (uint i = 0; i < data->constantTableSize; ++i)
+ bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]);
+ constants = bigEndianConstants;
+#else
+ constants = reinterpret_cast<const StaticValue*>(data->constants());
+#endif
- QScopedPointer<CompilationUnitMapper> backingFile;
- QStringList dynamicStrings;
+ m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
+ m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
+ }
- // --- interface for QQmlPropertyCacheCreator
- typedef Object CompiledObject;
- int objectCount() const { return qmlData->nObjects; }
- const Object *objectAt(int index) const { return qmlData->objectAt(index); }
- int importCount() const { return qmlData->nImports; }
- const Import *importAt(int index) const { return qmlData->importAt(index); }
QString stringAt(int index) const
{
if (uint(index) >= data->stringTableSize)
@@ -1194,117 +1238,84 @@ public:
return data->stringAtInternal(index);
}
- Heap::Object *templateObjectAt(int index) const;
-
- struct FunctionIterator
- {
- FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {}
- const Unit *unit;
- const Object *object;
- int index;
-
- const Function *operator->() const { return unit->functionAt(object->functionOffsetTable()[index]); }
- void operator++() { ++index; }
- bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
- bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
- };
- FunctionIterator objectFunctionsBegin(const Object *object) const { return FunctionIterator(data, object, 0); }
- FunctionIterator objectFunctionsEnd(const Object *object) const { return FunctionIterator(data, object, object->nFunctions); }
- // ---
-
- bool isESModule() const { return data->flags & Unit::IsESModule; }
- bool isSharedLibrary() const { return data->flags & Unit::IsSharedLibrary; }
- QStringList moduleRequests() const;
- Heap::Module *instantiate(ExecutionEngine *engine);
- const Value *resolveExport(QV4::String *exportName);
- QStringList exportedNames() const;
- void evaluate();
- void evaluateModuleRequests();
-
- QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
- void unlink();
-
- void markObjects(MarkStack *markStack);
-
- bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
-
- static QString localCacheFilePath(const QUrl &url);
-
-protected:
- quint32 totalStringCount() const
- { return data->stringTableSize; }
+ QString fileName() const { return m_fileName; }
+ QString finalUrlString() const { return m_finalUrlString; }
-#else // V4_BOOTSTRAP
- QString stringAt(int index) const { return data->stringAtInternal(index); }
-#endif // V4_BOOTSTRAP
+ Heap::Module *module() const { return m_module; }
+ void setModule(Heap::Module *module) { m_module = module; }
private:
- void destroy();
-
- struct ResolveSetEntry
- {
- ResolveSetEntry() {}
- ResolveSetEntry(CompilationUnit *module, QV4::String *exportName)
- : module(module), exportName(exportName) {}
- CompilationUnit *module = nullptr;
- QV4::String *exportName = nullptr;
- };
-
- const Value *resolveExportRecursively(QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet);
- const ExportEntry *lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const;
- void getExportedNamesRecursively(QStringList *names, QVector<const CompilationUnit *> *exportNameSet, bool includeDefaultExport = true) const;
-
QString m_fileName; // initialized from data->sourceFileIndex
QString m_finalUrlString; // initialized from data->finalUrlIndex
- QAtomicInt refCount = 1;
-
- Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
-
Heap::Module *m_module = nullptr;
+};
+class SaveableUnitPointer
+{
+ Q_DISABLE_COPY_MOVE(SaveableUnitPointer)
public:
-#if defined(V4_BOOTSTRAP)
- bool saveToDisk(const QString &outputFileName, QString *errorString);
+ SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) :
+ unit(unit),
+ temporaryFlags(temporaryFlags)
+ {
+ }
+
+ ~SaveableUnitPointer() = default;
+
+ template<typename Char>
+ bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
+ {
+ auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
+ mutableFlags() |= temporaryFlags;
+ return writer(data<Char>(), size());
+ }
+
+ static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size,
+ QString *errorString)
+ {
+#if QT_CONFIG(temporaryfile)
+ QSaveFile cacheFile(outputFileName);
+ if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)
+ || cacheFile.write(data, size) != size
+ || !cacheFile.commit()) {
+ *errorString = cacheFile.errorString();
+ return false;
+ }
+
+ errorString->clear();
+ return true;
#else
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+ Q_UNUSED(outputFileName)
+ *errorString = QStringLiteral("features.temporaryfile is disabled.");
+ return false;
#endif
-};
-
-#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
+ }
- QQmlType type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+private:
+ const Unit *unit;
+ quint32 temporaryFlags;
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
+ quint32_le &mutableFlags() const
+ {
+ return const_cast<Unit *>(unit)->flags;
+ }
- QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
- QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
+ template<typename Char>
+ const Char *data() const
+ {
+ Q_STATIC_ASSERT(sizeof(Char) == 1);
+ const Char *dataPtr;
+ memcpy(&dataPtr, &unit, sizeof(dataPtr));
+ return dataPtr;
+ }
- void doDynamicTypeCheck();
+ quint32 size() const
+ {
+ return unit->unitSize;
+ }
};
-IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
-{
- auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
- if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
- return createNamedObjectsPerComponent(componentObjectIndex);
- return *it;
-}
-#endif // V4_BOOTSTRAP
} // CompiledData namespace
} // QV4 namespace
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
new file mode 100644
index 0000000000..0716f7ea20
--- /dev/null
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STATICVALUE_P_H
+#define QV4STATICVALUE_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/private/qnumeric_p.h>
+#include <cstring>
+
+#ifdef QT_NO_DEBUG
+#define QV4_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
+#else
+#define QV4_NEARLY_ALWAYS_INLINE inline
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+// ReturnedValue is used to return values from runtime methods
+// the type has to be a primitive type (no struct or union), so that the compiler
+// will return it in a register on all platforms.
+// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
+typedef quint64 ReturnedValue;
+
+struct Double {
+ quint64 d;
+
+ Double(double dbl) {
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ int sign() const {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ bool isDenormal() const {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ int exponent() const {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ quint64 significant() const {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ static int toInt32(double d) {
+ int i = static_cast<int>(d);
+ if (i == d)
+ return i;
+ return Double(d).toInt32();
+ }
+
+ int toInt32() {
+ int e = exponent() - 52;
+ if (e < 0) {
+ if (e <= -53)
+ return 0;
+ return sign() * static_cast<int>(significant() >> -e);
+ } else {
+ if (e > 31)
+ return 0;
+ return sign() * (static_cast<int>(significant()) << e);
+ }
+ }
+};
+
+struct StaticValue
+{
+ StaticValue() = default;
+ constexpr StaticValue(quint64 val) : _val(val) {}
+
+ StaticValue &operator=(ReturnedValue v)
+ {
+ _val = v;
+ return *this;
+ }
+
+ template<typename Value>
+ StaticValue &operator=(const Value &);
+
+ template<typename Value>
+ const Value &asValue() const;
+
+ template<typename Value>
+ Value &asValue();
+
+ /*
+ We use 8 bytes for a value and a different variant of NaN boxing. A Double
+ NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
+ signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
+ processor, and are thus free for us to store other data. We keep pointers in there for
+ managed objects, and encode the other types using the free space given to use by the unused
+ bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
+ only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
+ pointers.)
+
+ We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
+ get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
+ managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
+ the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
+ set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
+ used to encode Null/Int/Bool.
+
+ Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
+
+ Specific bit-sequences:
+ 0 = always 0
+ 1 = always 1
+ x = stored value
+ a,b,c,d = specific bit values, see notes
+
+ 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
+ 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
+ ------------------------------------------------------------------------+--------------
+ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
+ 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
+ a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
+ dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
+ 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
+ 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
+ 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
+ 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
+
+ Notes:
+ - a: xor-ed signbit, always 1 for NaN
+ - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
+ - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
+ - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
+ and JS
+ - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
+ - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
+ so: (val >> (64-15)) == 1
+ - Null, Bool, and Int have bit 48 set, indicating integer-convertible
+ - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
+ any non double results in a NaN
+ - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
+ 63) are zero. No need to shift.
+ */
+
+ quint64 _val;
+
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 0; }
+ static inline int tagOffset() { return 4; }
+#else // !Q_LITTLE_ENDIAN
+ static inline int valueOffset() { return 4; }
+ static inline int tagOffset() { return 0; }
+#endif
+ static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+
+ QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
+ {
+ return int(value());
+ }
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
+ {
+ setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
+ }
+ QV4_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
+
+ QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
+ {
+ setTagValue(quint32(ValueTypeInternal::Empty), 0);
+ }
+
+ // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
+ // and use negative numbers here
+ enum QuickType {
+ QT_ManagedOrUndefined = 0,
+ QT_ManagedOrUndefined1 = 1,
+ QT_ManagedOrUndefined2 = 2,
+ QT_ManagedOrUndefined3 = 3,
+ QT_Empty = 4,
+ QT_Null = 5,
+ QT_Bool = 6,
+ QT_Int = 7
+ // all other values are doubles
+ };
+
+ enum Type {
+ Undefined_Type = 0,
+ Managed_Type = 1,
+ Empty_Type = 4,
+ Null_Type = 5,
+ Boolean_Type = 6,
+ Integer_Type = 7,
+ Double_Type = 8
+ };
+
+ inline Type type() const {
+ int t = quickType();
+ if (t < QT_Empty)
+ return _val ? Managed_Type : Undefined_Type;
+ if (t > QT_Int)
+ return Double_Type;
+ return static_cast<Type>(t);
+ }
+
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-15,
+ IsIntegerOrBool_Shift = 64-16,
+ QuickType_Shift = 64 - 17,
+ IsPositiveIntShift = 31
+ };
+
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ enum class ValueTypeInternal_64 {
+ Empty = Immediate_Mask_64 | 0,
+ Null = Immediate_Mask_64 | 0x08000u,
+ Boolean = Immediate_Mask_64 | 0x10000u,
+ Integer = Immediate_Mask_64 | 0x18000u
+ };
+
+ // Used only by 32-bit encoding
+ enum Masks {
+ SilentNaNBit = 0x00040000,
+ NotDouble_Mask = 0x7ffa0000,
+ };
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
+
+ enum class ValueTypeInternal_32 {
+ Empty = Immediate_Mask_32 | 0,
+ Null = Immediate_Mask_32 | 0x08000u,
+ Boolean = Immediate_Mask_32 | 0x10000u,
+ Integer = Immediate_Mask_32 | 0x18000u
+ };
+
+ enum {
+ Managed_Type_Internal = 0
+ };
+
+ using ValueTypeInternal = ValueTypeInternal_64;
+
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
+
+ inline quint64 quickType() const { return (_val >> QuickType_Shift); }
+
+ // used internally in property
+ inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
+ inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
+ inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
+ inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
+ inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
+ inline bool isNumber() const { return quickType() >= QT_Int; }
+
+ inline bool isUndefined() const { return _val == 0; }
+ inline bool isDouble() const { return (_val >> IsDouble_Shift); }
+ inline bool isManaged() const
+ {
+#if QT_POINTER_SIZE == 4
+ return value() && tag() == Managed_Type_Internal;
+#else
+ return _val && ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+ inline bool isManagedOrUndefined() const
+ {
+#if QT_POINTER_SIZE == 4
+ return tag() == Managed_Type_Internal;
+#else
+ return ((_val >> IsManagedOrUndefined_Shift) == 0);
+#endif
+ }
+
+ inline bool isIntOrBool() const {
+ return (_val >> IsIntegerOrBool_Shift) == 3;
+ }
+
+ inline bool integerCompatible() const {
+ Q_ASSERT(!isEmpty());
+ return (_val >> IsIntegerConvertible_Shift) == 1;
+ }
+
+ static inline bool integerCompatible(StaticValue a, StaticValue b) {
+ return a.integerCompatible() && b.integerCompatible();
+ }
+
+ static inline bool bothDouble(StaticValue a, StaticValue b) {
+ return a.isDouble() && b.isDouble();
+ }
+
+ inline bool isNaN() const
+ {
+ return (tag() & 0x7ffc0000 ) == 0x00040000;
+ }
+
+ inline bool isPositiveInt() const {
+#if QT_POINTER_SIZE == 4
+ return isInteger() && int_32() >= 0;
+#else
+ return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
+#endif
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE double doubleValue() const {
+ Q_ASSERT(isDouble());
+ double d;
+ StaticValue v = *this;
+ v._val ^= NaNEncodeMask;
+ memcpy(&d, &v._val, 8);
+ return d;
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
+ if (qt_is_nan(d))
+ d = qt_qnan();
+ memcpy(&_val, &d, 8);
+ _val ^= NaNEncodeMask;
+ Q_ASSERT(isDouble());
+ }
+
+ inline bool isInt32() {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return true;
+ if (isDouble()) {
+ double d = doubleValue();
+ if (isInt32(d)) {
+ setInt_32(int(d));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ QV4_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
+ int i = int(d);
+ return (i == d && !(d == 0 && std::signbit(d)));
+ }
+
+ double asDouble() const {
+ if (tag() == quint32(ValueTypeInternal::Integer))
+ return int_32();
+ return doubleValue();
+ }
+
+ bool booleanValue() const {
+ return int_32();
+ }
+
+ int integerValue() const {
+ return int_32();
+ }
+
+ inline bool tryIntegerConversion() {
+ bool b = integerCompatible();
+ if (b)
+ setTagValue(quint32(ValueTypeInternal::Integer), value());
+ return b;
+ }
+
+ bool toBoolean() const {
+ if (integerCompatible())
+ return static_cast<bool>(int_32());
+
+ if (isManagedOrUndefined())
+ return false;
+
+ // double
+ const double d = doubleValue();
+ return d && !std::isnan(d);
+ }
+
+ inline int toInt32() const
+ {
+ switch (type()) {
+ case Null_Type:
+ case Boolean_Type:
+ case Integer_Type:
+ return int_32();
+ case Double_Type:
+ return Double::toInt32(doubleValue());
+ case Empty_Type:
+ case Undefined_Type:
+ case Managed_Type:
+ break;
+ }
+ return Double::toInt32(std::numeric_limits<double>::quiet_NaN());
+ }
+
+ ReturnedValue *data_ptr() { return &_val; }
+ constexpr ReturnedValue asReturnedValue() const { return _val; }
+ constexpr static StaticValue fromReturnedValue(ReturnedValue val) { return {val}; }
+
+ inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
+ static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
+ static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
+ inline static constexpr StaticValue undefinedValue() { return { 0 }; }
+ static inline constexpr StaticValue nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
+
+ static inline StaticValue fromDouble(double d)
+ {
+ StaticValue v;
+ v.setDouble(d);
+ return v;
+ }
+
+ static inline StaticValue fromUInt32(uint i)
+ {
+ StaticValue v;
+ if (i < uint(std::numeric_limits<int>::max())) {
+ v.setTagValue(quint32(ValueTypeInternal::Integer), i);
+ } else {
+ v.setDouble(i);
+ }
+ return v;
+ }
+
+ static double toInteger(double d)
+ {
+ if (std::isnan(d))
+ return +0;
+ if (!d || std::isinf(d))
+ return d;
+ return d >= 0 ? std::floor(d) : std::ceil(d);
+ }
+
+ static int toInt32(double d)
+ {
+ return Double::toInt32(d);
+ }
+
+ static unsigned int toUInt32(double d)
+ {
+ return static_cast<uint>(toInt32(d));
+ }
+};
+Q_STATIC_ASSERT(std::is_trivial<StaticValue>::value);
+
+struct Encode {
+ static constexpr ReturnedValue undefined() {
+ return StaticValue::undefinedValue().asReturnedValue();
+ }
+ static constexpr ReturnedValue null() {
+ return StaticValue::nullValue().asReturnedValue();
+ }
+
+ explicit constexpr Encode(bool b)
+ : val(StaticValue::fromBoolean(b).asReturnedValue())
+ {
+ }
+ explicit Encode(double d) {
+ val = StaticValue::fromDouble(d).asReturnedValue();
+ }
+ explicit constexpr Encode(int i)
+ : val(StaticValue::fromInt32(i).asReturnedValue())
+ {
+ }
+ explicit Encode(uint i) {
+ val = StaticValue::fromUInt32(i).asReturnedValue();
+ }
+ explicit constexpr Encode(ReturnedValue v)
+ : val(v)
+ {
+ }
+ constexpr Encode(StaticValue v)
+ : val(v.asReturnedValue())
+ {
+ }
+
+ template<typename HeapBase>
+ explicit Encode(HeapBase *o);
+
+ explicit Encode(StaticValue *o) {
+ Q_ASSERT(o);
+ val = o->asReturnedValue();
+ }
+
+ static ReturnedValue smallestNumber(double d) {
+ if (StaticValue::isInt32(d))
+ return Encode(static_cast<int>(d));
+ else
+ return Encode(d);
+ }
+
+ constexpr operator ReturnedValue() const {
+ return val;
+ }
+ quint64 val;
+private:
+ explicit Encode(void *);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4STATICVALUE_P_H
diff --git a/src/qml/common/qv4stringtoarrayindex_p.h b/src/qml/common/qv4stringtoarrayindex_p.h
new file mode 100644
index 0000000000..61bd988d1e
--- /dev/null
+++ b/src/qml/common/qv4stringtoarrayindex_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4STRINGTOARRAYINDEX_P_H
+#define QV4STRINGTOARRAYINDEX_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/private/qnumeric_p.h>
+#include <QtCore/qstring.h>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+inline uint charToUInt(const QChar *ch) { return ch->unicode(); }
+inline uint charToUInt(const char *ch) { return static_cast<unsigned char>(*ch); }
+
+template <typename T>
+uint stringToArrayIndex(const T *ch, const T *end)
+{
+ uint i = charToUInt(ch) - '0';
+ if (i > 9)
+ return std::numeric_limits<uint>::max();
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return std::numeric_limits<uint>::max();
+
+ while (ch < end) {
+ uint x = charToUInt(ch) - '0';
+ if (x > 9)
+ return std::numeric_limits<uint>::max();
+ if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
+ return std::numeric_limits<uint>::max();
+ ++ch;
+ }
+ return i;
+}
+
+inline uint stringToArrayIndex(const QString &str)
+{
+ return stringToArrayIndex(str.constData(), str.constData() + str.length());
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4STRINGTOARRAYINDEX_P_H
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index da3c173545..4d6926d420 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -3,20 +3,19 @@ INCLUDEPATH += $$OUT_PWD
HEADERS += \
$$PWD/qv4bytecodegenerator_p.h \
- $$PWD/qv4compileddata_p.h \
$$PWD/qv4compiler_p.h \
$$PWD/qv4compilercontext_p.h \
$$PWD/qv4compilercontrolflow_p.h \
+ $$PWD/qv4compilerglobal_p.h \
$$PWD/qv4compilerscanfunctions_p.h \
$$PWD/qv4codegen_p.h \
$$PWD/qqmlirbuilder_p.h \
- $$PWD/qqmltypecompiler_p.h \
$$PWD/qv4instr_moth_p.h \
- $$PWD/qv4bytecodehandler_p.h
+ $$PWD/qv4bytecodehandler_p.h \
+ $$PWD/qv4util_p.h
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
- $$PWD/qv4compileddata.cpp \
$$PWD/qv4compiler.cpp \
$$PWD/qv4compilercontext.cpp \
$$PWD/qv4compilerscanfunctions.cpp \
@@ -25,25 +24,6 @@ SOURCES += \
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4bytecodehandler.cpp
-!qmldevtools_build {
-
-HEADERS += \
- $$PWD/qqmltypecompiler_p.h \
- $$PWD/qqmlpropertycachecreator_p.h \
- $$PWD/qqmlpropertyvalidator_p.h \
- $$PWD/qv4compilationunitmapper_p.h
-
-
-SOURCES += \
- $$PWD/qqmltypecompiler.cpp \
- $$PWD/qqmlpropertycachecreator.cpp \
- $$PWD/qqmlpropertyvalidator.cpp \
- $$PWD/qv4compilationunitmapper.cpp
-
-unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
-else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-}
-
gcc {
equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 9218c4a652..665d2633a7 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -39,7 +39,7 @@
#include "qqmlirbuilder_p.h"
-#include <private/qv4value_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
@@ -48,12 +48,6 @@
#include <QCryptographicHash>
#include <cmath>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmlglobal_p.h>
-#include <private/qqmltypeloader_p.h>
-#include <private/qqmlengine_p.h>
-#endif
-
#ifdef CONST
#undef CONST
#endif
@@ -61,12 +55,8 @@
QT_USE_NAMESPACE
static const quint32 emptyStringIndex = 0;
-
-#if 0 //ndef V4_BOOTSTRAP
-DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS);
-#endif // V4_BOOTSTRAP
-
using namespace QmlIR;
+using namespace QQmlJS;
#define COMPILE_EXCEPTION(location, desc) \
{ \
@@ -74,6 +64,84 @@ using namespace QmlIR;
return false; \
}
+bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName,
+ const QString &typeName)
+{
+ return init(this, stringGenerator, stringGenerator->registerString(parameterName), stringGenerator->registerString(typeName));
+}
+
+bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex)
+{
+ param->nameIndex = parameterNameIndex;
+ return initType(&param->type, stringGenerator, typeNameIndex);
+}
+
+bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
+{
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = 0;
+ const QString typeName = stringGenerator->stringForIndex(typeNameIndex);
+ auto builtinType = stringToBuiltinType(typeName);
+ if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) {
+ if (typeName.isEmpty() || !typeName.at(0).isUpper())
+ return false;
+ paramType->indexIsBuiltinType = false;
+ paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ } else {
+ paramType->indexIsBuiltinType = true;
+ paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
+ Q_ASSERT(quint32(builtinType) < (1u << 31));
+ }
+ return true;
+}
+
+QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typeName)
+{
+ static const struct TypeNameToType {
+ const char *name;
+ size_t nameLength;
+ QV4::CompiledData::BuiltinType type;
+ } propTypeNameToTypes[] = {
+ { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool },
+ { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real },
+ { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real },
+ { "string", strlen("string"), QV4::CompiledData::BuiltinType::String },
+ { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url },
+ { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color },
+ // Internally QTime, QDate and QDateTime are all supported.
+ // To be more consistent with JavaScript we expose only
+ // QDateTime as it matches closely with the Date JS type.
+ // We also call it "date" to match.
+ // { "time", strlen("time"), Property::Time },
+ // { "date", strlen("date"), Property::Date },
+ { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime },
+ { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect },
+ { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point },
+ { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size },
+ { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font },
+ { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D },
+ { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D },
+ { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D },
+ { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion },
+ { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 },
+ { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant },
+ { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var }
+ };
+ static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
+ sizeof(propTypeNameToTypes[0]);
+
+ for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
+ const TypeNameToType *t = propTypeNameToTypes + typeIndex;
+ if (typeName == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
+ return t->type;
+ }
+ }
+ return QV4::CompiledData::BuiltinType::InvalidBuiltin;
+}
+
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
{
inheritedTypeNameIndex = typeNameIndex;
@@ -258,64 +326,11 @@ QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerato
{
QStringList result;
result.reserve(parameters->count);
- for (SignalParameter *param = parameters->first; param; param = param->next)
+ for (Parameter *param = parameters->first; param; param = param->next)
result << stringPool->stringForIndex(param->nameIndex);
return result;
}
-static void replaceWithSpace(QString &str, int idx, int n)
-{
- QChar *data = str.data() + idx;
- const QChar space(QLatin1Char(' '));
- for (int ii = 0; ii < n; ++ii)
- *data++ = space;
-}
-
-void Document::removeScriptPragmas(QString &script)
-{
- const QLatin1String pragma("pragma");
- const QLatin1String library("library");
-
- QQmlJS::Lexer l(nullptr);
- l.setCode(script, 0);
-
- int token = l.lex();
-
- while (true) {
- if (token != QQmlJSGrammar::T_DOT)
- return;
-
- int startOffset = l.tokenOffset();
- int startLine = l.tokenStartLine();
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_PRAGMA ||
- l.tokenStartLine() != startLine ||
- script.midRef(l.tokenOffset(), l.tokenLength()) != pragma)
- return;
-
- token = l.lex();
-
- if (token != QQmlJSGrammar::T_IDENTIFIER ||
- l.tokenStartLine() != startLine)
- return;
-
- const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength());
- int endOffset = l.tokenLength() + l.tokenOffset();
-
- token = l.lex();
- if (l.tokenStartLine() == startLine)
- return;
-
- if (pragmaValue == library) {
- replaceWithSpace(script, startOffset, endOffset - startOffset);
- } else {
- return;
- }
- }
-}
-
Document::Document(bool debugMode)
: jsModule(debugMode)
, program(nullptr)
@@ -385,13 +400,12 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
if (!parseResult || !diagnosticMessages.isEmpty()) {
// Extract errors from the parser
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
-
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(url), m.line, qPrintable(m.message));
continue;
}
- recordError(m.loc, m.message);
+ errors << m;
}
return false;
}
@@ -661,11 +675,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
return false;
}
- if (node->versionToken.isValid()) {
- int major, minor;
- extractVersion(textRefAt(node->versionToken), &major, &minor);
- import->majorVersion = major;
- import->minorVersion = minor;
+ if (node->version) {
+ import->majorVersion = node->version->majorVersion;
+ import->minorVersion = node->version->minorVersion;
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
return false;
@@ -778,40 +790,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
- static const struct TypeNameToType {
- const char *name;
- size_t nameLength;
- QV4::CompiledData::Property::Type type;
- } propTypeNameToTypes[] = {
- { "int", strlen("int"), QV4::CompiledData::Property::Int },
- { "bool", strlen("bool"), QV4::CompiledData::Property::Bool },
- { "double", strlen("double"), QV4::CompiledData::Property::Real },
- { "real", strlen("real"), QV4::CompiledData::Property::Real },
- { "string", strlen("string"), QV4::CompiledData::Property::String },
- { "url", strlen("url"), QV4::CompiledData::Property::Url },
- { "color", strlen("color"), QV4::CompiledData::Property::Color },
- // Internally QTime, QDate and QDateTime are all supported.
- // To be more consistent with JavaScript we expose only
- // QDateTime as it matches closely with the Date JS type.
- // We also call it "date" to match.
- // { "time", strlen("time"), Property::Time },
- // { "date", strlen("date"), Property::Date },
- { "date", strlen("date"), QV4::CompiledData::Property::DateTime },
- { "rect", strlen("rect"), QV4::CompiledData::Property::Rect },
- { "point", strlen("point"), QV4::CompiledData::Property::Point },
- { "size", strlen("size"), QV4::CompiledData::Property::Size },
- { "font", strlen("font"), QV4::CompiledData::Property::Font },
- { "vector2d", strlen("vector2d"), QV4::CompiledData::Property::Vector2D },
- { "vector3d", strlen("vector3d"), QV4::CompiledData::Property::Vector3D },
- { "vector4d", strlen("vector4d"), QV4::CompiledData::Property::Vector4D },
- { "quaternion", strlen("quaternion"), QV4::CompiledData::Property::Quaternion },
- { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::Property::Matrix4x4 },
- { "variant", strlen("variant"), QV4::CompiledData::Property::Variant },
- { "var", strlen("var"), QV4::CompiledData::Property::Var }
- };
- static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
- sizeof(propTypeNameToTypes[0]);
-
if (node->type == QQmlJS::AST::UiPublicMember::Signal) {
Signal *signal = New<Signal>();
QString signalName = node->name.toString();
@@ -821,7 +799,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
signal->location.line = loc.startLine;
signal->location.column = loc.startColumn;
- signal->parameters = New<PoolList<SignalParameter> >();
+ signal->parameters = New<PoolList<Parameter> >();
QQmlJS::AST::UiParameterList *p = node->parameters;
while (p) {
@@ -832,38 +810,13 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- const TypeNameToType *type = nullptr;
- for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
- const TypeNameToType *t = propTypeNameToTypes + typeIndex;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t;
- break;
- }
- }
-
- SignalParameter *param = New<SignalParameter>();
-
- if (!type) {
- if (memberType.at(0).isUpper()) {
- // Must be a QML object type.
- // Lazily determine type during compilation.
- param->type = QV4::CompiledData::Property::Custom;
- param->customTypeNameIndex = registerString(memberType);
- } else {
- QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
- errStr.append(memberType);
- recordError(node->typeToken, errStr);
- return false;
- }
- } else {
- // the parameter is a known basic type
- param->type = type->type;
- param->customTypeNameIndex = emptyStringIndex;
+ Parameter *param = New<Parameter>();
+ if (!param->init(jsGenerator, p->name.toString(), memberType)) {
+ QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
+ errStr.append(memberType);
+ recordError(node->typeToken, errStr);
+ return false;
}
-
- param->nameIndex = registerString(p->name.toString());
- param->location.line = p->identifierToken.startLine;
- param->location.column = p->identifierToken.startColumn;
signal->parameters->append(param);
p = p->next;
}
@@ -886,25 +839,21 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
} else {
const QStringRef &name = node->name;
- bool typeFound = false;
- QV4::CompiledData::Property::Type type = QV4::CompiledData::Property::Var;
+ Property *property = New<Property>();
+ property->isReadOnly = node->isReadonlyMember;
- for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
- const TypeNameToType *t = propTypeNameToTypes + ii;
- if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
- type = t->type;
- typeFound = true;
- }
- }
+ QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
+ bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
+ if (typeFound)
+ property->setBuiltinType(builtinPropertyType);
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
- if (typeModifier.isEmpty()) {
- type = QV4::CompiledData::Property::Custom;
- } else if (typeModifier == QLatin1String("list")) {
- type = QV4::CompiledData::Property::CustomList;
- } else {
+ property->setCustomType(registerString(memberType));
+ if (typeModifier == QLatin1String("list")) {
+ property->isList = true;
+ } else if (!typeModifier.isEmpty()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
}
@@ -919,16 +868,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
return false;
}
- Property *property = New<Property>();
- property->flags = 0;
- if (node->isReadonlyMember)
- property->flags |= QV4::CompiledData::Property::IsReadOnly;
- property->type = type;
- if (type >= QV4::CompiledData::Property::Custom)
- property->customTypeNameIndex = registerString(memberType);
- else
- property->customTypeNameIndex = emptyStringIndex;
-
const QString propName = name.toString();
property->nameIndex = registerString(propName);
@@ -969,7 +908,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
{
- if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
+ if (QQmlJS::AST::FunctionExpression *funDecl = node->sourceElement->asFunctionDefinition()) {
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
foe->node = funDecl;
foe->parentNode = funDecl;
@@ -983,13 +922,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
- const QStringList formals = funDecl->formals ? funDecl->formals->formals() : QStringList();
+ QString returnTypeName = funDecl->typeAnnotation ? funDecl->typeAnnotation->type->toString() : QString();
+ Parameter::initType(&f->returnType, jsGenerator, registerString(returnTypeName));
+
+ const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames();
int formalsCount = formals.size();
f->formals.allocate(pool, formalsCount);
int i = 0;
- for (const QString &arg : formals) {
- f->formals[i] = registerString(arg);
+ for (const auto &arg : formals) {
+ f->formals[i].init(jsGenerator, arg.id, arg.typeName());
++i;
}
@@ -1022,7 +964,7 @@ QStringRef IRBuilder::asStringRef(QQmlJS::AST::Node *node)
return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
}
-void IRBuilder::extractVersion(QStringRef string, int *maj, int *min)
+void IRBuilder::extractVersion(const QStringRef &string, int *maj, int *min)
{
*maj = -1; *min = -1;
@@ -1051,7 +993,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->valueLocation.line = loc.startLine;
binding->valueLocation.column = loc.startColumn;
binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
@@ -1282,7 +1224,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
binding->flags = 0;
- if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
// No type name on the initializer means it must be a group property
@@ -1513,7 +1455,8 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
{
QQmlJS::DiagnosticMessage error;
- error.loc = location;
+ error.line = location.startLine;
+ error.column = location.startColumn;
error.message = description;
errors << error;
}
@@ -1545,7 +1488,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->type != QV4::CompiledData::Property::Custom)
+ if (property->isBuiltinType || property->isList)
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1559,17 +1502,12 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = output.javaScriptCompilationUnit;
-
QV4::CompiledData::Unit *jsUnit = nullptr;
- const bool finalize = !compilationUnit->data;
// We may already have unit data if we're loading an ahead-of-time generated cache file.
- if (!finalize) {
- jsUnit = const_cast<QV4::CompiledData::Unit *>(compilationUnit->data);
-#ifndef V4_BOOTSTRAP
- output.javaScriptCompilationUnit->dynamicStrings = output.jsGenerator.stringTable.allStrings();
-#endif
+ if (output.javaScriptCompilationUnit.data) {
+ jsUnit = const_cast<QV4::CompiledData::Unit *>(output.javaScriptCompilationUnit.data);
+ output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings();
} else {
QV4::CompiledData::Unit *createdUnit;
jsUnit = createdUnit = output.jsGenerator.generateUnit();
@@ -1581,22 +1519,15 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
break;
}
}
- // This unit's memory was allocated with malloc on the heap, so it's
- // definitely not suitable for StaticData access.
- createdUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
-#ifndef V4_BOOTSTRAP
if (dependencyHasher) {
- QCryptographicHash hash(QCryptographicHash::Md5);
- if (dependencyHasher(&hash)) {
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(createdUnit->dependencyMD5Checksum));
- memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(), sizeof(createdUnit->dependencyMD5Checksum));
+ const QByteArray checksum = dependencyHasher();
+ if (checksum.size() == sizeof(createdUnit->dependencyMD5Checksum)) {
+ memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(),
+ sizeof(createdUnit->dependencyMD5Checksum));
}
}
-#else
- Q_UNUSED(dependencyHasher);
-#endif
+
createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName);
createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl);
}
@@ -1730,7 +1661,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
signalToWrite->nParameters = s->parameters->count;
QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr + sizeof(*signalToWrite));
- for (SignalParameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
+ for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
*parameterToWrite = *param;
int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
@@ -1765,14 +1696,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
}
}
- if (finalize) {
+ if (!output.javaScriptCompilationUnit.data) {
// Combine the qml data into the general unit data.
jsUnit = static_cast<QV4::CompiledData::Unit *>(realloc(jsUnit, jsUnit->unitSize + totalSize));
jsUnit->offsetToQmlUnit = jsUnit->unitSize;
jsUnit->unitSize += totalSize;
memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize);
free(qmlUnit);
- jsUnit->generateChecksum();
+ QV4::Compiler::JSUnitGenerator::generateUnitChecksum(jsUnit);
qmlUnit = jsUnit->qmlUnit();
}
@@ -1798,7 +1729,8 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
qDebug() << " " << totalStringSize << "bytes total strings";
}
- compilationUnit->setUnitData(jsUnit, qmlUnit, output.jsModule.fileName, output.jsModule.finalUrl);
+ output.javaScriptCompilationUnit.setUnitData(jsUnit, qmlUnit, output.jsModule.fileName,
+ output.jsModule.finalUrl);
}
char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
@@ -1815,19 +1747,11 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
return bindingPtr;
}
-JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
- QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames)
- : QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false)
- , sourceCode(sourceCode)
- , jsEngine(jsEngine)
- , qmlRoot(qmlRoot)
- , stringPool(stringPool)
+JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames)
+ : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/false), document(document)
{
m_globalNames = globalNames;
-
- _module = jsModule;
+ _module = &document->jsModule;
_fileNameIsUrl = true;
}
@@ -1835,18 +1759,18 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
{
auto qmlName = [&](const CompiledFunctionOrExpression &c) {
if (c.nameIndex != 0)
- return stringPool->stringForIndex(c.nameIndex);
+ return document->stringAt(c.nameIndex);
else
return QStringLiteral("%qml-expression-entry");
};
QVector<int> runtimeFunctionIndices(functions.size());
- QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::ContextType::Global);
+ QV4::Compiler::ScanFunctions scan(this, document->code, QV4::Compiler::ContextType::Global);
scan.enterGlobalEnvironment(QV4::Compiler::ContextType::Binding);
for (const CompiledFunctionOrExpression &f : functions) {
- Q_ASSERT(f.node != qmlRoot);
- Q_ASSERT(f.parentNode && f.parentNode != qmlRoot);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
+ Q_ASSERT(f.node != document->program);
+ Q_ASSERT(f.parentNode && f.parentNode != document->program);
+ auto function = f.node->asFunctionDefinition();
if (function) {
scan.enterQmlFunction(function);
@@ -1860,7 +1784,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
}
scan.leaveEnvironment();
- if (hasError)
+ if (hasError())
return QVector<int>();
_context = nullptr;
@@ -1868,9 +1792,9 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
for (int i = 0; i < functions.count(); ++i) {
const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
QQmlJS::AST::Node *node = qmlFunction.node;
- Q_ASSERT(node != qmlRoot);
+ Q_ASSERT(node != document->program);
- QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(node);
+ QQmlJS::AST::FunctionExpression *function = node->asFunctionDefinition();
QString name;
if (function)
@@ -1883,7 +1807,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
body = function->body;
} else {
// Synthesize source elements.
- QQmlJS::MemoryPool *pool = jsEngine->pool();
+ QQmlJS::MemoryPool *pool = document->jsParserEngine.pool();
QQmlJS::AST::Statement *stmt = node->statementCast();
if (!stmt) {
@@ -1904,213 +1828,57 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-#ifndef V4_BOOTSTRAP
-
-QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const
-{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
-
- // Find the first property
- while (d && d->isFunction())
- d = cache->overrideData(d);
-
- if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else {
- return d;
- }
-}
-
-
-QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision) const
+bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots)
{
- if (notInRevision) *notInRevision = false;
-
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
- if (notInRevision) *notInRevision = false;
-
- while (d && !(d->isFunction()))
- d = cache->overrideData(d);
-
- if (d && !cache->isAllowedInRevision(d)) {
- if (notInRevision) *notInRevision = true;
- return nullptr;
- } else if (d && d->isSignal()) {
- return d;
- }
-
- if (name.endsWith(QLatin1String("Changed"))) {
- QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
-
- d = property(propName, notInRevision);
- if (d)
- return cache->signal(d->notifyIndex());
+ for (int i = 0; i < componentRoots.count(); ++i) {
+ if (!compileComponent(componentRoots.at(i)))
+ return false;
}
- return nullptr;
-}
-
-IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
- : unit(qmlData)
- , output(output)
-{
- pool = output->jsParserEngine.pool();
+ return compileComponent(/*root object*/0);
}
-void IRLoader::load()
+bool JSCodeGen::compileComponent(int contextObject)
{
- output->jsGenerator.stringTable.initializeFromBackingUnit(unit);
-
- const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit();
-
- for (quint32 i = 0; i < qmlUnit->nImports; ++i)
- output->imports << qmlUnit->importAt(i);
-
- if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
- QmlIR::Pragma *p = New<QmlIR::Pragma>();
- p->location = QV4::CompiledData::Location();
- p->type = QmlIR::Pragma::PragmaSingleton;
- output->pragmas << p;
+ const QmlIR::Object *obj = document->objects.at(contextObject);
+ if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ Q_ASSERT(obj->bindingCount() == 1);
+ const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
+ Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ contextObject = componentBinding->value.objectIndex;
}
- for (uint i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
- QmlIR::Object *object = loadObject(serializedObject);
- output->objects.append(object);
- }
+ return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
}
-struct FakeExpression : public QQmlJS::AST::NullExpression
-{
- FakeExpression(int start, int length)
- : location(start, length)
- {}
-
- virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
- { return location; }
-
- virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
- { return location; }
-
-private:
- QQmlJS::AST::SourceLocation location;
-};
-
-QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
{
- QmlIR::Object *object = pool->New<QmlIR::Object>();
- object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
-
- object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
- object->location = serializedObject->location;
- object->locationOfIdProperty = serializedObject->locationOfIdProperty;
-
- QVector<int> functionIndices;
- functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
-
- for (uint i = 0; i < serializedObject->nBindings; ++i) {
- QmlIR::Binding *b = pool->New<QmlIR::Binding>();
- *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
- object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
- functionIndices.append(b->value.compiledScriptIndex);
- b->value.compiledScriptIndex = functionIndices.count() - 1;
-
- QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
- foe->nameIndex = 0;
-
- QQmlJS::AST::ExpressionNode *expr;
-
- if (b->stringIndex != quint32(0)) {
- const int start = output->code.length();
- const QString script = output->stringAt(b->stringIndex);
- const int length = script.length();
- output->code.append(script);
- expr = new (pool) FakeExpression(start, length);
- } else
- expr = new (pool) QQmlJS::AST::NullExpression();
- foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
- object->functionsAndExpressions->append(foe);
- }
- }
-
- Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+ QmlIR::Object *object = document->objects.at(objectIndex);
+ if (object->flags & QV4::CompiledData::Object::IsComponent)
+ return true;
- for (uint i = 0; i < serializedObject->nSignals; ++i) {
- const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
- QmlIR::Signal *s = pool->New<QmlIR::Signal>();
- s->nameIndex = serializedSignal->nameIndex;
- s->location = serializedSignal->location;
- s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
-
- for (uint i = 0; i < serializedSignal->nParameters; ++i) {
- QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
- *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
- s->parameters->append(p);
- }
-
- object->qmlSignals->append(s);
- }
-
- for (uint i = 0; i < serializedObject->nEnums; ++i) {
- const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i);
- QmlIR::Enum *e = pool->New<QmlIR::Enum>();
- e->nameIndex = serializedEnum->nameIndex;
- e->location = serializedEnum->location;
- e->enumValues = pool->New<QmlIR::PoolList<QmlIR::EnumValue> >();
-
- for (uint i = 0; i < serializedEnum->nEnumValues; ++i) {
- QmlIR::EnumValue *v = pool->New<QmlIR::EnumValue>();
- *static_cast<QV4::CompiledData::EnumValue*>(v) = *serializedEnum->enumValueAt(i);
- e->enumValues->append(v);
- }
-
- object->qmlEnums->append(e);
- }
-
- const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
- for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
- QmlIR::Property *p = pool->New<QmlIR::Property>();
- *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
- object->properties->append(p);
- }
+ if (object->functionsAndExpressions->count > 0) {
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
+ functionsToCompile << *foe;
+ const QVector<int> runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
- {
- const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
- for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
- QmlIR::Alias *a = pool->New<QmlIR::Alias>();
- *static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
- object->aliases->append(a);
- }
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
}
- const quint32_le *functionIdx = serializedObject->functionOffsetTable();
- for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
- QmlIR::Function *f = pool->New<QmlIR::Function>();
- const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
-
- functionIndices.append(*functionIdx);
- f->index = functionIndices.count() - 1;
- f->location = compiledFunction->location;
- f->nameIndex = compiledFunction->nameIndex;
+ for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
+ if (binding->type < QV4::CompiledData::Binding::Type_Object)
+ continue;
- f->formals.allocate(pool, int(compiledFunction->nFormals));
- const quint32_le *formalNameIdx = compiledFunction->formalsTable();
- for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
- f->formals[i] = *formalNameIdx;
+ int target = binding->value.objectIndex;
+ int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
- object->functions->append(f);
+ if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
+ return false;
}
- object->runtimeFunctionIndices.allocate(pool, functionIndices);
-
- return object;
+ return true;
}
-
-#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 22bc2d2953..4279f5b768 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -55,25 +55,22 @@
#include <private/qv4compiler_p.h>
#include <private/qv4compileddata_p.h>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qqmljsfixedpoolarray_p.h>
#include <private/qv4codegen_p.h>
#include <private/qv4compiler_p.h>
#include <QTextStream>
#include <QCoreApplication>
-#ifndef V4_BOOTSTRAP
-#include <private/qqmlpropertycache_p.h>
-#endif
-
QT_BEGIN_NAMESPACE
class QQmlPropertyCache;
class QQmlContextData;
class QQmlTypeNameCache;
+struct QQmlIRLoader;
namespace QmlIR {
struct Document;
-struct IRLoader;
template <typename T>
struct PoolList
@@ -219,22 +216,30 @@ struct Enum
};
-struct SignalParameter : public QV4::CompiledData::Parameter
+struct Parameter : public QV4::CompiledData::Parameter
{
- SignalParameter *next;
+ Parameter *next;
+
+ bool init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString &parameterName, const QString &typeName);
+ static bool init(QV4::CompiledData::Parameter *param, const QV4::Compiler::JSUnitGenerator *stringGenerator,
+ int parameterNameIndex, int typeNameIndex);
+ static bool initType(QV4::CompiledData::ParameterType *paramType,
+ const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex);
+
+ static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName);
};
struct Signal
{
int nameIndex;
QV4::CompiledData::Location location;
- PoolList<SignalParameter> *parameters;
+ PoolList<Parameter> *parameters;
QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
int parameterCount() const { return parameters->count; }
- PoolList<SignalParameter>::Iterator parametersBegin() const { return parameters->begin(); }
- PoolList<SignalParameter>::Iterator parametersEnd() const { return parameters->end(); }
+ PoolList<Parameter>::Iterator parametersBegin() const { return parameters->begin(); }
+ PoolList<Parameter>::Iterator parametersEnd() const { return parameters->end(); }
Signal *next;
};
@@ -264,17 +269,18 @@ struct Function
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
- FixedPoolArray<int> formals;
+ QQmlJS::FixedPoolArray<Parameter> formals;
+ QV4::CompiledData::ParameterType returnType;
// --- QQmlPropertyCacheCreator interface
- const int *formalsBegin() const { return formals.begin(); }
- const int *formalsEnd() const { return formals.end(); }
+ const Parameter *formalsBegin() const { return formals.begin(); }
+ const Parameter *formalsEnd() const { return formals.end(); }
// ---
Function *next;
};
-struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
+struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
{}
@@ -285,7 +291,7 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
CompiledFunctionOrExpression *next = nullptr;
};
-struct Q_QML_PRIVATE_EXPORT Object
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Object
{
Q_DECLARE_TR_FUNCTIONS(Object)
public:
@@ -344,14 +350,14 @@ public:
QString bindingAsString(Document *doc, int scriptIndex) const;
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
- FixedPoolArray<int> runtimeFunctionIndices;
+ QQmlJS::FixedPoolArray<int> runtimeFunctionIndices;
- FixedPoolArray<quint32> namedObjectsInComponent;
+ QQmlJS::FixedPoolArray<quint32> namedObjectsInComponent;
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
private:
- friend struct IRLoader;
+ friend struct ::QQmlIRLoader;
PoolList<Property> *properties;
PoolList<Alias> *aliases;
@@ -361,7 +367,7 @@ private:
PoolList<Function> *functions;
};
-struct Q_QML_PRIVATE_EXPORT Pragma
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
{
enum PragmaType {
PragmaSingleton = 0x1
@@ -371,7 +377,7 @@ struct Q_QML_PRIVATE_EXPORT Pragma
QV4::CompiledData::Location location;
};
-struct Q_QML_PRIVATE_EXPORT Document
+struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
{
Document(bool debugMode);
QString code;
@@ -383,15 +389,13 @@ struct Q_QML_PRIVATE_EXPORT Document
QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
+ QV4::CompiledData::CompilationUnit javaScriptCompilationUnit;
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
-
- static void removeScriptPragmas(QString &script);
};
-class Q_QML_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
+class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
{
QmlIR::Document *document;
QQmlJS::Engine *engine;
@@ -405,7 +409,7 @@ public:
void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override;
};
-struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
+struct Q_QMLCOMPILER_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
@@ -436,7 +440,7 @@ public:
void throwRecursionDepthError() override
{
- recordError(AST::SourceLocation(),
+ recordError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
@@ -449,19 +453,25 @@ public:
static QString asString(QQmlJS::AST::UiQualifiedId *node);
QStringRef asStringRef(QQmlJS::AST::Node *node);
- static void extractVersion(QStringRef string, int *maj, int *min);
+ static void extractVersion(const QStringRef &string, int *maj, int *min);
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &loc) const
{ return QStringRef(&sourceCode, loc.offset, loc.length); }
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
const QQmlJS::AST::SourceLocation &last) const;
- void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, AST::Node *parentNode);
+ void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement,
+ QQmlJS::AST::Node *parentNode);
void tryGeneratingTranslationBinding(const QStringRef &base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding);
- void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, AST::Node *parentNode);
+ void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value,
+ QQmlJS::AST::Node *parentNode);
void appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment = false);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value, AST::Node *parentNode);
- void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode);
+ void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
@@ -503,7 +513,7 @@ public:
QV4::Compiler::JSUnitGenerator *jsGenerator;
};
-struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
+struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator
{
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher());
@@ -512,76 +522,23 @@ private:
char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
};
-#ifndef V4_BOOTSTRAP
-struct Q_QML_EXPORT PropertyResolver
-{
- PropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
- : cache(cache)
- {}
-
- QQmlPropertyData *property(int index) const
- {
- return cache->property(index);
- }
-
- enum RevisionCheck {
- CheckRevision,
- IgnoreRevision
- };
-
- QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr, RevisionCheck check = CheckRevision) const;
-
- // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
-
- QQmlRefPointer<QQmlPropertyCache> cache;
-};
-#endif
-
-struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
- JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule,
- QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot,
- const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
+ JSCodeGen(Document *document, const QSet<QString> &globalNames);
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
-private:
- QString sourceCode;
- QQmlJS::Engine *jsEngine; // needed for memory pool
- QQmlJS::AST::UiProgram *qmlRoot;
- const QV4::Compiler::StringTableGenerator *stringPool;
-};
-
-struct Q_QML_PRIVATE_EXPORT IRLoader {
- IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
-
- void load();
+ bool generateCodeForComponents(const QVector<quint32> &componentRoots);
+ bool compileComponent(int contextObject);
+ bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
private:
- QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
-
- template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
-
- const QV4::CompiledData::Unit *unit;
- QmlIR::Document *output;
- QQmlJS::MemoryPool *pool;
+ Document *document;
};
} // namespace QmlIR
-struct QQmlCompileError
-{
- QQmlCompileError() {}
- QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
- : location(location), description(description) {}
- QV4::CompiledData::Location location;
- QString description;
-
- bool isSet() const { return !description.isEmpty(); }
-};
-
QT_END_NAMESPACE
#endif // QQMLIRBUILDER_P_H
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index ea252a6013..7df1614ffe 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -206,7 +206,6 @@ int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, in
lastInstrType = int(type);
lastInstr = i;
-#if QT_CONFIG(qml_debug)
if (debugMode && type != Instr::Type::Debug) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instruction::Debug()
@@ -219,9 +218,6 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instru
}
QT_WARNING_POP
}
-#else
- Q_UNUSED(debugMode);
-#endif
const int pos = instructions.size();
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 1d0a57c536..8c509dd9f1 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -62,12 +62,15 @@ class SourceLocation;
}
namespace QV4 {
+
+namespace Compiler {
+struct Context;
+}
+
namespace Moth {
class BytecodeGenerator {
public:
- typedef CompiledData::Function::TraceInfoCount TraceInfoCount;
-
BytecodeGenerator(int line, bool debug)
: startLine(line), debugMode(debug) {}
@@ -164,15 +167,6 @@ public:
addInstructionHelper(Moth::Instr::Type(InstrT), genericInstr);
}
- // Same as addInstruction, but also add a trace slot. Move only, because the instruction cannot
- // be reused afterwards.
- template<int InstrT>
- void addTracingInstruction(InstrData<InstrT> data)
- {
- data.traceSlot = nextTraceInfo();
- addInstruction(data);
- }
-
Q_REQUIRED_RESULT Jump jump()
{
QT_WARNING_PUSH
@@ -184,12 +178,12 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpTrue()
{
- return addTracingJumpInstruction(Instruction::JumpTrue());
+ return addJumpInstruction(Instruction::JumpTrue());
}
Q_REQUIRED_RESULT Jump jumpFalse()
{
- return addTracingJumpInstruction(Instruction::JumpFalse());
+ return addJumpInstruction(Instruction::JumpFalse());
}
Q_REQUIRED_RESULT Jump jumpNotUndefined()
@@ -209,7 +203,7 @@ QT_WARNING_POP
Instruction::CmpStrictEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
}
void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
@@ -217,7 +211,13 @@ QT_WARNING_POP
Instruction::CmpStrictNotEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
+ }
+
+ void checkException()
+ {
+ Instruction::CheckException chk;
+ addInstruction(chk);
}
void setUnwindHandler(ExceptionHandler *handler)
@@ -258,13 +258,6 @@ QT_WARNING_POP
void finalize(Compiler::Context *context);
template<int InstrT>
- Jump addTracingJumpInstruction(InstrData<InstrT> &&data)
- {
- data.traceSlot = nextTraceInfo();
- return addJumpInstruction(data);
- }
-
- template<int InstrT>
Jump addJumpInstruction(const InstrData<InstrT> &data)
{
Instr genericInstr;
@@ -275,9 +268,9 @@ QT_WARNING_POP
void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
{
if (jumpOnFalse)
- addTracingJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
+ addJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
else
- addTracingJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
+ addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
void clearLastInstruction()
@@ -285,27 +278,6 @@ QT_WARNING_POP
lastInstrType = -1;
}
- TraceInfoCount nextTraceInfo()
- {
- // If tracing is disabled, use slot 0 to unconditionally store all trace info
- if (nTraceInfos == CompiledData::Function::NoTracing())
- return TraceInfoCount(0);
- return nTraceInfos++;
- }
-
- void setTracing(bool onoff, int argumentCount)
- {
- if (onoff)
- nTraceInfos = argumentCount;
- else
- nTraceInfos = CompiledData::Function::NoTracing();
- }
-
- TraceInfoCount traceInfoCount() const
- {
- return nTraceInfos;
- }
-
void addLoopStart(const Label &start)
{
_labelInfos.push_back({ start.index });
@@ -346,8 +318,6 @@ private:
int lastInstrType = -1;
Moth::Instr lastInstr;
- TraceInfoCount nTraceInfos = TraceInfoCount(0);
-
struct LabelInfo {
int labelIndex;
};
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index 92b112c2fa..f9f755b8c0 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -58,9 +58,10 @@ ByteCodeHandler::~ByteCodeHandler()
Q_UNUSED(base_ptr); \
_currentOffset = _nextOffset; \
_nextOffset = code - start; \
- startInstruction(Instr::Type::instr); \
- INSTR_##instr(DISPATCH) \
- endInstruction(Instr::Type::instr); \
+ if (startInstruction(Instr::Type::instr) == ProcessInstruction) { \
+ INSTR_##instr(DISPATCH) \
+ endInstruction(Instr::Type::instr); \
+ } \
continue; \
}
diff --git a/src/qml/compiler/qv4bytecodehandler_p.h b/src/qml/compiler/qv4bytecodehandler_p.h
index 797d25b8d0..f1e7c99447 100644
--- a/src/qml/compiler/qv4bytecodehandler_p.h
+++ b/src/qml/compiler/qv4bytecodehandler_p.h
@@ -105,7 +105,8 @@ public:
protected:
FOR_EACH_MOTH_INSTR(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
- virtual void startInstruction(Moth::Instr::Type instr) = 0;
+ enum Verdict { ProcessInstruction, SkipInstruction };
+ virtual Verdict startInstruction(Moth::Instr::Type instr) = 0;
virtual void endInstruction(Moth::Instr::Type instr) = 0;
private:
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 5acc64bd81..c43ea64e2e 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -43,18 +43,18 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QStack>
+#include <QtCore/qurl.h>
#include <QScopeGuard>
#include <private/qqmljsast_p.h>
-#include <private/qv4string_p.h>
-#include <private/qv4value_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4compilercontrolflow_p.h>
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4compilerscanfunctions_p.h>
-
-#ifndef V4_BOOTSTRAP
-# include <qqmlerror.h>
-#endif
+#include <private/qv4stringtoarrayindex_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <cmath>
#include <iostream>
@@ -68,6 +68,7 @@ static const bool disable_lookups = false;
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGenerator,
@@ -97,7 +98,6 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
, jsUnitGenerator(jsUnitGenerator)
, _strictMode(strict)
, _fileNameIsUrl(false)
- , hasError(false)
{
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
pushExpr();
@@ -190,7 +190,7 @@ void Codegen::generateFromProgram(const QString &fileName,
ScanFunctions scan(this, sourceCode, contextType);
scan(node);
- if (hasError)
+ if (hasError())
return;
defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements);
@@ -214,7 +214,7 @@ void Codegen::generateFromModule(const QString &fileName,
ScanFunctions scan(this, sourceCode, ContextType::ESModule);
scan(node);
- if (hasError)
+ if (hasError())
return;
{
@@ -264,17 +264,30 @@ Context *Codegen::enterBlock(Node *node)
Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
{
- if (hasError)
+ if (hasError())
return exprResult();
if (expr.isConstant()) {
- auto v = Value::fromReturnedValue(expr.constant);
+ auto v = StaticValue::fromReturnedValue(expr.constant);
if (v.isNumber()) {
switch (op) {
case Not:
return Reference::fromConst(this, Encode(!v.toBoolean()));
case UMinus:
- return Reference::fromConst(this, Runtime::method_uMinus(v));
+ // This duplicates some of the logic from Runtime::UMinus::call()
+ ReturnedValue r;
+ if (v.isInteger()) {
+ int intVal = v.integerValue();
+ if (intVal && intVal != std::numeric_limits<int>::min())
+ r = QV4::Encode(-intVal);
+ else
+ r = QV4::Encode(-double(intVal));
+ } else if (v.isDouble()) {
+ r = QV4::Encode(-v.doubleValue());
+ } else {
+ r = QV4::Encode(-v.int_32());
+ }
+ return Reference::fromConst(this, r);
case UPlus:
return expr;
case Compl:
@@ -289,12 +302,12 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case UMinus: {
expr.loadInAccumulator();
Instruction::UMinus uminus = {};
- bytecodeGenerator->addTracingInstruction(uminus);
+ bytecodeGenerator->addInstruction(uminus);
return Reference::fromAccumulator(this);
}
case UPlus: {
expr.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
return Reference::fromAccumulator(this);
}
@@ -314,11 +327,11 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
if (!exprAccept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -330,7 +343,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -340,11 +353,11 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
if (!exprAccept(nx) || requiresReturnValue) {
Reference e = expr.asLValue();
e.loadInAccumulator();
- Instruction::UPlus uplus;
+ Instruction::UPlus uplus = {};
bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -356,7 +369,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -402,7 +415,7 @@ void Codegen::statement(ExpressionNode *ast)
qSwap(_volatileMemoryLocations, vLocs);
Reference result = popResult();
- if (hasError)
+ if (hasError())
return;
if (result.loadTriggersSideEffect())
result.loadInAccumulator(); // triggers side effects
@@ -412,7 +425,7 @@ void Codegen::statement(ExpressionNode *ast)
void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition)
{
- if (hasError)
+ if (hasError())
return;
if (!ast)
@@ -422,7 +435,7 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift
accept(ast);
Result r = popExpr();
- if (hasError)
+ if (hasError())
return;
if (r.format() == ex) {
@@ -576,7 +589,7 @@ Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
if (!p->bindingTarget || p->destructuringPattern())
return Codegen::Reference::fromStackSlot(this);
Reference lhs = expression(p->bindingTarget);
- if (hasError)
+ if (hasError())
return lhs;
if (!lhs.isLValue()) {
throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral("Binding target is not a reference."));
@@ -594,14 +607,16 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
Reference varToStore = targetForPatternElement(e);
if (isDefinition)
varToStore.isReferenceToConst = false;
- if (hasError)
+ if (hasError())
return;
+ accept(e->typeAnnotation);
+
if (e->initializer) {
if (!baseRef.isValid()) {
// assignment
Reference expr = expression(e->initializer);
- if (hasError)
+ if (hasError())
return;
expr.loadInAccumulator();
varToStore.storeConsumeAccumulator();
@@ -609,7 +624,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -620,7 +635,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con
baseRef.loadInAccumulator();
BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
Reference expr = expression(e->initializer);
- if (hasError) {
+ if (hasError()) {
jump.link();
return;
}
@@ -657,7 +672,7 @@ Codegen::Reference Codegen::referenceForPropertyName(const Codegen::Reference &o
Reference property;
if (cname) {
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return Reference();
computedName = computedName.storeOnStack();
property = Reference::fromSubscript(object, computedName).asLValue();
@@ -680,10 +695,10 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP
PatternProperty *p = it->property;
RegisterScope scope(this);
Reference property = referenceForPropertyName(object, p->name);
- if (hasError)
+ if (hasError())
return;
initializeAndDestructureBindingElement(p, property, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -739,7 +754,7 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError)
+ if (hasError())
return;
}
}
@@ -872,6 +887,12 @@ bool Codegen::visit(ExportDeclaration *ast)
return false;
}
+bool Codegen::visit(TypeAnnotation *ast)
+{
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Type annotations are not supported (yet)."));
+ return false;
+}
+
bool Codegen::visit(StatementList *)
{
Q_UNREACHABLE();
@@ -1003,11 +1024,11 @@ bool Codegen::visit(ClassExpression *ast)
if (ast->heritage) {
bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation());
Reference r = expression(ast->heritage);
- if (hasError)
+ if (hasError())
return false;
r.storeOnStack(heritage.stackSlot());
} else {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
heritage.storeConsumeAccumulator();
}
@@ -1022,7 +1043,7 @@ bool Codegen::visit(ClassExpression *ast)
RegisterScope scope(this);
bytecodeGenerator->setLocation(cname->firstSourceLocation());
Reference computedName = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++);
}
@@ -1055,7 +1076,7 @@ bool Codegen::visit(ClassDeclaration *ast)
bool Codegen::visit(Expression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1068,7 +1089,7 @@ bool Codegen::visit(Expression *ast)
bool Codegen::visit(ArrayPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1085,12 +1106,12 @@ bool Codegen::visit(ArrayPattern *ast)
if (args == -1)
args = temp;
if (!arg) {
- auto c = Reference::fromConst(this, Value::emptyValue().asReturnedValue());
+ auto c = Reference::fromConst(this, StaticValue::emptyValue().asReturnedValue());
(void) c.storeOnStack(temp);
} else {
RegisterScope scope(this);
Reference r = expression(arg);
- if (hasError)
+ if (hasError())
return;
(void) r.storeOnStack(temp);
}
@@ -1108,7 +1129,7 @@ bool Codegen::visit(ArrayPattern *ast)
continue;
push(e->initializer);
- if (hasError)
+ if (hasError())
return false;
}
@@ -1140,13 +1161,14 @@ bool Codegen::visit(ArrayPattern *ast)
index.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
index.storeConsumeAccumulator();
};
while (it) {
for (Elision *elision = it->elision; elision; elision = elision->next) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).loadInAccumulator();
+ Reference::fromConst(
+ this, StaticValue::emptyValue().asReturnedValue()).loadInAccumulator();
pushAccumulator();
}
@@ -1168,7 +1190,7 @@ bool Codegen::visit(ArrayPattern *ast)
{
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1202,13 +1224,14 @@ bool Codegen::visit(ArrayPattern *ast)
lhsValue.loadInAccumulator();
pushAccumulator();
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
end.link();
}
} else {
RegisterScope innerScope(this);
Reference expr = expression(it->element->initializer);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -1226,12 +1249,12 @@ bool Codegen::visit(ArrayPattern *ast)
bool Codegen::visit(ArrayMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Reference index = expression(ast->expression).storeOnStack();
@@ -1239,11 +1262,11 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
base = base.storeOnStack();
- if (hasError)
+ if (hasError())
return false;
if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) {
QString s = str->value.toString();
- uint arrayIndex = QV4::String::toArrayIndex(s);
+ uint arrayIndex = stringToArrayIndex(s);
if (arrayIndex == UINT_MAX) {
setExprResult(Reference::fromMember(base, str->value.toString()));
return false;
@@ -1253,7 +1276,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
return false;
}
Reference index = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSubscript(base, index));
return false;
@@ -1280,7 +1303,7 @@ static QSOperator::Op baseOp(int op)
bool Codegen::visit(BinaryExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -1298,7 +1321,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1308,7 +1331,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1329,7 +1352,7 @@ bool Codegen::visit(BinaryExpression *ast)
auto endif = bytecodeGenerator->newLabel();
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
left.loadInAccumulator();
@@ -1339,7 +1362,7 @@ bool Codegen::visit(BinaryExpression *ast)
blockTailCalls.unblock();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right.loadInAccumulator();
@@ -1352,7 +1375,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
right = right.storeOnStack();
destructurePattern(p, right);
@@ -1363,7 +1386,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
if (!left.isLValue()) {
@@ -1375,7 +1398,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
blockTailCalls.unblock();
Reference r = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
r.loadInAccumulator();
if (exprAccept(nx))
@@ -1386,7 +1409,7 @@ bool Codegen::visit(BinaryExpression *ast)
}
Reference left = expression(ast->left);
- if (hasError)
+ if (hasError())
return false;
switch (ast->op) {
@@ -1420,7 +1443,7 @@ bool Codegen::visit(BinaryExpression *ast)
Reference tempLeft = left.storeOnStack();
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator();
@@ -1434,7 +1457,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::BitXor:
if (left.isConstant()) {
Reference right = expression(ast->right);
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
break;
@@ -1467,7 +1490,7 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it
right = expression(ast->right);
}
- if (hasError)
+ if (hasError())
return false;
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
@@ -1488,20 +1511,20 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Add add;
add.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(add);
+ bytecodeGenerator->addInstruction(add);
break;
}
case QSOperator::Sub: {
if (right.isConstant() && right.constant == Encode(int(1))) {
left.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
} else {
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Sub sub;
sub.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(sub);
+ bytecodeGenerator->addInstruction(sub);
}
break;
}
@@ -1518,7 +1541,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mul mul;
mul.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mul);
+ bytecodeGenerator->addInstruction(mul);
break;
}
case QSOperator::Div: {
@@ -1534,14 +1557,14 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mod mod;
mod.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mod);
+ bytecodeGenerator->addInstruction(mod);
break;
}
case QSOperator::BitAnd:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() & rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() & rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1557,9 +1580,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitOr:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() | rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() | rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1575,9 +1598,9 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
break;
case QSOperator::BitXor:
if (right.isConstant()) {
- int rightAsInt = Value::fromReturnedValue(right.constant).toInt32();
+ int rightAsInt = StaticValue::fromReturnedValue(right.constant).toInt32();
if (left.isConstant()) {
- int result = Value::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
+ int result = StaticValue::fromReturnedValue(left.constant).toInt32() ^ rightAsInt;
return Reference::fromConst(this, Encode(result));
}
left.loadInAccumulator();
@@ -1595,7 +1618,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::UShrConst ushr;
- ushr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ ushr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(ushr);
} else {
right.loadInAccumulator();
@@ -1608,7 +1631,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShrConst shr;
- shr.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shr.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shr);
} else {
right.loadInAccumulator();
@@ -1621,7 +1644,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
if (right.isConstant()) {
left.loadInAccumulator();
Instruction::ShlConst shl;
- shl.rhs = Value::fromReturnedValue(right.constant).toInt32() & 0x1f;
+ shl.rhs = StaticValue::fromReturnedValue(right.constant).toInt32() & 0x1f;
bytecodeGenerator->addInstruction(shl);
} else {
right.loadInAccumulator();
@@ -1749,7 +1772,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
qSwap(left, right); // null==a -> a==null
if (right.isConstant()) {
- Value c = Value::fromReturnedValue(right.constant);
+ StaticValue c = StaticValue::fromReturnedValue(right.constant);
if (c.isNull() || c.isUndefined()) {
left.loadInAccumulator();
if (oper == QSOperator::Equal) {
@@ -1851,7 +1874,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
bool Codegen::visit(CallExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -1859,7 +1882,7 @@ bool Codegen::visit(CallExpression *ast)
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
switch (base.type) {
case Reference::Member:
@@ -1882,7 +1905,7 @@ bool Codegen::visit(CallExpression *ast)
int functionObject = bytecodeGenerator->newRegister();
auto calldata = pushArgs(ast->arguments);
- if (hasError)
+ if (hasError())
return false;
blockTailCalls.unblock();
@@ -1903,7 +1926,7 @@ bool Codegen::visit(CallExpression *ast)
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::TailCall call;
call.func = base.stackSlot();
@@ -1932,14 +1955,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallProperty call;
call.base = base.propertyBase.stackSlot();
call.name = base.propertyNameIndex;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
@@ -1947,33 +1970,33 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.index = base.elementSubscript.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
if (base.name == QStringLiteral("eval")) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::SuperProperty) {
Reference receiver = base.baseObject();
@@ -1990,14 +2013,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.thisObject = receiver.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Q_ASSERT(base.isStackSlot());
Instruction::CallValue call;
call.name = base.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
setExprResult(Reference::fromAccumulator(this));
@@ -2023,12 +2046,14 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
if (it->isSpreadElement) {
- Reference::fromConst(this, Value::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
+ Reference::fromConst(
+ this,
+ StaticValue::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
++argc;
}
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
@@ -2057,7 +2082,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
RegisterScope scope(this);
Reference e = expression(it->expression);
- if (hasError)
+ if (hasError())
break;
(void) e.storeOnStack(calldata + argc);
++argc;
@@ -2068,7 +2093,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
bool Codegen::visit(ConditionalExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2082,14 +2107,14 @@ bool Codegen::visit(ConditionalExpression *ast)
iftrue.link();
Reference ok = expression(ast->ok);
- if (hasError)
+ if (hasError())
return false;
ok.loadInAccumulator();
BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
iffalse.link();
Reference ko = expression(ast->ko);
- if (hasError) {
+ if (hasError()) {
jump_endif.link(); // dummy link, to prevent assert in Jump destructor from triggering
return false;
}
@@ -2103,13 +2128,13 @@ bool Codegen::visit(ConditionalExpression *ast)
bool Codegen::visit(DeleteExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
switch (expr.type) {
@@ -2174,7 +2199,7 @@ bool Codegen::visit(DeleteExpression *ast)
bool Codegen::visit(FalseLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(false)));
@@ -2183,7 +2208,7 @@ bool Codegen::visit(FalseLiteral *)
bool Codegen::visit(SuperLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromSuper(this));
@@ -2192,7 +2217,7 @@ bool Codegen::visit(SuperLiteral *)
bool Codegen::visit(FieldMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2215,7 +2240,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
}
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
Instruction::LoadRuntimeString load;
@@ -2231,7 +2256,7 @@ bool Codegen::visit(FieldMemberExpression *ast)
bool Codegen::visit(TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2240,7 +2265,7 @@ bool Codegen::visit(TaggedTemplate *ast)
bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
{
- if (hasError)
+ if (hasError())
return false;
int functionObject = -1, thisObject = -1;
@@ -2264,7 +2289,7 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
int templateObjectTemp = Reference::fromAccumulator(this).storeOnStack().stackSlot();
Q_UNUSED(templateObjectTemp);
auto calldata = pushTemplateArgs(ast->templateLiteral);
- if (hasError)
+ if (hasError())
return false;
++calldata.argc;
Q_ASSERT(calldata.argv == templateObjectTemp + 1);
@@ -2293,7 +2318,7 @@ void Codegen::createTemplateObject(TemplateLiteral *t)
bool Codegen::visit(FunctionExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2301,7 +2326,7 @@ bool Codegen::visit(FunctionExpression *ast)
RegisterScope scope(this);
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
- if (hasError)
+ if (hasError())
return false;
loadClosure(function);
setExprResult(Reference::fromAccumulator(this));
@@ -2357,7 +2382,7 @@ void Codegen::loadClosure(int closureId)
bool Codegen::visit(IdentifierExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation()));
@@ -2366,7 +2391,7 @@ bool Codegen::visit(IdentifierExpression *ast)
bool Codegen::visit(NestedExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
accept(ast->expression);
@@ -2385,7 +2410,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
}
auto calldata = pushArgs(arguments);
- if (hasError)
+ if (hasError())
return;
if (base.isSuper())
@@ -2415,14 +2440,14 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
bool Codegen::visit(NewExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2435,14 +2460,14 @@ bool Codegen::visit(NewExpression *ast)
bool Codegen::visit(NewMemberExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (base.isSuper()) {
throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super."));
@@ -2455,7 +2480,7 @@ bool Codegen::visit(NewMemberExpression *ast)
bool Codegen::visit(NotExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2465,7 +2490,7 @@ bool Codegen::visit(NotExpression *ast)
bool Codegen::visit(NullExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (exprAccept(cx))
@@ -2478,7 +2503,7 @@ bool Codegen::visit(NullExpression *)
bool Codegen::visit(NumericLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value)));
@@ -2487,7 +2512,7 @@ bool Codegen::visit(NumericLiteral *ast)
bool Codegen::visit(ObjectPattern *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2513,7 +2538,7 @@ bool Codegen::visit(ObjectPattern *ast)
if (cname || p->type != PatternProperty::Literal)
break;
QString name = p->name->asString();
- uint arrayIndex = QV4::String::toArrayIndex(name);
+ uint arrayIndex = stringToArrayIndex(name);
if (arrayIndex != UINT_MAX)
break;
if (members.contains(name))
@@ -2523,7 +2548,7 @@ bool Codegen::visit(ObjectPattern *ast)
{
RegisterScope innerScope(this);
Reference value = expression(p->initializer, name);
- if (hasError)
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2550,7 +2575,7 @@ bool Codegen::visit(ObjectPattern *ast)
if (cname) {
RegisterScope innerScope(this);
Reference name = expression(cname->expression);
- if (hasError)
+ if (hasError())
return false;
name.loadInAccumulator();
} else {
@@ -2575,12 +2600,12 @@ bool Codegen::visit(ObjectPattern *ast)
FunctionExpression *f = p->initializer->asFunctionDefinition();
Q_ASSERT(f);
int function = defineFunction(f->name.toString(), f, f->formals, f->body);
- if (hasError)
+ if (hasError())
return false;
Reference::fromConst(this, Encode(function)).loadInAccumulator();
} else {
Reference value = expression(p->initializer);
- if (hasError)
+ if (hasError())
return false;
value.loadInAccumulator();
}
@@ -2599,11 +2624,11 @@ bool Codegen::visit(ObjectPattern *ast)
bool Codegen::visit(PostDecrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2619,11 +2644,11 @@ bool Codegen::visit(PostDecrementExpression *ast)
bool Codegen::visit(PostIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->base);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation"));
@@ -2637,11 +2662,11 @@ bool Codegen::visit(PostIncrementExpression *ast)
}
bool Codegen::visit(PreDecrementExpression *ast)
-{ if (hasError)
+{ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2656,11 +2681,11 @@ bool Codegen::visit(PreDecrementExpression *ast)
bool Codegen::visit(PreIncrementExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (!expr.isLValue()) {
throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference."));
@@ -2675,7 +2700,7 @@ bool Codegen::visit(PreIncrementExpression *ast)
bool Codegen::visit(RegExpLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromStackSlot(this);
@@ -2691,7 +2716,7 @@ bool Codegen::visit(RegExpLiteral *ast)
bool Codegen::visit(StringLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
auto r = Reference::fromAccumulator(this);
@@ -2706,7 +2731,7 @@ bool Codegen::visit(StringLiteral *ast)
bool Codegen::visit(TemplateLiteral *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2723,7 +2748,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bytecodeGenerator->addInstruction(store);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (ast->next) {
@@ -2733,14 +2758,14 @@ bool Codegen::visit(TemplateLiteral *ast)
Instruction::Add instr;
instr.lhs = temp2;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
} else {
expr.loadInAccumulator();
}
Instruction::Add instr;
instr.lhs = temp;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
}
auto r = Reference::fromAccumulator(this);
@@ -2753,7 +2778,7 @@ bool Codegen::visit(TemplateLiteral *ast)
bool Codegen::visit(ThisExpression *)
{
- if (hasError)
+ if (hasError())
return false;
if (_context->isArrowFunction) {
@@ -2768,7 +2793,7 @@ bool Codegen::visit(ThisExpression *)
bool Codegen::visit(TildeExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2778,7 +2803,7 @@ bool Codegen::visit(TildeExpression *ast)
bool Codegen::visit(TrueLiteral *)
{
- if (hasError)
+ if (hasError())
return false;
setExprResult(Reference::fromConst(this, QV4::Encode(true)));
@@ -2787,14 +2812,14 @@ bool Codegen::visit(TrueLiteral *)
bool Codegen::visit(TypeOfExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
if (expr.type == Reference::Name) {
@@ -2814,7 +2839,7 @@ bool Codegen::visit(TypeOfExpression *ast)
bool Codegen::visit(UnaryMinusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2824,7 +2849,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
bool Codegen::visit(UnaryPlusExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
TailCallBlocker blockTailCalls(this);
@@ -2834,7 +2859,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
bool Codegen::visit(VoidExpression *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -2847,7 +2872,7 @@ bool Codegen::visit(VoidExpression *ast)
bool Codegen::visit(FunctionDeclaration * ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls: the function body isn't visited here.
@@ -2869,7 +2894,7 @@ bool Codegen::visit(YieldExpression *ast)
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
- if (hasError)
+ if (hasError())
return false;
Reference acc = Reference::fromAccumulator(this);
@@ -2998,10 +3023,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool savedFunctionEndsWithReturn = functionEndsWithReturn;
functionEndsWithReturn = endsWithReturn(_module, body);
- bytecodeGenerator->setTracing(_functionContext->canUseTracingJit(), _context->arguments.size());
// reserve the js stack frame (Context & js Function & accumulator)
- bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
+ bytecodeGenerator->newRegisterArray(
+ sizeof(CallData) / sizeof(StaticValue) - 1 + _context->arguments.size());
bool _inFormalParameterList = false;
qSwap(_inFormalParameterList, inFormalParameterList);
@@ -3047,7 +3072,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
} else {
if (e->bindingTarget || e->initializer) {
initializeAndDestructureBindingElement(e, arg);
- if (hasError)
+ if (hasError())
break;
}
}
@@ -3063,7 +3088,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
statementList(body);
- if (!hasError) {
+ if (!hasError()) {
bytecodeGenerator->setLocation(ast->lastSourceLocation());
_context->emitBlockFooter(this);
@@ -3085,7 +3110,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
_context->registerCountInFunction = bytecodeGenerator->registerCount();
- _context->nTraceInfos = bytecodeGenerator->traceInfoCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
@@ -3111,7 +3135,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool Codegen::visit(Block *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3123,7 +3147,7 @@ bool Codegen::visit(Block *ast)
bool Codegen::visit(BreakStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3148,7 +3172,7 @@ bool Codegen::visit(BreakStatement *ast)
bool Codegen::visit(ContinueStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
// no need to block tail calls here: children aren't visited
@@ -3181,7 +3205,7 @@ bool Codegen::visit(DebuggerStatement *)
bool Codegen::visit(DoWhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3191,22 +3215,28 @@ bool Codegen::visit(DoWhileStatement *ast)
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
ControlFlowLoop flow(this, &end, &cond);
- bytecodeGenerator->jump().link(body);
-
- cond.link();
- bytecodeGenerator->addLoopStart(cond);
- if (!AST::cast<TrueLiteral *>(ast->expression)) {
- TailCallBlocker blockTailCalls(this);
- condition(ast->expression, &body, &end, true);
- }
+ // special case that is not a loop:
+ // do {...} while (false)
+ if (!AST::cast<FalseLiteral *>(ast->expression))
+ bytecodeGenerator->addLoopStart(body);
body.link();
statement(ast->statement);
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->semicolonToken);
- if (!AST::cast<FalseLiteral *>(ast->expression))
- bytecodeGenerator->jump().link(cond);
+ cond.link();
+ if (AST::cast<TrueLiteral *>(ast->expression)) {
+ // do {} while (true) -> just jump back to the loop body, no need to generate a condition
+ bytecodeGenerator->checkException();
+ bytecodeGenerator->jump().link(body);
+ } else if (AST::cast<FalseLiteral *>(ast->expression)) {
+ // do {} while (false) -> fall through, no need to generate a condition
+ } else {
+ TailCallBlocker blockTailCalls(this);
+ bytecodeGenerator->checkException();
+ condition(ast->expression, &body, &end, false);
+ }
end.link();
@@ -3220,7 +3250,7 @@ bool Codegen::visit(EmptyStatement *)
bool Codegen::visit(ExpressionStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3228,7 +3258,7 @@ bool Codegen::visit(ExpressionStatement *ast)
if (requiresReturnValue) {
Reference e = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
(void) e.storeOnStack(_returnAddress);
} else {
@@ -3239,7 +3269,7 @@ bool Codegen::visit(ExpressionStatement *ast)
bool Codegen::visit(ForEachStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3255,7 +3285,7 @@ bool Codegen::visit(ForEachStatement *ast)
RegisterScope innerScope(this);
ControlFlowBlock controlFlow(this, ast);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3285,7 +3315,7 @@ bool Codegen::visit(ForEachStatement *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
// each iteration gets it's own context, as per spec
{
@@ -3298,7 +3328,7 @@ bool Codegen::visit(ForEachStatement *ast)
destructurePattern(p, lhsValue);
} else {
Reference lhs = expression(e);
- if (hasError)
+ if (hasError())
goto error;
if (!lhs.isLValue()) {
throwReferenceError(e->firstSourceLocation(), QStringLiteral("Invalid left-hand side expression for 'in' expression"));
@@ -3310,7 +3340,7 @@ bool Codegen::visit(ForEachStatement *ast)
}
} else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
initializeAndDestructureBindingElement(p, lhsValue, /*isDefinition =*/ true);
- if (hasError)
+ if (hasError())
goto error;
} else {
Q_UNREACHABLE();
@@ -3321,6 +3351,7 @@ bool Codegen::visit(ForEachStatement *ast)
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
}
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
error:
@@ -3335,7 +3366,7 @@ bool Codegen::visit(ForEachStatement *ast)
bool Codegen::visit(ForStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3369,6 +3400,7 @@ bool Codegen::visit(ForStatement *ast)
bytecodeGenerator->addInstruction(clone);
}
statement(ast->expression);
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(cond);
end.link();
@@ -3378,7 +3410,7 @@ bool Codegen::visit(ForStatement *ast)
bool Codegen::visit(IfStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3410,7 +3442,7 @@ bool Codegen::visit(IfStatement *ast)
bool Codegen::visit(LabelledStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3458,7 +3490,7 @@ void Codegen::emitReturn(const Reference &expr)
bool Codegen::visit(ReturnStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
@@ -3468,7 +3500,7 @@ bool Codegen::visit(ReturnStatement *ast)
Reference expr;
if (ast->expression) {
expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
} else {
expr = Reference::fromConst(this, Encode::undefined());
@@ -3481,7 +3513,7 @@ bool Codegen::visit(ReturnStatement *ast)
bool Codegen::visit(SwitchStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (requiresReturnValue)
@@ -3494,7 +3526,7 @@ bool Codegen::visit(SwitchStatement *ast)
BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
Reference lhs = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
lhs = lhs.storeOnStack();
@@ -3513,7 +3545,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3522,7 +3554,7 @@ bool Codegen::visit(SwitchStatement *ast)
for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
CaseClause *clause = it->clause;
Reference rhs = expression(clause->expression);
- if (hasError)
+ if (hasError())
return false;
rhs.loadInAccumulator();
bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause));
@@ -3568,14 +3600,14 @@ bool Codegen::visit(SwitchStatement *ast)
bool Codegen::visit(ThrowStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
expr.loadInAccumulator();
@@ -3612,7 +3644,7 @@ void Codegen::handleTryFinally(TryStatement *ast)
bool Codegen::visit(TryStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
@@ -3628,7 +3660,7 @@ bool Codegen::visit(TryStatement *ast)
bool Codegen::visit(VariableStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
variableDeclarationList(ast->declarations);
@@ -3637,7 +3669,7 @@ bool Codegen::visit(VariableStatement *ast)
bool Codegen::visit(WhileStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
if (AST::cast<FalseLiteral *>(ast->expression))
@@ -3651,6 +3683,8 @@ bool Codegen::visit(WhileStatement *ast)
ControlFlowLoop flow(this, &end, &cond);
bytecodeGenerator->addLoopStart(cond);
+ bytecodeGenerator->checkException();
+
if (!AST::cast<TrueLiteral *>(ast->expression)) {
TailCallBlocker blockTailCalls(this);
condition(ast->expression, &start, &end, true);
@@ -3667,14 +3701,14 @@ bool Codegen::visit(WhileStatement *ast)
bool Codegen::visit(WithStatement *ast)
{
- if (hasError)
+ if (hasError())
return false;
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference src = expression(ast->expression);
- if (hasError)
+ if (hasError())
return false;
src = src.storeOnStack(); // trigger load before we setup the exception handler, so exceptions here go to the right place
src.loadInAccumulator();
@@ -3744,52 +3778,79 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
return isArgOrEval;
}
-void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwError(ErrorType errorType, const SourceLocation &loc, const QString &detail)
{
- if (hasError)
+ if (hasError())
return;
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+ _errorType = errorType;
+ _error.message = detail;
+ _error.line = loc.startLine;
+ _error.column = loc.startColumn;
}
-void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
+void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
- if (hasError)
- return;
-
- hasError = true;
- QQmlJS::DiagnosticMessage error;
- error.message = detail;
- error.loc = loc;
- _errors << error;
+ throwError(SyntaxError, loc, detail);
}
-QList<QQmlJS::DiagnosticMessage> Codegen::errors() const
+void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
- return _errors;
+ throwError(ReferenceError, loc, detail);
}
-QQmlRefPointer<CompiledData::CompilationUnit> Codegen::generateCompilationUnit(bool generateUnitData)
+QQmlJS::DiagnosticMessage Codegen::error() const
{
- CompiledData::Unit *unitData = nullptr;
- if (generateUnitData)
- unitData = jsUnitGenerator->generateUnit();
- CompiledData::CompilationUnit *compilationUnit = new CompiledData::CompilationUnit(unitData);
+ return _error;
+}
- QQmlRefPointer<CompiledData::CompilationUnit> unit;
- unit.adopt(compilationUnit);
- return unit;
+QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit(
+ bool generateUnitData)
+{
+ return QV4::CompiledData::CompilationUnit(
+ generateUnitData ? jsUnitGenerator->generateUnit() : nullptr);
}
-QQmlRefPointer<CompiledData::CompilationUnit> Codegen::createUnitForLoading()
+CompiledData::CompilationUnit Codegen::compileModule(
+ bool debugMode, const QString &url, const QString &sourceCode,
+ const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
{
- QQmlRefPointer<CompiledData::CompilationUnit> result;
- result.adopt(new CompiledData::CompilationUnit);
- return result;
+ QQmlJS::Engine ee;
+ QQmlJS::Lexer lexer(&ee);
+ lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false);
+ QQmlJS::Parser parser(&ee);
+
+ const bool parsed = parser.parseModule();
+
+ if (diagnostics)
+ *diagnostics = parser.diagnosticMessages();
+
+ if (!parsed)
+ return CompiledData::CompilationUnit();
+
+ QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
+ if (!moduleNode) {
+ // if parsing was successful, and we have no module, then
+ // the file was empty.
+ if (diagnostics)
+ diagnostics->clear();
+ return nullptr;
+ }
+
+ using namespace QV4::Compiler;
+ Compiler::Module compilerModule(debugMode);
+ compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
+ compilerModule.sourceTimeStamp = sourceTimeStamp;
+ JSUnitGenerator jsGenerator(&compilerModule);
+ Codegen cg(&jsGenerator, /*strictMode*/true);
+ cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule);
+ if (cg.hasError()) {
+ if (diagnostics)
+ *diagnostics << cg.error();
+ return CompiledData::CompilationUnit();
+ }
+
+ return cg.generateCompilationUnit();
}
class Codegen::VolatileMemoryLocationScanner: protected QQmlJS::AST::Visitor
@@ -3905,34 +3966,11 @@ Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node
return scanner.scan(ast);
}
-
-#ifndef V4_BOOTSTRAP
-
-QList<QQmlError> Codegen::qmlErrors() const
+QUrl Codegen::url() const
{
- QList<QQmlError> qmlErrors;
-
- // Short circuit to avoid costly (de)heap allocation of QUrl if there are no errors.
- if (_errors.size() == 0)
- return qmlErrors;
-
- qmlErrors.reserve(_errors.size());
-
- QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
- for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) {
- QQmlError e;
- e.setUrl(url);
- e.setLine(msg.loc.startLine);
- e.setColumn(msg.loc.startColumn);
- e.setDescription(msg.message);
- qmlErrors << e;
- }
-
- return qmlErrors;
+ return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName));
}
-#endif // V4_BOOTSTRAP
-
bool Codegen::RValue::operator==(const RValue &other) const
{
switch (type) {
@@ -4222,7 +4260,7 @@ void Codegen::Reference::storeAccumulator() const
Instruction::StoreElement store;
store.base = elementBase;
store.index = elementSubscript.stackSlot();
- codegen->bytecodeGenerator->addTracingInstruction(store);
+ codegen->bytecodeGenerator->addInstruction(store);
} return;
case Invalid:
case Accumulator:
@@ -4280,7 +4318,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
Instruction::LoadUndefined load;
codegen->bytecodeGenerator->addInstruction(load);
} else {
- Value p = Value::fromReturnedValue(constant);
+ StaticValue p = StaticValue::fromReturnedValue(constant);
if (p.isNumber()) {
double d = p.asDouble();
int i = static_cast<int>(d);
@@ -4291,7 +4329,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
return;
}
Instruction::LoadInt load;
- load.value = Value::fromReturnedValue(constant).toInt32();
+ load.value = StaticValue::fromReturnedValue(constant).toInt32();
codegen->bytecodeGenerator->addInstruction(load);
return;
}
@@ -4312,12 +4350,12 @@ QT_WARNING_POP
if (!scope) {
Instruction::LoadLocal load;
load.index = index;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadScopedLocal load;
load.index = index;
load.scope = scope;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
tdzCheck(requiresTDZCheck);
return;
@@ -4341,16 +4379,16 @@ QT_WARNING_POP
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Member:
@@ -4359,11 +4397,11 @@ QT_WARNING_POP
if (!disable_lookups && codegen->useFastLookups) {
Instruction::GetLookup load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadProperty load;
load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Import: {
@@ -4378,7 +4416,7 @@ QT_WARNING_POP
tdzCheck(subscriptRequiresTDZCheck);
Instruction::LoadElement load;
load.base = elementBase;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} return;
case Invalid:
break;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 958dd16816..82a4fc3289 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -50,19 +50,18 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsengine_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qv4compiler_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4util_p.h>
#include <private/qv4bytecodegenerator_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4calldata_p.h>
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -79,7 +78,7 @@ struct ControlFlow;
struct ControlFlowCatch;
struct ControlFlowFinally;
-class Q_QML_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
+class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
{
protected:
using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
@@ -91,14 +90,14 @@ public:
void generateFromProgram(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::Program *ast,
+ QQmlJS::AST::Program *ast,
Module *module,
ContextType contextType = ContextType::Global);
void generateFromModule(const QString &fileName,
const QString &finalUrl,
const QString &sourceCode,
- AST::ESModule *ast,
+ QQmlJS::AST::ESModule *ast,
Module *module);
public:
@@ -256,7 +255,8 @@ public:
}
static Reference fromArgument(Codegen *cg, int index, bool isVolatile) {
Reference r(cg, StackSlot);
- r.theStackSlot = Moth::StackSlot::createRegister(index + sizeof(CallData)/sizeof(Value) - 1);
+ r.theStackSlot = Moth::StackSlot::createRegister(
+ index + sizeof(CallData) / sizeof(StaticValue) - 1);
r.stackSlotIsLocalOrArgument = true;
r.isVolatile = isVolatile;
return r;
@@ -484,10 +484,10 @@ protected:
}
};
- void enterContext(AST::Node *node);
+ void enterContext(QQmlJS::AST::Node *node);
int leaveContext();
public:
- Context *enterBlock(AST::Node *node);
+ Context *enterBlock(QQmlJS::AST::Node *node);
int leaveBlock() { return leaveContext(); }
protected:
void leaveLoop();
@@ -518,20 +518,20 @@ public:
int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); }
// Returns index in _module->functions
- virtual int defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::StatementList *body);
+ virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body);
protected:
- void statement(AST::Statement *ast);
- void statement(AST::ExpressionNode *ast);
- void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
+ void statement(QQmlJS::AST::Statement *ast);
+ void statement(QQmlJS::AST::ExpressionNode *ast);
+ void condition(QQmlJS::AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
- inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
+ inline Reference expression(QQmlJS::AST::ExpressionNode *ast, const QString &name = QString())
{
- if (!ast || hasError)
+ if (!ast || hasError())
return Reference();
pushExpr(name);
@@ -539,160 +539,173 @@ protected:
return popResult();
}
- inline void accept(AST::Node *node)
+ inline void accept(QQmlJS::AST::Node *node)
{
- if (!hasError && node)
+ if (!hasError() && node)
node->accept(this);
}
- void program(AST::Program *ast);
- void statementList(AST::StatementList *ast);
- void variableDeclaration(AST::PatternElement *ast);
- void variableDeclarationList(AST::VariableDeclarationList *ast);
+ void program(QQmlJS::AST::Program *ast);
+ void statementList(QQmlJS::AST::StatementList *ast);
+ void variableDeclaration(QQmlJS::AST::PatternElement *ast);
+ void variableDeclarationList(QQmlJS::AST::VariableDeclarationList *ast);
- Reference targetForPatternElement(AST::PatternElement *p);
- void initializeAndDestructureBindingElement(AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
- void destructurePropertyList(const Reference &object, AST::PatternPropertyList *bindingList, bool isDefinition = false);
- void destructureElementList(const Reference &array, AST::PatternElementList *bindingList, bool isDefinition = false);
- void destructurePattern(AST::Pattern *p, const Reference &rhs);
+ Reference targetForPatternElement(QQmlJS::AST::PatternElement *p);
+ void initializeAndDestructureBindingElement(QQmlJS::AST::PatternElement *e, const Reference &baseRef = Reference(), bool isDefinition = false);
+ void destructurePropertyList(const Reference &object, QQmlJS::AST::PatternPropertyList *bindingList, bool isDefinition = false);
+ void destructureElementList(const Reference &array, QQmlJS::AST::PatternElementList *bindingList, bool isDefinition = false);
+ void destructurePattern(QQmlJS::AST::Pattern *p, const Reference &rhs);
- Reference referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name);
+ Reference referenceForPropertyName(const Codegen::Reference &object, QQmlJS::AST::PropertyName *name);
void emitReturn(const Reference &expr);
// nodes
- bool visit(AST::ArgumentList *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- bool visit(AST::CaseClause *ast) override;
- bool visit(AST::CaseClauses *ast) override;
- bool visit(AST::Catch *ast) override;
- bool visit(AST::DefaultClause *ast) override;
- bool visit(AST::Elision *ast) override;
- bool visit(AST::Finally *ast) override;
- bool visit(AST::FormalParameterList *ast) override;
- bool visit(AST::Program *ast) override;
- bool visit(AST::StatementList *ast) override;
- bool visit(AST::UiArrayMemberList *ast) override;
- bool visit(AST::UiImport *ast) override;
- bool visit(AST::UiHeaderItemList *ast) override;
- bool visit(AST::UiPragma *ast) override;
- bool visit(AST::UiObjectInitializer *ast) override;
- bool visit(AST::UiObjectMemberList *ast) override;
- bool visit(AST::UiParameterList *ast) override;
- bool visit(AST::UiProgram *ast) override;
- bool visit(AST::UiQualifiedId *ast) override;
- bool visit(AST::VariableDeclarationList *ast) override;
-
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::PatternElementList *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- bool visit(AST::PatternPropertyList *ast) override;
-
- bool visit(AST::ExportDeclaration *ast) override;
+ bool visit(QQmlJS::AST::ArgumentList *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseClause *ast) override;
+ bool visit(QQmlJS::AST::CaseClauses *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::DefaultClause *ast) override;
+ bool visit(QQmlJS::AST::Elision *ast) override;
+ bool visit(QQmlJS::AST::Finally *ast) override;
+ bool visit(QQmlJS::AST::FormalParameterList *ast) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ bool visit(QQmlJS::AST::StatementList *ast) override;
+ bool visit(QQmlJS::AST::UiArrayMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiImport *ast) override;
+ bool visit(QQmlJS::AST::UiHeaderItemList *ast) override;
+ bool visit(QQmlJS::AST::UiPragma *ast) override;
+ bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
+ bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
+ bool visit(QQmlJS::AST::UiParameterList *ast) override;
+ bool visit(QQmlJS::AST::UiProgram *ast) override;
+ bool visit(QQmlJS::AST::UiQualifiedId *ast) override;
+ bool visit(QQmlJS::AST::VariableDeclarationList *ast) override;
+
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::PatternElementList *ast) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ bool visit(QQmlJS::AST::PatternPropertyList *ast) override;
+
+ bool visit(QQmlJS::AST::ExportDeclaration *ast) override;
+
+ bool visit(QQmlJS::AST::TypeAnnotation *ast) override;
// expressions
- bool visit(AST::Expression *ast) override;
- bool visit(AST::ArrayPattern *ast) override;
- bool visit(AST::ArrayMemberExpression *ast) override;
- bool visit(AST::BinaryExpression *ast) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::ConditionalExpression *ast) override;
- bool visit(AST::DeleteExpression *ast) override;
- bool visit(AST::FalseLiteral *ast) override;
- bool visit(AST::SuperLiteral *ast) override;
- bool visit(AST::FieldMemberExpression *ast) override;
- bool visit(AST::TaggedTemplate *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::NestedExpression *ast) override;
- bool visit(AST::NewExpression *ast) override;
- bool visit(AST::NewMemberExpression *ast) override;
- bool visit(AST::NotExpression *ast) override;
- bool visit(AST::NullExpression *ast) override;
- bool visit(AST::NumericLiteral *ast) override;
- bool visit(AST::ObjectPattern *ast) override;
- bool visit(AST::PostDecrementExpression *ast) override;
- bool visit(AST::PostIncrementExpression *ast) override;
- bool visit(AST::PreDecrementExpression *ast) override;
- bool visit(AST::PreIncrementExpression *ast) override;
- bool visit(AST::RegExpLiteral *ast) override;
- bool visit(AST::StringLiteral *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::ThisExpression *ast) override;
- bool visit(AST::TildeExpression *ast) override;
- bool visit(AST::TrueLiteral *ast) override;
- bool visit(AST::TypeOfExpression *ast) override;
- bool visit(AST::UnaryMinusExpression *ast) override;
- bool visit(AST::UnaryPlusExpression *ast) override;
- bool visit(AST::VoidExpression *ast) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- bool visit(AST::YieldExpression *ast) override;
- bool visit(AST::ClassExpression *ast) override;
- bool visit(AST::ClassDeclaration *ast) override;
+ bool visit(QQmlJS::AST::Expression *ast) override;
+ bool visit(QQmlJS::AST::ArrayPattern *ast) override;
+ bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::BinaryExpression *ast) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
+ bool visit(QQmlJS::AST::DeleteExpression *ast) override;
+ bool visit(QQmlJS::AST::FalseLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *ast) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::TaggedTemplate *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::NestedExpression *ast) override;
+ bool visit(QQmlJS::AST::NewExpression *ast) override;
+ bool visit(QQmlJS::AST::NewMemberExpression *ast) override;
+ bool visit(QQmlJS::AST::NotExpression *ast) override;
+ bool visit(QQmlJS::AST::NullExpression *ast) override;
+ bool visit(QQmlJS::AST::NumericLiteral *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::PostDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PostIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreDecrementExpression *ast) override;
+ bool visit(QQmlJS::AST::PreIncrementExpression *ast) override;
+ bool visit(QQmlJS::AST::RegExpLiteral *ast) override;
+ bool visit(QQmlJS::AST::StringLiteral *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::TildeExpression *ast) override;
+ bool visit(QQmlJS::AST::TrueLiteral *ast) override;
+ bool visit(QQmlJS::AST::TypeOfExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryMinusExpression *ast) override;
+ bool visit(QQmlJS::AST::UnaryPlusExpression *ast) override;
+ bool visit(QQmlJS::AST::VoidExpression *ast) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ bool visit(QQmlJS::AST::YieldExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
// statements
- bool visit(AST::Block *ast) override;
- bool visit(AST::BreakStatement *ast) override;
- bool visit(AST::ContinueStatement *ast) override;
- bool visit(AST::DebuggerStatement *ast) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::EmptyStatement *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::ForEachStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- bool visit(AST::IfStatement *ast) override;
- bool visit(AST::LabelledStatement *ast) override;
- bool visit(AST::ReturnStatement *ast) override;
- bool visit(AST::SwitchStatement *ast) override;
- bool visit(AST::ThrowStatement *ast) override;
- bool visit(AST::TryStatement *ast) override;
- bool visit(AST::VariableStatement *ast) override;
- bool visit(AST::WhileStatement *ast) override;
- bool visit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ bool visit(QQmlJS::AST::BreakStatement *ast) override;
+ bool visit(QQmlJS::AST::ContinueStatement *ast) override;
+ bool visit(QQmlJS::AST::DebuggerStatement *ast) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::EmptyStatement *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ bool visit(QQmlJS::AST::IfStatement *ast) override;
+ bool visit(QQmlJS::AST::LabelledStatement *ast) override;
+ bool visit(QQmlJS::AST::ReturnStatement *ast) override;
+ bool visit(QQmlJS::AST::SwitchStatement *ast) override;
+ bool visit(QQmlJS::AST::ThrowStatement *ast) override;
+ bool visit(QQmlJS::AST::TryStatement *ast) override;
+ bool visit(QQmlJS::AST::VariableStatement *ast) override;
+ bool visit(QQmlJS::AST::WhileStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
// ui object members
- bool visit(AST::UiArrayBinding *ast) override;
- bool visit(AST::UiObjectBinding *ast) override;
- bool visit(AST::UiObjectDefinition *ast) override;
- bool visit(AST::UiPublicMember *ast) override;
- bool visit(AST::UiScriptBinding *ast) override;
- bool visit(AST::UiSourceElement *ast) override;
-
- bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, const AST::SourceLocation &loc);
- virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
- virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+ bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
+ bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiPublicMember *ast) override;
+ bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
+ bool visit(QQmlJS::AST::UiSourceElement *ast) override;
+
+ bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r,
+ const QQmlJS::AST::SourceLocation &loc);
+ virtual void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail);
void throwRecursionDepthError() override
{
- throwSyntaxError(AST::SourceLocation(),
+ throwSyntaxError(QQmlJS::AST::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
public:
- QList<DiagnosticMessage> errors() const;
-#ifndef V4_BOOTSTRAP
- QList<QQmlError> qmlErrors() const;
-#endif
+ enum ErrorType {
+ NoError,
+ SyntaxError,
+ ReferenceError
+ };
+
+ ErrorType errorType() const { return _errorType; }
+ bool hasError() const { return _errorType != NoError; }
+ QQmlJS::DiagnosticMessage error() const;
+ QUrl url() const;
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
struct Arguments { int argc; int argv; bool hasSpread; };
- Arguments pushArgs(AST::ArgumentList *args);
+ Arguments pushArgs(QQmlJS::AST::ArgumentList *args);
void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
- Arguments pushTemplateArgs(AST::TemplateLiteral *args);
- bool handleTaggedTemplate(Reference base, AST::TaggedTemplate *ast);
- void createTemplateObject(AST::TemplateLiteral *t);
+ Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
+ bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
+ void createTemplateObject(QQmlJS::AST::TemplateLiteral *t);
void setUseFastLookups(bool b) { useFastLookups = b; }
- void handleTryCatch(AST::TryStatement *ast);
- void handleTryFinally(AST::TryStatement *ast);
+ void handleTryCatch(QQmlJS::AST::TryStatement *ast);
+ void handleTryFinally(QQmlJS::AST::TryStatement *ast);
- Reference referenceForName(const QString &name, bool lhs, const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
+ Reference referenceForName(
+ const QString &name, bool lhs,
+ const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> generateCompilationUnit(bool generateUnitData = true);
- static QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading();
+ QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true);
+ static QV4::CompiledData::CompilationUnit compileModule(
+ bool debugMode, const QString &url, const QString &sourceCode,
+ const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
Context *currentContext() const { return _context; }
BytecodeGenerator *generator() const { return bytecodeGenerator; }
@@ -751,7 +764,7 @@ protected:
int _returnAddress;
Context *_context;
Context *_functionContext = nullptr;
- AST::LabelledStatement *_labelledStatement;
+ QQmlJS::AST::LabelledStatement *_labelledStatement;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
BytecodeGenerator *bytecodeGenerator = nullptr;
Moth::BytecodeGenerator::Label *_returnLabel = nullptr;
@@ -767,8 +780,8 @@ protected:
ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
- bool hasError;
- QList<QQmlJS::DiagnosticMessage> _errors;
+ ErrorType _errorType = NoError;
+ QQmlJS::DiagnosticMessage _error;
class TailCallBlocker
{
@@ -795,8 +808,10 @@ protected:
};
private:
- VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast);
- void handleConstruct(const Reference &base, AST::ArgumentList *args);
+ VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
+ void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
+ void throwError(ErrorType errorType, const QQmlJS::AST::SourceLocation &loc,
+ const QString &detail);
};
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 01c033cb2a..acc4b02e96 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -38,16 +38,24 @@
****************************************************************************/
#include <qv4compiler_p.h>
-#include <qv4compileddata_p.h>
#include <qv4codegen_p.h>
-#include <private/qv4string_p.h>
-#include <private/qv4value_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qv4alloca_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsast_p.h>
-#include <wtf/MathExtras.h>
+#include <private/qml_compile_hash_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <QCryptographicHash>
+// Efficient implementation that takes advantage of powers of two.
+static inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
+{
+ Q_ASSERT(divisor && !(divisor & (divisor - 1)));
+ const size_t remainderMask = divisor - 1;
+ return (x + remainderMask) & ~remainderMask;
+}
+
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
clear();
@@ -92,7 +100,7 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
- char *stringData = reinterpret_cast<char *>(stringTable) + WTF::roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
+ char *stringData = reinterpret_cast<char *>(stringTable) + roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
const int index = i - backingUnitTableSize;
stringTable[index] = stringData - dataStart;
@@ -119,6 +127,25 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
}
}
+void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Unit *unit)
+{
+#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ const int checksummableDataOffset
+ = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum);
+
+ const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset;
+ hash.addData(dataPtr, unit->unitSize - checksummableDataOffset);
+
+ QByteArray checksum = hash.result();
+ Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum));
+ memcpy(unit->md5Checksum, checksum.constData(), sizeof(unit->md5Checksum));
+#else
+ memset(unit->md5Checksum, 0, sizeof(unit->md5Checksum));
+#endif
+}
+
QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module)
: module(module)
{
@@ -242,8 +269,11 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(module->finalUrl);
for (Context *f : qAsConst(module->functions)) {
registerString(f->name);
- for (int i = 0; i < f->arguments.size(); ++i)
- registerString(f->arguments.at(i));
+ registerString(f->returnType);
+ for (int i = 0; i < f->arguments.size(); ++i) {
+ registerString(f->arguments.at(i).id);
+ registerString(f->arguments.at(i).typeName());
+ }
for (int i = 0; i < f->locals.size(); ++i)
registerString(f->locals.at(i));
}
@@ -385,7 +415,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
if (option == GenerateWithStringTable)
stringTable.serialize(unit);
- unit->generateChecksum();
+ generateUnitChecksum(unit);
return unit;
}
@@ -394,7 +424,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*function)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*function)));
function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
@@ -410,7 +440,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
- currentOffset += function->nFormals * sizeof(quint32);
+ currentOffset += function->nFormals * sizeof(CompiledData::Parameter);
+
+ QmlIR::Parameter::initType(&function->returnType, this, getStringId(irFunction->returnType));
function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
@@ -424,7 +456,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
Q_ASSERT(function->lineNumberOffset() == currentOffset);
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
if (!irFunction->labelInfo.empty()) {
@@ -440,9 +471,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->codeSize = irFunction->code.size();
// write formals
- quint32_le *formals = (quint32_le *)(f + function->formalsOffset);
- for (int i = 0; i < irFunction->arguments.size(); ++i)
- formals[i] = getStringId(irFunction->arguments.at(i));
+ CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset);
+ for (int i = 0; i < irFunction->arguments.size(); ++i) {
+ QmlIR::Parameter::init(&formals[i], this, getStringId(irFunction->arguments.at(i).id),
+ getStringId(irFunction->arguments.at(i).typeName()));
+ }
// write locals
quint32_le *locals = (quint32_le *)(f + function->localsOffset);
@@ -545,7 +578,7 @@ void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context
{
QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
- quint32 currentOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, sizeof(*block)));
+ quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*block)));
block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
block->nLocals = irBlock->locals.size();
@@ -575,7 +608,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
- qstrcpy(unit.libraryVersionHash, CompiledData::qml_compile_hash);
+ qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
@@ -608,7 +641,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.constantTableSize = constants.size();
// Ensure we load constants from well-aligned addresses into for example SSE registers.
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(16, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(16, nextOffset));
unit.offsetToConstantTable = nextOffset;
nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
@@ -619,19 +652,19 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.translationTableSize = translations.count();
unit.offsetToTranslationTable = nextOffset;
nextOffset += unit.translationTableSize * sizeof(CompiledData::TranslationData);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
*tableSizePtr = count;
*offsetPtr = nextOffset;
nextOffset += count * sizeof(CompiledData::ExportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
};
reserveExportTable(module->localExportEntries.count(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
@@ -641,12 +674,12 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.importEntryTableSize = module->importEntries.count();
unit.offsetToImportEntryTable = nextOffset;
nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.moduleRequestTableSize = module->moduleRequests.count();
unit.offsetToModuleRequestTable = nextOffset;
nextOffset += unit.moduleRequestTableSize * sizeof(uint);
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
quint32 functionSize = 0;
for (int i = 0; i < module->functions.size(); ++i) {
@@ -686,7 +719,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
- nextOffset = static_cast<quint32>(WTF::roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
unit.offsetToStringTable = nextOffset;
nextOffset += stringTable.sizeOfTableAndData();
} else {
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 49e334bb81..4f3c718175 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -53,9 +53,10 @@
#include <QtCore/qstring.h>
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
-#include <private/qv4global_p.h>
+#include <private/qv4compilerglobal_p.h>
#include <private/qqmljsastfwd_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -72,10 +73,12 @@ struct JSClassMember;
namespace Compiler {
+struct Context;
+struct Module;
struct Class;
struct TemplateObject;
-struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT StringTableGenerator {
StringTableGenerator();
int registerString(const QString &str);
@@ -102,7 +105,9 @@ private:
bool frozen = false;
};
-struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
+ static void generateUnitChecksum(CompiledData::Unit *unit);
+
struct MemberInfo {
QString name;
bool isAccessor;
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index ca2d5128f4..88837b0feb 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -156,7 +156,7 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
result.isConst = false;
return result;
} else {
- result.index = argIdx + sizeof(CallData)/sizeof(Value) - 1;
+ result.index = argIdx + sizeof(CallData) / sizeof(StaticValue) - 1;
result.scope = 0;
result.type = ResolvedName::Stack;
result.isConst = false;
@@ -410,28 +410,4 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
-bool Context::canUseTracingJit() const
-{
-#if QT_CONFIG(qml_tracing)
- static bool forceTracing = !qEnvironmentVariableIsEmpty("QV4_FORCE_TRACING");
- if (forceTracing) //### we can probably remove this when tracing is turned on by default
- return true; // to be used by unittests
-
- static bool disableTracing = !qEnvironmentVariableIsEmpty("QV4_DISABLE_TRACING");
- if (disableTracing)
- return false;
-
- static QStringList onlyTrace =
- qEnvironmentVariable("QV4_ONLY_TRACE").split(QLatin1Char(','), QString::SkipEmptyParts);
- if (!onlyTrace.isEmpty())
- return onlyTrace.contains(name);
-
- //### the next condition should be refined and have the IR distinguish between escaping and
- // non-escaping locals
- return !requiresExecutionContext && !hasNestedFunctions;
-#else
- return false;
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 57ef4be36e..8c124ac409 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include "private/qv4global_p.h"
#include <private/qqmljsast_p.h>
#include <private/qv4compileddata_p.h>
#include <QtCore/QStringList>
@@ -62,8 +61,13 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace Moth {
+class BytecodeGenerator;
+}
+
namespace Compiler {
+class Codegen;
struct ControlFlow;
enum class ContextType {
@@ -162,7 +166,6 @@ struct Context {
int line = 0;
int column = 0;
int registerCountInFunction = 0;
- uint nTraceInfos = 0;
int functionIndex = -1;
int blockIndex = -1;
@@ -190,7 +193,8 @@ struct Context {
MemberMap members;
QSet<QString> usedVariables;
QQmlJS::AST::FormalParameterList *formals = nullptr;
- QStringList arguments;
+ QQmlJS::AST::BoundNames arguments;
+ QString returnType;
QStringList locals;
QStringList moduleRequests;
QVector<ImportEntry> importEntries;
@@ -289,7 +293,7 @@ struct Context {
{
// search backwards to handle duplicate argument names correctly
for (int i = arguments.size() - 1; i >= 0; --i) {
- if (arguments.at(i) == name)
+ if (arguments.at(i).id == name)
return i;
}
return -1;
@@ -363,8 +367,6 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
-
- bool canUseTracingJit() const;
};
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 5b622e81d8..5623473726 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include <private/qv4global_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmljsast_p.h>
#include <private/qv4bytecodegenerator_p.h>
@@ -279,7 +278,7 @@ struct ControlFlowWith : public ControlFlowUnwind
struct ControlFlowBlock : public ControlFlowUnwind
{
- ControlFlowBlock(Codegen *cg, AST::Node *ast)
+ ControlFlowBlock(Codegen *cg, QQmlJS::AST::Node *ast)
: ControlFlowUnwind(cg, Block)
{
block = cg->enterBlock(ast);
@@ -314,11 +313,11 @@ struct ControlFlowBlock : public ControlFlowUnwind
struct ControlFlowCatch : public ControlFlowUnwind
{
- AST::Catch *catchExpression;
+ QQmlJS::AST::Catch *catchExpression;
bool insideCatch = false;
BytecodeGenerator::ExceptionHandler exceptionLabel;
- ControlFlowCatch(Codegen *cg, AST::Catch *catchExpression)
+ ControlFlowCatch(Codegen *cg, QQmlJS::AST::Catch *catchExpression)
: ControlFlowUnwind(cg, Catch), catchExpression(catchExpression),
exceptionLabel(generator()->newExceptionHandler())
{
@@ -372,10 +371,10 @@ struct ControlFlowCatch : public ControlFlowUnwind
struct ControlFlowFinally : public ControlFlowUnwind
{
- AST::Finally *finally;
+ QQmlJS::AST::Finally *finally;
bool insideFinally = false;
- ControlFlowFinally(Codegen *cg, AST::Finally *finally)
+ ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally)
: ControlFlowUnwind(cg, Finally), finally(finally)
{
Q_ASSERT(finally != nullptr);
diff --git a/src/qml/qmldirparser/qqmlsourcecoordinate_p.h b/src/qml/compiler/qv4compilerglobal_p.h
index 76ac741ae8..3478074827 100644
--- a/src/qml/qmldirparser/qqmlsourcecoordinate_p.h
+++ b/src/qml/compiler/qv4compilerglobal_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLSOURCECOORDINATE_P_H
-#define QQMLSOURCECOORDINATE_P_H
+#ifndef QV4COMPILERGLOBAL_H
+#define QV4COMPILERGLOBAL_H
//
// W A R N I N G
@@ -52,21 +52,23 @@
//
#include <QtCore/qglobal.h>
+#include <QString>
-#include <climits>
+#include <private/qtqmlcompilerglobal_p.h>
QT_BEGIN_NAMESPACE
-inline quint16 qmlSourceCoordinate(int n)
-{
- return (n > 0 && n <= static_cast<int>(USHRT_MAX)) ? static_cast<quint16>(n) : 0;
-}
+namespace QV4 {
-inline int qmlSourceCoordinate(quint16 n)
-{
- return (n == 0) ? -1 : static_cast<int>(n);
-}
+enum class ObjectLiteralArgument {
+ Value,
+ Method,
+ Getter,
+ Setter
+};
+
+} // namespace QV4
QT_END_NAMESPACE
-#endif // QQMLSOURCECOORDINATE_P_H
+#endif // QV4COMPILERGLOBAL_H
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 8984b6931e..ab0ebf3d4b 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -44,18 +44,26 @@
#include <QtCore/QSet>
#include <QtCore/QBuffer>
#include <QtCore/QBitArray>
-#include <QtCore/QLinkedList>
#include <QtCore/QStack>
#include <private/qqmljsast_p.h>
#include <private/qv4compilercontext_p.h>
#include <private/qv4codegen_p.h>
-#include <private/qv4string_p.h>
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
+using namespace QQmlJS;
using namespace QQmlJS::AST;
+static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation)
+{
+ CompiledData::Location target;
+ target.line = astLocation.startLine;
+ target.column = astLocation.startColumn;
+ return target;
+}
+
+
ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType)
: QQmlJS::AST::Visitor(cg->recursionDepth())
, _cg(cg)
@@ -177,7 +185,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
entry.importName = QStringLiteral("*");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
} else if (declaration->exportClause) {
for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) {
@@ -190,22 +198,22 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.moduleRequest = module;
entry.exportName = spec->exportedIdentifier.toString();
- entry.location = it->firstSourceLocation();
+ entry.location = location(it->firstSourceLocation());
_context->exportEntries << entry;
}
} else if (auto *vstmt = AST::cast<AST::VariableStatement*>(declaration->variableStatementOrDeclaration)) {
- QStringList boundNames;
+ BoundNames boundNames;
for (VariableDeclarationList *it = vstmt->declarations; it; it = it->next) {
if (!it->declaration)
continue;
it->declaration->boundNames(&boundNames);
}
- for (const QString &name: boundNames) {
+ for (const auto &name: boundNames) {
Compiler::ExportEntry entry;
- entry.localName = name;
- entry.exportName = name;
- entry.location = vstmt->firstSourceLocation();
+ entry.localName = name.id;
+ entry.exportName = name.id;
+ entry.location = location(vstmt->firstSourceLocation());
_context->exportEntries << entry;
}
} else if (auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) {
@@ -214,7 +222,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = name;
entry.exportName = name;
- entry.location = classDecl->firstSourceLocation();
+ entry.location = location(classDecl->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -233,7 +241,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
Compiler::ExportEntry entry;
entry.localName = functionName;
entry.exportName = functionName;
- entry.location = fdef->firstSourceLocation();
+ entry.location = location(fdef->firstSourceLocation());
_context->exportEntries << entry;
if (declaration->exportDefault)
localNameForDefaultExport = entry.localName;
@@ -245,7 +253,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
entry.localName = localNameForDefaultExport;
_context->localNameForDefaultExport = localNameForDefaultExport;
entry.exportName = QStringLiteral("default");
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->exportEntries << entry;
}
@@ -270,7 +278,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("default");
entry.localName = import->importedDefaultBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -279,7 +287,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.moduleRequest = module;
entry.importName = QStringLiteral("*");
entry.localName = import->nameSpaceImport->importedBinding.toString();
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
@@ -292,7 +300,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
entry.importName = it->importSpecifier->identifier.toString();
else
entry.importName = entry.localName;
- entry.location = declaration->firstSourceLocation();
+ entry.location = location(declaration->firstSourceLocation());
_context->importEntries << entry;
}
}
@@ -319,26 +327,26 @@ bool ScanFunctions::visit(PatternElement *ast)
if (!ast->isVariableDeclaration())
return true;
- QStringList names;
+ BoundNames names;
ast->boundNames(&names);
QQmlJS::AST::SourceLocation lastInitializerLocation = ast->lastSourceLocation();
if (_context->lastBlockInitializerLocation.isValid())
lastInitializerLocation = _context->lastBlockInitializerLocation;
- for (const QString &name : qAsConst(names)) {
- if (_context->isStrict && (name == QLatin1String("eval") || name == QLatin1String("arguments")))
+ for (const auto &name : qAsConst(names)) {
+ if (_context->isStrict && (name.id == QLatin1String("eval") || name.id == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- checkName(QStringRef(&name), ast->identifierToken);
- if (name == QLatin1String("arguments"))
+ checkName(QStringRef(&name.id), ast->identifierToken);
+ if (name.id == QLatin1String("arguments"))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
return false;
}
- if (!_context->addLocalVar(name, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
+ if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
/*function*/nullptr, lastInitializerLocation)) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name.id));
return false;
}
}
@@ -672,6 +680,9 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
_context->isArrowFunction = true;
else if (expr->isGenerator)
_context->isGenerator = true;
+
+ if (expr->typeAnnotation)
+ _context->returnType = expr->typeAnnotation->type->toString();
}
@@ -684,11 +695,11 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
bool isSimpleParameterList = formals && formals->isSimpleParameterList();
- _context->arguments = formals ? formals->formals() : QStringList();
+ _context->arguments = formals ? formals->formals() : BoundNames();
- const QStringList boundNames = formals ? formals->boundNames() : QStringList();
+ const BoundNames boundNames = formals ? formals->boundNames() : BoundNames();
for (int i = 0; i < boundNames.size(); ++i) {
- const QString &arg = boundNames.at(i);
+ const QString &arg = boundNames.at(i).id;
if (_context->isStrict || !isSimpleParameterList) {
bool duplicate = (boundNames.indexOf(arg, i + 1) != -1);
if (duplicate) {
@@ -705,6 +716,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (!_context->arguments.contains(arg))
_context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var);
}
+
return true;
}
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 0f7bf1818a..2de80eac44 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -50,7 +50,7 @@
// We mean it.
//
-#include "private/qv4global_p.h"
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qqmljsastvisitor_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
@@ -62,8 +62,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlJS;
-
namespace QV4 {
namespace Moth {
@@ -83,84 +81,87 @@ class ScanFunctions: protected QQmlJS::AST::Visitor
typedef QScopedValueRollback<bool> TemporaryBoolAssignment;
public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
- void operator()(AST::Node *node);
+ void operator()(QQmlJS::AST::Node *node);
void enterGlobalEnvironment(ContextType compilationMode);
- void enterEnvironment(AST::Node *node, ContextType compilationMode, const QString &name);
+ void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
+ const QString &name);
void leaveEnvironment();
- void enterQmlFunction(AST::FunctionDeclaration *ast)
+ void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
{ enterFunction(ast, false); }
protected:
using Visitor::visit;
using Visitor::endVisit;
- void checkDirectivePrologue(AST::StatementList *ast);
+ void checkDirectivePrologue(QQmlJS::AST::StatementList *ast);
- void checkName(const QStringRef &name, const AST::SourceLocation &loc);
+ void checkName(const QStringRef &name, const QQmlJS::AST::SourceLocation &loc);
- bool visit(AST::Program *ast) override;
- void endVisit(AST::Program *) override;
+ bool visit(QQmlJS::AST::Program *ast) override;
+ void endVisit(QQmlJS::AST::Program *) override;
- bool visit(AST::ESModule *ast) override;
- void endVisit(AST::ESModule *) override;
+ bool visit(QQmlJS::AST::ESModule *ast) override;
+ void endVisit(QQmlJS::AST::ESModule *) override;
- bool visit(AST::ExportDeclaration *declaration) override;
- bool visit(AST::ImportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ExportDeclaration *declaration) override;
+ bool visit(QQmlJS::AST::ImportDeclaration *declaration) override;
- bool visit(AST::CallExpression *ast) override;
- bool visit(AST::PatternElement *ast) override;
- bool visit(AST::IdentifierExpression *ast) override;
- bool visit(AST::ExpressionStatement *ast) override;
- bool visit(AST::FunctionExpression *ast) override;
- bool visit(AST::TemplateLiteral *ast) override;
- bool visit(AST::SuperLiteral *) override;
- bool visit(AST::FieldMemberExpression *) override;
- bool visit(AST::ArrayPattern *) override;
+ bool visit(QQmlJS::AST::CallExpression *ast) override;
+ bool visit(QQmlJS::AST::PatternElement *ast) override;
+ bool visit(QQmlJS::AST::IdentifierExpression *ast) override;
+ bool visit(QQmlJS::AST::ExpressionStatement *ast) override;
+ bool visit(QQmlJS::AST::FunctionExpression *ast) override;
+ bool visit(QQmlJS::AST::TemplateLiteral *ast) override;
+ bool visit(QQmlJS::AST::SuperLiteral *) override;
+ bool visit(QQmlJS::AST::FieldMemberExpression *) override;
+ bool visit(QQmlJS::AST::ArrayPattern *) override;
- bool enterFunction(AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName);
- void endVisit(AST::FunctionExpression *) override;
+ void endVisit(QQmlJS::AST::FunctionExpression *) override;
- bool visit(AST::ObjectPattern *ast) override;
+ bool visit(QQmlJS::AST::ObjectPattern *ast) override;
- bool visit(AST::PatternProperty *ast) override;
- void endVisit(AST::PatternProperty *) override;
+ bool visit(QQmlJS::AST::PatternProperty *ast) override;
+ void endVisit(QQmlJS::AST::PatternProperty *) override;
- bool visit(AST::FunctionDeclaration *ast) override;
- void endVisit(AST::FunctionDeclaration *) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
- bool visit(AST::ClassExpression *ast) override;
- void endVisit(AST::ClassExpression *) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ void endVisit(QQmlJS::AST::ClassExpression *) override;
- bool visit(AST::ClassDeclaration *ast) override;
- void endVisit(AST::ClassDeclaration *) override;
+ bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
+ void endVisit(QQmlJS::AST::ClassDeclaration *) override;
- bool visit(AST::DoWhileStatement *ast) override;
- bool visit(AST::ForStatement *ast) override;
- void endVisit(AST::ForStatement *) override;
- bool visit(AST::ForEachStatement *ast) override;
- void endVisit(AST::ForEachStatement *) override;
+ bool visit(QQmlJS::AST::DoWhileStatement *ast) override;
+ bool visit(QQmlJS::AST::ForStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForStatement *) override;
+ bool visit(QQmlJS::AST::ForEachStatement *ast) override;
+ void endVisit(QQmlJS::AST::ForEachStatement *) override;
- bool visit(AST::ThisExpression *ast) override;
+ bool visit(QQmlJS::AST::ThisExpression *ast) override;
- bool visit(AST::Block *ast) override;
- void endVisit(AST::Block *ast) override;
+ bool visit(QQmlJS::AST::Block *ast) override;
+ void endVisit(QQmlJS::AST::Block *ast) override;
- bool visit(AST::CaseBlock *ast) override;
- void endVisit(AST::CaseBlock *ast) override;
+ bool visit(QQmlJS::AST::CaseBlock *ast) override;
+ void endVisit(QQmlJS::AST::CaseBlock *ast) override;
- bool visit(AST::Catch *ast) override;
- void endVisit(AST::Catch *ast) override;
+ bool visit(QQmlJS::AST::Catch *ast) override;
+ void endVisit(QQmlJS::AST::Catch *ast) override;
- bool visit(AST::WithStatement *ast) override;
- void endVisit(AST::WithStatement *ast) override;
+ bool visit(QQmlJS::AST::WithStatement *ast) override;
+ void endVisit(QQmlJS::AST::WithStatement *ast) override;
void throwRecursionDepthError() override;
protected:
- bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
+ bool enterFunction(QQmlJS::AST::Node *ast, const QString &name,
+ QQmlJS::AST::FormalParameterList *formals,
+ QQmlJS::AST::StatementList *body, bool enterName);
void calcEscapingVariables();
// fields:
@@ -173,7 +174,7 @@ protected:
ContextType defaultProgramType;
private:
- static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
+ static constexpr QQmlJS::AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 345f03ae8a..640a908dd3 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -39,7 +39,9 @@
#include "qv4instr_moth_p.h"
#include <private/qv4compileddata_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4calldata_p.h>
+
+#include <QtCore/qdebug.h>
using namespace QV4;
using namespace QV4::Moth;
@@ -56,9 +58,7 @@ int InstrInfo::size(Instr::Type type)
static QByteArray alignedNumber(int n) {
QByteArray number = QByteArray::number(n);
- while (number.size() < 8)
- number.prepend(' ');
- return number;
+ return number.prepend(8 - number.size(), ' ');
}
static QByteArray alignedLineNumber(int line) {
@@ -83,25 +83,6 @@ static QByteArray rawBytes(const char *data, int n)
return ba;
}
-static QString toString(QV4::ReturnedValue v)
-{
-#ifdef V4_BOOTSTRAP
- return QStringLiteral("string-const(%1)").arg(v);
-#else // !V4_BOOTSTRAP
- Value val = Value::fromReturnedValue(v);
- QString result;
- if (val.isInt32())
- result = QLatin1String("int ");
- else if (val.isDouble())
- result = QLatin1String("double ");
- if (val.isEmpty())
- result += QLatin1String("empty");
- else
- result += val.toQStringNoThrow();
- return result;
-#endif // V4_BOOTSTRAP
-}
-
#define ABSOLUTE_OFFSET() \
(code - start + offset)
@@ -128,22 +109,12 @@ const int InstrInfo::argumentCount[] = {
FOR_EACH_MOTH_INSTR_ALL(MOTH_COLLECT_NARGS)
};
-
-void dumpConstantTable(const Value *constants, uint count)
-{
- QDebug d = qDebug();
- d.nospace();
- for (uint i = 0; i < count; ++i)
- d << alignedNumber(int(i)).constData() << ": "
- << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
-}
-
QString dumpRegister(int reg, int nFormals)
{
Q_STATIC_ASSERT(offsetof(CallData, function) == 0);
- Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(Value));
- Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(Value));
+ Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(StaticValue));
+ Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(StaticValue));
if (reg == CallData::Function)
return QStringLiteral("(function)");
else if (reg == CallData::Context)
@@ -171,8 +142,6 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-#define TRACE_SLOT QStringLiteral(" {%1}").arg(traceSlot)
-
void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
{
MOTH_JUMP_TABLE;
@@ -241,9 +210,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index << TRACE_SLOT;
+ d << "l" << index;
else
- d << "a" << (index - nLocals) << TRACE_SLOT;
+ d << "a" << (index - nLocals);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -255,9 +224,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope << TRACE_SLOT;
+ d << "l" << index << "@" << scope;
else
- d << "a" << (index - nLocals) << "@" << scope << TRACE_SLOT;
+ d << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -280,15 +249,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name << TRACE_SLOT;
+ d << name;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
@@ -300,20 +269,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]" << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]" << TRACE_SLOT;
+ d << "acc[" << name << "]";
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")" << TRACE_SLOT;
+ d << "acc(" << index << ")";
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -343,49 +311,48 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ ;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
d << dumpRegister(base, nFormals) << "." << lookupIndex
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
@@ -528,11 +495,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
@@ -543,6 +510,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNoException)
+ MOTH_BEGIN_INSTR(CheckException)
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
@@ -596,22 +566,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(Increment)
- d << TRACE_SLOT;
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- d << TRACE_SLOT;
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
@@ -667,7 +634,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
@@ -675,11 +642,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 26901c297c..c0dd696b8a 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -50,9 +50,8 @@
//
// We mean it.
//
-#include <private/qv4global_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4runtime_p.h>
+
+#include <private/qv4staticvalue_p.h>
#include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper
#include <qendian.h>
@@ -77,20 +76,20 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg)
#define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg)
#define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index)
-#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 2, index, traceSlot)
+#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index)
#define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index)
-#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 3, scope, index, traceSlot)
+#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index)
#define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index)
#define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId)
#define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg)
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
-#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
-#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
-#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
+#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name)
+#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
-#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
-#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
+#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -100,18 +99,18 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
-#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
-#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
-#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 5, name, thisObject, argc, argv, traceSlot)
-#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 5, name, base, argc, argv, traceSlot)
-#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 5, lookupIndex, base, argc, argv, traceSlot)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 5, base, index, argc, argv, traceSlot)
-#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
-#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
-#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
+#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base)
+#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index)
+#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv)
+#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
+#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
+#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
+#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
+#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
+#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
+#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
@@ -148,10 +147,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
-#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 2, traceSlot, offset)
-#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 2, traceSlot, offset)
+#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
+#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset)
+#define INSTR_CheckException(op) INSTRUCTION(op, CheckException, 0)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -168,11 +168,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
-#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 1, traceSlot)
+#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
#define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0)
-#define INSTR_Increment(op) INSTRUCTION(op, Increment, 1, traceSlot)
-#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 1, traceSlot)
-#define INSTR_Add(op) INSTRUCTION(op, Add, 2, lhs, traceSlot)
+#define INSTR_Increment(op) INSTRUCTION(op, Increment, 0)
+#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0)
+#define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs)
#define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs)
#define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs)
#define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs)
@@ -186,10 +186,10 @@ QT_BEGIN_NAMESPACE
#define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs)
#define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs)
#define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs)
-#define INSTR_Mul(op) INSTRUCTION(op, Mul, 2, lhs, traceSlot)
+#define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
-#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
-#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
+#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
+#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -241,6 +241,7 @@ QT_BEGIN_NAMESPACE
F(JumpFalse) \
F(JumpNoException) \
F(JumpNotUndefined) \
+ F(CheckException) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
@@ -532,7 +533,6 @@ inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackS
// When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
-void dumpConstantTable(const Value *constants, uint count);
void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1,
const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>());
inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1,
diff --git a/src/qml/jsruntime/qv4util_p.h b/src/qml/compiler/qv4util_p.h
index 073832937d..bd9758c1fb 100644
--- a/src/qml/jsruntime/qv4util_p.h
+++ b/src/qml/compiler/qv4util_p.h
@@ -50,7 +50,6 @@
// We mean it.
//
-#include "qv4global_p.h"
#include <QtCore/QBitArray>
#include <algorithm>
#include <vector>
diff --git a/src/qml/configure.json b/src/qml/configure.json
index c35f5be06b..3fc1fd528b 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -8,7 +8,6 @@
"commandline": {
"options": {
"qml-network": "boolean",
- "qml-tracing": "boolean",
"qml-debug": "boolean"
}
},
@@ -24,6 +23,52 @@
],
"qmake": "CONFIG += c++11"
}
+ },
+ "pointer_32bit": {
+ "label": "32bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 4, \"fail\");"
+ }
+ },
+ "pointer_64bit": {
+ "label": "64bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 8, \"fail\");"
+ }
+ },
+ "arm_thumb": {
+ "label": "THUMB mode on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "#if defined(thumb2) || defined(__thumb2__)",
+ "# define THUMB_OK",
+ "#elif (defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4",
+ "# define THUMB_OK",
+ "#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 THUMB_OK",
+ "#else",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
+ },
+ "arm_fp": {
+ "label": "Sufficiently recent FPU on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "// if !defined(__ARM_FP) we might be on MSVC or we might have a device",
+ "// without an FPU.",
+ "// TODO: The latter case is not supported, but the test still succeeds.",
+ "#if defined(__ARM_FP) && (__ARM_FP <= 0x04)",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
}
},
@@ -40,12 +85,26 @@
"condition": "features.network",
"output": [ "publicFeature" ]
},
- "qml-tracing": {
- "label": "QML tracing JIT support",
- "purpose": "Provides a JIT that uses trace information generated by the interpreter.",
+ "qml-jit": {
+ "label": "QML just-in-time compiler",
+ "purpose": "Provides a JIT for QML and JavaScript",
"section": "QML",
+ "condition": [
+ " (arch.i386 && tests.pointer_32bit && features.sse2)
+ || (arch.x86_64 && tests.pointer_64bit && features.sse2)
+ || (arch.arm && tests.pointer_32bit && tests.arm_fp && tests.arm_thumb
+ && (config.linux || config.ios || config.tvos || config.qnx))
+ || (arch.arm64 && tests.pointer_64bit && tests.arm_fp
+ && (config.linux || config.ios || config.tvos || config.qnx || config.integrity))"
+ ],
"output": [ "privateFeature" ],
- "autoDetect": false
+ "autoDetect": "!config.ios && !config.tvos",
+ "comment": "On arm and arm64 we need a specialization of cacheFlush() for each OS to be
+ enabeled. Therefore the config white list.
+ Also Mind that e.g. x86_32 has arch.x86_64 but 32bit pointers. Therefore
+ the checks for architecture and pointer size.
+ Finally, ios and tvos can technically use the JIT but Apple does not allow
+ it. Therefore, it's disabled by default."
},
"qml-debug": {
"label": "QML debugging and profiling support",
@@ -90,12 +149,6 @@
"section": "QML",
"output": [ "privateFeature" ]
},
- "qml-list-model": {
- "label": "QML list model",
- "purpose": "Provides the ListModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-xml-http-request": {
"label": "QML XML http request",
"purpose": "Provides support for sending XML http requests.",
@@ -119,18 +172,19 @@
"condition": "features.animation",
"output": [ "privateFeature" ]
},
- "qml-delegate-model": {
- "label": "QML delegate model",
- "purpose": "Provides the DelegateModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-worker-script": {
"label": "QML WorkerScript",
"purpose": "Enables the use of threads in QML.",
"section": "QML",
"condition": "features.thread",
"output": [ "privateFeature" ]
+ },
+ "qml-itemmodel": {
+ "label": "QML Item Model",
+ "purpose": "Provides the item model for item views in QML",
+ "section": "QML",
+ "condition": "features.itemmodel",
+ "output": [ "privateFeature" ]
}
},
@@ -140,12 +194,10 @@
"entries": [
"qml-network",
"qml-debug",
- "qml-tracing",
+ "qml-jit",
"qml-sequence-object",
- "qml-list-model",
"qml-xml-http-request",
- "qml-locale",
- "qml-delegate-model"
+ "qml-locale"
]
}
]
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index 202a46e550..1281886816 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -14,7 +14,6 @@ qtConfig(qml-debug) {
$$PWD/qqmldebugconnector.cpp \
$$PWD/qqmldebugservice.cpp \
$$PWD/qqmlabstractprofileradapter.cpp \
- $$PWD/qqmlmemoryprofiler.cpp \
$$PWD/qqmlprofiler.cpp \
$$PWD/qqmldebugserviceinterfaces.cpp
}
@@ -24,7 +23,6 @@ HEADERS += \
$$PWD/qqmldebugserviceinterfaces_p.h \
$$PWD/qqmldebugstatesdelegate_p.h \
$$PWD/qqmldebug.h \
- $$PWD/qqmlmemoryprofiler_p.h \
$$PWD/qqmlprofiler_p.h
INCLUDEPATH += $$PWD
diff --git a/src/qml/debugger/qqmlconfigurabledebugservice_p.h b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
index 96ec46f475..38f41047c0 100644
--- a/src/qml/debugger/qqmlconfigurabledebugservice_p.h
+++ b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
@@ -64,7 +64,7 @@ class QQmlConfigurableDebugService : public Base
{
protected:
QQmlConfigurableDebugService(float version, QObject *parent = nullptr) :
- Base(version, parent), m_configMutex(QMutex::Recursive)
+ Base(version, parent)
{
init();
}
@@ -103,7 +103,7 @@ protected:
emit Base::attachedToEngine(engine);
}
- QMutex m_configMutex;
+ QRecursiveMutex m_configMutex;
QList<QJSEngine *> m_waitingEngines;
bool m_waitingForConfiguration;
};
diff --git a/src/qml/debugger/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp
deleted file mode 100644
index b89dbfd02d..0000000000
--- a/src/qml/debugger/qqmlmemoryprofiler.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlmemoryprofiler_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-QQmlMemoryScope::LibraryState QQmlMemoryScope::state = QQmlMemoryScope::Unloaded;
-
-typedef void (qmlmemprofile_stats)(int *allocCount, int *bytesAllocated);
-typedef void (qmlmemprofile_clear)();
-typedef void (qmlmemprofile_enable)();
-typedef void (qmlmemprofile_disable)();
-typedef void (qmlmemprofile_push_location)(const char *filename, int lineNumber);
-typedef void (qmlmemprofile_pop_location)();
-typedef void (qmlmemprofile_save)(const char *filename);
-typedef int (qmlmemprofile_is_enabled)();
-
-static qmlmemprofile_stats *memprofile_stats;
-static qmlmemprofile_clear *memprofile_clear;
-static qmlmemprofile_enable *memprofile_enable;
-static qmlmemprofile_disable *memprofile_disable;
-static qmlmemprofile_push_location *memprofile_push_location;
-static qmlmemprofile_pop_location *memprofile_pop_location;
-static qmlmemprofile_save *memprofile_save;
-static qmlmemprofile_is_enabled *memprofile_is_enabled;
-
-#if QT_CONFIG(library)
-extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol);
-#endif
-
-bool QQmlMemoryScope::doOpenLibrary()
-{
-#if defined(Q_OS_LINUX) && QT_CONFIG(library)
- if (state == Unloaded) {
- memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats");
- memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear");
- memprofile_enable = (qmlmemprofile_enable *) qt_linux_find_symbol_sys("qmlmemprofile_enable");
- memprofile_disable = (qmlmemprofile_disable *) qt_linux_find_symbol_sys("qmlmemprofile_disable");
- memprofile_push_location = (qmlmemprofile_push_location *) qt_linux_find_symbol_sys("qmlmemprofile_push_location");
- memprofile_pop_location = (qmlmemprofile_pop_location *) qt_linux_find_symbol_sys("qmlmemprofile_pop_location");
- memprofile_save = (qmlmemprofile_save *) qt_linux_find_symbol_sys("qmlmemprofile_save");
- memprofile_is_enabled = (qmlmemprofile_is_enabled *) qt_linux_find_symbol_sys("qmlmemprofile_is_enabled");
-
- if (memprofile_stats && memprofile_clear && memprofile_enable && memprofile_disable &&
- memprofile_push_location && memprofile_pop_location && memprofile_save && memprofile_is_enabled)
- state = Loaded;
- else
- state = Failed;
- }
-#endif // Q_OS_LINUX
-
- return state == Loaded;
-}
-
-void QQmlMemoryScope::init(const char *string)
-{
- if (memprofile_is_enabled()) {
- memprofile_push_location(string, 0);
- pushed = true;
- }
-}
-
-void QQmlMemoryScope::done()
-{
- memprofile_pop_location();
-}
-
-bool QQmlMemoryProfiler::isEnabled()
-{
- if (QQmlMemoryScope::openLibrary())
- return memprofile_is_enabled();
-
- return false;
-}
-
-void QQmlMemoryProfiler::enable()
-{
- if (QQmlMemoryScope::openLibrary())
- memprofile_enable();
-}
-
-void QQmlMemoryProfiler::disable()
-{
- if (QQmlMemoryScope::openLibrary())
- memprofile_disable();
-}
-
-void QQmlMemoryProfiler::clear()
-{
- if (QQmlMemoryScope::openLibrary())
- memprofile_clear();
-}
-
-void QQmlMemoryProfiler::stats(int *allocCount, int *bytesAllocated)
-{
- if (QQmlMemoryScope::openLibrary())
- memprofile_stats(allocCount, bytesAllocated);
-}
-
-void QQmlMemoryProfiler::save(const char *filename)
-{
- if (QQmlMemoryScope::openLibrary())
- memprofile_save(filename);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index d01e2bc429..d3eedab1c6 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -171,10 +171,11 @@ public:
: Location(ref->sourceLocation()), locationType(Binding), sent(false)
{
function = ref;
- function->compilationUnit->addref();
+ function->executableCompilationUnit()->addref();
}
- RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj, const QString &type)
+ RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url,
+ const QV4::CompiledData::Object *obj, const QString &type)
: Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
locationType(Creating), sent(false)
{
@@ -230,7 +231,7 @@ public:
switch (locationType) {
case Binding:
- function->compilationUnit->addref();
+ function->executableCompilationUnit()->addref();
break;
case Creating:
unit->addref();
@@ -254,7 +255,7 @@ public:
switch (locationType) {
case Binding:
- function->compilationUnit->release();
+ function->executableCompilationUnit()->release();
break;
case Creating:
unit->release();
@@ -284,7 +285,7 @@ public:
RangeType locationType;
union {
QV4::Function *function;
- QV4::CompiledData::CompilationUnit *unit;
+ QV4::ExecutableCompilationUnit *unit;
QQmlBoundSignalExpression *boundSignal;
QQmlDataBlob *blob;
void *something;
@@ -356,7 +357,7 @@ public:
}
void updateCreating(const QV4::CompiledData::Object *obj,
- QV4::CompiledData::CompilationUnit *ref,
+ QV4::ExecutableCompilationUnit *ref,
const QUrl &url, const QString &type)
{
quintptr locationId(id(obj));
@@ -492,7 +493,7 @@ public:
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
- void update(QV4::CompiledData::CompilationUnit *ref, const QV4::CompiledData::Object *obj,
+ void update(QV4::ExecutableCompilationUnit *ref, const QV4::CompiledData::Object *obj,
const QString &typeName, const QUrl &url)
{
profiler->updateCreating(obj, ref, url, typeName);
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index cb9fb575b2..74d0a3b27c 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -37,11 +37,17 @@ tagfile = ../../../doc/qtqml/qtqml.tags
depends += qtcore qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets qtxmlpatterns qtquickcontrols
headerdirs += .. \
- ../../imports/models
+ ../../imports/models \
+ ../../qmlmodels \
+ ../../qml \
+ ../../qmlworkerscript
sourcedirs += .. \
../../imports/models \
- ../../imports/statemachine
+ ../../imports/statemachine \
+ ../../qmlmodels \
+ ../../qml \
+ ../../qmlworkerscript
exampledirs += ../../../examples/qml \
../ \
diff --git a/src/qml/doc/snippets/delegatemodel/delegatemodel.qml b/src/qml/doc/snippets/delegatemodel/delegatemodel.qml
deleted file mode 100644
index 1a7baa6b1e..0000000000
--- a/src/qml/doc/snippets/delegatemodel/delegatemodel.qml
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
-
-Rectangle {
- width: 200; height: 100
-
- DelegateModel {
- id: visualModel
- model: ListModel {
- ListElement { name: "Apple" }
- ListElement { name: "Orange" }
- }
- delegate: Rectangle {
- height: 25
- width: 100
- Text { text: "Name: " + name}
- }
- }
-
- ListView {
- anchors.fill: parent
- model: visualModel
- }
-}
-//![0]
diff --git a/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/main.cpp b/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/main.cpp
deleted file mode 100644
index a56eb69616..0000000000
--- a/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/main.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <QQuickView>
-#include <QQmlContext>
-
-#include <QApplication>
-#include <QDirModel>
-
-//![0]
-int main(int argc, char ** argv)
-{
- QApplication app(argc, argv);
-
- QQuickView view;
-
- QDirModel model;
- view.rootContext()->setContextProperty("dirModel", &model);
-
- view.setSource(QUrl::fromLocalFile("view.qml"));
- view.show();
-
- return app.exec();
-}
-//![0]
-
diff --git a/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml b/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml
deleted file mode 100644
index 2e17eed8f0..0000000000
--- a/src/qml/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
-
-ListView {
- id: view
- width: 300
- height: 400
-
- model: DelegateModel {
- model: dirModel
-
- delegate: Rectangle {
- width: 200; height: 25
- Text { text: filePath }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (model.hasModelChildren)
- view.model.rootIndex = view.model.modelIndex(index)
- }
- }
- }
- }
-}
-//![0]
diff --git a/src/qml/doc/snippets/delegatemodel/delegatemodelgroup.qml b/src/qml/doc/snippets/delegatemodel/delegatemodelgroup.qml
deleted file mode 100644
index 8562deeeda..0000000000
--- a/src/qml/doc/snippets/delegatemodel/delegatemodelgroup.qml
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
-
-Rectangle {
- width: 200; height: 100
-
- DelegateModel {
- id: visualModel
- model: ListModel {
- ListElement { name: "Apple" }
- ListElement { name: "Orange" }
- }
-
- groups: [
- DelegateModelGroup { name: "selected" }
- ]
-
- delegate: Rectangle {
- id: item
- height: 25
- width: 200
- Text {
- text: {
- var text = "Name: " + name
- if (item.DelegateModel.inSelected)
- text += " (" + item.DelegateModel.selectedIndex + ")"
- return text;
- }
- }
- MouseArea {
- anchors.fill: parent
- onClicked: item.DelegateModel.inSelected = !item.DelegateModel.inSelected
- }
- }
- }
-
- ListView {
- anchors.fill: parent
- model: visualModel
- }
-}
-//![0]
diff --git a/src/qml/doc/snippets/package/Delegate.qml b/src/qml/doc/snippets/package/Delegate.qml
deleted file mode 100644
index 7c73f35c3d..0000000000
--- a/src/qml/doc/snippets/package/Delegate.qml
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.0
-
-//! [0]
-Package {
- Text { id: listDelegate; width: parent.width; height: 25; text: 'Empty'; Package.name: 'list' }
- Text { id: gridDelegate; width: parent.width / 2; height: 50; text: 'Empty'; Package.name: 'grid' }
-
- Rectangle {
- id: wrapper
- width: parent.width; height: 25
- color: 'lightsteelblue'
-
- Text { text: display; anchors.centerIn: parent }
- state: root.upTo > index ? 'inGrid' : 'inList'
- states: [
- State {
- name: 'inList'
- ParentChange { target: wrapper; parent: listDelegate }
- },
- State {
- name: 'inGrid'
- ParentChange {
- target: wrapper; parent: gridDelegate
- x: 0; y: 0; width: gridDelegate.width; height: gridDelegate.height
- }
- }
- ]
-
- transitions: [
- Transition {
- ParentAnimation {
- NumberAnimation { properties: 'x,y,width,height'; duration: 300 }
- }
- }
- ]
- }
-}
-//! [0]
diff --git a/src/qml/doc/snippets/package/view.qml b/src/qml/doc/snippets/package/view.qml
deleted file mode 100644
index 311cc3be8e..0000000000
--- a/src/qml/doc/snippets/package/view.qml
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.0
-import QtQml.Models 2.1
-
-Rectangle {
- id: root
- color: "white"
- width: 320
- height: 480
- property int upTo: 0
- SequentialAnimation on upTo {
- loops: -1
- NumberAnimation { to: 8; duration: 3500 }
- NumberAnimation { to: 0; duration: 3500 }
- }
-
- ListModel {
- id: myModel
- ListElement { display: "One" }
- ListElement { display: "Two" }
- ListElement { display: "Three" }
- ListElement { display: "Four" }
- ListElement { display: "Five" }
- ListElement { display: "Six" }
- ListElement { display: "Seven" }
- ListElement { display: "Eight" }
- }
- //![0]
- DelegateModel {
- id: visualModel
- delegate: Delegate {}
- model: myModel
- }
-
- ListView {
- id: lv
- height: parent.height/2
- width: parent.width
-
- model: visualModel.parts.list
- }
- GridView {
- y: parent.height/2
- height: parent.height/2
- width: parent.width
- cellWidth: width / 2
- cellHeight: 50
- model: visualModel.parts.grid
- }
- //![0]
- Text {
- anchors.bottom: parent.bottom
- }
-}
diff --git a/src/qml/doc/snippets/qml/events.qml b/src/qml/doc/snippets/qml/events.qml
index 90bf5d7b3d..f437e32890 100644
--- a/src/qml/doc/snippets/qml/events.qml
+++ b/src/qml/doc/snippets/qml/events.qml
@@ -59,8 +59,8 @@ Rectangle {
//! [signal declaration]
signal trigger
- signal send (string notice)
- signal perform (string task, variant object)
+ signal send(notice: string)
+ signal perform(task: string, object: variant)
//! [signal declaration]
//! [signal handler declaration]
@@ -88,7 +88,7 @@ Rectangle {
Rectangle {
id: messenger
- signal send( string person, string notice)
+ signal send(person: string, notice: string)
onSend: {
console.log("For " + person + ", the notice is: " + notice)
@@ -102,7 +102,7 @@ Rectangle {
Rectangle {
id: relay
- signal send( string person, string notice)
+ signal send(person: string, notice: string)
onSend: console.log("Send signal to: " + person + ", " + notice)
Component.onCompleted: {
diff --git a/src/qml/doc/snippets/qml/listmodel/listelements.qml b/src/qml/doc/snippets/qml/listmodel/listelements.qml
deleted file mode 100644
index 12146c1420..0000000000
--- a/src/qml/doc/snippets/qml/listmodel/listelements.qml
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-
-Item {
- width: 200; height: 250
-
- //! [model]
- ListModel {
- id: fruitModel
-
- ListElement {
- name: "Apple"
- cost: 2.45
- }
- ListElement {
- name: "Orange"
- cost: 3.25
- }
- ListElement {
- name: "Banana"
- cost: 1.95
- }
- }
- //! [model]
-
- //! [view]
- ListView {
- anchors.fill: parent
- model: fruitModel
- delegate: Row {
- Text { text: "Fruit: " + name }
- Text { text: "Cost: $" + cost }
- }
- }
- //! [view]
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/listmodel/listmodel-modify.qml b/src/qml/doc/snippets/qml/listmodel/listmodel-modify.qml
deleted file mode 100644
index f293eff8ec..0000000000
--- a/src/qml/doc/snippets/qml/listmodel/listmodel-modify.qml
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-import QtQuick 2.0
-
-Rectangle {
- width: 200; height: 200
-
-ListModel {
- id: fruitModel
-
- ListElement {
- name: "Apple"
- cost: 2.45
- attributes: [
- ListElement { description: "Core" },
- ListElement { description: "Deciduous" }
- ]
- }
- ListElement {
- name: "Orange"
- cost: 3.25
- attributes: [
- ListElement { description: "Citrus" }
- ]
- }
- ListElement {
- name: "Banana"
- cost: 1.95
- attributes: [
- ListElement { description: "Tropical" },
- ListElement { description: "Seedless" }
- ]
- }
-}
-
-//![delegate]
- Component {
- id: fruitDelegate
- Item {
- width: 200; height: 50
- Text { text: name }
- Text { text: '$' + cost; anchors.right: parent.right }
-
- // Double the price when clicked.
- MouseArea {
- anchors.fill: parent
- onClicked: fruitModel.setProperty(index, "cost", cost * 2)
- }
- }
- }
-//![delegate]
-
-ListView {
- width: 200; height: 200
- model: fruitModel
- delegate: fruitDelegate
-}
-
-}
diff --git a/src/qml/doc/snippets/qml/listmodel/listmodel-nested.qml b/src/qml/doc/snippets/qml/listmodel/listmodel-nested.qml
deleted file mode 100644
index 8c193d6a5e..0000000000
--- a/src/qml/doc/snippets/qml/listmodel/listmodel-nested.qml
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-import QtQuick 2.0
-
-Rectangle {
- width: 200; height: 200
-
-
-//![model]
-ListModel {
- id: fruitModel
-
- ListElement {
- name: "Apple"
- cost: 2.45
- attributes: [
- ListElement { description: "Core" },
- ListElement { description: "Deciduous" }
- ]
- }
- ListElement {
- name: "Orange"
- cost: 3.25
- attributes: [
- ListElement { description: "Citrus" }
- ]
- }
- ListElement {
- name: "Banana"
- cost: 1.95
- attributes: [
- ListElement { description: "Tropical" },
- ListElement { description: "Seedless" }
- ]
- }
-}
-//![model]
-
-//![delegate]
-Component {
- id: fruitDelegate
- Item {
- width: 200; height: 50
- Text { id: nameField; text: name }
- Text { text: '$' + cost; anchors.left: nameField.right }
- Row {
- anchors.top: nameField.bottom
- spacing: 5
- Text { text: "Attributes:" }
- Repeater {
- model: attributes
- Text { text: description }
- }
- }
- }
-}
-//![delegate]
-
-ListView {
- width: 200; height: 200
- model: fruitModel
- delegate: fruitDelegate
-}
-
-}
diff --git a/src/qml/doc/snippets/qml/listmodel/listmodel-simple.qml b/src/qml/doc/snippets/qml/listmodel/listmodel-simple.qml
deleted file mode 100644
index d07f868476..0000000000
--- a/src/qml/doc/snippets/qml/listmodel/listmodel-simple.qml
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//![0]
-import QtQuick 2.0
-
-Rectangle {
- width: 200; height: 200
-
- ListModel {
- id: fruitModel
-//![0]
- ListElement {
- name: "Apple"
- cost: 2.45
- }
- ListElement {
- name: "Orange"
- cost: 3.25
- }
- ListElement {
- name: "Banana"
- cost: 1.95
- }
-//![1]
- }
-
- Component {
- id: fruitDelegate
- Row {
- spacing: 10
- Text { text: name }
- Text { text: '$' + cost }
- }
- }
-
- ListView {
- anchors.fill: parent
- model: fruitModel
- delegate: fruitDelegate
- }
-}
-//![1]
diff --git a/src/qml/doc/snippets/qml/listmodel/listmodel.qml b/src/qml/doc/snippets/qml/listmodel/listmodel.qml
deleted file mode 100644
index c2a69d6e8f..0000000000
--- a/src/qml/doc/snippets/qml/listmodel/listmodel.qml
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//![0]
-import QtQuick 2.0
-
-ListModel {
- id: fruitModel
-
- ListElement {
- name: "Apple"
- cost: 2.45
- }
- ListElement {
- name: "Orange"
- cost: 3.25
- }
- ListElement {
- name: "Banana"
- cost: 1.95
- }
-}
-//![0]
diff --git a/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
index 073a5dc361..59907c38e7 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
@@ -52,7 +52,7 @@
import QtQuick 2.0
Item {
- function myQmlFunction(msg) {
+ function myQmlFunction(msg: string) : string {
console.log("Got message:", msg)
return "some return value"
}
diff --git a/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp b/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
index c82f71f749..a562eae2b4 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
@@ -60,13 +60,13 @@ QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
-QVariant returnedValue;
-QVariant msg = "Hello from C++";
+QString returnedValue;
+QString msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
- Q_RETURN_ARG(QVariant, returnedValue),
- Q_ARG(QVariant, msg));
+ Q_RETURN_ARG(QString, returnedValue),
+ Q_ARG(QString, msg));
-qDebug() << "QML function returned:" << returnedValue.toString();
+qDebug() << "QML function returned:" << returnedValue;
delete object;
//![0]
}
diff --git a/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
index eebf2db832..aadc89b72c 100644
--- a/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
@@ -55,7 +55,7 @@ Item {
id: item
width: 100; height: 100
- signal qmlSignal(string msg)
+ signal qmlSignal(msg: string)
MouseArea {
anchors.fill: parent
diff --git a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml b/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
index 8388b96c21..f1ec89b6ba 100644
--- a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
+++ b/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
@@ -70,7 +70,7 @@ Rectangle {
}
}
// define the signal the SignalTransition is connected with
- signal mysignal(string mystr)
+ signal mysignal(mystr: string)
// on clicking the button emit the signal with a single string argument
onClicked: button.mysignal("test")
}
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 9c33979f40..0a824bb5b5 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -166,9 +166,12 @@ updated, and any \c onButtonTextChanged handlers would not be called.
\section2 Invoking QML Methods
-All QML methods are exposed to the meta-object system and can be called from C++
-using QMetaObject::invokeMethod(). Method parameters and return values passed
-from QML are always translated into QVariant values in C++.
+All QML methods are exposed to the meta-object system and can be called from
+C++ using QMetaObject::invokeMethod(). You can specify types for the parameters
+and the return value after the colon character, as shown in the code snippet
+below. This can be useful, for example, when you want to connect a signal in
+C++ with a certain signature to a QML-defined method. If you omit the types,
+the C++ signature will use QVariant.
Here is a C++ application that calls a QML method using
QMetaObject::invokeMethod():
@@ -182,9 +185,12 @@ QMetaObject::invokeMethod():
\li \snippet qml/qtbinding/functions-qml/main.cpp 0
\endtable
-Notice the Q_RETURN_ARG() and Q_ARG() arguments for QMetaObject::invokeMethod()
-must be specified as QVariant types, as this is the generic data type used for
-QML method parameters and return values.
+Notice the parameter and return type specified after the colon. You can use \l
+{QML Basic Types}{basic types} and \l {QML Object Types}{object types} as type
+names.
+
+If the type is omitted in QML, then you must specify QVariant as type with
+Q_RETURN_ARG() and Q_ARG() when calling QMetaObject::invokeMethod.
\section2 Connecting to QML Signals
@@ -210,9 +216,8 @@ QObject::connect(), so that the \c cppSlot() method is called whenever the
\snippet qml/qtbinding/signals-qml/main.cpp 0
\endtable
-When a QML object type is used as a signal parameter, the parameter should
-use \l var as the type, and the value should be received in C++ using the
-QVariant type:
+A QML object type in a signal parameter is translated to a pointer to the class
+in C++:
\table
\row
@@ -226,7 +231,7 @@ QVariant type:
id: item
width: 100; height: 100
- signal qmlSignal(var anObject)
+ signal qmlSignal(anObject: Item)
MouseArea {
anchors.fill: parent
@@ -241,18 +246,16 @@ QVariant type:
{
Q_OBJECT
public slots:
- void cppSlot(const QVariant &v) {
- qDebug() << "Called the C++ slot with value:" << v;
+ void cppSlot(QQuickItem *item) {
+ qDebug() << "Called the C++ slot with item:" << item;
- QQuickItem *item =
- qobject_cast<QQuickItem*>(v.value<QObject*>());
qDebug() << "Item dimensions:" << item->width()
<< item->height();
}
};
int main(int argc, char *argv[]) {
- QApplication app(argc, argv);
+ QGuiApplication app(argc, argv);
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 969dd51433..b2d322465d 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -274,17 +274,16 @@
*/
/*!
- \fn int qmlRegisterType()
- \relates QQmlEngine
- \overload
+ \fn int qmlRegisterAnonymousType(const char *uri, int versionMajor)
- This template function registers the C++ type in the QML
- system. Instances of this type cannot be created from the QML
- system.
+ This template function registers the C++ type in the QML system as an anonymous type. The
+ resulting QML type does not have a name. Therefore, instances of this type cannot be created from
+ the QML system. You can, however, access instances of the type when they are exposed as properties
+ of other types.
- This function should be used when the type will not be referenced by name.
- Specifically, it has to be used for C++ types that are used as the left-hand
- side of a property binding.
+ Use this function when the type will not be referenced by name, specifically for C++ types that
+ are used on the left-hand side of a property binding. To indicate to which module the type belongs
+ use \a uri and \a versionMajor.
For example, consider the following two classes:
@@ -344,18 +343,29 @@
\code
qmlRegisterType<Foo>("App", 1, 0, "Foo");
- qmlRegisterType<Bar>();
+ qmlRegisterAnonymousType<Bar>("App", 1);
\endcode
As the \c Foo type is instantiated in QML, it must be registered
- with the version of \l qmlRegisterType() that takes an import URI.
+ with the version of \l qmlRegisterType() that takes an element name.
Returns the QML type id.
+ \since 5.14
\sa {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
+ \fn int qmlRegisterType()
+ \relates QQmlEngine
+ \overload
+ \deprecated
+
+ Do not use this function. For anonymous type registrations, use \l qmlRegisterAnonymousType(),
+ and make sure to provide a URI and a major version.
+*/
+
+/*!
\fn int qmlRegisterInterface(const char *typeName)
\relates QQmlEngine
@@ -448,7 +458,7 @@
*/
/*!
- \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool create = true)
+ \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool create)
\relates QQmlEngine
The form of this template function is:
@@ -487,8 +497,7 @@
A QObject singleton type may be referenced via the type name with which it was registered, and this
typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
- One exception to this is that a QObject singleton type property may not be aliased (because the
- singleton type name does not identify an object within the same component as any other item).
+ One exception to this is that a QObject singleton type property may not be aliased.
\b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
@@ -538,7 +547,7 @@
Alternatively, you can use a C++11 lambda:
\code
- qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
+ qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
@@ -564,6 +573,14 @@
\sa {Choosing the Correct Integration Method Between C++ and QML}
*/
+
+/*!
+ \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
+ \relates QQmlEngine
+
+ \overload qmlRegisterSingletonType
+*/
+
/*!
\fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
\relates QQmlEngine
@@ -611,6 +628,99 @@
*/
/*!
+ \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject* cppObject)
+ \relates QQmlEngine
+ \since 5.14
+
+ This function is used to register a singleton object \a cppObject, with a
+ particular \a uri and \a typeName. Its version is a combination of \a
+ versionMajor and \a versionMinor.
+
+ Installing a singleton type into a URI allows you to provide arbitrary
+ functionality (methods and properties) to QML code without requiring
+ individual instances of the type to be instantiated by the client.
+
+ Use this function to register an object of the given type T as a singleton
+ type.
+
+ A QObject singleton type may be referenced via the type name with which it
+ was registered; in turn this type name may be used as the target in a \l
+ Connections type, or like any other type ID. However, there's one
+ exception: a QObject singleton type property can't be aliased because the
+ singleton type name does not identify an object within the same component
+ as any other item.
+
+ \note \a cppObject must outlive the QML engine in which it is used.
+ Moreover, \cppObject must have the same thread affinity as the engine. If
+ you want separate singleton instances for multiple engines, you need to use
+ \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
+ information about thread safety.
+
+ Usage:
+ \code
+ // First, define your QObject which provides the functionality.
+ class SingletonTypeExample : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
+
+ public:
+ explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
+
+ Q_INVOKABLE int doSomething()
+ {
+ setSomeProperty(5);
+ return m_someProperty;
+ }
+
+ int someProperty() const { return m_someProperty; }
+ void setSomeProperty(int val) {
+ if (m_someProperty != val) {
+ m_someProperty = val;
+ emit somePropertyChanged(val);
+ }
+ }
+
+ signals:
+ void somePropertyChanged(int newValue);
+
+ private:
+ int m_someProperty = 0;
+ };
+ \endcode
+
+ \code
+ // Second, create an instance of the object
+
+ // allocate example before the engine to ensure that it outlives it
+ QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
+ QQmlEngine engine;
+
+ // Third, register the singleton type provider with QML by calling this
+ // function in an initialization function.
+ qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
+ \endcode
+
+
+ In order to use the registered singleton type in QML, you must import the
+ URI with the corresponding version.
+ \qml
+ import QtQuick 2.0
+ import Qt.example.qobjectSingleton 1.0
+ Item {
+ id: root
+ property int someValue: MyApi.someProperty
+
+ Component.onCompleted: {
+ console.log(MyApi.doSomething())
+ }
+ }
+ \endqml
+
+ \sa qmlRegisterSingletonType
+ */
+
+/*!
\fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
\relates QQmlEngine
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index 2c664af188..503ce0ebcd 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -2,13 +2,11 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
SOURCES += \
- $$PWD/qv4jithelpers.cpp \
$$PWD/qv4baselinejit.cpp \
$$PWD/qv4baselineassembler.cpp \
$$PWD/qv4assemblercommon.cpp
HEADERS += \
- $$PWD/qv4jithelpers_p.h \
$$PWD/qv4baselinejit_p.h \
$$PWD/qv4baselineassembler_p.h \
$$PWD/qv4assemblercommon_p.h
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index dd810d9d70..800ee22cd7 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -53,8 +53,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -366,5 +364,3 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index 67c7c9cd82..b18d082be6 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -58,7 +58,7 @@
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
-#ifdef V4_ENABLE_JIT
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -449,7 +449,7 @@ public:
// r6 is used by MacroAssemblerARMv7
static const RegisterID JSStackFrameRegister = JSC::ARMRegisters::r8;
static const RegisterID CppStackFrameRegister = JSC::ARMRegisters::r10;
-#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
+#if CPU(ARM_THUMB2)
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
static const RegisterID EngineRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
@@ -619,6 +619,9 @@ public:
for (Jump j : catchyJumps)
j.link(this);
+ // We don't need to check for isInterrupted here because if that is set,
+ // then the first checkException() in any exception handler will find another "exception"
+ // and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
loadUndefined();
@@ -633,6 +636,8 @@ public:
void checkException()
{
+ // This actually reads 4 bytes, starting at hasException.
+ // Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
addCatchyJump(
branch32(NotEqual,
Address(EngineRegister, offsetof(EngineBase, hasException)),
@@ -735,6 +740,4 @@ private:
QT_END_NAMESPACE
-#endif // V4_ENABLE_JIT
-
#endif // QV4PLATFORMASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 0751704a29..59de86a85d 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -55,8 +55,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -943,7 +941,7 @@ void BaselineAssembler::uminus()
saveAccumulatorInFrame();
pasm()->prepareCallWithArgCount(1);
pasm()->passAccumulatorAsArg(0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_uMinus, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(UMinus, CallResultDestination::InAccumulator);
checkException();
}
@@ -1044,7 +1042,7 @@ void BaselineAssembler::add(int lhs)
pasm()->passAccumulatorAsArg(2);
pasm()->passJSSlotAsArg(lhs, 1);
pasm()->passEngineAsArg(0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_add, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(Add, CallResultDestination::InAccumulator);
checkException();
// done.
@@ -1196,7 +1194,7 @@ void BaselineAssembler::mul(int lhs)
pasm()->prepareCallWithArgCount(2);
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_mul, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(Mul, CallResultDestination::InAccumulator);
checkException();
// done.
@@ -1209,7 +1207,7 @@ void BaselineAssembler::div(int lhs)
pasm()->prepareCallWithArgCount(2);
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_div, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(Div, CallResultDestination::InAccumulator);
checkException();
}
@@ -1219,7 +1217,7 @@ void BaselineAssembler::mod(int lhs)
pasm()->prepareCallWithArgCount(2);
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_mod, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(Mod, CallResultDestination::InAccumulator);
checkException();
}
@@ -1239,7 +1237,7 @@ void BaselineAssembler::sub(int lhs)
pasm()->prepareCallWithArgCount(2);
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_sub, CallResultDestination::InAccumulator);
+ ASM_GENERATE_RUNTIME_CALL(Sub, CallResultDestination::InAccumulator);
checkException();
// done.
@@ -1269,7 +1267,7 @@ void BaselineAssembler::cmpeqInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
- pasm()->callRuntimeUnchecked("Runtime::method_equal", (void*)Runtime::method_equal);
+ pasm()->callRuntimeUnchecked("Equal", (void*)Runtime::Equal::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@@ -1293,7 +1291,7 @@ void BaselineAssembler::cmpneInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
- pasm()->callRuntimeUnchecked("Runtime::method_notEqual", (void*)Runtime::method_notEqual);
+ pasm()->callRuntimeUnchecked("NotEqual", (void*)Runtime::NotEqual::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@@ -1314,7 +1312,6 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
pasm()->compare32(c, PlatformAssembler::ScratchRegister,
PlatformAssembler::AccumulatorRegisterValue,
PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
return PlatformAssembler::Jump();
});
@@ -1326,60 +1323,58 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
callRuntime(functionName, reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
checkException();
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
// done.
done.link(pasm());
+ pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
}
void BaselineAssembler::cmpeq(int lhs)
{
- cmp(PlatformAssembler::Equal, &Runtime::method_compareEqual,
- "Runtime::method_compareEqual", lhs);
+ cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call,
+ "CompareEqual", lhs);
}
void BaselineAssembler::cmpne(int lhs)
{
- cmp(PlatformAssembler::NotEqual, &Runtime::method_compareNotEqual,
- "Runtime::method_compareNotEqual", lhs);
+ cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call,
+ "CompareNotEqual", lhs);
}
void BaselineAssembler::cmpgt(int lhs)
{
- cmp(PlatformAssembler::GreaterThan, &Runtime::method_compareGreaterThan,
- "Runtime::method_compareGreaterThan", lhs);
+ cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call,
+ "CompareGreaterThan", lhs);
}
void BaselineAssembler::cmpge(int lhs)
{
- cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::method_compareGreaterEqual,
- "Runtime::method_compareGreaterEqual", lhs);
+ cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call,
+ "CompareGreaterEqual", lhs);
}
void BaselineAssembler::cmplt(int lhs)
{
- cmp(PlatformAssembler::LessThan, &Runtime::method_compareLessThan,
- "Runtime::method_compareLessThan", lhs);
+ cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call,
+ "CompareLessThan", lhs);
}
void BaselineAssembler::cmple(int lhs)
{
- cmp(PlatformAssembler::LessThanOrEqual, &Runtime::method_compareLessEqual,
- "Runtime::method_compareLessEqual", lhs);
+ cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call,
+ "CompareLessEqual", lhs);
}
void BaselineAssembler::cmpStrictEqual(int lhs)
{
- cmp(PlatformAssembler::Equal, &RuntimeHelpers::strictEqual,
+ cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call,
"RuntimeHelpers::strictEqual", lhs);
}
void BaselineAssembler::cmpStrictNotEqual(int lhs)
{
- cmp(PlatformAssembler::Equal, &RuntimeHelpers::strictEqual,
- "RuntimeHelpers::strictEqual", lhs);
- pasm()->xor32(TrustedImm32(1), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
+ cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call,
+ "RuntimeHelpers::strictNotEqual", lhs);
}
int BaselineAssembler::jump(int offset)
@@ -1487,7 +1482,7 @@ void BaselineAssembler::loadAccumulatorFromFrame()
static ReturnedValue TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing(CppStackFrame *frame, ExecutionEngine *engine)
{
- return Runtime::method_tailCall(frame, engine);
+ return Runtime::TailCall::call(frame, engine);
}
void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
@@ -1594,9 +1589,8 @@ void BaselineAssembler::pushCatchContext(int index, int name)
pasm()->prepareCallWithArgCount(3);
pasm()->passInt32AsArg(name, 2);
pasm()->passInt32AsArg(index, 1);
- pasm()->passJSSlotAsArg(CallData::Context, 0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_createCatchContext, CallResultDestination::InAccumulator);
- pasm()->storeAccumulator(pasm()->contextAddress());
+ pasm()->passEngineAsArg(0);
+ ASM_GENERATE_RUNTIME_CALL(PushCatchContext, CallResultDestination::Ignore);
}
void BaselineAssembler::popContext()
@@ -1615,7 +1609,7 @@ void BaselineAssembler::deadTemporalZoneCheck(int offsetForSavedIP, int variable
prepareCallWithArgCount(2);
passInt32AsArg(variableName, 1);
passEngineAsArg(0);
- ASM_GENERATE_RUNTIME_CALL(Runtime::method_throwReferenceError, CallResultDestination::Ignore);
+ ASM_GENERATE_RUNTIME_CALL(ThrowReferenceError, CallResultDestination::Ignore);
gotoCatchException();
valueIsAliveJump.link(pasm());
}
@@ -1629,5 +1623,3 @@ void BaselineAssembler::ret()
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index 97cb522244..33fd288ac3 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -55,6 +55,8 @@
#include <private/qv4function_p.h>
#include <QHash>
+QT_REQUIRE_CONFIG(qml_jit);
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -65,7 +67,7 @@ namespace JIT {
#define GENERATE_RUNTIME_CALL(function, destination) \
callRuntime(JIT_STRINGIFY(function), \
- reinterpret_cast<void *>(&function), \
+ reinterpret_cast<void *>(&Runtime::function::call), \
destination)
#define GENERATE_TAIL_CALL(function) \
tailCallRuntime(JIT_STRINGIFY(function), \
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index d8d4e36f35..fcaa87290e 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -38,13 +38,10 @@
****************************************************************************/
#include "qv4baselinejit_p.h"
-#include "qv4jithelpers_p.h"
#include "qv4baselineassembler_p.h"
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
-#ifdef V4_ENABLE_JIT
-
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
@@ -52,7 +49,7 @@ using namespace QV4::Moth;
BaselineJIT::BaselineJIT(Function *function)
: function(function)
- , as(new BaselineAssembler(function->compilationUnit->constants))
+ , as(new BaselineAssembler(&(function->compilationUnit->constants->asValue<Value>())))
{}
BaselineJIT::~BaselineJIT()
@@ -78,10 +75,11 @@ void BaselineJIT::generate()
#define STORE_IP() as->storeInstructionPointer(nextInstructionOffset())
#define STORE_ACC() as->saveAccumulatorInFrame()
#define LOAD_ACC() as->loadAccumulatorFromFrame()
-#define BASELINEJIT_GENERATE_RUNTIME_CALL(function, destination) \
- as->GENERATE_RUNTIME_CALL(function, destination)
-#define BASELINEJIT_GENERATE_TAIL_CALL(function) \
- as->GENERATE_TAIL_CALL(function)
+#define BASELINEJIT_GENERATE_RUNTIME_CALL(function, destination) { \
+ as->GENERATE_RUNTIME_CALL(function, destination); \
+ if (Runtime::function::throws) \
+ as->checkException(); \
+ else {} } // this else prevents else statements after the macro from attaching to the if above
void BaselineJIT::generate_Ret()
{
@@ -152,7 +150,7 @@ void BaselineJIT::generate_LoadImport(int index)
as->loadImport(index);
}
-void BaselineJIT::generate_LoadLocal(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadLocal(int index)
{
as->loadLocal(index);
}
@@ -163,7 +161,7 @@ void BaselineJIT::generate_StoreLocal(int index)
as->storeLocal(index);
}
-void BaselineJIT::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
{
as->loadLocal(index, scope);
}
@@ -184,7 +182,7 @@ void BaselineJIT::generate_MoveRegExp(int regExpId, int destReg)
as->prepareCallWithArgCount(2);
as->passInt32AsArg(regExpId, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_regexpLiteral, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(RegexpLiteral, CallResultDestination::InAccumulator);
as->storeReg(destReg);
}
@@ -193,37 +191,33 @@ void BaselineJIT::generate_LoadClosure(int value)
as->prepareCallWithArgCount(2);
as->passInt32AsArg(value, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_closure, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Closure, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadName, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadGlobalLookup(int index)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
- as->passEngineAsArg(1);
- as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::loadGlobalLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ as->passFunctionAsArg(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
- as->prepareCallWithArgCount(3);
- as->passInt32AsArg(index, 2);
- as->passEngineAsArg(1);
- as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::loadQmlContextPropertyLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ as->prepareCallWithArgCount(2);
+ as->passInt32AsArg(index, 1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreNameSloppy(int name)
@@ -234,8 +228,7 @@ void BaselineJIT::generate_StoreNameSloppy(int name)
as->passAccumulatorAsArg(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeNameSloppy, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameSloppy, CallResultDestination::Ignore);
LOAD_ACC();
}
@@ -247,12 +240,11 @@ void BaselineJIT::generate_StoreNameStrict(int name)
as->passAccumulatorAsArg(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeNameStrict, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameStrict, CallResultDestination::Ignore);
LOAD_ACC();
}
-void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
+void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
@@ -260,11 +252,10 @@ void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadElement, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
+void BaselineJIT::generate_StoreElement(int base, int index)
{
STORE_IP();
STORE_ACC();
@@ -273,12 +264,11 @@ void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
as->passJSSlotAsArg(index, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeElement, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(StoreElement, CallResultDestination::Ignore);
LOAD_ACC();
}
-void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
@@ -286,21 +276,19 @@ void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
as->passInt32AsArg(name, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadProperty, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_GetLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(index, 3);
as->passAccumulatorAsArg(2);
- as->passEngineAsArg(1);
- as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::getLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ as->passFunctionAsArg(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(GetLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreProperty(int name, int base)
@@ -312,8 +300,7 @@ void BaselineJIT::generate_StoreProperty(int name, int base)
as->passInt32AsArg(name, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeProperty, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(StoreProperty, CallResultDestination::Ignore);
LOAD_ACC();
}
@@ -323,12 +310,13 @@ void BaselineJIT::generate_SetLookup(int index, int base)
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passAccumulatorAsArg(3);
- as->passJSSlotAsArg(base, 2);
- as->passInt32AsArg(index, 1);
+ as->passInt32AsArg(index, 2);
+ as->passJSSlotAsArg(base, 1);
as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL((function->isStrict() ? Helpers::setLookupStrict : Helpers::setLookupSloppy),
- CallResultDestination::InAccumulator);
- as->checkException();
+ if (function->isStrict())
+ BASELINEJIT_GENERATE_RUNTIME_CALL(SetLookupStrict, CallResultDestination::InAccumulator)
+ else
+ BASELINEJIT_GENERATE_RUNTIME_CALL(SetLookupSloppy, CallResultDestination::InAccumulator)
}
void BaselineJIT::generate_LoadSuperProperty(int property)
@@ -337,8 +325,7 @@ void BaselineJIT::generate_LoadSuperProperty(int property)
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(property, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadSuperProperty, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadSuperProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreSuperProperty(int property)
@@ -349,8 +336,7 @@ void BaselineJIT::generate_StoreSuperProperty(int property)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(property, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeSuperProperty, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(StoreSuperProperty, CallResultDestination::Ignore);
LOAD_ACC();
}
@@ -372,7 +358,7 @@ void BaselineJIT::generate_Resume(int)
Q_UNREACHABLE();
}
-void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -380,11 +366,10 @@ void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSl
as->passJSSlotAsArg(argv, 2);
as->passJSSlotAsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callValue, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallValue, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -393,11 +378,10 @@ void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc,
as->passJSSlotAsArg(thisObject, 2);
as->passJSSlotAsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callWithReceiver, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithReceiver, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -406,11 +390,10 @@ void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv,
as->passInt32AsArg(name, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callProperty, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -419,11 +402,10 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
as->passInt32AsArg(lookupIndex, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callPropertyLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -432,11 +414,10 @@ void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv,
as->passJSSlotAsArg(index, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callElement, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -444,22 +425,20 @@ void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlo
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callName, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(argc, 2);
as->passJSSlotAsArg(argv, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callPossiblyDirectEval, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallPossiblyDirectEval, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -467,12 +446,10 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callGlobalLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -480,11 +457,10 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlContextPropertyLookup, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -493,8 +469,7 @@ void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, in
as->passJSSlotAsArg(thisObject, 2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callWithSpread, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithSpread, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TailCall(int func, int thisObject, int argc, int argv)
@@ -513,8 +488,7 @@ void BaselineJIT::generate_Construct(int func, int argc, int argv)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_construct, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Construct, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
@@ -527,8 +501,7 @@ void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_constructWithSpread, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ConstructWithSpread, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_SetUnwindHandler(int offset)
@@ -561,7 +534,7 @@ void BaselineJIT::generate_ThrowException()
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_throwException, CallResultDestination::Ignore);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
}
@@ -572,8 +545,7 @@ void BaselineJIT::generate_CreateCallContext()
{
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(ExecutionContext::newCallContext, CallResultDestination::Ignore); // keeps result in return value register
- as->storeHeapObject(CallData::Context);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
@@ -583,11 +555,9 @@ void BaselineJIT::generate_PushWithContext()
STORE_IP();
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
- as->passJSSlotAsArg(0, 1);
+ as->passJSSlotAsArg(CallData::Accumulator, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createWithContext, CallResultDestination::Ignore); // keeps result in return value register
- as->checkException();
- as->storeHeapObject(CallData::Context);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(PushWithContext, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_PushBlockContext(int index)
@@ -595,8 +565,8 @@ void BaselineJIT::generate_PushBlockContext(int index)
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
- as->passJSSlotAsArg(0, 0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::pushBlockContext, CallResultDestination::Ignore);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(PushBlockContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
@@ -604,29 +574,27 @@ void BaselineJIT::generate_CloneBlockContext()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(1);
- as->passJSSlotAsArg(CallData::Context, 0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::cloneBlockContext, CallResultDestination::Ignore);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CloneBlockContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PushScriptContext(int index)
{
as->saveAccumulatorInFrame();
- as->prepareCallWithArgCount(3);
- as->passInt32AsArg(index, 2);
- as->passEngineAsArg(1);
- as->passJSSlotAsArg(0, 0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::pushScriptContext, CallResultDestination::Ignore);
+ as->prepareCallWithArgCount(2);
+ as->passInt32AsArg(index, 1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(PushScriptContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PopScriptContext()
{
as->saveAccumulatorInFrame();
- as->prepareCallWithArgCount(2);
- as->passEngineAsArg(1);
- as->passJSSlotAsArg(0, 0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::popScriptContext, CallResultDestination::Ignore);
+ as->prepareCallWithArgCount(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(PopScriptContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
@@ -639,8 +607,7 @@ void BaselineJIT::generate_GetIterator(int iterator)
as->passInt32AsArg(iterator, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_getIterator, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(GetIterator, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_IteratorNext(int value, int done)
@@ -650,9 +617,8 @@ void BaselineJIT::generate_IteratorNext(int value, int done)
as->passJSSlotAsArg(value, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorNext, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNext, CallResultDestination::InAccumulator);
as->storeReg(done);
- as->checkException();
}
void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
@@ -663,8 +629,7 @@ void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
as->passJSSlotAsArg(iterator, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorNextForYieldStar, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNextForYieldStar, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_IteratorClose(int done)
@@ -674,8 +639,7 @@ void BaselineJIT::generate_IteratorClose(int done)
as->passJSSlotAsArg(done, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorClose, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorClose, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DestructureRestElement()
@@ -684,29 +648,28 @@ void BaselineJIT::generate_DestructureRestElement()
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_destructureRestElement, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(DestructureRestElement, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeleteProperty(int base, int index)
{
STORE_IP();
- as->prepareCallWithArgCount(3);
- as->passJSSlotAsArg(index, 2);
- as->passJSSlotAsArg(base, 1);
- as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::deleteProperty, CallResultDestination::InAccumulator);
- as->checkException();
+ as->prepareCallWithArgCount(4);
+ as->passJSSlotAsArg(index, 3);
+ as->passJSSlotAsArg(base, 2);
+ as->passFunctionAsArg(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(DeleteProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeleteName(int name)
{
STORE_IP();
- as->prepareCallWithArgCount(2);
- as->passInt32AsArg(name, 1);
- as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::deleteName, CallResultDestination::InAccumulator);
- as->checkException();
+ as->prepareCallWithArgCount(3);
+ as->passInt32AsArg(name, 2);
+ as->passFunctionAsArg(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(DeleteName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TypeofName(int name)
@@ -714,7 +677,7 @@ void BaselineJIT::generate_TypeofName(int name)
as->prepareCallWithArgCount(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_typeofName, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(TypeofName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TypeofValue()
@@ -723,7 +686,7 @@ void BaselineJIT::generate_TypeofValue()
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_typeofValue, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(TypeofValue, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeclareVar(int varName, int isDeletable)
@@ -733,7 +696,7 @@ void BaselineJIT::generate_DeclareVar(int varName, int isDeletable)
as->passInt32AsArg(varName, 2);
as->passInt32AsArg(isDeletable, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_declareVar, CallResultDestination::Ignore);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(DeclareVar, CallResultDestination::Ignore);
LOAD_ACC();
}
@@ -743,7 +706,7 @@ void BaselineJIT::generate_DefineArray(int argc, int args)
as->passInt32AsArg(argc, 2);
as->passJSSlotAsArg(args, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_arrayLiteral, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ArrayLiteral, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
@@ -753,7 +716,7 @@ void BaselineJIT::generate_DefineObjectLiteral(int internalClassId, int argc, in
as->passJSSlotAsArg(args, 2);
as->passInt32AsArg(internalClassId, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_objectLiteral, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ObjectLiteral, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateClass(int classIndex, int heritage, int computedNames)
@@ -763,14 +726,14 @@ void BaselineJIT::generate_CreateClass(int classIndex, int heritage, int compute
as->passJSSlotAsArg(heritage, 2);
as->passInt32AsArg(classIndex, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createClass, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CreateClass, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateMappedArgumentsObject()
{
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createMappedArgumentsObject,
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CreateMappedArgumentsObject,
CallResultDestination::InAccumulator);
}
@@ -778,7 +741,7 @@ void BaselineJIT::generate_CreateUnmappedArgumentsObject()
{
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createUnmappedArgumentsObject,
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CreateUnmappedArgumentsObject,
CallResultDestination::InAccumulator);
}
@@ -787,7 +750,7 @@ void BaselineJIT::generate_CreateRestParameter(int argIndex)
as->prepareCallWithArgCount(2);
as->passInt32AsArg(argIndex, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createRestParameter, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(CreateRestParameter, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ConvertThisToObject()
@@ -796,8 +759,8 @@ void BaselineJIT::generate_ConvertThisToObject()
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(CallData::This, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::convertThisToObject, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ConvertThisToObject, CallResultDestination::InAccumulator);
+ as->storeReg(CallData::This);
LOAD_ACC();
}
@@ -806,8 +769,7 @@ void BaselineJIT::generate_LoadSuperConstructor()
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(CallData::Function, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadSuperConstructor, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(LoadSuperConstructor, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ToObject()
@@ -816,8 +778,7 @@ void BaselineJIT::generate_ToObject()
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::toObject, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ToObject, CallResultDestination::InAccumulator);
}
@@ -826,12 +787,12 @@ void BaselineJIT::generate_Jump(int offset)
labels.insert(as->jump(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpTrue(int offset)
{
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpFalse(int offset)
{
labels.insert(as->jumpFalse(absoluteOffset(offset)));
}
@@ -846,6 +807,11 @@ void BaselineJIT::generate_JumpNotUndefined(int offset)
labels.insert(as->jumpNotUndefined(absoluteOffset(offset)));
}
+void BaselineJIT::generate_CheckException()
+{
+ as->checkException();
+}
+
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
void BaselineJIT::generate_CmpEqInt(int lhs) { as->cmpeqInt(lhs); }
@@ -866,8 +832,7 @@ void BaselineJIT::generate_CmpIn(int lhs)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(lhs, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_in, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(In, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CmpInstanceOf(int lhs)
@@ -877,17 +842,16 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(lhs, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_instanceof, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Instanceof, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_UNot() { as->unot(); }
void BaselineJIT::generate_UPlus() { as->toNumber(); }
-void BaselineJIT::generate_UMinus(int /*traceSlot*/) { as->uminus(); }
+void BaselineJIT::generate_UMinus() { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
-void BaselineJIT::generate_Increment(int /*traceSlot*/) { as->inc(); }
-void BaselineJIT::generate_Decrement(int /*traceSlot*/) { as->dec(); }
-void BaselineJIT::generate_Add(int lhs, int /*traceSlot*/) { as->add(lhs); }
+void BaselineJIT::generate_Increment() { as->inc(); }
+void BaselineJIT::generate_Decrement() { as->dec(); }
+void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
@@ -909,13 +873,12 @@ void BaselineJIT::generate_Exp(int lhs) {
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passJSSlotAsArg(lhs, 0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::exp, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Exp, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_Mul(int lhs, int /*traceSlot*/) { as->mul(lhs); }
+void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
-void BaselineJIT::generate_Mod(int lhs, int /*traceSlot*/) { as->mod(lhs); }
-void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
+void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
+void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
@@ -942,8 +905,7 @@ void BaselineJIT::generate_ThrowOnNullOrUndefined()
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::throwOnNullOrUndefined, CallResultDestination::Ignore);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowOnNullOrUndefined, CallResultDestination::Ignore);
LOAD_ACC();
}
@@ -952,19 +914,17 @@ void BaselineJIT::generate_GetTemplateObject(int index)
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passFunctionAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(RuntimeHelpers::getTemplateObject, CallResultDestination::InAccumulator);
- as->checkException();
+ BASELINEJIT_GENERATE_RUNTIME_CALL(GetTemplateObject, CallResultDestination::InAccumulator);
}
-void BaselineJIT::startInstruction(Instr::Type /*instr*/)
+ByteCodeHandler::Verdict BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
if (labels.contains(currentInstructionOffset()))
as->addLabel(currentInstructionOffset());
+ return ProcessInstruction;
}
void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 10c89bc74b..284faf0ff0 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -56,7 +56,7 @@
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
-//QT_REQUIRE_CONFIG(qml_jit);
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -65,7 +65,6 @@ namespace JIT {
class BaselineAssembler;
-#ifdef V4_ENABLE_JIT
class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
@@ -88,22 +87,22 @@ public:
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
+ void generate_LoadLocal(int index) override;
void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
+ void generate_LoadScopedLocal(int scope, int index) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
+ void generate_LoadName(int name) override;
+ void generate_LoadGlobalLookup(int index) override;
+ void generate_LoadQmlContextPropertyLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
+ void generate_LoadElement(int base) override;
+ void generate_StoreElement(int base, int index) override;
+ void generate_LoadProperty(int name) override;
+ void generate_GetLookup(int index) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -112,16 +111,16 @@ public:
void generate_YieldStar() override;
void generate_Resume(int) override;
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
+ void generate_CallValue(int name, int argc, int argv) override;
+ void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
+ void generate_CallProperty(int name, int base, int argc, int argv) override;
+ void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
+ void generate_CallElement(int base, int index, int argc, int argv) override;
+ void generate_CallName(int name, int argc, int argv) override;
+ void generate_CallPossiblyDirectEval(int argc, int argv) override;
+ void generate_CallGlobalLookup(int index, int argc, int argv) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
@@ -160,10 +159,11 @@ public:
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
+ void generate_JumpTrue(int offset) override;
+ void generate_JumpFalse(int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
+ void generate_CheckException() override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
@@ -180,11 +180,11 @@ public:
void generate_CmpInstanceOf(int lhs) override;
void generate_UNot() override;
void generate_UPlus() override;
- void generate_UMinus(int traceSlot) override;
+ void generate_UMinus() override;
void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
+ void generate_Increment() override;
+ void generate_Decrement() override;
+ void generate_Add(int lhs) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
@@ -198,15 +198,15 @@ public:
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
+ void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
+ void generate_Mod(int lhs) override;
+ void generate_Sub(int lhs) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
- void startInstruction(Moth::Instr::Type instr) override;
+ Verdict startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
private:
@@ -214,7 +214,6 @@ private:
QScopedPointer<BaselineAssembler> as;
QSet<int> labels;
};
-#endif // V4_ENABLE_JIT
} // namespace JIT
} // namespace QV4
diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp
deleted file mode 100644
index 674fd8c8c8..0000000000
--- a/src/qml/jit/qv4jithelpers.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4jithelpers_p.h"
-#include "qv4engine_p.h"
-#include "qv4function_p.h"
-#include "qv4value_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4lookup_p.h"
-#include <QtCore/private/qnumeric_p.h>
-
-#ifdef V4_ENABLE_JIT
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace JIT {
-namespace Helpers {
-
-void convertThisToObject(ExecutionEngine *engine, Value *t)
-{
- if (!t->isObject()) {
- if (t->isNullOrUndefined()) {
- *t = engine->globalObject->asReturnedValue();
- } else {
- *t = t->toObject(engine)->asReturnedValue();
- }
- }
-}
-
-ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index)
-{
- Lookup *l = f->compilationUnit->runtimeLookups + index;
- return l->globalGetter(l, engine);
-}
-
-ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index)
-{
- Lookup *l = f->compilationUnit->runtimeLookups + index;
- return l->qmlContextPropertyGetter(l, engine, nullptr);
-}
-
-ReturnedValue toObject(ExecutionEngine *engine, const Value &obj)
-{
- if (obj.isObject())
- return obj.asReturnedValue();
-
- return obj.toObject(engine)->asReturnedValue();
-}
-
-ReturnedValue exp(const Value &base, const Value &exp)
-{
- double b = base.toNumber();
- double e = exp.toNumber();
- if (qt_is_inf(e) && (b == 1 || b == -1))
- return Encode(qt_snan());
- return Encode(pow(b,e));
-}
-
-ReturnedValue getLookup(Function *f, ExecutionEngine *engine, const Value &base, int index)
-{
- Lookup *l = f->compilationUnit->runtimeLookups + index;
- return l->getter(l, engine, base);
-}
-
-void setLookupSloppy(Function *f, int index, Value &base, const Value &value)
-{
- ExecutionEngine *engine = f->internalClass->engine;
- QV4::Lookup *l = f->compilationUnit->runtimeLookups + index;
- l->setter(l, engine, base, value);
-}
-
-void setLookupStrict(Function *f, int index, Value &base, const Value &value)
-{
- ExecutionEngine *engine = f->internalClass->engine;
- QV4::Lookup *l = f->compilationUnit->runtimeLookups + index;
- if (!l->setter(l, engine, base, value))
- engine->throwTypeError();
-}
-
-
-void pushBlockContext(Value *stack, int index)
-{
- ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- stack[CallData::Context] = Runtime::method_createBlockContext(c, index);
-}
-
-void cloneBlockContext(Value *contextSlot)
-{
- *contextSlot = Runtime::method_cloneBlockContext(static_cast<QV4::ExecutionContext *>(contextSlot));
-}
-
-void pushScriptContext(Value *stack, ExecutionEngine *engine, int index)
-{
- stack[CallData::Context] = Runtime::method_createScriptContext(engine, index);
-}
-
-void popScriptContext(Value *stack, ExecutionEngine *engine)
-{
- stack[CallData::Context] = Runtime::method_popScriptContext(engine);
-}
-
-ReturnedValue deleteProperty(QV4::Function *function, const QV4::Value &base, const QV4::Value &index)
-{
- auto engine = function->internalClass->engine;
- if (!Runtime::method_deleteProperty(engine, base, index)) {
- if (function->isStrict())
- engine->throwTypeError();
- return Encode(false);
- } else {
- return Encode(true);
- }
-}
-
-ReturnedValue deleteName(Function *function, int name)
-{
- auto engine = function->internalClass->engine;
- if (!Runtime::method_deleteName(engine, name)) {
- if (function->isStrict())
- engine->throwTypeError();
- return Encode(false);
- } else {
- return Encode(true);
- }
-}
-
-void throwOnNullOrUndefined(ExecutionEngine *engine, const Value &v)
-{
- if (v.isNullOrUndefined())
- engine->throwTypeError();
-}
-
-} // Helpers namespace
-} // JIT namespace
-} // QV4 namespace
-QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index c41738c811..065fbc1c0a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -41,7 +41,6 @@
#include "qjsengine_p.h"
#include "qjsvalue.h"
#include "qjsvalue_p.h"
-#include "private/qv8engine_p.h"
#include "private/qv4engine_p.h"
#include "private/qv4mm_p.h"
@@ -348,7 +347,6 @@ QJSEngine::QJSEngine(QObject *parent)
: QObject(*new QJSEnginePrivate, parent)
, m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
QJSEnginePrivate::addToDebugServer(this);
@@ -361,7 +359,6 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
: QObject(dd, parent)
, m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
}
@@ -375,7 +372,6 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
QJSEngine::~QJSEngine()
{
QJSEnginePrivate::removeFromDebugServer(this);
- delete m_v4Engine->v8Engine;
delete m_v4Engine;
}
@@ -470,6 +466,33 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
QV4::GlobalExtensions::init(obj, extensions);
}
+/*!
+ \since 5.14
+ Interrupts or re-enables JavaScript execution.
+
+ If \a interrupted is \c true, any JavaScript executed by this engine
+ immediately aborts and returns an error object until this function is
+ called again with a value of \c false for \a interrupted.
+
+ This function is thread safe. You may call it from a different thread
+ in order to interrupt, for example, an infinite loop in JavaScript.
+*/
+void QJSEngine::setInterrupted(bool interrupted)
+{
+ m_v4Engine->isInterrupted = interrupted;
+}
+
+/*!
+ \since 5.14
+ Returns whether JavaScript execution is currently interrupted.
+
+ \sa setInterrupted()
+*/
+bool QJSEngine::isInterrupted() const
+{
+ return m_v4Engine->isInterrupted.loadAcquire();
+}
+
static QUrl urlForFileName(const QString &fileName)
{
if (!fileName.startsWith(QLatin1Char(':')))
@@ -527,6 +550,8 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
result = script.run();
if (scope.engine->hasException)
result = v4->catchException();
+ if (v4->isInterrupted.loadAcquire())
+ result = v4->newErrorObject(QStringLiteral("Interrupted"));
QJSValue retval(v4, result->asReturnedValue());
@@ -565,7 +590,12 @@ QJSValue QJSEngine::importModule(const QString &fileName)
if (m_v4Engine->hasException)
return QJSValue(m_v4Engine, m_v4Engine->catchException());
moduleUnit->evaluate();
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+ if (!m_v4Engine->isInterrupted.loadAcquire())
+ return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+
+ return QJSValue(
+ m_v4Engine,
+ m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
}
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6300842341..31a4d68baa 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -113,6 +113,9 @@ public:
void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
+ void setInterrupted(bool interrupted);
+ bool isInterrupted() const;
+
QV4::ExecutionEngine *handle() const { return m_v4Engine; }
void throwError(const QString &message);
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index a77d710cff..164a70d000 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -74,7 +74,7 @@ public:
static const QJSEnginePrivate* get(const QJSEngine*e) { return e->d_func(); }
static QJSEnginePrivate* get(QV4::ExecutionEngine *e);
- QJSEnginePrivate() : mutex(QMutex::Recursive) {}
+ QJSEnginePrivate() = default;
~QJSEnginePrivate() override;
static void addToDebugServer(QJSEngine *q);
@@ -105,7 +105,7 @@ public:
};
// Shared by QQmlEngine
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
// These methods may be called from the QML loader thread
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 1ab6e8c767..c2957dd294 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -51,7 +51,6 @@
#include "qv4variantobject_p.h"
#include "qv4regexpobject_p.h"
#include "qv4errorobject_p.h"
-#include "private/qv8engine_p.h"
#include <private/qv4mm_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -770,6 +769,8 @@ QJSValue QJSValue::call(const QJSValueList &args)
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted.loadAcquire())
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -826,6 +827,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted.loadAcquire())
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -874,6 +877,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted.loadAcquire())
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -1042,7 +1047,7 @@ bool QJSValue::equals(const QJSValue& other) const
if (!ov)
return other.equals(*this);
- return Runtime::method_compareEqual(*v, *ov);
+ return Runtime::CompareEqual::call(*v, *ov);
}
/*!
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index a24ee0a188..32acc6affc 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -1,8 +1,8 @@
INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
-!qmldevtools_build {
SOURCES += \
+ $$PWD/qv4engine.cpp \
$$PWD/qv4context.cpp \
$$PWD/qv4persistent.cpp \
$$PWD/qv4lookup.cpp \
@@ -36,13 +36,13 @@ SOURCES += \
$$PWD/qv4reflect.cpp \
$$PWD/qv4regexpobject.cpp \
$$PWD/qv4stackframe.cpp \
+ $$PWD/qv4string.cpp \
$$PWD/qv4stringiterator.cpp \
$$PWD/qv4stringobject.cpp \
$$PWD/qv4variantobject.cpp \
$$PWD/qv4objectiterator.cpp \
$$PWD/qv4regexp.cpp \
$$PWD/qv4runtimecodegen.cpp \
- $$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
$$PWD/qv4symbol.cpp \
$$PWD/qv4setobject.cpp \
@@ -57,13 +57,17 @@ SOURCES += \
$$PWD/qv4mapiterator.cpp \
$$PWD/qv4estable.cpp \
$$PWD/qv4module.cpp \
- $$PWD/qv4promiseobject.cpp
+ $$PWD/qv4promiseobject.cpp \
+ $$PWD/qv4runtime.cpp \
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4compilationunitmapper.cpp \
+ $$PWD/qv4executablecompilationunit.cpp \
+ $$PWD/qv4executableallocator.cpp
qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp
HEADERS += \
$$PWD/qv4global_p.h \
- $$PWD/qv4alloca_p.h \
$$PWD/qv4engine_p.h \
$$PWD/qv4enginebase_p.h \
$$PWD/qv4context_p.h \
@@ -103,13 +107,13 @@ HEADERS += \
$$PWD/qv4regexpobject_p.h \
$$PWD/qv4runtimecodegen_p.h \
$$PWD/qv4stackframe_p.h \
+ $$PWD/qv4string_p.h \
$$PWD/qv4stringiterator_p.h \
$$PWD/qv4stringobject_p.h \
$$PWD/qv4variantobject_p.h \
$$PWD/qv4property_p.h \
$$PWD/qv4objectiterator_p.h \
$$PWD/qv4regexp_p.h \
- $$PWD/qv4serialize_p.h \
$$PWD/qv4script_p.h \
$$PWD/qv4symbol_p.h \
$$PWD/qv4setobject_p.h \
@@ -128,7 +132,13 @@ HEADERS += \
$$PWD/qv4estable_p.h \
$$PWD/qv4vtable_p.h \
$$PWD/qv4module_p.h \
- $$PWD/qv4promiseobject_p.h
+ $$PWD/qv4promiseobject_p.h \
+ $$PWD/qv4runtime_p.h \
+ $$PWD/qv4value_p.h \
+ $$PWD/qv4compilationunitmapper_p.h \
+ $$PWD/qv4executablecompilationunit_p.h \
+ $$PWD/qv4functiontable_p.h \
+ $$PWD/qv4runtimeapi_p.h
qtConfig(qml-sequence-object) {
HEADERS += \
@@ -138,29 +148,10 @@ qtConfig(qml-sequence-object) {
$$PWD/qv4sequenceobject.cpp
}
-}
-
-
-HEADERS += \
- $$PWD/qv4runtime_p.h \
- $$PWD/qv4runtimeapi_p.h \
- $$PWD/qv4value_p.h \
- $$PWD/qv4string_p.h \
- $$PWD/qv4util_p.h \
- $$PWD/qv4value_p.h \
- $$PWD/qv4functiontable_p.h
-
-SOURCES += \
- $$PWD/qv4engine.cpp \
- $$PWD/qv4runtime.cpp \
- $$PWD/qv4string.cpp \
- $$PWD/qv4value.cpp \
- $$PWD/qv4executableallocator.cpp
+unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
+else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qmldevtools_build {
- SOURCES += \
- $$PWD/qv4functiontable_noop.cpp
-} else:win32 {
+win32 {
!winrt:equals(QT_ARCH, x86_64) {
SOURCES += \
$$PWD/qv4functiontable_win64.cpp
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 4a21f62cf2..206e2b9aa4 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -38,13 +38,14 @@
****************************************************************************/
#include <qv4argumentsobject_p.h>
#include <qv4arrayobject_p.h>
-#include <qv4alloca_p.h>
#include <qv4scopedvalue_p.h>
#include <qv4string_p.h>
#include <qv4function_p.h>
#include <qv4jscall_p.h>
#include <qv4symbol_p.h>
+#include <private/qv4alloca_p.h>
+
using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
@@ -116,6 +117,9 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
args->fullyCreate();
+ if (!id.isArrayIndex())
+ return Object::virtualDefineOwnProperty(m, id, desc, attrs);
+
uint index = id.asArrayIndex();
if (!args->isMapped(index))
@@ -148,36 +152,42 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const
ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
- const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
- uint index = id.asArrayIndex();
- if (index < args->d()->argCount && !args->d()->fullyCreated) {
- if (hasProperty)
- *hasProperty = true;
- return args->context()->args()[index].asReturnedValue();
+ if (id.isArrayIndex()) {
+ const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
+ uint index = id.asArrayIndex();
+ if (index < args->d()->argCount && !args->d()->fullyCreated) {
+ if (hasProperty)
+ *hasProperty = true;
+ return args->context()->args()[index].asReturnedValue();
+ }
+
+ if (args->isMapped(index)) {
+ Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
+ if (hasProperty)
+ *hasProperty = true;
+ return args->context()->args()[index].asReturnedValue();
+ }
}
- if (!args->isMapped(index))
- return Object::virtualGet(m, id, receiver, hasProperty);
- Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
- if (hasProperty)
- *hasProperty = true;
- return args->context()->args()[index].asReturnedValue();
+ return Object::virtualGet(m, id, receiver, hasProperty);
}
bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
- ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
- uint index = id.asArrayIndex();
-
- if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) {
- args->context()->setArg(index, value);
- return true;
+ if (id.isArrayIndex()) {
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ uint index = id.asArrayIndex();
+
+ if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) {
+ args->context()->setArg(index, value);
+ return true;
+ }
+
+ bool isMapped = (args == receiver && args->isMapped(index));
+ if (isMapped)
+ args->context()->setArg(index, value);
}
- bool isMapped = (args == receiver && args->isMapped(index));
- if (isMapped)
- args->context()->setArg(index, value);
-
return Object::virtualPut(m, id, value, receiver);
}
@@ -186,13 +196,16 @@ bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id)
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
args->fullyCreate();
bool result = Object::virtualDeleteProperty(m, id);
- if (result)
+ if (result && id.isArrayIndex())
args->removeMapping(id.asArrayIndex());
return result;
}
PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
{
+ if (!id.isArrayIndex())
+ return Object::virtualGetOwnProperty(m, id, p);
+
const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
uint index = id.asArrayIndex();
if (index < args->d()->argCount && !args->d()->fullyCreated) {
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index b5b421fa39..af1a2d1de0 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -175,7 +175,8 @@ static ScopedObject createObjectFromCtorOrArray(Scope &scope, ScopedFunctionObje
// this isn't completely kosher. for instance:
// Array.from.call(Object, []).constructor == Object
// is expected by the tests, but naturally, we get Number.
- ScopedValue argument(scope, useLen ? QV4::Encode(len) : Value::undefinedValue());
+ ScopedValue argument(scope, useLen ? Value::fromReturnedValue(QV4::Encode(len))
+ : Value::undefinedValue());
a = ctor->callAsConstructor(argument, useLen ? 1 : 0);
} else {
a = scope.engine->newArrayObject(len);
@@ -219,7 +220,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
// Item iteration supported, so let's go ahead and try use that.
ScopedObject a(createObjectFromCtorOrArray(scope, thatCtor, false, 0));
CHECK_EXCEPTION();
- ScopedObject iterator(scope, Runtime::method_getIterator(scope.engine, itemsObject, true));
+ ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
if (!iterator) {
return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
@@ -236,11 +237,11 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
if (k > (static_cast<qint64>(1) << 53) - 1) {
ScopedValue falsey(scope, Encode(false));
ScopedValue error(scope, scope.engine->throwTypeError());
- return Runtime::method_iteratorClose(scope.engine, iterator, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
}
// Retrieve the next value. If the iteration ends, we're done here.
- done = Value::fromReturnedValue(Runtime::method_iteratorNext(scope.engine, iterator, nextValue));
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
CHECK_EXCEPTION();
if (done->toBoolean()) {
if (ArrayObject *ao = a->as<ArrayObject>()) {
@@ -257,7 +258,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
mapArguments[1] = Value::fromDouble(k);
mappedValue = mapfn->call(thisArg, mapArguments, 2);
if (scope.engine->hasException)
- return Runtime::method_iteratorClose(scope.engine, iterator, Value::fromBoolean(false));
+ return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
} else {
mappedValue = *nextValue;
}
@@ -271,7 +272,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
if (scope.engine->hasException) {
ScopedValue falsey(scope, Encode(false));
- return Runtime::method_iteratorClose(scope.engine, iterator, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
}
k++;
@@ -387,7 +388,7 @@ ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *b, con
v = instance->get(k);
if (v->isNullOrUndefined())
continue;
- v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
+ v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
s = v->toString(scope.engine);
if (scope.hasException())
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 3e5f51c302..a9b4ecb607 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -103,7 +103,7 @@ ReturnedValue BooleanPrototype::method_toString(const FunctionObject *b, const V
if (exception)
return v4->throwTypeError();
- return Encode(result ? v4->id_true() : v4->id_false());
+ return (result ? v4->id_true() : v4->id_false())->asReturnedValue();
}
ReturnedValue BooleanPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index 350f6f9485..74f34a284d 100644
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -39,7 +39,7 @@
#include "qv4compilationunitmapper_p.h"
-#include "qv4compileddata_p.h"
+#include <private/qv4compileddata_p.h>
#include <QFileInfo>
#include <QDateTime>
#include <QCoreApplication>
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/jsruntime/qv4compilationunitmapper_p.h
index 80f914c141..80f914c141 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/jsruntime/qv4compilationunitmapper_p.h
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
index 6768bc9596..a9ab2f5ccb 100644
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
@@ -45,7 +45,7 @@
#include <QScopeGuard>
#include <QDateTime>
-#include "qv4compileddata_p.h"
+#include "qv4executablecompilationunit_p.h"
QT_BEGIN_NAMESPACE
@@ -73,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!header.verifyHeader(sourceTimeStamp, errorString))
+ if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
index 779c1288fe..9e8babc5e6 100644
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
@@ -39,7 +39,7 @@
#include "qv4compilationunitmapper_p.h"
-#include "qv4compileddata_p.h"
+#include "qv4executablecompilationunit_p.h"
#include <QScopeGuard>
#include <QFileInfo>
#include <QDateTime>
@@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!header.verifyHeader(sourceTimeStamp, errorString))
+ if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 94b1a9fb73..018571e325 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -60,7 +60,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
{
Function *function = frame->v4Function;
- Heap::InternalClass *ic = function->compilationUnit->runtimeBlocks.at(blockIndex);
+ Heap::InternalClass *ic = function->executableCompilationUnit()->runtimeBlocks.at(blockIndex);
uint nLocals = ic->size;
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals;
@@ -71,27 +71,28 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(frame->jsFrame->function.m()));
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ Value::fromStaticValue(frame->jsFrame->function).m()));
c->locals.size = nLocals;
c->locals.alloc = nLocals;
- c->setupLocalTemporalDeadZone(function->compilationUnit->unitData()->blockAt(blockIndex));
+ c->setupLocalTemporalDeadZone(function->executableCompilationUnit()->unitData()->blockAt(blockIndex));
return c;
}
-Heap::CallContext *ExecutionContext::cloneBlockContext(Heap::CallContext *context)
+Heap::CallContext *ExecutionContext::cloneBlockContext(ExecutionEngine *engine,
+ Heap::CallContext *callContext)
{
- uint nLocals = context->locals.alloc;
+ uint nLocals = callContext->locals.alloc;
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals;
- ExecutionEngine *v4 = context->internalClass->engine;
- Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory, context->internalClass);
- memcpy(c, context, requiredMemory);
+ Heap::CallContext *c = engine->memoryManager->allocManaged<CallContext>(
+ requiredMemory, callContext->internalClass);
+ memcpy(c, callContext, requiredMemory);
return c;
-
}
Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
@@ -108,7 +109,8 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
c->init();
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(frame->jsFrame->function.m()));
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ Value::fromStaticValue(frame->jsFrame->function).m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
uint nLocals = compiledFunction->nLocals;
@@ -128,7 +130,7 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
return c;
}
-Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with)
+Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with) const
{
Heap::ExecutionContext *c = engine()->memoryManager->alloc<ExecutionContext>(Heap::ExecutionContext::Type_WithContext);
c->outer.set(engine(), d());
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 5cd2f9ddf0..75fa2d08e6 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -150,9 +150,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
V4_INTERNALCLASS(ExecutionContext)
static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex);
- static Heap::CallContext *cloneBlockContext(Heap::CallContext *context);
+ static Heap::CallContext *cloneBlockContext(ExecutionEngine *engine,
+ Heap::CallContext *callContext);
static Heap::CallContext *newCallContext(QV4::CppStackFrame *frame);
- Heap::ExecutionContext *newWithContext(Heap::Object *with);
+ Heap::ExecutionContext *newWithContext(Heap::Object *with) const;
static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName);
void createMutableBinding(String *name, bool deletable);
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index e313ebe300..cc89947cec 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -52,11 +52,9 @@
#include <time.h>
-#include <private/qqmljsengine_p.h>
-
#include <wtf/MathExtras.h>
-#if defined(Q_OS_LINUX) && QT_CONFIG(timezone)
+#if defined(Q_OS_LINUX) && QT_CONFIG(timezone) && !defined(Q_OS_ANDROID)
/*
See QTBUG-56899. Although we don't (yet) have a proper way to reset the
system zone, the code below, that uses QTimeZone::systemTimeZone(), works
@@ -618,8 +616,7 @@ static inline double ParseString(const QString &s, double localTZA)
QStringLiteral("d MMMM, yyyy hh:mm:ss"),
};
- for (uint i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
- const QString &format(formats[i]);
+ for (const QString &format : formats) {
dt = format.indexOf(QLatin1String("hh:mm")) < 0
? QDateTime(QDate::fromString(s, format),
QTime(0, 0, 0), Qt::UTC)
@@ -746,14 +743,16 @@ void Heap::DateObject::init(const QTime &time)
* time from it, which shall (via toQDateTime(), below) discard the date
* part. We need a date for which time-zone data is likely to be sane (so
* MakeDay(0, 0, 0) was a bad choice; 2 BC, December 31st is before
- * time-zones were standardized), with no transition nearby in date. We
- * ignore DST transitions before 1970, but even then zone transitions did
- * happen. Some do happen at new year, others on DST transitions in spring
- * and autumn; so pick the three hundredth anniversary of the birth of
- * Giovanni Domenico Cassini (1625-06-08), whose work first let us
- * synchronize clocks tolerably accurately at distant locations.
+ * time-zones were standardized), with no transition nearby in date.
+ * QDateTime ignores DST transitions before 1970, but even then zone
+ * transitions did happen; and DaylightSavingTA() will include DST, at odds
+ * with QDateTime. So pick a date since 1970 and prefer one when no zone
+ * was in DST. One such interval (according to the Olson database, at
+ * least) was 1971 March 15th to April 17th. Since converting a time to a
+ * date-time without specifying a date is foolish, let's use April Fools'
+ * day.
*/
- static const double d = MakeDay(1925, 5, 8);
+ static const double d = MakeDay(1971, 3, 1);
double t = MakeTime(time.hour(), time.minute(), time.second(), time.msec());
date = TimeClip(UTC(MakeDate(d, t), internalClass->engine->localTZA));
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 5b9934282c..a87eb92caf 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -96,7 +96,7 @@ struct DateObject: Object {
double date() const { return d()->date; }
void setDate(double date) { d()->date = date; }
- QDateTime toQDateTime() const;
+ Q_QML_PRIVATE_EXPORT QDateTime toQDateTime() const;
};
template<>
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 9b41bb6e7a..52263105fa 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -52,6 +52,7 @@
//
#include "qv4global_p.h"
+#include <private/qv4staticvalue_p.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 3002945945..3d3f452073 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -38,21 +38,18 @@
****************************************************************************/
#include <qv4engine_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsast_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qv4compiler_p.h>
-#include <private/qv4compilercontext_p.h>
#include <private/qv4codegen_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/QTextStream>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QLoggingCategory>
-
-#ifndef V4_BOOTSTRAP
+#if QT_CONFIG(regularexpression)
+#include <QRegularExpression>
+#endif
#include <qv4qmlcontext_p.h>
#include <qv4value_p.h>
@@ -104,7 +101,6 @@
#include "qv4dataview_p.h"
#include "qv4promiseobject_p.h"
#include "qv4typedarray_p.h"
-#include <private/qv8engine_p.h>
#include <private/qjsvalue_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
@@ -112,9 +108,15 @@
#include <private/qqmllistwrapper_p.h>
#include <private/qqmllist_p.h>
#include <private/qqmltypeloader_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
#endif
+#if QT_CONFIG(qml_xml_http_request)
+#include <private/qv4domerrors_p.h>
+#include <private/qqmlxmlhttprequest_p.h>
+#endif
+#include <private/qv4sqlerrors_p.h>
#include <qqmlfile.h>
#if USE(PTHREADS)
@@ -131,16 +133,12 @@
#include <valgrind/memcheck.h>
#endif
-#endif // #ifndef V4_BOOTSTRAP
+Q_DECLARE_METATYPE(QList<int>)
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTracingAll, "qt.v4.tracing.all")
-
using namespace QV4;
-#ifndef V4_BOOTSTRAP
-
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
@@ -150,6 +148,43 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const
qint32 ExecutionEngine::maxCallDepth = -1;
+template <typename ReturnType>
+ReturnType convertJSValueToVariantType(const QJSValue &value)
+{
+ return value.toVariant().value<ReturnType>();
+}
+
+static void saveJSValue(QDataStream &stream, const void *data)
+{
+ const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
+ quint32 isNullOrUndefined = 0;
+ if (jsv->isNull())
+ isNullOrUndefined |= 0x1;
+ if (jsv->isUndefined())
+ isNullOrUndefined |= 0x2;
+ stream << isNullOrUndefined;
+ if (!isNullOrUndefined)
+ reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
+}
+
+static void restoreJSValue(QDataStream &stream, void *data)
+{
+ QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
+
+ quint32 isNullOrUndefined;
+ stream >> isNullOrUndefined;
+
+ if (isNullOrUndefined & 0x1) {
+ *jsv = QJSValue(QJSValue::NullValue);
+ } else if (isNullOrUndefined & 0x2) {
+ *jsv = QJSValue();
+ } else {
+ QVariant v;
+ v.load(stream);
+ QJSValuePrivate::setVariant(jsv, v);
+ }
+}
+
ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
: executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
@@ -157,19 +192,31 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
, jsStack(new WTF::PageAllocation)
, gcStack(new WTF::PageAllocation)
, globalCode(nullptr)
- , v8Engine(nullptr)
, publicEngine(jsEngine)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(nullptr)
, m_multiplyWrappedQObjects(nullptr)
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
, m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
#endif
+#if QT_CONFIG(qml_xml_http_request)
+ , m_xmlHttpRequestData(nullptr)
+#endif
+ , m_qmlEngine(nullptr)
{
+ bool ok = false;
+ const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok);
+ if (ok && envMaxJSStackSize > 0)
+ m_maxJSStackSize = envMaxJSStackSize;
+
+ const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok);
+ if (ok && envMaxGCStackSize > 0)
+ m_maxGCStackSize = envMaxGCStackSize;
+
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
- bool ok = false;
+ ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer)
@@ -183,24 +230,24 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
Q_ASSERT(maxCallDepth > 0);
// reserve space for the JS stack
- // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
+ // we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
// allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages,
+ *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
#endif
jsStackTop = jsStackBase;
- *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
+ *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
{
- bool ok = false;
+ ok = false;
jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok);
if (!ok)
jitCallCountThreshold = 3;
@@ -218,7 +265,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsSymbols = jsAlloca(NJSSymbols);
// set up stack limits
- jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
+ jsStackLimit = jsStackBase + m_maxJSStackSize/sizeof(Value);
identifierTable = new IdentifierTable(this);
@@ -643,7 +690,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
- t->setInternalClass(t->internalClass()->frozen());
+ t->setInternalClass(t->internalClass()->cryopreserved());
jsObjects[ThrowerObject] = t;
ScopedProperty pd(scope);
@@ -651,18 +698,27 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
pd->set = thrower();
functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
+
+ qMetaTypeId<QJSValue>();
+ qMetaTypeId<QList<int> >();
+
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
+ QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
+ QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
+ QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
+ QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue);
+
+ QV4::QObjectWrapper::initializeBindings(this);
+
+ m_delayedCallQueue.init(this);
}
ExecutionEngine::~ExecutionEngine()
{
- if (Q_UNLIKELY(lcTracingAll().isDebugEnabled())) {
- for (auto cu : compilationUnits) {
- for (auto f : qAsConst(cu->runtimeFunctions))
- qCDebug(lcTracingAll).noquote().nospace() << f->traceInfoToString();
- }
- }
-
modules.clear();
+ qDeleteAll(m_extensionData);
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = nullptr;
delete identifierTable;
@@ -679,6 +735,11 @@ ExecutionEngine::~ExecutionEngine()
delete jsStack;
gcStack->deallocate();
delete gcStack;
+
+#if QT_CONFIG(qml_xml_http_request)
+ qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
+ m_xmlHttpRequestData = nullptr;
+#endif
}
ExecutionContext *ExecutionEngine::currentContext() const
@@ -860,6 +921,13 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
return memoryManager->allocate<RegExpObject>(re);
}
+#if QT_CONFIG(regularexpression)
+Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
+{
+ return memoryManager->allocate<RegExpObject>(re);
+}
+#endif
+
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
{
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
@@ -1072,6 +1140,12 @@ extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext));
}
+extern "C" Q_QML_EXPORT char *qt_v4StackTraceForEngine(void *executionEngine)
+{
+ auto engine = (reinterpret_cast<const ExecutionEngine *>(executionEngine));
+ return v4StackTrace(engine->currentContext());
+}
+
QUrl ExecutionEngine::resolvedUrl(const QString &file)
{
QUrl src(file);
@@ -1269,6 +1343,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &va
const QByteArray &targetType,
void **result);
static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
+static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
{
@@ -1305,7 +1380,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
- return qVariantFromValue<QObject *>(wrapper->object());
+ return QVariant::fromValue<QObject *>(wrapper->object());
} else if (object->as<QV4::QQmlContextWrapper>()) {
return QVariant();
} else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
@@ -1336,7 +1411,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
}
}
- return qVariantFromValue<QList<QObject*> >(list);
+ return QVariant::fromValue<QList<QObject*> >(list);
} else if (typeHint == QMetaType::QJsonArray) {
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
@@ -1379,8 +1454,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
QV4::ScopedObject o(scope, value);
Q_ASSERT(o);
- if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
+ if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
+#if QT_CONFIG(regularexpression)
+ if (typeHint != QMetaType::QRegExp)
+ return re->toQRegularExpression();
+#endif
return re->toQRegExp();
+ }
if (createJSValueForObjects)
return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
@@ -1442,35 +1522,6 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
return result;
}
-static QV4::ReturnedValue arrayFromVariantList(QV4::ExecutionEngine *e, const QVariantList &list)
-{
- QV4::Scope scope(e);
- QV4::ScopedArrayObject a(scope, e->newArrayObject());
- int len = list.count();
- a->arrayReserve(len);
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < len; ++ii)
- a->arrayPut(ii, (v = scope.engine->fromVariant(list.at(ii))));
-
- a->setArrayLengthUnchecked(len);
- return a.asReturnedValue();
-}
-
-static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QVariantMap &map)
-{
- QV4::Scope scope(e);
- QV4::ScopedObject o(scope, e->newObject());
- QV4::ScopedString s(scope);
- QV4::ScopedValue v(scope);
- for (QVariantMap::const_iterator iter = map.begin(), cend = map.end(); iter != cend; ++iter) {
- s = e->newString(iter.key());
- o->put(s, (v = e->fromVariant(iter.value())));
- }
- return o.asReturnedValue();
-}
-
-Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-
QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
{
int type = variant.userType();
@@ -1520,6 +1571,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
case QMetaType::QRegExp:
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
+#endif
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
#if QT_CONFIG(qml_sequence_object)
@@ -1534,9 +1589,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
}
#endif
case QMetaType::QVariantList:
- return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
+ return variantListToJS(this, *reinterpret_cast<const QVariantList *>(ptr));
case QMetaType::QVariantMap:
- return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
+ return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(ptr));
case QMetaType::QJsonValue:
return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(ptr));
case QMetaType::QJsonObject:
@@ -1597,6 +1652,11 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return retn->asReturnedValue();
#endif
+ if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
+ QSequentialIterable lst = variant.value<QSequentialIterable>();
+ return sequentialIterableToJS(this, lst);
+ }
+
if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
}
@@ -1661,9 +1721,8 @@ static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVarian
s = v4->newIdentifier(it.key());
key = s->propertyKey();
v = variantToJS(v4, it.value());
- uint idx = key->asArrayIndex();
- if (idx < UINT_MAX)
- o->arraySet(idx, v);
+ if (key->isArrayIndex())
+ o->arraySet(key->asArrayIndex(), v);
else
o->insertMember(s, v);
}
@@ -1676,99 +1735,23 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
{
Q_ASSERT(data != nullptr);
- // check if it's one of the types we know
- switch (QMetaType::Type(type)) {
- case QMetaType::UnknownType:
- case QMetaType::Void:
- return QV4::Encode::undefined();
- case QMetaType::Nullptr:
- case QMetaType::VoidStar:
- return QV4::Encode::null();
- case QMetaType::Bool:
- return QV4::Encode(*reinterpret_cast<const bool*>(data));
- case QMetaType::Int:
- return QV4::Encode(*reinterpret_cast<const int*>(data));
- case QMetaType::UInt:
- return QV4::Encode(*reinterpret_cast<const uint*>(data));
- case QMetaType::LongLong:
- return QV4::Encode(double(*reinterpret_cast<const qlonglong*>(data)));
- case QMetaType::ULongLong:
-#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
-#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
- return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
-#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
- return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
-#else
- return QV4::Encode(double(*reinterpret_cast<const qulonglong*>(data)));
-#endif
- case QMetaType::Double:
- return QV4::Encode(*reinterpret_cast<const double*>(data));
- case QMetaType::QString:
- return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
- case QMetaType::QByteArray:
- return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue();
- case QMetaType::Float:
- return QV4::Encode(*reinterpret_cast<const float*>(data));
- case QMetaType::Short:
- return QV4::Encode((int)*reinterpret_cast<const short*>(data));
- case QMetaType::UShort:
- return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(data));
- case QMetaType::Char:
- return QV4::Encode((int)*reinterpret_cast<const char*>(data));
- case QMetaType::UChar:
- return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(data));
- case QMetaType::QChar:
- return QV4::Encode((int)(*reinterpret_cast<const QChar*>(data)).unicode());
- case QMetaType::QStringList:
- return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(data)));
- case QMetaType::QVariantList:
- return variantListToJS(this, *reinterpret_cast<const QVariantList *>(data));
- case QMetaType::QVariantMap:
- return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(data));
- case QMetaType::QDateTime:
- return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(data)));
- case QMetaType::QDate:
- return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
- case QMetaType::QRegExp:
- return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(data)));
- case QMetaType::QObjectStar:
- return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
- case QMetaType::QVariant:
+ QVariant variant(type, data);
+ if (QMetaType::Type(variant.type()) == QMetaType::QVariant) {
+ // unwrap it: this is tested in QJSEngine, and makes the most sense for
+ // end-user code too.
return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
- case QMetaType::QJsonValue:
- return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(data));
- case QMetaType::QJsonObject:
- return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(data));
- case QMetaType::QJsonArray:
- return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(data));
- default:
- if (type == qMetaTypeId<QJSValue>()) {
- return QJSValuePrivate::convertedToValue(this, *reinterpret_cast<const QJSValue*>(data));
- } else {
- QByteArray typeName = QMetaType::typeName(type);
- if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
- return QV4::Encode::null();
- }
- QMetaType mt(type);
- if (auto metaObject = mt.metaObject()) {
- auto flags = mt.flags();
- if (flags & QMetaType::IsGadget) {
- return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), metaObject, type);
- } else if (flags & QMetaType::PointerToQObject) {
- return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
- }
- }
- if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
- auto v = QVariant(type, data);
- QSequentialIterable lst = v.value<QSequentialIterable>();
- return sequentialIterableToJS(this, lst);
- }
- // Fall back to wrapping in a QVariant.
- return QV4::Encode(newVariantObject(QVariant(type, data)));
- }
}
- Q_UNREACHABLE();
- return 0;
+ return fromVariant(variant);
+}
+
+int ExecutionEngine::maxJSStackSize() const
+{
+ return m_maxJSStackSize;
+}
+
+int ExecutionEngine::maxGCStackSize() const
+{
+ return m_maxGCStackSize;
}
ReturnedValue ExecutionEngine::global()
@@ -1776,13 +1759,12 @@ ReturnedValue ExecutionEngine::global()
return globalObject->asReturnedValue();
}
-QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(const QUrl &url)
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const QUrl &url)
{
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url, &cacheError)) {
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> jsUnit;
- jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit, url.fileName(), url.toString()));
- return jsUnit;
+ return ExecutableCompilationUnit::create(
+ QV4::CompiledData::CompilationUnit(cachedUnit, url.fileName(), url.toString()));
}
QFile f(QQmlFile::urlToLocalFileOrQrc(url));
@@ -1800,69 +1782,26 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(con
}
-QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp)
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(
+ const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp)
{
QList<QQmlJS::DiagnosticMessage> diagnostics;
- auto unit = compileModule(/*debugMode*/debugger() != nullptr, url.toString(), sourceCode, sourceTimeStamp, &diagnostics);
+ auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url.toString(),
+ sourceCode, sourceTimeStamp, &diagnostics);
for (const QQmlJS::DiagnosticMessage &m : diagnostics) {
if (m.isError()) {
- throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn);
+ throwSyntaxError(m.message, url.toString(), m.line, m.column);
return nullptr;
} else {
- qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn
+ qWarning() << url << ':' << m.line << ':' << m.column
<< ": warning: " << m.message;
}
}
- return unit;
-}
-
-#endif // ifndef V4_BOOTSTRAP
-
-QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(bool debugMode, const QString &url, const QString &sourceCode,
- const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
-{
- QQmlJS::Engine ee;
- QQmlJS::Lexer lexer(&ee);
- lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false);
- QQmlJS::Parser parser(&ee);
-
- const bool parsed = parser.parseModule();
-
- if (diagnostics)
- *diagnostics = parser.diagnosticMessages();
-
- if (!parsed)
- return nullptr;
-
- QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
- if (!moduleNode) {
- // if parsing was successful, and we have no module, then
- // the file was empty.
- if (diagnostics)
- diagnostics->clear();
- return nullptr;
- }
-
- using namespace QV4::Compiler;
- Compiler::Module compilerModule(debugMode);
- compilerModule.unitFlags |= CompiledData::Unit::IsESModule;
- compilerModule.sourceTimeStamp = sourceTimeStamp;
- JSUnitGenerator jsGenerator(&compilerModule);
- Codegen cg(&jsGenerator, /*strictMode*/true);
- cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule);
- auto errors = cg.errors();
- if (diagnostics)
- *diagnostics << errors;
-
- if (!errors.isEmpty())
- return nullptr;
- return cg.generateCompilationUnit();
+ return ExecutableCompilationUnit::create(std::move(unit));
}
-#ifndef V4_BOOTSTRAP
-
-void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit)
+void ExecutionEngine::injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit)
{
// Injection can happen from the QML type loader thread for example, but instantiation and
// evaluation must be limited to the ExecutionEngine's thread.
@@ -1870,7 +1809,7 @@ void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::Compilatio
modules.insert(moduleUnit->finalUrl(), moduleUnit);
}
-QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer) const
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer) const
{
QUrl url = QQmlTypeLoader::normalize(_url);
if (referrer)
@@ -1883,7 +1822,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::moduleForUrl(cons
return *existingModule;
}
-QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer)
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer)
{
QUrl url = QQmlTypeLoader::normalize(_url);
if (referrer)
@@ -1905,6 +1844,131 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const
return newModule;
}
+void ExecutionEngine::initQmlGlobalObject()
+{
+ initializeGlobal();
+ freezeObject(*globalObject);
+}
+
+void ExecutionEngine::initializeGlobal()
+{
+ QV4::Scope scope(this);
+ QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
+
+ QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine()));
+ globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
+
+#if QT_CONFIG(qml_locale)
+ QQmlLocale::registerStringLocaleCompare(this);
+ QQmlDateExtension::registerExtension(this);
+ QQmlNumberExtension::registerExtension(this);
+#endif
+
+#if QT_CONFIG(qml_xml_http_request)
+ qt_add_domexceptions(this);
+ m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
+#endif
+
+ qt_add_sqlexceptions(this);
+
+ {
+ for (uint i = 0; i < globalObject->internalClass()->size; ++i) {
+ if (globalObject->internalClass()->nameMap.at(i).isString()) {
+ QV4::PropertyKey id = globalObject->internalClass()->nameMap.at(i);
+ m_illegalNames.insert(id.toQString());
+ }
+ }
+ }
+}
+
+const QSet<QString> &ExecutionEngine::illegalNames() const
+{
+ return m_illegalNames;
+}
+
+void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
+{
+ m_qmlEngine = engine;
+ initQmlGlobalObject();
+}
+
+static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
+{
+ if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
+ return;
+
+ QV4::Scope scope(v4);
+
+ bool instanceOfObject = false;
+ QV4::ScopedObject p(scope, object->getPrototypeOf());
+ while (p) {
+ if (p->d() == v4->objectPrototype()->d()) {
+ instanceOfObject = true;
+ break;
+ }
+ p = p->getPrototypeOf();
+ }
+ if (!instanceOfObject)
+ return;
+
+ Heap::InternalClass *frozen = object->internalClass()->frozen();
+ object->setInternalClass(frozen); // Immediately assign frozen to prevent it from getting GC'd
+
+ QV4::ScopedObject o(scope);
+ for (uint i = 0; i < frozen->size; ++i) {
+ if (!frozen->nameMap.at(i).isStringOrSymbol())
+ continue;
+ o = *object->propertyData(i);
+ if (o)
+ freeze_recursive(v4, o);
+ }
+}
+
+void ExecutionEngine::freezeObject(const QV4::Value &value)
+{
+ QV4::Scope scope(this);
+ QV4::ScopedObject o(scope, value);
+ freeze_recursive(this, o);
+}
+
+void ExecutionEngine::startTimer(const QString &timerName)
+{
+ if (!m_time.isValid())
+ m_time.start();
+ m_startedTimers[timerName] = m_time.elapsed();
+}
+
+qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning)
+{
+ if (!m_startedTimers.contains(timerName)) {
+ *wasRunning = false;
+ return 0;
+ }
+ *wasRunning = true;
+ qint64 startedAt = m_startedTimers.take(timerName);
+ return m_time.elapsed() - startedAt;
+}
+
+int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column)
+{
+ const QString key = file + QString::number(line) + QString::number(column);
+ int number = m_consoleCount.value(key, 0);
+ number++;
+ m_consoleCount.insert(key, number);
+ return number;
+}
+
+void ExecutionEngine::setExtensionData(int index, Deletable *data)
+{
+ if (m_extensionData.count() <= index)
+ m_extensionData.resize(index + 1);
+
+ if (m_extensionData.at(index))
+ delete m_extensionData.at(index);
+
+ m_extensionData[index] = data;
+}
+
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
@@ -1980,6 +2044,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
*reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
return true;
} break;
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
+ *reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
+ return true;
+ } break;
+#endif
case QMetaType::QObjectStar: {
const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
if (qobjectWrapper || value->isNull()) {
@@ -2144,6 +2215,23 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v
return wrapper->object();
}
-#endif // ifndef V4_BOOTSTRAP
+struct QV4EngineRegistrationData
+{
+ QV4EngineRegistrationData() : extensionCount(0) {}
+
+ QMutex mutex;
+ int extensionCount;
+};
+Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData);
+
+QMutex *ExecutionEngine::registrationMutex()
+{
+ return &registrationData()->mutex;
+}
+
+int ExecutionEngine::registerExtension()
+{
+ return registrationData()->extensionCount++;
+}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 86367c0ece..d233347060 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -53,25 +53,82 @@
#include "qv4global_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
+#include "qv4stackframe_p.h"
#include <private/qintrusivelist_p.h>
#include "qv4enginebase_p.h"
#include <private/qqmlrefcount_p.h>
-#include <private/qqmljsengine_p.h>
+#include <private/qqmldelayedcallqueue_p.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmutex.h>
-#ifndef V4_BOOTSTRAP
-# include "qv4function_p.h"
-# include <private/qv8engine_p.h>
-# include <private/qv4compileddata_p.h>
-#endif
+#include "qv4function_p.h"
+#include <private/qv4compileddata_p.h>
+#include <private/qv4executablecompilationunit_p.h>
namespace WTF {
class BumpPointerAllocator;
class PageAllocation;
}
+#define V4_DEFINE_EXTENSION(dataclass, datafunction) \
+ static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \
+ { \
+ static int extensionId = -1; \
+ if (extensionId == -1) { \
+ QV4::ExecutionEngine::registrationMutex()->lock(); \
+ if (extensionId == -1) \
+ extensionId = QV4::ExecutionEngine::registerExtension(); \
+ QV4::ExecutionEngine::registrationMutex()->unlock(); \
+ } \
+ dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
+ if (!rv) { \
+ rv = new dataclass(engine); \
+ engine->setExtensionData(extensionId, rv); \
+ } \
+ return rv; \
+ } \
+
+
QT_BEGIN_NAMESPACE
-class QV8Engine;
+namespace QV4 { struct QObjectMethod; }
+
+// Used to allow a QObject method take and return raw V4 handles without having to expose
+// 48 in the public API.
+// Use like this:
+// class MyClass : public QObject {
+// Q_OBJECT
+// ...
+// Q_INVOKABLE void myMethod(QQmlV4Function*);
+// };
+// The QQmlV8Function - and consequently the arguments and return value - only remains
+// valid during the call. If the return value isn't set within myMethod(), the will return
+// undefined.
+
+class QQmlV4Function
+{
+public:
+ int length() const { return callData->argc(); }
+ QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); }
+ void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; }
+ QV4::ExecutionEngine *v4engine() const { return e; }
+private:
+ friend struct QV4::QObjectMethod;
+ QQmlV4Function();
+ QQmlV4Function(const QQmlV4Function &);
+ QQmlV4Function &operator=(const QQmlV4Function &);
+
+ QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e)
+ : callData(callData), retVal(retVal), e(e)
+ {
+ callData->thisObject = QV4::Encode::undefined();
+ }
+
+ QV4::CallData *callData;
+ QV4::Value *retVal;
+ QV4::ExecutionEngine *e;
+};
+
class QQmlError;
class QJSEngine;
class QQmlEngine;
@@ -112,10 +169,6 @@ public:
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum {
- JSStackLimit = 4*1024*1024,
- GCStackLimit = 2*1024*1024
- };
WTF::PageAllocation *jsStack;
WTF::PageAllocation *gcStack;
@@ -128,14 +181,8 @@ public:
Function *globalCode;
-#ifdef V4_BOOTSTRAP
- QJSEngine *jsEngine() const;
- QQmlEngine *qmlEngine() const;
-#else // !V4_BOOTSTRAP
QJSEngine *jsEngine() const { return publicEngine; }
- QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; }
-#endif // V4_BOOTSTRAP
- QV8Engine *v8Engine;
+ QQmlEngine *qmlEngine() const { return m_qmlEngine; }
QJSEngine *publicEngine;
enum JSObjects {
@@ -438,9 +485,7 @@ public:
Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); }
Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); }
-#ifndef V4_BOOTSTRAP
- QIntrusiveList<CompiledData::CompilationUnit, &CompiledData::CompilationUnit::nextCompilationUnit> compilationUnits;
-#endif
+ QIntrusiveList<ExecutableCompilationUnit, &ExecutableCompilationUnit::nextCompilationUnit> compilationUnits;
quint32 m_engineId;
@@ -464,7 +509,7 @@ public:
// but any time a QObject is wrapped a second time in another engine, we have to do
// bookkeeping.
MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
const bool m_canAllocateExecutableMemory;
#endif
@@ -520,6 +565,9 @@ public:
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
Heap::RegExpObject *newRegExpObject(RegExp *re);
Heap::RegExpObject *newRegExpObject(const QRegExp &re);
+#if QT_CONFIG(regularexpression)
+ Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
+#endif
Heap::Object *newErrorObject(const Value &value);
Heap::Object *newErrorObject(const QString &message);
@@ -588,11 +636,14 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
+ int maxJSStackSize() const;
+ int maxGCStackSize() const;
+
bool checkStackLimits();
bool canJIT(Function *f = nullptr)
{
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
if (!m_canAllocateExecutableMemory)
return false;
if (f)
@@ -605,42 +656,86 @@ public:
}
QV4::ReturnedValue global();
+ void initQmlGlobalObject();
+ void initializeGlobal();
+
+ void freezeObject(const QV4::Value &value);
+
+ // Return the list of illegal id names (the names of the properties on the global object)
+ const QSet<QString> &illegalNames() const;
+
+#if QT_CONFIG(qml_xml_http_request)
+ void *xmlHttpRequestData() const { return m_xmlHttpRequestData; }
+#endif
+
+ void setQmlEngine(QQmlEngine *engine);
+
+ QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
+
+ // used for console.time(), console.timeEnd()
+ void startTimer(const QString &timerName);
+ qint64 stopTimer(const QString &timerName, bool *wasRunning);
+
+ // used for console.count()
+ int consoleCountHelper(const QString &file, quint16 line, quint16 column);
+
+ struct Deletable {
+ virtual ~Deletable() {}
+ };
+
+ static QMutex *registrationMutex();
+ static int registerExtension();
+
+ void setExtensionData(int, Deletable *);
+ Deletable *extensionData(int index) const
+ {
+ if (index < m_extensionData.count())
+ return m_extensionData[index];
+ else
+ return nullptr;
+ }
double localTZA = 0.0; // local timezone, initialized at startup
- static QQmlRefPointer<CompiledData::CompilationUnit> compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
-#ifndef V4_BOOTSTRAP
- QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url);
- QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
+ QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url);
+ QQmlRefPointer<ExecutableCompilationUnit> compileModule(
+ const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
mutable QMutex moduleMutex;
- QHash<QUrl, QQmlRefPointer<CompiledData::CompilationUnit>> modules;
- void injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit);
- QQmlRefPointer<CompiledData::CompilationUnit> moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const;
- QQmlRefPointer<CompiledData::CompilationUnit> loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr);
-#endif
+ QHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> modules;
+ void injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit);
+ QQmlRefPointer<ExecutableCompilationUnit> moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
+ QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
private:
#if QT_CONFIG(qml_debug)
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
#endif
+ QSet<QString> m_illegalNames;
int jitCallCountThreshold;
// used by generated Promise objects to handle 'then' events
QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
-};
-// This is a trick to tell the code generators that functions taking a NoThrowContext won't
-// throw exceptions and therefore don't need a check after the call.
-#ifndef V4_BOOTSTRAP
-struct NoThrowEngine : public ExecutionEngine
-{
-};
-#else
-struct NoThrowEngine;
+#if QT_CONFIG(qml_xml_http_request)
+ void *m_xmlHttpRequestData;
#endif
+ QQmlEngine *m_qmlEngine;
+
+ QQmlDelayedCallQueue m_delayedCallQueue;
+
+ QElapsedTimer m_time;
+ QHash<QString, qint64> m_startedTimers;
+
+ QHash<QString, quint32> m_consoleCount;
+
+ QVector<Deletable *> m_extensionData;
+
+ int m_maxJSStackSize = 4 * 1024 * 1024;
+ int m_maxGCStackSize = 2 * 1024 * 1024;
+};
#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index b5cfea8863..788897bdad 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -69,9 +69,20 @@ struct Q_QML_EXPORT EngineBase {
CppStackFrame *currentStackFrame = nullptr;
Value *jsStackTop = nullptr;
+
+ // The JIT expects hasException and isInterrupted to be in the same 32bit word in memory.
quint8 hasException = false;
- quint8 writeBarrierActive = false;
+ // isInterrupted is expected to be set from a different thread
+#if defined(Q_ATOMIC_INT8_IS_SUPPORTED)
+ QAtomicInteger<quint8> isInterrupted = false;
quint16 unused = 0;
+#elif defined(Q_ATOMIC_INT16_IS_SUPPORTED)
+ quint8 unused = 0;
+ QAtomicInteger<quint16> isInterrupted = false;
+#else
+# error V4 needs either 8bit or 16bit atomics.
+#endif
+
quint8 isExecutingInRegExpJIT = false;
quint8 padding[3];
MemoryManager *memoryManager = nullptr;
@@ -136,6 +147,7 @@ Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current
Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8);
Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4);
}
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index c6d6c77d11..525d3458f4 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -47,7 +47,7 @@
#include "qv4string_p.h"
#include <private/qv4mm_p.h>
-#include <qv4codegen_p.h>
+#include <private/qv4codegen_p.h>
#ifndef Q_OS_WIN
# include <time.h>
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index c836d121e3..7ee6f39aa2 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -147,9 +147,7 @@ bool ExecutableAllocator::ChunkOfPages::contains(Allocation *alloc) const
}
ExecutableAllocator::ExecutableAllocator()
- : mutex(QMutex::NonRecursive)
-{
-}
+ = default;
ExecutableAllocator::~ExecutableAllocator()
{
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 013c6d7120..f98f2c7d33 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -130,7 +130,7 @@ public:
private:
QMultiMap<size_t, Allocation*> freeAllocations;
QMap<quintptr, ChunkOfPages*> chunks;
- mutable QMutex mutex;
+ mutable QRecursiveMutex mutex;
};
}
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index c0ce125741..79e2ec2a5d 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -1,9 +1,9 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,48 +37,31 @@
**
****************************************************************************/
-#include "qv4compileddata_p.h"
-#include <private/qv4value_p.h>
-#ifndef V4_BOOTSTRAP
+#include "qv4executablecompilationunit_p.h"
+
#include <private/qv4engine_p.h>
-#include <private/qv4function_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4regexpobject_p.h>
#include <private/qv4regexp_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmltypeloader_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4objectproto_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qv4vme_moth_p.h>
-#include <private/qv4module_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include "qv4compilationunitmapper_p.h"
-#include <QQmlPropertyMap>
-#include <QDateTime>
-#include <QFile>
-#include <QFileInfo>
-#include <QScopedValueRollback>
-#include <QStandardPaths>
-#include <QDir>
-#include <private/qv4identifiertable_p.h>
-#endif
-#include <private/qqmlirbuilder_p.h>
-#include <QCoreApplication>
-#include <QCryptographicHash>
-#include <QSaveFile>
-#include <QScopeGuard>
-
-// generated by qmake:
-#include "qml_compile_hash_p.h"
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
+#include <private/qqmlscriptdata_p.h>
+#include <private/qv4module_p.h>
+#include <private/qv4compilationunitmapper_p.h>
+#include <private/qml_compile_hash_p.h>
+#include <private/qqmltypewrapper_p.h>
-namespace QV4 {
+#include <QtQml/qqmlfile.h>
+#include <QtQml/qqmlpropertymap.h>
-namespace CompiledData {
+#include <QtCore/qdir.h>
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qcryptographichash.h>
#if defined(QML_COMPILE_HASH)
# ifdef Q_OS_LINUX
@@ -87,49 +70,29 @@ namespace CompiledData {
__attribute__((section(".qml_compile_hash")))
# endif
const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH;
-static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
+static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1,
+ "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
#else
# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
#endif
+QT_BEGIN_NAMESPACE
-CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, const QString &finalUrlString)
-{
- setUnitData(unitData, nullptr, fileName, finalUrlString);
-}
-
-CompilationUnit::~CompilationUnit()
-{
-#ifndef V4_BOOTSTRAP
- unlink();
-#endif
+namespace QV4 {
- if (data) {
- if (data->qmlUnit() != qmlData)
- free(const_cast<QmlUnit *>(qmlData));
- qmlData = nullptr;
+ExecutableCompilationUnit::ExecutableCompilationUnit() = default;
-#ifndef V4_BOOTSTRAP
- if (!(data->flags & QV4::CompiledData::Unit::StaticData))
- free(const_cast<Unit *>(data));
-#else
- // Unconditionally free the memory. In the dev tools we create units that have
- // the flag set and will be saved to disk, so intended to persist later.
- free(const_cast<Unit *>(data));
-#endif
- }
- data = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
- constants = nullptr;
-#endif
+ExecutableCompilationUnit::ExecutableCompilationUnit(
+ CompiledData::CompilationUnit &&compilationUnit)
+ : CompiledData::CompilationUnit(std::move(compilationUnit))
+{}
- delete [] imports;
- imports = nullptr;
+ExecutableCompilationUnit::~ExecutableCompilationUnit()
+{
+ unlink();
}
-#ifndef V4_BOOTSTRAP
-QString CompilationUnit::localCacheFilePath(const QUrl &url)
+QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url)
{
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
@@ -140,7 +103,32 @@ QString CompilationUnit::localCacheFilePath(const QUrl &url)
return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
}
-QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
+static QString toString(QV4::ReturnedValue v)
+{
+ Value val = Value::fromReturnedValue(v);
+ QString result;
+ if (val.isInt32())
+ result = QLatin1String("int ");
+ else if (val.isDouble())
+ result = QLatin1String("double ");
+ if (val.isEmpty())
+ result += QLatin1String("empty");
+ else
+ result += val.toQStringNoThrow();
+ return result;
+}
+
+static void dumpConstantTable(const StaticValue *constants, uint count)
+{
+ QDebug d = qDebug();
+ d.nospace() << right;
+ for (uint i = 0; i < count; ++i) {
+ d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": "
+ << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
+ }
+}
+
+QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
{
this->engine = engine;
engine->compilationUnits.insert(this);
@@ -154,14 +142,17 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < stringCount; ++i)
runtimeStrings[i] = engine->newString(stringAt(i));
- runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
+ runtimeRegularExpressions
+ = new QV4::Value[data->regexpTableSize];
// memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value));
+ memset(runtimeRegularExpressions, 0,
+ data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
uint f = re->flags;
const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
- runtimeRegularExpressions[i] = QV4::RegExp::create(engine, stringAt(re->stringIndex), flags);
+ runtimeRegularExpressions[i] = QV4::RegExp::create(
+ engine, stringAt(re->stringIndex), flags);
}
if (data->lookupTableSize) {
@@ -171,7 +162,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup *l = runtimeLookups + i;
- Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags));
+ CompiledData::Lookup::Type type
+ = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -185,15 +177,26 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
}
if (data->jsClassTableSize) {
- runtimeClasses = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
+ runtimeClasses
+ = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize
+ * sizeof(QV4::Heap::InternalClass *));
// memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeClasses, 0, data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
+ memset(runtimeClasses, 0,
+ data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
for (uint i = 0; i < data->jsClassTableSize; ++i) {
int memberCount = 0;
- const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
- runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object);
+ const CompiledData::JSClassMember *member
+ = data->jsClassAt(i, &memberCount);
+ runtimeClasses[i]
+ = engine->internalClasses(QV4::ExecutionEngine::Class_Object);
for (int j = 0; j < memberCount; ++j, ++member)
- runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
+ runtimeClasses[i]
+ = runtimeClasses[i]->addMember(
+ engine->identifierTable->asPropertyKey(
+ runtimeStrings[member->nameOffset]),
+ member->isAccessor
+ ? QV4::Attr_Accessor
+ : QV4::Attr_Data);
}
}
@@ -214,21 +217,25 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
// first locals
const quint32_le *localsIndices = compiledBlock->localsTable();
for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
- ic = ic->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]), Attr_NotConfigurable);
+ ic = ic->addMember(
+ engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]),
+ Attr_NotConfigurable);
runtimeBlocks[i] = ic->d();
}
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Constant table";
- Moth::dumpConstantTable(constants, data->constantTableSize);
+ dumpConstantTable(constants, data->constantTableSize);
qDebug() << "=== String table";
for (uint i = 0, end = totalStringCount(); i < end; ++i)
qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
qDebug() << "=== Closure table";
for (uint i = 0; i < data->functionTableSize; ++i)
qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
- qDebug() << "root function at index " << (data->indexOfRootFunction != -1 ? data->indexOfRootFunction : 0);
+ qDebug() << "root function at index "
+ << (data->indexOfRootFunction != -1
+ ? data->indexOfRootFunction : 0);
}
if (data->indexOfRootFunction != -1)
@@ -237,7 +244,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
return nullptr;
}
-Heap::Object *CompilationUnit::templateObjectAt(int index) const
+Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const
{
Q_ASSERT(index < int(data->templateObjectTableSize));
if (!templateObjects.size())
@@ -267,7 +274,7 @@ Heap::Object *CompilationUnit::templateObjectAt(int index) const
return templateObjects.at(index);
}
-void CompilationUnit::unlink()
+void ExecutableCompilationUnit::unlink()
{
if (engine)
nextCompilationUnit.remove();
@@ -285,15 +292,18 @@ void CompilationUnit::unlink()
if (runtimeLookups) {
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter) {
+ if (l.getter == QV4::QObjectWrapper::lookupGetter
+ || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
pc->release();
- } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) {
+ } else if (l.getter == QQmlValueTypeWrapper::lookupGetter
+ || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
pc->release();
}
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) {
+ if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
+ || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
pc->release();
}
@@ -309,20 +319,23 @@ void CompilationUnit::unlink()
engine = nullptr;
qmlEngine = nullptr;
- free(runtimeStrings);
- runtimeStrings = nullptr;
+
delete [] runtimeLookups;
runtimeLookups = nullptr;
+
+ for (QV4::Function *f : qAsConst(runtimeFunctions))
+ f->destroy();
+ runtimeFunctions.clear();
+
+ free(runtimeStrings);
+ runtimeStrings = nullptr;
delete [] runtimeRegularExpressions;
runtimeRegularExpressions = nullptr;
free(runtimeClasses);
runtimeClasses = nullptr;
- for (QV4::Function *f : qAsConst(runtimeFunctions))
- f->destroy();
- runtimeFunctions.clear();
}
-void CompilationUnit::markObjects(QV4::MarkStack *markStack)
+void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
{
if (runtimeStrings) {
for (uint i = 0, end = totalStringCount(); i < end; ++i)
@@ -331,7 +344,7 @@ void CompilationUnit::markObjects(QV4::MarkStack *markStack)
}
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(markStack);
+ Value::fromStaticValue(runtimeRegularExpressions[i]).mark(markStack);
}
if (runtimeClasses) {
for (uint i = 0; i < data->jsClassTableSize; ++i)
@@ -354,11 +367,11 @@ void CompilationUnit::markObjects(QV4::MarkStack *markStack)
runtimeLookups[i].markObjects(markStack);
}
- if (m_module)
- m_module->mark(markStack);
+ if (auto mod = module())
+ mod->mark(markStack);
}
-IdentifierHash CompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
+IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
{
IdentifierHash namedObjectCache(engine);
const CompiledData::Object *component = objectAt(componentObjectIndex);
@@ -370,7 +383,7 @@ IdentifierHash CompilationUnit::createNamedObjectsPerComponent(int componentObje
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
-void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
+void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
{
this->qmlEngine = qmlEngine;
@@ -417,7 +430,7 @@ void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
totalObjectCount = objectCount;
}
-bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const
+bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
{
if (!dependencyHasher) {
for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
@@ -426,16 +439,13 @@ bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHashe
}
return true;
}
- QCryptographicHash hash(QCryptographicHash::Md5);
- if (!dependencyHasher(&hash))
- return false;
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum));
- return memcmp(data->dependencyMD5Checksum, checksum.constData(),
- sizeof(data->dependencyMD5Checksum)) == 0;
+ const QByteArray checksum = dependencyHasher();
+ return checksum.size() == sizeof(data->dependencyMD5Checksum)
+ && memcmp(data->dependencyMD5Checksum, checksum.constData(),
+ sizeof(data->dependencyMD5Checksum)) == 0;
}
-QStringList CompilationUnit::moduleRequests() const
+QStringList ExecutableCompilationUnit::moduleRequests() const
{
QStringList requests;
requests.reserve(data->moduleRequestTableSize);
@@ -444,10 +454,10 @@ QStringList CompilationUnit::moduleRequests() const
return requests;
}
-Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
+Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
{
- if (isESModule() && m_module)
- return m_module;
+ if (isESModule() && module())
+ return module();
if (data->indexOfRootFunction < 0)
return nullptr;
@@ -459,7 +469,7 @@ Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(engine, this));
if (isESModule())
- m_module = module->d();
+ setModule(module->d());
for (const QString &request: moduleRequests()) {
auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
@@ -472,12 +482,12 @@ Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
const uint importCount = data->importEntryTableSize;
if (importCount > 0) {
- imports = new const Value *[importCount];
- memset(imports, 0, importCount * sizeof(Value *));
+ imports = new const StaticValue *[importCount];
+ memset(imports, 0, importCount * sizeof(StaticValue *));
}
for (uint i = 0; i < importCount; ++i) {
const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
+ auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
importName = runtimeStrings[entry.importName];
const Value *valuePtr = dependentModuleUnit->resolveExport(importName);
if (!valuePtr) {
@@ -491,7 +501,7 @@ Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
+ auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
if (!dependentModuleUnit)
return nullptr;
@@ -507,26 +517,10 @@ Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine)
return module->d();
}
-const Value *CompilationUnit::resolveExport(QV4::String *exportName)
-{
- QVector<ResolveSetEntry> resolveSet;
- return resolveExportRecursively(exportName, &resolveSet);
-}
-
-QStringList CompilationUnit::exportedNames() const
+const Value *ExecutableCompilationUnit::resolveExportRecursively(
+ QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
{
- QStringList names;
- QVector<const CompiledData::CompilationUnit*> exportNameSet;
- getExportedNamesRecursively(&names, &exportNameSet);
- names.sort();
- auto last = std::unique(names.begin(), names.end());
- names.erase(last, names.end());
- return names;
-}
-
-const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
-{
- if (!m_module)
+ if (!module())
return nullptr;
for (const auto &entry: *resolveSet)
@@ -536,22 +530,24 @@ const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName,
(*resolveSet) << ResolveSetEntry(this, exportName);
if (exportName->toQString() == QLatin1String("*"))
- return &m_module->self;
+ return &module()->self;
Scope scope(engine);
- if (auto localExport = lookupNameInExportTable(data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) {
+ if (auto localExport = lookupNameInExportTable(
+ data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) {
ScopedString localName(scope, runtimeStrings[localExport->localName]);
- uint index = m_module->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey());
+ uint index = module()->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey());
if (index == UINT_MAX)
return nullptr;
- if (index >= m_module->scope->locals.size)
- return imports[index - m_module->scope->locals.size];
- return &m_module->scope->locals[index];
+ if (index >= module()->scope->locals.size)
+ return &(imports[index - module()->scope->locals.size]->asValue<Value>());
+ return &module()->scope->locals[index];
}
- if (auto indirectExport = lookupNameInExportTable(data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) {
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(indirectExport->moduleRequest)), this);
+ if (auto indirectExport = lookupNameInExportTable(
+ data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) {
+ auto dependentModuleUnit = engine->loadModule(urlAt(indirectExport->moduleRequest), this);
if (!dependentModuleUnit)
return nullptr;
ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
@@ -566,7 +562,7 @@ const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName,
for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
+ auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
if (!dependentModuleUnit)
return nullptr;
@@ -585,7 +581,8 @@ const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName,
return starResolution;
}
-const ExportEntry *CompilationUnit::lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
+const CompiledData::ExportEntry *ExecutableCompilationUnit::lookupNameInExportTable(
+ const CompiledData::ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
{
const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize;
auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) {
@@ -596,7 +593,9 @@ const ExportEntry *CompilationUnit::lookupNameInExportTable(const ExportEntry *f
return matchingExport;
}
-void CompilationUnit::getExportedNamesRecursively(QStringList *names, QVector<const CompilationUnit*> *exportNameSet, bool includeDefaultExport) const
+void ExecutableCompilationUnit::getExportedNamesRecursively(
+ QStringList *names, QVector<const ExecutableCompilationUnit*> *exportNameSet,
+ bool includeDefaultExport) const
{
if (exportNameSet->contains(this))
return;
@@ -620,21 +619,21 @@ void CompilationUnit::getExportedNamesRecursively(QStringList *names, QVector<co
for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this);
+ auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
if (!dependentModuleUnit)
return;
dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false);
}
}
-void CompilationUnit::evaluate()
+void ExecutableCompilationUnit::evaluate()
{
QV4::Scope scope(engine);
- QV4::Scoped<Module> module(scope, m_module);
- module->evaluate();
+ QV4::Scoped<Module> mod(scope, module());
+ mod->evaluate();
}
-void CompilationUnit::evaluateModuleRequests()
+void ExecutableCompilationUnit::evaluateModuleRequests()
{
for (const QString &request: moduleRequests()) {
auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
@@ -646,7 +645,7 @@ void CompilationUnit::evaluateModuleRequests()
}
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
+bool ExecutableCompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
{
if (!QQmlFile::isLocalFile(url)) {
*errorString = QStringLiteral("File has to be a local file.");
@@ -662,20 +661,23 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeS
if (!mappedUnit)
continue;
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- const Unit *oldData = data;
+ const CompiledData::Unit * const oldDataPtr
+ = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data
+ : nullptr;
+ const CompiledData::Unit *oldData = data;
auto dataPtrRevert = qScopeGuard([this, oldData](){
setUnitData(oldData);
});
setUnitData(mappedUnit);
- if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ if (data->sourceFileIndex != 0
+ && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
*errorString = QStringLiteral("QML source file has moved to a different location.");
continue;
}
dataPtrRevert.dismiss();
- free(const_cast<Unit*>(oldDataPtr));
+ free(const_cast<CompiledData::Unit*>(oldDataPtr));
backingFile.reset(cacheFile.take());
return true;
}
@@ -683,17 +685,8 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeS
return false;
}
-#endif // V4_BOOTSTRAP
-
-#if defined(V4_BOOTSTRAP)
-bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString)
-#else
-bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
-#endif
+bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
{
- errorString->clear();
-
-#if !defined(V4_BOOTSTRAP)
if (data->sourceTimeStamp == 0) {
*errorString = QStringLiteral("Missing time stamp for source file");
return false;
@@ -703,168 +696,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
- const QString outputFileName = localCacheFilePath(unitUrl);
-#endif
-
-#if QT_CONFIG(temporaryfile)
- // Foo.qml -> Foo.qmlc
- QSaveFile cacheFile(outputFileName);
- if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- QByteArray modifiedUnit;
- modifiedUnit.resize(data->unitSize);
- memcpy(modifiedUnit.data(), data, data->unitSize);
- const char *dataPtr = modifiedUnit.data();
- Unit *unitPtr;
- memcpy(&unitPtr, &dataPtr, sizeof(unitPtr));
- unitPtr->flags |= Unit::StaticData;
-
- qint64 headerWritten = cacheFile.write(modifiedUnit);
- if (headerWritten != modifiedUnit.size()) {
- *errorString = cacheFile.errorString();
- return false;
- }
- if (!cacheFile.commit()) {
- *errorString = cacheFile.errorString();
- return false;
- }
-
- return true;
-#else
- Q_UNUSED(outputFileName)
- *errorString = QStringLiteral("features.temporaryfile is disabled.");
- return false;
-#endif // QT_CONFIG(temporaryfile)
-}
-
-void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit,
- const QString &fileName, const QString &finalUrlString)
-{
- data = unitData;
- qmlData = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
-#endif
- constants = nullptr;
- m_fileName.clear();
- m_finalUrlString.clear();
- if (!data)
- return;
-
- qmlData = qmlUnit ? qmlUnit : data->qmlUnit();
-
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- Value *bigEndianConstants = new Value[data->constantTableSize];
- const quint64_le *littleEndianConstants = data->constants();
- for (uint i = 0; i < data->constantTableSize; ++i)
- bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]);
- constants = bigEndianConstants;
-#else
- constants = reinterpret_cast<const Value*>(data->constants());
-#endif
-
- m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex);
- m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
-}
-
-#ifndef V4_BOOTSTRAP
-QString Binding::valueAsString(const CompilationUnit *unit) const
-{
- switch (type) {
- case Type_Script:
- case Type_String:
- return unit->stringAt(stringIndex);
- case Type_Null:
- return QStringLiteral("null");
- case Type_Boolean:
- return value.b ? QStringLiteral("true") : QStringLiteral("false");
- case Type_Number:
- return QString::number(valueAsNumber(unit->constants));
- case Type_Invalid:
- return QString();
-#if !QT_CONFIG(translation)
- case Type_TranslationById:
- case Type_Translation:
- return unit->stringAt(unit->unitData()->translations()[value.translationDataIndex].stringIndex);
-#else
- case Type_TranslationById: {
- const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex];
- QByteArray id = unit->stringAt(translation.stringIndex).toUtf8();
- return qtTrId(id.constData(), translation.number);
- }
- case Type_Translation: {
- const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex];
- // This code must match that in the qsTr() implementation
- const QString &path = unit->fileName();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
- : QStringRef();
- QByteArray contextUtf8 = context.toUtf8();
- QByteArray comment = unit->stringAt(translation.commentIndex).toUtf8();
- QByteArray text = unit->stringAt(translation.stringIndex).toUtf8();
- return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
- comment.constData(), translation.number);
- }
-#endif
- default:
- break;
- }
- return QString();
-}
-
-//reverse of Lexer::singleEscape()
-QString Binding::escapedString(const QString &string)
-{
- QString tmp = QLatin1String("\"");
- for (int i = 0; i < string.length(); ++i) {
- const QChar &c = string.at(i);
- switch (c.unicode()) {
- case 0x08:
- tmp += QLatin1String("\\b");
- break;
- case 0x09:
- tmp += QLatin1String("\\t");
- break;
- case 0x0A:
- tmp += QLatin1String("\\n");
- break;
- case 0x0B:
- tmp += QLatin1String("\\v");
- break;
- case 0x0C:
- tmp += QLatin1String("\\f");
- break;
- case 0x0D:
- tmp += QLatin1String("\\r");
- break;
- case 0x22:
- tmp += QLatin1String("\\\"");
- break;
- case 0x27:
- tmp += QLatin1String("\\\'");
- break;
- case 0x5C:
- tmp += QLatin1String("\\\\");
- break;
- default:
- tmp += c;
- break;
- }
- }
- tmp += QLatin1Char('\"');
- return tmp;
-}
-
-QString Binding::valueAsScriptString(const CompilationUnit *unit) const
-{
- if (type == Type_String)
- return escapedString(unit->stringAt(stringIndex));
- else
- return valueAsString(unit);
+ return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
+ [&unitUrl, errorString](const char *data, quint32 size) {
+ return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
+ size, errorString);
+ });
}
/*!
@@ -902,7 +739,8 @@ bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engi
}
if (!compilationUnit)
return false;
- hash->addData(compilationUnit->unitData()->md5Checksum, sizeof(compilationUnit->unitData()->md5Checksum));
+ hash->addData(compilationUnit->data->md5Checksum,
+ sizeof(compilationUnit->data->md5Checksum));
return true;
}
@@ -938,93 +776,106 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e
return true;
}
-#endif
-
-void CompilationUnit::destroy()
+QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
{
-#if !defined(V4_BOOTSTRAP)
- if (qmlEngine)
- QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this);
- else
+ using namespace CompiledData;
+ switch (binding->type) {
+ case Binding::Type_Script:
+ case Binding::Type_String:
+ return stringAt(binding->stringIndex);
+ case Binding::Type_Null:
+ return QStringLiteral("null");
+ case Binding::Type_Boolean:
+ return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
+ case Binding::Type_Number:
+ return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
+ case Binding::Type_Invalid:
+ return QString();
+#if !QT_CONFIG(translation)
+ case Binding::Type_TranslationById:
+ case Binding::Type_Translation:
+ return stringAt(
+ data->translations()[binding->value.translationDataIndex].stringIndex);
+#else
+ case Binding::Type_TranslationById: {
+ const TranslationData &translation
+ = data->translations()[binding->value.translationDataIndex];
+ QByteArray id = stringAt(translation.stringIndex).toUtf8();
+ return qtTrId(id.constData(), translation.number);
+ }
+ case Binding::Type_Translation: {
+ const TranslationData &translation
+ = data->translations()[binding->value.translationDataIndex];
+ // This code must match that in the qsTr() implementation
+ const QString &path = fileName();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
+ : QStringRef();
+ QByteArray contextUtf8 = context.toUtf8();
+ QByteArray comment = stringAt(translation.commentIndex).toUtf8();
+ QByteArray text = stringAt(translation.stringIndex).toUtf8();
+ return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
+ comment.constData(), translation.number);
+ }
#endif
- delete this;
+ default:
+ break;
+ }
+ return QString();
}
-
-void Unit::generateChecksum()
+QString ExecutableCompilationUnit::bindingValueAsScriptString(
+ const CompiledData::Binding *binding) const
{
-#ifndef V4_BOOTSTRAP
- QCryptographicHash hash(QCryptographicHash::Md5);
-
- const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum);
-
- const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset;
- hash.addData(dataPtr, unitSize - checksummableDataOffset);
-
- QByteArray checksum = hash.result();
- Q_ASSERT(checksum.size() == sizeof(md5Checksum));
- memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum));
-#else
- memset(md5Checksum, 0, sizeof(md5Checksum));
-#endif
+ return (binding->type == CompiledData::Binding::Type_String)
+ ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
+ : bindingValueAsString(binding);
}
-bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
+bool ExecutableCompilationUnit::verifyHeader(
+ const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, QString *errorString)
{
-#ifndef V4_BOOTSTRAP
- if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
+ if (strncmp(unit->magic, CompiledData::magic_str, sizeof(unit->magic))) {
*errorString = QStringLiteral("Magic bytes in the header do not match");
return false;
}
- if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ if (unit->version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2")
+ .arg(unit->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
return false;
}
- if (qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ if (unit->qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2")
+ .arg(unit->qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
return false;
}
- if (sourceTimeStamp) {
+ if (unit->sourceTimeStamp) {
// Files from the resource system do not have any time stamps, so fall back to the application
// executable.
if (!expectedSourceTimeStamp.isValid())
expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
- if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
+ if (expectedSourceTimeStamp.isValid()
+ && expectedSourceTimeStamp.toMSecsSinceEpoch() != unit->sourceTimeStamp) {
*errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
return false;
}
}
#if defined(QML_COMPILE_HASH)
- if (qstrcmp(CompiledData::qml_compile_hash, libraryVersionHash) != 0) {
+ if (qstrcmp(qml_compile_hash, unit->libraryVersionHash) != 0) {
*errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
return false;
}
#else
#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
#endif
-
return true;
-#else
- Q_UNUSED(expectedSourceTimeStamp)
- Q_UNUSED(errorString)
- return false;
-#endif
}
-Location &Location::operator=(const QQmlJS::AST::SourceLocation &astLocation)
-{
- line = astLocation.startLine;
- column = astLocation.startColumn;
- return *this;
-}
-
-}
-
-}
+} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
new file mode 100644
index 0000000000..6eef3b12c3
--- /dev/null
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4EXECUTABLECOMPILATIONUNIT_P_H
+#define QV4EXECUTABLECOMPILATIONUNIT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4compileddata_p.h>
+#include <private/qv4identifier_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qintrusivelist_p.h>
+#include <private/qqmlpropertycachevector_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmlnullablevalue_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptData;
+class QQmlEnginePrivate;
+namespace QV4 {
+
+// index is per-object binding index
+typedef QVector<QQmlPropertyData*> BindingPropertyData;
+
+class CompilationUnitMapper;
+struct ResolvedTypeReference;
+// map from name index
+// While this could be a hash, a map is chosen here to provide a stable
+// order, which is used to calculating a check-sum on dependent meta-objects.
+struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
+{
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
+};
+
+class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
+ public QQmlRefCount
+{
+ Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
+public:
+ friend class QQmlRefPointer<ExecutableCompilationUnit>;
+
+ static QQmlRefPointer<ExecutableCompilationUnit> create(
+ CompiledData::CompilationUnit &&compilationUnit)
+ {
+ return QQmlRefPointer<ExecutableCompilationUnit>(
+ new ExecutableCompilationUnit(std::move(compilationUnit)),
+ QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
+ }
+
+ static QQmlRefPointer<ExecutableCompilationUnit> create()
+ {
+ return QQmlRefPointer<ExecutableCompilationUnit>(
+ new ExecutableCompilationUnit,
+ QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
+ }
+
+ QIntrusiveListNode nextCompilationUnit;
+ ExecutionEngine *engine = nullptr;
+ QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
+
+ // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
+ // warnings about that code. They include any potential URL interceptions and thus represent the
+ // "physical" location of the code.
+ //
+ // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
+ // They are _not_ intercepted and thus represent the "logical" name for the code.
+
+ QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
+ QUrl finalUrl() const
+ {
+ if (m_finalUrl.isNull)
+ m_finalUrl = QUrl(finalUrlString());
+ return m_finalUrl;
+ }
+
+ QV4::Lookup *runtimeLookups = nullptr;
+ QVector<QV4::Function *> runtimeFunctions;
+ QVector<QV4::Heap::InternalClass *> runtimeBlocks;
+ mutable QVector<QV4::Heap::Object *> templateObjects;
+ mutable QQmlNullableValue<QUrl> m_url;
+ mutable QQmlNullableValue<QUrl> m_finalUrl;
+
+ // QML specific fields
+ QQmlPropertyCacheVector propertyCaches;
+ QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+
+ // index is object index. This allows fast access to the
+ // property data when initializing bindings, avoiding expensive
+ // lookups by string (property name).
+ QVector<BindingPropertyData> bindingPropertyDataPerObject;
+
+ // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
+ // this is initialized on-demand by QQmlContextData
+ QHash<int, IdentifierHash> namedObjectsPerComponentCache;
+ inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
+
+ void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
+
+ int totalBindingsCount = 0; // Number of bindings used in this type
+ int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
+ int totalObjectCount = 0; // Number of objects explicitly instantiated
+
+ QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
+ ResolvedTypeReferenceMap resolvedTypes;
+ ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
+
+ bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
+
+ int metaTypeId = -1;
+ int listMetaTypeId = -1;
+ bool isRegisteredWithEngine = false;
+
+ QScopedPointer<CompilationUnitMapper> backingFile;
+
+ // --- interface for QQmlPropertyCacheCreator
+ using CompiledObject = CompiledData::Object;
+ using CompiledFunction = CompiledData::Function;
+
+ int objectCount() const { return qmlData->nObjects; }
+ const CompiledObject *objectAt(int index) const
+ {
+ return qmlData->objectAt(index);
+ }
+
+ int importCount() const { return qmlData->nImports; }
+ const CompiledData::Import *importAt(int index) const
+ {
+ return qmlData->importAt(index);
+ }
+
+ Heap::Object *templateObjectAt(int index) const;
+
+ struct FunctionIterator
+ {
+ FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
+ : unit(unit), object(object), index(index) {}
+ const CompiledData::Unit *unit;
+ const CompiledObject *object;
+ int index;
+
+ const CompiledFunction *operator->() const
+ {
+ return unit->functionAt(object->functionOffsetTable()[index]);
+ }
+
+ void operator++() { ++index; }
+ bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
+ };
+
+ FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
+ {
+ return FunctionIterator(data, object, 0);
+ }
+
+ FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
+ {
+ return FunctionIterator(data, object, object->nFunctions);
+ }
+
+ bool isESModule() const
+ {
+ return data->flags & CompiledData::Unit::IsESModule;
+ }
+
+ bool isSharedLibrary() const
+ {
+ return data->flags & CompiledData::Unit::IsSharedLibrary;
+ }
+
+ QStringList moduleRequests() const;
+ Heap::Module *instantiate(ExecutionEngine *engine);
+ const Value *resolveExport(QV4::String *exportName)
+ {
+ QVector<ResolveSetEntry> resolveSet;
+ return resolveExportRecursively(exportName, &resolveSet);
+ }
+
+ QStringList exportedNames() const
+ {
+ QStringList names;
+ QVector<const ExecutableCompilationUnit*> exportNameSet;
+ getExportedNamesRecursively(&names, &exportNameSet);
+ names.sort();
+ auto last = std::unique(names.begin(), names.end());
+ names.erase(last, names.end());
+ return names;
+ }
+
+ void evaluate();
+ void evaluateModuleRequests();
+
+ QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
+ void unlink();
+
+ void markObjects(MarkStack *markStack);
+
+ bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
+
+ static QString localCacheFilePath(const QUrl &url);
+ bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+
+ QString bindingValueAsString(const CompiledData::Binding *binding) const;
+ QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
+ double bindingValueAsNumber(const CompiledData::Binding *binding) const
+ {
+ if (binding->type != CompiledData::Binding::Type_Number)
+ return 0.0;
+ return constants[binding->value.constantValueIndex].doubleValue();
+ }
+
+ static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp,
+ QString *errorString);
+
+protected:
+ quint32 totalStringCount() const
+ { return data->stringTableSize; }
+
+private:
+ struct ResolveSetEntry
+ {
+ ResolveSetEntry() {}
+ ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName)
+ : module(module), exportName(exportName) {}
+ ExecutableCompilationUnit *module = nullptr;
+ QV4::String *exportName = nullptr;
+ };
+
+ ExecutableCompilationUnit();
+ ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit);
+ ~ExecutableCompilationUnit();
+
+ const Value *resolveExportRecursively(QV4::String *exportName,
+ QVector<ResolveSetEntry> *resolveSet);
+
+ QUrl urlAt(int index) const { return QUrl(stringAt(index)); }
+
+ Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex);
+ const CompiledData::ExportEntry *lookupNameInExportTable(
+ const CompiledData::ExportEntry *firstExportEntry, int tableSize,
+ QV4::String *name) const;
+
+ void getExportedNamesRecursively(
+ QStringList *names, QVector<const ExecutableCompilationUnit *> *exportNameSet,
+ bool includeDefaultExport = true) const;
+};
+
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
+ QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
+
+ void doDynamicTypeCheck();
+};
+
+IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
+{
+ auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
+ if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
+ return createNamedObjectsPerComponent(componentObjectIndex);
+ return *it;
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4EXECUTABLECOMPILATIONUNIT_P_H
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 1bd4329fe8..aeb4835c40 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -73,24 +73,19 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg
return result;
}
-Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
+Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
+ const CompiledData::Function *function)
{
- quint16 traceSlotCount = 0;
-#if QT_CONFIG(qml_tracing)
- traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing()
- ? 1
- : function->nTraceInfos;
-#endif
- quint8 *storage = new quint8[sizeof(Function) + traceSlotCount];
- return new(storage) Function(engine, unit, function);
+ return new Function(engine, unit, function);
}
void Function::destroy()
{
- delete[] reinterpret_cast<quint8 *>(this);
+ delete this;
}
-Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
+Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
+ const CompiledData::Function *function)
: FunctionData(unit)
, compiledFunction(function)
, codeData(function->code())
@@ -105,19 +100,12 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- const quint32_le *formalsIndices = compiledFunction->formalsTable();
+ const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
- ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable);
+ ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable);
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
-
-#if QT_CONFIG(qml_tracing)
- if (tracingEnabled()) {
- for (uint i = 0; i < function->nTraceInfos; ++i)
- *traceInfo(i) = 0;
- }
-#endif
}
Function::~Function()
@@ -160,8 +148,11 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
// first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
- for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
- internalClass = internalClass->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
+ for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
+ internalClass = internalClass->addMember(
+ engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]),
+ Attr_NotConfigurable);
+ }
Scope scope(engine);
ScopedString arg(scope);
@@ -188,22 +179,4 @@ QQmlSourceLocation Function::sourceLocation() const
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
-QString Function::traceInfoToString()
-{
- QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':');
- if (!tracingEnabled())
- return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount);
- if (compiledFunction->nTraceInfos == 0)
- return info + QLatin1String(" none.\n");
-
- info += QLatin1Char('\n');
- for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) {
- auto bits = QString::number(*traceInfo(i), 2);
- if (bits.size() < 8)
- bits.prepend(QString(8 - bits.size(), '0'));
- info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits);
- }
- return info;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index f8125a58f8..51960863c4 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -51,8 +51,9 @@
//
#include "qv4global_p.h"
-#include <private/qv4compileddata_p.h>
+#include <private/qv4executablecompilationunit_p.h>
#include <private/qv4context_p.h>
+#include <private/qv4string_p.h>
namespace JSC {
class MacroAssemblerCodeRef;
@@ -65,9 +66,13 @@ struct QQmlSourceLocation;
namespace QV4 {
struct Q_QML_EXPORT FunctionData {
- CompiledData::CompilationUnit *compilationUnit;
+ CompiledData::CompilationUnitBase *compilationUnit;
- FunctionData(CompiledData::CompilationUnit *compilationUnit)
+ // Intentionally require an ExecutableCompilationUnit but save only a pointer to
+ // CompilationUnitBase. This is so that we can take advantage of the standard layout
+ // of CompilationUnitBase in the JIT. Furthermore we can safely static_cast to
+ // ExecutableCompilationUnit where we need it.
+ FunctionData(ExecutableCompilationUnit *compilationUnit)
: compilationUnit(compilationUnit)
{}
};
@@ -76,12 +81,24 @@ Q_STATIC_ASSERT(std::is_standard_layout< FunctionData >::value);
struct Q_QML_EXPORT Function : public FunctionData {
private:
- Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
+ Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
+ const CompiledData::Function *function);
~Function();
public:
const CompiledData::Function *compiledFunction;
+ QV4::ExecutableCompilationUnit *executableCompilationUnit() const
+ {
+ // This is safe: We require an ExecutableCompilationUnit in the ctor.
+ return static_cast<QV4::ExecutableCompilationUnit *>(compilationUnit);
+ }
+
+ QV4::Heap::String *runtimeString(uint i) const
+ {
+ return compilationUnit->runtimeStrings[i];
+ }
+
ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context);
const char *codeData;
@@ -96,20 +113,21 @@ public:
int interpreterCallCount = 0;
bool isEval = false;
- static Function *create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
+ static Function *create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
+ const CompiledData::Function *function);
void destroy();
// used when dynamically assigning signal handlers (QQmlConnection)
void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
inline Heap::String *name() const {
- return compilationUnit->runtimeStrings[compiledFunction->nameIndex];
+ return runtimeString(compiledFunction->nameIndex);
}
static QString prettyName(const Function *function, const void *address);
- inline QString sourceFile() const { return compilationUnit->fileName(); }
- inline QUrl finalUrl() const { return compilationUnit->finalUrl(); }
+ inline QString sourceFile() const { return executableCompilationUnit()->fileName(); }
+ inline QUrl finalUrl() const { return executableCompilationUnit()->finalUrl(); }
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
@@ -121,32 +139,7 @@ public:
{
if (compiledFunction->nestedFunctionIndex == std::numeric_limits<uint32_t>::max())
return nullptr;
- return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
- }
-
- Q_NEVER_INLINE QString traceInfoToString();
-
- quint8 *traceInfo(uint i)
- {
-#if QT_CONFIG(qml_tracing)
- Q_ASSERT((tracingEnabled() && i < traceInfoCount()) || (i == 0));
- return reinterpret_cast<quint8 *>(this) + sizeof(Function) + i;
-#else
- Q_UNUSED(i);
- return nullptr;
-#endif
- }
-
- quint32 traceInfoCount() const
- { return compiledFunction->nTraceInfos; }
-
- bool tracingEnabled() const
- {
-#if QT_CONFIG(qml_tracing)
- return traceInfoCount() != CompiledData::Function::NoTracing();
-#else
- return false;
-#endif
+ return executableCompilationUnit()->runtimeFunctions[compiledFunction->nestedFunctionIndex];
}
};
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 41a21ba379..6fb7946023 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -59,10 +59,10 @@
#include "private/qqmlbuiltinfunctions_p.h"
#include <private/qv4jscall_p.h>
#include <private/qv4vme_moth_p.h>
+#include <private/qv4alloca_p.h>
#include <QtCore/QDebug>
#include <algorithm>
-#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
using namespace QV4;
@@ -135,13 +135,13 @@ void Heap::FunctionObject::setFunction(Function *f)
{
if (f) {
function = f;
- function->compilationUnit->addref();
+ function->executableCompilationUnit()->addref();
}
}
void Heap::FunctionObject::destroy()
{
if (function)
- function->compilationUnit->release();
+ function->executableCompilationUnit()->release();
Object::destroy();
}
@@ -229,7 +229,7 @@ void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
}
// 15.3.2
-QQmlRefPointer<CompiledData::CompilationUnit> FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t)
+QQmlRefPointer<ExecutableCompilationUnit> FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t)
{
QString arguments;
QString body;
@@ -273,14 +273,15 @@ QQmlRefPointer<CompiledData::CompilationUnit> FunctionCtor::parse(ExecutionEngin
if (engine->hasException)
return nullptr;
- return cg.generateCompilationUnit();
+ return ExecutableCompilationUnit::create(cg.generateCompilationUnit());
}
ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
ExecutionEngine *engine = f->engine();
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Function);
+ QQmlRefPointer<ExecutableCompilationUnit> compilationUnit
+ = parse(engine, argv, argc, Type_Function);
if (engine->hasException)
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index e03d49c74d..c99cad8e33 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -87,11 +87,11 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
}
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call);
- void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- void init(QV4::ExecutionContext *scope, const QString &name);
- void init();
- void destroy();
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_PRIVATE_EXPORT void init();
+ Q_QML_PRIVATE_EXPORT void destroy();
void setFunction(Function *f);
@@ -244,7 +244,7 @@ protected:
Type_Function,
Type_Generator
};
- static QQmlRefPointer<CompiledData::CompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function);
+ static QQmlRefPointer<ExecutableCompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function);
};
struct FunctionPrototype: FunctionObject
@@ -260,7 +260,7 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct IndexedBuiltinFunction : FunctionObject
+struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
};
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index 14caa6953f..4eee6f4338 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -58,7 +58,7 @@ ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObje
{
ExecutionEngine *engine = f->engine();
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Generator);
+ QQmlRefPointer<ExecutableCompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Generator);
if (engine->hasException)
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d47393b3bb..c6a737b467 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -52,6 +52,7 @@
//
#include <QtCore/qglobal.h>
+#include <private/qv4compilerglobal_p.h>
#include <QString>
#ifdef QT_NO_DEBUG
@@ -63,10 +64,6 @@
#include <qtqmlglobal.h>
#include <private/qtqmlglobal_p.h>
-#ifdef QT_QML_BOOTSTRAPPED
-#define V4_BOOTSTRAP
-#endif
-
#if defined(Q_CC_MSVC)
#include <float.h>
#include <math.h>
@@ -82,53 +79,9 @@ inline bool isfinite(double d) { return _finite(d); }
inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#endif
-// 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_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_INTEGRITY))
-# 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
-#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8)
-# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_INTEGRITY)
-# define V4_ENABLE_JIT
-# endif
-//#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
-//# define V4_ENABLE_JIT
-#endif
-
-// check FPU with double precision on ARM platform
-#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04)
-# undef V4_ENABLE_JIT
-#endif
-
-// Black list some platforms
-#if defined(V4_ENABLE_JIT)
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-# undef V4_ENABLE_JIT
-#endif
-#endif
-
-// For debug purposes: add CONFIG+=force-compile-jit to qmake's command-line to always compile the JIT.
-#if defined(V4_FORCE_COMPILE_JIT) && !defined(V4_ENABLE_JIT)
-# define V4_ENABLE_JIT
-#endif
-
// Do certain things depending on whether the JIT is enabled or disabled
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
#define ENABLE_YARR_JIT 1
#define ENABLE_JIT 1
#define ENABLE_ASSEMBLER 1
@@ -255,11 +208,6 @@ struct SetMapObject;
struct PromiseObject;
struct PromiseCapability;
-// ReturnedValue is used to return values from runtime methods
-// the type has to be a primitive type (no struct or union), so that the compiler
-// will return it in a register on all platforms.
-// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
-typedef quint64 ReturnedValue;
struct CallData;
struct Scope;
struct ScopedValue;
@@ -280,20 +228,6 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
-enum class ObservedTraceValues : quint8 {
- Integer = 1 << 0,
- Boolean = 1 << 1,
- Double = 1 << 2,
- Other = 1 << 3,
- TypeMask = Integer | Boolean | Double | Other,
-
- TruePathTaken = 1 << 0,
- FalsePathTaken = 1 << 1,
-
- ArrayWasAccessed = 1 << 7,
- ArrayAccessNeededFallback = 1 << 6,
-};
-
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
@@ -403,13 +337,6 @@ struct Q_QML_EXPORT StackFrame {
};
typedef QVector<StackFrame> StackTrace;
-enum class ObjectLiteralArgument {
- Value,
- Method,
- Getter,
- Setter
-};
-
namespace JIT {
enum class CallResultDestination {
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index becdc3bc55..bb81fb52d4 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -49,18 +49,14 @@
#include "qv4string_p.h"
#include "qv4jscall_p.h"
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsast_p.h>
-#include <qv4codegen_p.h>
+#include <private/qv4codegen_p.h>
+#include <private/qv4alloca_p.h>
#include "private/qlocale_tools_p.h"
#include "private/qtools_p.h"
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <iostream>
-#include "qv4alloca_p.h"
#include <wtf/MathExtras.h>
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 5db5bd46ec..c3d7165f71 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -39,29 +39,19 @@
#include "qv4identifier_p.h"
#include "qv4identifiertable_p.h"
#include "qv4string_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits)
: size(0)
, numBits(numBits)
, identifierTable(table)
{
- refCount.store(1);
- alloc = primeForNumBits(numBits);
+ refCount.storeRelaxed(1);
+ alloc = qPrimeForNumBits(numBits);
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
identifierTable->addIdentifierHash(this);
@@ -72,7 +62,7 @@ IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
, numBits(other->numBits)
, identifierTable(other->identifierTable)
{
- refCount.store(1);
+ refCount.storeRelaxed(1);
alloc = other->alloc;
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
@@ -92,7 +82,7 @@ IdentifierHash::IdentifierHash(ExecutionEngine *engine)
void IdentifierHash::detach()
{
- if (!d || d->refCount == 1)
+ if (!d || d->refCount.loadAcquire() == 1)
return;
IdentifierHashData *newData = new IdentifierHashData(d);
if (d && !d->refCount.deref())
@@ -110,7 +100,7 @@ IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
if (grow) {
++d->numBits;
- int newAlloc = primeForNumBits(d->numBits);
+ int newAlloc = qPrimeForNumBits(d->numBits);
IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
for (int i = 0; i < d->alloc; ++i) {
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 4305bc4647..21b47c3909 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -38,28 +38,18 @@
****************************************************************************/
#include "qv4identifiertable_p.h"
#include "qv4symbol_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierTable::IdentifierTable(ExecutionEngine *engine, int numBits)
: engine(engine)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entriesByHash = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
entriesById = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
memset(entriesByHash, 0, alloc*sizeof(Heap::String *));
@@ -87,7 +77,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
if (grow) {
++numBits;
- int newAlloc = primeForNumBits(numBits);
+ int newAlloc = qPrimeForNumBits(numBits);
Heap::StringOrSymbol **newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *));
memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *));
for (uint i = 0; i < alloc; ++i) {
@@ -216,9 +206,8 @@ PropertyKey IdentifierTable::asPropertyKeyImpl(const Heap::String *str)
Heap::StringOrSymbol *IdentifierTable::resolveId(PropertyKey i) const
{
- uint arrayIdx = i.asArrayIndex();
- if (arrayIdx < UINT_MAX)
- return engine->newString(QString::number(arrayIdx));
+ if (i.isArrayIndex())
+ return engine->newString(QString::number(i.asArrayIndex()));
if (!i.isValid())
return nullptr;
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 36569b0a60..92face6f94 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -72,13 +72,17 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine,
m_resultObject.set(v4, resultValue(v4));
#if QT_CONFIG(qml_network)
- m_network = engine->v8Engine->networkAccessManager();
+ if (QQmlEngine *qmlEngine = engine->qmlEngine()) {
+ m_network = qmlEngine->networkAccessManager();
- QNetworkRequest request;
- request.setUrl(url);
+ QNetworkRequest request;
+ request.setUrl(url);
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ } else {
+ finished();
+ }
#else
finished();
#endif
@@ -163,7 +167,6 @@ void QV4Include::finished()
QByteArray data = m_reply->readAll();
QString code = QString::fromUtf8(data);
- QmlIR::Document::removeScriptPragmas(code);
QV4::Scoped<QV4::QmlContext> qml(scope, m_qmlContext.value());
QV4::Script script(v4, qml, /*parse as QML binding*/false, code, m_url.toString());
@@ -197,7 +200,7 @@ void QV4Include::finished()
}
/*
- Documented in qv8engine.cpp
+ Documented in qv4engine.cpp
*/
QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
{
@@ -214,7 +217,6 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
if (argc >= 2 && argv[1].as<QV4::FunctionObject>())
callbackFunction = argv[1];
-#if QT_CONFIG(qml_network)
QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow()));
if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
@@ -225,9 +227,13 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext());
if (localFile.isEmpty()) {
+#if QT_CONFIG(qml_network)
QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction);
result = i->result();
-
+#else
+ result = resultValue(scope.engine, NetworkError);
+ callback(callbackFunction, result);
+#endif
} else {
QScopedPointer<QV4::Script> script;
QString error;
@@ -252,12 +258,6 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
callback(callbackFunction, result);
}
-#else
- QV4::ScopedValue result(scope);
- result = resultValue(scope.engine, NetworkError);
- callback(callbackFunction, result);
-#endif
-
return result->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index a10fda79f2..70849775cb 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -45,27 +45,18 @@
#include "qv4identifiertable_p.h"
#include "qv4value_p.h"
#include "qv4mm_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
PropertyHashData::PropertyHashData(int numBits)
: refCount(1)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
}
@@ -299,7 +290,6 @@ void InternalClass::init(ExecutionEngine *engine)
void InternalClass::init(Heap::InternalClass *other)
{
Base::init();
- Q_ASSERT(!other->isFrozen);
new (&propertyTable) PropertyHash(other->propertyTable);
new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap);
new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
@@ -573,22 +563,6 @@ Heap::InternalClass *InternalClass::sealed()
if (isSealed)
return this;
- bool alreadySealed = !extensible;
- for (uint i = 0; i < size; ++i) {
- PropertyAttributes attrs = propertyData.at(i);
- if (attrs.isEmpty())
- continue;
- if (attrs.isConfigurable()) {
- alreadySealed = false;
- break;
- }
- }
-
- if (alreadySealed) {
- isSealed = true;
- return this;
- }
-
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed };
Transition &t = lookupOrInsertTransition(temp);
@@ -601,14 +575,15 @@ Heap::InternalClass *InternalClass::sealed()
Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
Heap::InternalClass *s = ic->d();
- for (uint i = 0; i < size; ++i) {
- PropertyAttributes attrs = propertyData.at(i);
- if (attrs.isEmpty())
- continue;
- attrs.setConfigurable(false);
- s->propertyData.set(i, attrs);
+ if (!isFrozen) { // freezing also makes all properties non-configurable
+ for (uint i = 0; i < size; ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
+ continue;
+ attrs.setConfigurable(false);
+ s->propertyData.set(i, attrs);
+ }
}
- s->extensible = false;
s->isSealed = true;
t.lookup = s;
@@ -620,28 +595,11 @@ Heap::InternalClass *InternalClass::frozen()
if (isFrozen)
return this;
- bool alreadyFrozen = !extensible;
- for (uint i = 0; i < size; ++i) {
- PropertyAttributes attrs = propertyData.at(i);
- if (attrs.isEmpty())
- continue;
- if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable()) {
- alreadyFrozen = false;
- break;
- }
- }
-
- if (alreadyFrozen) {
- isSealed = true;
- isFrozen = true;
- return this;
- }
-
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isSealed && t.lookup->isFrozen);
+ Q_ASSERT(t.lookup && t.lookup->isFrozen);
return t.lookup;
}
@@ -658,29 +616,42 @@ Heap::InternalClass *InternalClass::frozen()
attrs.setConfigurable(false);
f->propertyData.set(i, attrs);
}
- f->extensible = false;
- f->isSealed = true;
f->isFrozen = true;
t.lookup = f;
return f;
}
-Heap::InternalClass *InternalClass::propertiesFrozen()
+InternalClass *InternalClass::canned()
+{
+ // scope the intermediate result to prevent it from getting garbage collected
+ Scope scope(engine);
+ Scoped<QV4::InternalClass> ic(scope, sealed());
+ return ic->d()->nonExtensible();
+}
+
+InternalClass *InternalClass::cryopreserved()
{
+ // scope the intermediate result to prevent it from getting garbage collected
Scope scope(engine);
- Scoped<QV4::InternalClass> frozen(scope, this);
+ Scoped<QV4::InternalClass> ic(scope, frozen());
+ return ic->d()->canned();
+}
+
+bool InternalClass::isImplicitlyFrozen() const
+{
+ if (isFrozen)
+ return true;
+
for (uint i = 0; i < size; ++i) {
- PropertyAttributes attrs = propertyData.at(i);
- if (!nameMap.at(i).isValid())
+ const PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
continue;
- if (!attrs.isEmpty()) {
- attrs.setWritable(false);
- attrs.setConfigurable(false);
- }
- frozen = frozen->changeMember(nameMap.at(i), attrs);
+ if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable())
+ return false;
}
- return frozen->d();
+
+ return true;
}
Heap::InternalClass *InternalClass::asProtoClass()
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 7bb10f47a3..403702ae55 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -432,7 +432,9 @@ struct InternalClass : Base {
Q_REQUIRED_RESULT InternalClass *sealed();
Q_REQUIRED_RESULT InternalClass *frozen();
- Q_REQUIRED_RESULT InternalClass *propertiesFrozen();
+ Q_REQUIRED_RESULT InternalClass *canned(); // sealed + nonExtensible
+ Q_REQUIRED_RESULT InternalClass *cryopreserved(); // frozen + sealed + nonExtensible
+ bool isImplicitlyFrozen() const;
Q_REQUIRED_RESULT InternalClass *asProtoClass();
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 6b8fb509a8..0cda6b864a 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -467,11 +467,11 @@ bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object,
return false;
}
- if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) {
+ if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) {
l->objectLookupTwoClasses.ic = first.objectLookup.ic;
l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.offset;
+ l->objectLookupTwoClasses.offset = first.objectLookup.index;
+ l->objectLookupTwoClasses.offset2 = second.objectLookup.index;
l->setter = setter0setter0;
return true;
}
@@ -492,11 +492,11 @@ bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c
return o->put(name, value);
}
-bool Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o && o->internalClass == l->objectLookup.ic) {
- o->setProperty(engine, l->objectLookup.offset, value);
+ o->memberData->values.set(engine, l->objectLookup.offset, value);
return true;
}
@@ -507,7 +507,7 @@ bool Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co
{
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o && o->internalClass == l->objectLookup.ic) {
- o->setInlineProperty(engine, l->objectLookup.offset, value);
+ o->setInlinePropertyWithOffset(engine, l->objectLookup.offset, value);
return true;
}
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 4fd5e133f7..31c90b31f6 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -54,17 +54,14 @@
#include "qv4runtime_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
-
-#if !defined(V4_BOOTSTRAP)
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
-#endif
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Lookup {
+struct Q_QML_PRIVATE_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
@@ -81,8 +78,9 @@ struct Lookup {
} markDef;
struct {
Heap::InternalClass *ic;
- quintptr _unused;
- int offset;
+ quintptr unused;
+ uint index;
+ uint offset;
} objectLookup;
struct {
quintptr protoId;
@@ -92,8 +90,8 @@ struct Lookup {
struct {
Heap::InternalClass *ic;
Heap::InternalClass *ic2;
- int offset;
- int offset2;
+ uint offset;
+ uint offset2;
} objectLookupTwoClasses;
struct {
quintptr protoId;
@@ -111,12 +109,14 @@ struct Lookup {
struct {
Heap::InternalClass *newClass;
quintptr protoId;
- int offset;
+ uint offset;
+ uint unused;
} insertionLookup;
struct {
quintptr _unused;
quintptr _unused2;
uint index;
+ uint unused;
} indexedLookup;
struct {
Heap::InternalClass *ic;
@@ -151,6 +151,19 @@ struct Lookup {
quintptr reserved3;
ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine);
} qmlContextGlobalLookup;
+ struct {
+ Heap::Object *qmlTypeWrapper;
+ quintptr unused2;
+ } qmlTypeLookup;
+ struct {
+ Heap::InternalClass *ic;
+ quintptr unused;
+ ReturnedValue encodedEnumValue;
+ } qmlEnumValueLookup;
+ struct {
+ Heap::InternalClass *ic;
+ Heap::Object *qmlScopedEnumWrapper;
+ } qmlScopedEnumWrapperLookup;
};
uint nameIndex;
@@ -187,7 +200,7 @@ struct Lookup {
static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
Q_NEVER_INLINE static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static bool setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index d85b30a056..4f22dc7330 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -54,7 +54,6 @@
#include "qv4value_p.h"
#include "qv4enginebase_p.h"
#include <private/qv4heap_p.h>
-#include <private/qv4writebarrier_p.h>
#include <private/qv4vtable_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 68741e7677..90e1908a84 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -80,7 +80,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv,
if (!adder)
return scope.engine->throwTypeError();
- ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true));
+ ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true));
if (scope.hasException())
return Encode::undefined();
Q_ASSERT(iter);
@@ -89,7 +89,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv,
Value *arguments = scope.alloc(2);
ScopedValue done(scope);
forever {
- done = Runtime::method_iteratorNext(scope.engine, iter, obj);
+ done = Runtime::IteratorNext::call(scope.engine, iter, obj);
if (scope.hasException())
break;
if (done->toBoolean())
@@ -112,7 +112,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv,
break;
}
ScopedValue falsey(scope, Encode(false));
- return Runtime::method_iteratorClose(scope.engine, iter, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iter, falsey);
}
}
return a->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index a60a49a811..6632d69c27 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -52,6 +52,7 @@
#include <qglobal.h>
+#include <private/qv4staticvalue_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/private/qnumeric_p.h>
#include <cmath>
@@ -66,43 +67,28 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(add_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
- return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
- return Value::fromInt32(result).asReturnedValue();
+ if (Q_UNLIKELY(add_overflow(a, b, &result)))
+ return StaticValue::fromDouble(static_cast<double>(a) + b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(sub_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
- return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
- return Value::fromInt32(result).asReturnedValue();
+ if (Q_UNLIKELY(sub_overflow(a, b, &result)))
+ return StaticValue::fromDouble(static_cast<double>(a) - b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(mul_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
- return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
- return Value::fromInt32(result).asReturnedValue();
+ if (Q_UNLIKELY(mul_overflow(a, b, &result)))
+ return StaticValue::fromDouble(static_cast<double>(a) * b).asReturnedValue();
+ return StaticValue::fromInt32(result).asReturnedValue();
}
}
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp
index 237ada8321..08a1900383 100644
--- a/src/qml/jsruntime/qv4module.cpp
+++ b/src/qml/jsruntime/qv4module.cpp
@@ -52,7 +52,7 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(Module);
-void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit)
+void Heap::Module::init(ExecutionEngine *engine, ExecutableCompilationUnit *moduleUnit)
{
Object::init();
@@ -106,7 +106,7 @@ void Module::evaluate()
return;
d()->evaluated = true;
- CompiledData::CompilationUnit *unit = d()->unit;
+ ExecutableCompilationUnit *unit = d()->unit;
unit->evaluateModuleRequests();
diff --git a/src/qml/jsruntime/qv4module_p.h b/src/qml/jsruntime/qv4module_p.h
index dca0678fe9..aabb2e005e 100644
--- a/src/qml/jsruntime/qv4module_p.h
+++ b/src/qml/jsruntime/qv4module_p.h
@@ -60,7 +60,7 @@ namespace QV4 {
namespace Heap {
#define ModuleMembers(class, Member) \
- Member(class, NoMark, CompiledData::CompilationUnit *, unit) \
+ Member(class, NoMark, ExecutableCompilationUnit *, unit) \
Member(class, Pointer, CallContext *, scope) \
Member(class, HeapValue, HeapValue, self) \
Member(class, NoMark, bool, evaluated)
@@ -68,7 +68,7 @@ namespace Heap {
DECLARE_EXPORTED_HEAP_OBJECT(Module, Object) {
DECLARE_MARKOBJECTS(Module)
- void init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit);
+ void init(ExecutionEngine *engine, ExecutableCompilationUnit *moduleUnit);
};
}
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 02524b7da6..89161433ed 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -407,8 +407,8 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h
{
Heap::Object *o = d();
- uint index = id.asArrayIndex();
- if (index != UINT_MAX) {
+ if (id.isArrayIndex()) {
+ const uint index = id.asArrayIndex();
Scope scope(this);
PropertyAttributes attrs;
ScopedProperty pd(scope);
@@ -432,8 +432,6 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h
break;
}
} else {
- Q_ASSERT(!id.isArrayIndex());
-
while (1) {
auto idx = o->internalClass->findValueOrGetter(id);
if (idx.isValid()) {
@@ -471,14 +469,13 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver)
if (d()->internalClass->vtable->getOwnProperty == Object::virtualGetOwnProperty) {
// This object standard methods in the vtable, so we can take a shortcut
// and avoid the calls to getOwnProperty and defineOwnProperty
- uint index = id.asArrayIndex();
PropertyAttributes attrs;
PropertyIndex propertyIndex{nullptr, nullptr};
- if (index != UINT_MAX) {
+ if (id.isArrayIndex()) {
if (arrayData())
- propertyIndex = arrayData()->getValueOrSetter(index, &attrs);
+ propertyIndex = arrayData()->getValueOrSetter(id.asArrayIndex(), &attrs);
} else {
auto member = internalClass()->findValueOrSetter(id);
if (member.isValid()) {
@@ -547,12 +544,11 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver)
if (r->internalClass()->vtable->defineOwnProperty == virtualDefineOwnProperty) {
// standard object, we can avoid some more checks
- uint index = id.asArrayIndex();
- if (index == UINT_MAX) {
+ if (id.isArrayIndex()) {
+ r->arraySet(id.asArrayIndex(), value);
+ } else {
ScopedStringOrSymbol s(scope, id.asStringOrSymbol());
r->insertMember(s, value);
- } else {
- r->arraySet(index, value);
}
return true;
}
@@ -787,8 +783,15 @@ bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine,
return lookup->setter(lookup, engine, *object, value);
} else if (idx.attrs.isData() && idx.attrs.isWritable()) {
lookup->objectLookup.ic = object->internalClass();
- lookup->objectLookup.offset = idx.index;
- lookup->setter = idx.index < object->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
+ lookup->objectLookup.index = idx.index;
+ const auto nInline = object->d()->vtable()->nInlineProperties;
+ if (idx.index < nInline) {
+ lookup->setter = Lookup::setter0Inline;
+ lookup->objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset;
+ } else {
+ lookup->setter = Lookup::setter0MemberData;
+ lookup->objectLookup.offset = idx.index - nInline;
+ }
return lookup->setter(lookup, engine, *object, value);
} else {
// ### handle setter
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index bee4aadafe..f3375929a3 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -79,21 +79,21 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) {
}
const Value *inlinePropertyDataWithOffset(uint indexWithOffset) const {
- Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < vtable()->inlinePropertyOffset + vtable()->nInlineProperties);
+ Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
return reinterpret_cast<const Value *>(this) + indexWithOffset;
}
const Value *inlinePropertyData(uint index) const {
Q_ASSERT(index < vtable()->nInlineProperties);
return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
}
- void setInlineProperty(ExecutionEngine *e, uint index, Value v) {
- Q_ASSERT(index < vtable()->nInlineProperties);
- Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Value v) {
+ Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
+ Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset;
WriteBarrier::write(e, this, prop->data_ptr(), v.asReturnedValue());
}
- void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
- Q_ASSERT(index < vtable()->nInlineProperties);
- Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Heap::Base *b) {
+ Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties));
+ Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset;
WriteBarrier::write(e, this, prop->data_ptr(), Value::fromHeapObject(b).asReturnedValue());
}
@@ -115,7 +115,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) {
void setProperty(ExecutionEngine *e, uint index, Value v) {
uint nInline = vtable()->nInlineProperties;
if (index < nInline) {
- setInlineProperty(e, index, v);
+ setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, v);
return;
}
index -= nInline;
@@ -124,7 +124,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) {
void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
uint nInline = vtable()->nInlineProperties;
if (index < nInline) {
- setInlineProperty(e, index, b);
+ setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, b);
return;
}
index -= nInline;
@@ -410,7 +410,7 @@ private:
friend struct ObjectPrototype;
};
-struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
+struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
{
uint arrayIndex = 0;
uint memberIndex = 0;
@@ -543,13 +543,11 @@ inline const ArrayObject *Value::as() const {
return isManaged() && m()->internalClass->vtable->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr;
}
-#ifndef V4_BOOTSTRAP
template<>
inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v)
{
return v.toObject(e)->asReturnedValue();
}
-#endif
}
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 6b4c3ba71a..3d3b3f413f 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -422,7 +422,7 @@ ReturnedValue ObjectPrototype::method_seal(const FunctionObject *b, const Value
Scope scope(b);
ScopedObject o(scope, a);
- o->setInternalClass(o->internalClass()->sealed());
+ o->setInternalClass(o->internalClass()->canned());
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
@@ -448,7 +448,7 @@ ReturnedValue ObjectPrototype::method_freeze(const FunctionObject *b, const Valu
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
- o->setInternalClass(o->internalClass()->frozen());
+ o->setInternalClass(o->internalClass()->cryopreserved());
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
@@ -489,7 +489,7 @@ ReturnedValue ObjectPrototype::method_isSealed(const FunctionObject *b, const Va
if (o->isExtensible())
return Encode(false);
- if (o->internalClass() != o->internalClass()->sealed())
+ if (o->internalClass() != o->internalClass()->canned())
return Encode(false);
if (!o->arrayData() || !o->arrayData()->length())
@@ -521,7 +521,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(const FunctionObject *b, const Va
if (o->isExtensible())
return Encode(false);
- if (o->internalClass() != o->internalClass()->frozen())
+ if (!o->internalClass()->isImplicitlyFrozen())
return Encode(false);
if (!o->arrayData() || !o->arrayData()->length())
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index e9515b5b68..8707305dc2 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -74,7 +74,7 @@ struct ObjectCtor: FunctionObject
static ReturnedValue virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc);
};
-struct ObjectPrototype: Object
+struct Q_QML_PRIVATE_EXPORT ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index b337243204..26e1074fe3 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -49,7 +49,7 @@ namespace Profiling {
FunctionLocation FunctionCall::resolveLocation() const
{
return FunctionLocation(m_function->name()->toQString(),
- m_function->compilationUnit->fileName(),
+ m_function->executableCompilationUnit()->fileName(),
m_function->compiledFunction->location.line,
m_function->compiledFunction->location.column);
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 8461384e9a..ccf7c9210d 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -144,19 +144,19 @@ public:
FunctionCall(Function *function, qint64 start, qint64 end) :
m_function(function), m_start(start), m_end(end)
- { m_function->compilationUnit->addref(); }
+ { m_function->executableCompilationUnit()->addref(); }
FunctionCall(const FunctionCall &other) :
m_function(other.m_function), m_start(other.m_start), m_end(other.m_end)
- { m_function->compilationUnit->addref(); }
+ { m_function->executableCompilationUnit()->addref(); }
~FunctionCall()
- { m_function->compilationUnit->release(); }
+ { m_function->executableCompilationUnit()->release(); }
FunctionCall &operator=(const FunctionCall &other) {
if (&other != this) {
- other.m_function->compilationUnit->addref();
- m_function->compilationUnit->release();
+ other.m_function->executableCompilationUnit()->addref();
+ m_function->executableCompilationUnit()->release();
m_function = other.m_function;
m_start = other.m_start;
m_end = other.m_end;
@@ -189,22 +189,22 @@ public:
SentMarker(const SentMarker &other) : m_function(other.m_function)
{
if (m_function)
- m_function->compilationUnit->addref();
+ m_function->executableCompilationUnit()->addref();
}
~SentMarker()
{
if (m_function)
- m_function->compilationUnit->release();
+ m_function->executableCompilationUnit()->release();
}
SentMarker &operator=(const SentMarker &other)
{
if (&other != this) {
if (m_function)
- m_function->compilationUnit->release();
+ m_function->executableCompilationUnit()->release();
m_function = other.m_function;
- m_function->compilationUnit->addref();
+ m_function->executableCompilationUnit()->addref();
}
return *this;
}
@@ -213,7 +213,7 @@ public:
{
Q_ASSERT(m_function == nullptr);
m_function = function;
- m_function->compilationUnit->addref();
+ m_function->executableCompilationUnit()->addref();
}
bool isValid() const
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 851fee7bd8..17d218a6eb 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -558,7 +558,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
ScopedFunctionObject reject(scope, capability->d()->reject);
ScopedObject itemsObject(scope, argv);
- ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true));
+ ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject, true));
if (!iteratorObject || scope.hasException()) {
ScopedObject error(scope);
if (scope.hasException()) {
@@ -583,7 +583,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
for (;;) {
Scope scope(e);
ScopedValue nextValue(scope);
- doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue));
+ doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
if (doneValue->toBoolean())
break;
@@ -611,7 +611,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -619,7 +619,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
if (!nextPromise || scope.hasException()) {
- ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -641,7 +641,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -660,7 +660,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -708,7 +708,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
ScopedFunctionObject reject(scope, capability->d()->reject);
ScopedObject itemsObject(scope, argv);
- ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true));
+ ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject, true));
if (!iteratorObject) {
ScopedObject error(scope, e->newTypeErrorObject(QStringLiteral("Type error")));
reject->call(newPromise, error, 1);
@@ -719,10 +719,10 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
for (;;) {
Scope scope(e);
ScopedValue nextValue(scope);
- doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue));
+ doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
if (scope.hasException()) {
- ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -757,7 +757,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -765,7 +765,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
if (!nextPromise || scope.hasException()) {
- ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -785,7 +785,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -804,7 +804,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index 47867765db..b2a2ec3dea 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -113,8 +113,8 @@ public:
static PropertyKey invalid() { PropertyKey key; key.val = 0; return key; }
static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.val = ArrayIndexMask | static_cast<quint64>(idx); return key; }
bool isStringOrSymbol() const { return isManaged() && val != 0; }
- uint asArrayIndex() const { return (isManaged() || val == 0) ? std::numeric_limits<uint>::max() : static_cast<uint>(val & 0xffffffff); }
- uint isArrayIndex() const { return !isManaged() && val != 0 && static_cast<uint>(val & 0xffffffff) != std::numeric_limits<uint>::max(); }
+ uint asArrayIndex() const { Q_ASSERT(isArrayIndex()); return static_cast<uint>(val & 0xffffffff); }
+ uint isArrayIndex() const { return !isManaged() && val != 0; }
bool isValid() const { return val != 0; }
static PropertyKey fromStringOrSymbol(Heap::StringOrSymbol *b)
{ PropertyKey key; key.setM(b); return key; }
@@ -124,7 +124,7 @@ public:
return m();
}
- bool isString() const;
+ Q_QML_EXPORT bool isString() const;
bool isSymbol() const;
bool isCanonicalNumericIndexString() const;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 969d44ecf6..e2d3b98ff6 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qv4qmlcontext_p.h"
-#include <private/qv8engine_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcontext_p.h>
@@ -232,28 +231,32 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
} else if (r.type.isValid()) {
if (lookup) {
if (r.type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
- siinfo->init(e);
- if (siinfo->qobjectApi(e)) {
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) {
+ e->singletonInstance<QObject*>(r.type);
lookup->qmlContextSingletonLookup.singleton =
static_cast<Heap::Object*>(
Value::fromReturnedValue(
QQmlTypeWrapper::create(v4, nullptr, r.type)
).heapObject());
} else {
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
+ QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton));
lookup->qmlContextSingletonLookup.singleton = o->d();
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
return lookup->qmlContextPropertyGetter(lookup, v4, base);
}
}
- return QQmlTypeWrapper::create(v4, scopeObject, r.type);
+ result = QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
- return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
+ result = QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
}
- Q_ASSERT(!"Unreachable");
+ if (lookup) {
+ lookup->qmlTypeLookup.qmlTypeWrapper = static_cast<Heap::Object*>(result->heapObject());
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupType;
+ }
+ return result->asReturnedValue();
}
// Fall through
@@ -660,6 +663,27 @@ ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, Exec
return Encode::undefined();
}
+ReturnedValue QQmlContextWrapper::lookupType(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Scope scope(engine);
+ Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
+ if (!qmlContext)
+ return QV4::Encode::undefined();
+
+ QObject *scopeObject = qmlContext->qmlScope();
+ if (scopeObject && QQmlData::wasDeleted(scopeObject))
+ return QV4::Encode::undefined();
+
+ Heap::Object *heapObject = l->qmlTypeLookup.qmlTypeWrapper;
+ if (static_cast<Heap::QQmlTypeWrapper *>(heapObject)->object != scopeObject) {
+ l->qmlTypeLookup.qmlTypeWrapper = nullptr;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+ }
+
+ return Value::fromHeapObject(heapObject).asReturnedValue();
+}
+
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 4c8287ef2f..e3e7239fe5 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -112,6 +112,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupType(Lookup *l, ExecutionEngine *engine, Value *base);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 63b6435112..c36da3815d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -39,7 +39,7 @@
#include "qv4qobjectwrapper_p.h"
-#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlstaticmetaobject_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlbinding_p.h>
@@ -50,7 +50,6 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4functionobject_p.h>
@@ -58,6 +57,7 @@
#include <private/qv4variantobject_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4qmlcontext_p.h>
#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
@@ -81,7 +81,9 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
+#if QT_CONFIG(qml_itemmodel)
#include <QtCore/qabstractitemmodel.h>
+#endif
#include <QtCore/qloggingcategory.h>
#include <vector>
@@ -165,10 +167,6 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object
double v = 0;
property.readProperty(object, &v);
return QV4::Encode(v);
- } else if (property.isV4Handle()) {
- QQmlV4Handle handle;
- property.readProperty(object, &handle);
- return handle;
} else if (property.propType() == qMetaTypeId<QJSValue>()) {
QJSValue v;
property.readProperty(object, &v);
@@ -768,6 +766,8 @@ struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
~QObjectWrapperOwnPropertyKeyIterator() override = default;
PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
+private:
+ QSet<QByteArray> m_alreadySeen;
};
PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs)
@@ -808,6 +808,11 @@ PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Pro
++propertyIndex;
if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2)))
continue;
+ // filter out duplicates due to overloads:
+ if (m_alreadySeen.contains(method.name()))
+ continue;
+ else
+ m_alreadySeen.insert(method.name());
ExecutionEngine *thatEngine = that->engine();
Scope scope(thatEngine);
ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name())));
@@ -1193,15 +1198,14 @@ DEFINE_OBJECT_VTABLE(QObjectWrapper);
namespace {
-template<typename A, typename B, typename C, typename D, typename E,
- typename F, typename G, typename H>
-class MaxSizeOf8 {
+template<typename A, typename B, typename C, typename D, typename E, typename F, typename G>
+class MaxSizeOf7 {
template<typename Z, typename X>
struct SMax {
char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
};
public:
- static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >);
+ static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, G> > > > > >);
};
struct CallArgument {
@@ -1232,16 +1236,17 @@ private:
std::vector<bool> *stdVectorBoolPtr;
std::vector<QString> *stdVectorQStringPtr;
std::vector<QUrl> *stdVectorQUrlPtr;
+#if QT_CONFIG(qml_itemmodel)
std::vector<QModelIndex> *stdVectorQModelIndexPtr;
+#endif
- char allocData[MaxSizeOf8<QVariant,
- QString,
- QList<QObject *>,
- QJSValue,
- QQmlV4Handle,
- QJsonArray,
- QJsonObject,
- QJsonValue>::Size];
+ char allocData[MaxSizeOf7<QVariant,
+ QString,
+ QList<QObject *>,
+ QJSValue,
+ QJsonArray,
+ QJsonObject,
+ QJsonValue>::Size];
qint64 q_for_alignment;
};
@@ -1252,7 +1257,6 @@ private:
QVariant *qvariantPtr;
QList<QObject *> *qlistPtr;
QJSValue *qjsValuePtr;
- QQmlV4Handle *handlePtr;
QJsonArray *jsonArrayPtr;
QJsonObject *jsonObjectPtr;
QJsonValue *jsonValuePtr;
@@ -1271,7 +1275,8 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
QVarLengthArray<CallArgument, 9> args(argCount + 1);
args[0].initAsType(returnType);
for (int ii = 0; ii < argCount; ++ii) {
- if (!args[ii + 1].fromValue(argTypes[ii], engine, callArgs->args[ii])) {
+ if (!args[ii + 1].fromValue(argTypes[ii], engine,
+ callArgs->args[ii].asValue<QV4::Value>())) {
qWarning() << QString::fromLatin1("Could not convert argument %1 at").arg(ii);
const StackTrace stack = engine->stackTrace();
for (const StackFrame &frame : stack) {
@@ -1383,6 +1388,9 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
} else if (actual.as<QV4::RegExpObject>()) {
switch (conversionType) {
case QMetaType::QRegExp:
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+#endif
return 0;
default:
return 10;
@@ -1613,8 +1621,10 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
continue; // We already have a better option
int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii)
- methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
+ methodArgTypes[ii]);
+ }
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
best = *attempt;
@@ -1688,8 +1698,10 @@ void *CallArgument::dataPtr()
return stdVectorQStringPtr;
else if (type == qMetaTypeId<std::vector<QUrl>>())
return stdVectorQUrlPtr;
+#if QT_CONFIG(qml_itemmodel)
else if (type == qMetaTypeId<std::vector<QModelIndex>>())
return stdVectorQModelIndexPtr;
+#endif
else if (type != 0)
return (void *)&allocData;
return nullptr;
@@ -1721,9 +1733,6 @@ void CallArgument::initAsType(int callType)
} else if (callType == qMetaTypeId<QList<QObject *> >()) {
type = callType;
qlistPtr = new (&allocData) QList<QObject *>();
- } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
- type = callType;
- handlePtr = new (&allocData) QQmlV4Handle;
} else if (callType == QMetaType::QJsonArray) {
type = callType;
jsonArrayPtr = new (&allocData) QJsonArray();
@@ -1824,9 +1833,6 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
return false;
}
}
- } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
- handlePtr = new (&allocData) QQmlV4Handle(value.asReturnedValue());
- type = callType;
} else if (callType == QMetaType::QJsonArray) {
QV4::ScopedArrayObject a(scope, value);
jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a));
@@ -1846,7 +1852,10 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
|| callType == qMetaTypeId<std::vector<bool>>()
|| callType == qMetaTypeId<std::vector<QString>>()
|| callType == qMetaTypeId<std::vector<QUrl>>()
- || callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+#if QT_CONFIG(qml_itemmodel)
+ || callType == qMetaTypeId<std::vector<QModelIndex>>()
+#endif
+ ) {
queryEngine = true;
const QV4::Object* object = value.as<QV4::Object>();
if (callType == qMetaTypeId<std::vector<int>>()) {
@@ -1864,9 +1873,11 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
} else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
stdVectorQUrlPtr = nullptr;
fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
+#if QT_CONFIG(qml_itemmodel)
} else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
+#endif
}
#endif
} else if (QMetaType::typeFlags(callType)
@@ -1951,8 +1962,6 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(scope.engine, list.at(ii))));
array->setArrayLengthUnchecked(list.count());
return array.asReturnedValue();
- } else if (type == qMetaTypeId<QQmlV4Handle>()) {
- return *handlePtr;
} else if (type == QMetaType::QJsonArray) {
return QV4::JsonObject::fromJsonArray(scope.engine, *jsonArrayPtr);
} else if (type == QMetaType::QJsonObject) {
@@ -2258,8 +2267,10 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine
continue; // We already have a better option
int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii)
- methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
+ methodArgTypes[ii]);
+ }
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
best = attempt;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 5543c4d5a6..ac9cad2bdb 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -55,9 +55,7 @@
#include <QtCore/qmetatype.h>
#include <QtCore/qpair.h>
#include <QtCore/qhash.h>
-#include <private/qhashedstring_p.h>
#include <private/qqmldata_p.h>
-#include <private/qqmlpropertycache_p.h>
#include <private/qintrusivelist_p.h>
#include <private/qv4value_p.h>
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 15dcb602eb..0772770d63 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -148,7 +148,7 @@ ReturnedValue Reflect::method_deleteProperty(const FunctionObject *f, const Valu
if (!argc || !argv[0].isObject())
return e->throwTypeError();
- bool result = Runtime::method_deleteProperty(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
+ bool result = Runtime::DeleteProperty_NoThrow::call(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
return Encode(result);
}
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 39a2e96b45..c1a42c4afa 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -50,10 +50,13 @@
#include <QtCore/QDebug>
#include <QtCore/qregexp.h>
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
#include <cassert>
#include <typeinfo>
#include <iostream>
-#include "qv4alloca_p.h"
+#include <private/qv4alloca_p.h>
QT_BEGIN_NAMESPACE
@@ -134,6 +137,25 @@ void Heap::RegExpObject::init(const QRegExp &re)
o->initProperties();
}
+#if QT_CONFIG(regularexpression)
+// Converts a QRegularExpression to a JS RegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegularExpression
+// have different semantics/flags, but we try to do our best.
+void Heap::RegExpObject::init(const QRegularExpression &re)
+{
+ Object::init();
+
+ Scope scope(internalClass->engine);
+ Scoped<QV4::RegExpObject> o(scope, this);
+
+ const uint flags = (re.patternOptions() & QRegularExpression::CaseInsensitiveOption)
+ ? CompiledData::RegExp::RegExp_IgnoreCase
+ : CompiledData::RegExp::RegExp_NoFlags;
+ o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, re.pattern(), flags));
+ o->initProperties();
+}
+#endif
+
void RegExpObject::initProperties()
{
setProperty(Index_LastIndex, Value::fromInt32(0));
@@ -150,6 +172,20 @@ QRegExp RegExpObject::toQRegExp() const
return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2);
}
+#if QT_CONFIG(regularexpression)
+// Converts a JS RegExp to a QRegularExpression.
+// The conversion is not 100% exact since ECMA regexp and QRegularExpression
+// have different semantics/flags, but we try to do our best.
+QRegularExpression RegExpObject::toQRegularExpression() const
+{
+ QRegularExpression::PatternOptions caseSensitivity
+ = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase)
+ ? QRegularExpression::CaseInsensitiveOption
+ : QRegularExpression::NoPatternOption;
+ return QRegularExpression(*value()->pattern, caseSensitivity);
+}
+#endif
+
QString RegExpObject::toString() const
{
QString p = *value()->pattern;
@@ -162,13 +198,6 @@ QString RegExpObject::toString() const
return p;
}
-QString RegExpObject::source() const
-{
- Scope scope(engine());
- ScopedValue s(scope, get(scope.engine->id_source()));
- return s->toQString();
-}
-
ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *str)
{
QString s = str->toQString();
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index a584404c0b..b94889e9f0 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -81,6 +81,9 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
void init();
void init(QV4::RegExp *value);
void init(const QRegExp &re);
+#if QT_CONFIG(regularexpression)
+ void init(const QRegularExpression &re);
+#endif
};
#define RegExpCtorMembers(class, Member) \
@@ -98,7 +101,7 @@ DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
}
-struct RegExpObject: Object {
+struct Q_QML_PRIVATE_EXPORT RegExpObject: Object {
V4_OBJECT2(RegExpObject, Object)
Q_MANAGED_TYPE(RegExpObject)
V4_INTERNALCLASS(RegExpObject)
@@ -138,8 +141,16 @@ struct RegExpObject: Object {
}
QRegExp toQRegExp() const;
+#if QT_CONFIG(regularexpression)
+ QRegularExpression toQRegularExpression() const;
+#endif
QString toString() const;
- QString source() const;
+ QString source() const
+ {
+ Scope scope(engine());
+ ScopedValue s(scope, get(scope.engine->id_source()));
+ return s->toQString();
+ }
Heap::RegExp *value() const { return d()->value; }
uint flags() const { return d()->value->flags; }
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index f7c339dc26..aaa198c62a 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -38,9 +38,8 @@
****************************************************************************/
#include "qv4global_p.h"
-#include "qv4engine_p.h"
#include "qv4runtime_p.h"
-#ifndef V4_BOOTSTRAP
+#include "qv4engine_p.h"
#include "qv4object_p.h"
#include "qv4objectproto_p.h"
#include "qv4globalobject_p.h"
@@ -60,11 +59,10 @@
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmljsast_p.h>
#include "qv4qobjectwrapper_p.h"
#include "qv4symbol_p.h"
#include "qv4generatorobject_p.h"
-#include <private/qv8engine_p.h>
-#endif
#include <QtCore/QDebug>
#include <cassert>
@@ -223,13 +221,9 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2)
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
-#ifndef V4_BOOTSTRAP
-
-Runtime::Runtime()
+static QV4::Lookup *runtimeLookup(Function *f, uint i)
{
-#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast<void*>(&method_##name);
-FOR_EACH_RUNTIME_METHOD(INIT_METHOD)
-#undef INIT_METHOD
+ return f->executableCompilationUnit()->runtimeLookups + i;
}
void RuntimeHelpers::numberToString(QString *result, double num, int radix)
@@ -320,9 +314,10 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->prepend(QLatin1Char('-'));
}
-ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
+ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId)
{
- QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
+ QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
+ ->runtimeFunctions[functionId];
Q_ASSERT(clos);
ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
if (clos->isGenerator())
@@ -330,7 +325,7 @@ ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
}
-bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base, const Value &index)
+Bool Runtime::DeleteProperty_NoThrow::call(ExecutionEngine *engine, const Value &base, const Value &index)
{
Scope scope(engine);
ScopedObject o(scope, base.toObject(engine));
@@ -344,14 +339,36 @@ bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base,
return o->deleteProperty(key);
}
-bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
+ReturnedValue Runtime::DeleteProperty::call(ExecutionEngine *engine, QV4::Function *function, const QV4::Value &base, const QV4::Value &index)
+{
+ if (!Runtime::DeleteProperty_NoThrow::call(engine, base, index)) {
+ if (function->isStrict())
+ engine->throwTypeError();
+ return Encode(false);
+ } else {
+ return Encode(true);
+ }
+}
+
+Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name);
}
-QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
+ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name)
+{
+ if (!Runtime::DeleteName_NoThrow::call(engine, name)) {
+ if (function->isStrict())
+ engine->throwTypeError();
+ return Encode(false);
+ } else {
+ return Encode(true);
+ }
+}
+
+QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
// 11.8.6, 5: rval must be an Object
const Object *rhs = rval.as<Object>();
@@ -376,7 +393,7 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
return Encode(result->toBoolean());
}
-QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
Object *ro = right.objectValue();
if (!ro)
@@ -604,13 +621,12 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
return Encode(x + y);
}
-ReturnedValue RuntimeHelpers::getTemplateObject(Function *function, int index)
+ReturnedValue Runtime::GetTemplateObject::call(Function *function, int index)
{
- return function->compilationUnit->templateObjectAt(index)->asReturnedValue();
+ return function->executableCompilationUnit()->templateObjectAt(index)->asReturnedValue();
}
-
-void Runtime::method_storeProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
+void Runtime::StoreProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
{
Scope scope(engine);
QV4::Function *v4Function = engine->currentStackFrame->v4Function;
@@ -683,7 +699,7 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine,
return o->get(name);
}
-ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index)
+ReturnedValue Runtime::LoadElement::call(ExecutionEngine *engine, const Value &object, const Value &index)
{
if (index.isPositiveInt()) {
uint idx = static_cast<uint>(index.int_32());
@@ -704,30 +720,6 @@ ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &
return getElementFallback(engine, object, index);
}
-ReturnedValue Runtime::method_loadElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->vtable->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size)
- if (!s->data(idx).isEmpty())
- return s->data(idx).asReturnedValue();
- }
- }
- }
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementIntFallback(engine, object, idx);
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementFallback(engine, object, index);
-}
-
static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
@@ -761,7 +753,7 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val
return o->put(name, value);
}
-void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+void Runtime::StoreElement::call(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
if (index.isPositiveInt()) {
uint idx = static_cast<uint>(index.int_32());
@@ -783,31 +775,7 @@ void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object,
engine->throwTypeError();
}
-void Runtime::method_storeElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->vtable->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size) {
- s->setData(engine, idx, value);
- return;
- }
- }
- }
- }
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict())
- engine->throwTypeError();
-}
-
-ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &in, int iterator)
+ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &in, int iterator)
{
Scope scope(engine);
ScopedObject o(scope, (Object *)nullptr);
@@ -830,7 +798,7 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &
return engine->newForInIteratorObject(o)->asReturnedValue();
}
-ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value &iterator, Value *value)
+ReturnedValue Runtime::IteratorNext::call(ExecutionEngine *engine, const Value &iterator, Value *value)
{
// if we throw an exception from here, return true, not undefined. This is to ensure iteratorDone is set to true
// and the stack unwinding won't close the iterator
@@ -866,7 +834,7 @@ ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value
return Encode(false);
}
-ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)
+ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)
{
// the return value encodes how to continue the yield* iteration.
// true implies iteration is done, false for iteration to continue
@@ -903,7 +871,7 @@ ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine,
if (t->isUndefined()) {
// no throw method on the iterator
ScopedValue done(scope, Encode(false));
- method_iteratorClose(engine, iterator, done);
+ IteratorClose::call(engine, iterator, done);
if (engine->hasException)
return Encode::undefined();
return engine->throwTypeError();
@@ -938,7 +906,7 @@ ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine,
return Encode(false);
}
-ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value &iterator, const Value &done)
+ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done)
{
Q_ASSERT(iterator.isObject());
Q_ASSERT(done.isBoolean());
@@ -978,7 +946,7 @@ ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value
return originalCompletion();
}
-ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, const Value &iterator)
+ReturnedValue Runtime::DestructureRestElement::call(ExecutionEngine *engine, const Value &iterator)
{
Q_ASSERT(iterator.isObject());
@@ -988,7 +956,7 @@ ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, co
uint index = 0;
while (1) {
ScopedValue n(scope);
- ScopedValue done(scope, method_iteratorNext(engine, iterator, n));
+ ScopedValue done(scope, IteratorNext::call(engine, iterator, n));
if (engine->hasException)
return Encode::undefined();
Q_ASSERT(done->isBoolean());
@@ -1000,7 +968,7 @@ ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, co
return array->asReturnedValue();
}
-void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value)
+void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, const Value &value)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -1010,7 +978,7 @@ void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, con
engine->globalObject->put(name, value);
}
-void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, const Value &value)
+void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, const Value &value)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -1021,7 +989,7 @@ void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, con
engine->throwReferenceError(name);
}
-ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value &object, int nameIndex)
+ReturnedValue Runtime::LoadProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -1041,7 +1009,7 @@ ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value
return o->get(name);
}
-ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex)
+ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -1055,7 +1023,8 @@ static Object *getSuperBase(Scope &scope)
return nullptr;
}
- ScopedFunctionObject f(scope, scope.engine->currentStackFrame->jsFrame->function);
+ ScopedFunctionObject f(
+ scope, Value::fromStaticValue(scope.engine->currentStackFrame->jsFrame->function));
ScopedObject homeObject(scope, f->getHomeObject());
if (!homeObject) {
ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context));
@@ -1084,7 +1053,7 @@ static Object *getSuperBase(Scope &scope)
return proto;
}
-ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const Value &property)
+ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Value &property)
{
Scope scope(engine);
Object *base = getSuperBase(scope);
@@ -1093,10 +1062,11 @@ ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const V
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
- return base->get(key, &engine->currentStackFrame->jsFrame->thisObject);
+ return base->get(
+ key, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
}
-void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &property, const Value &value)
+void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value)
{
Scope scope(engine);
Object *base = getSuperBase(scope);
@@ -1105,12 +1075,46 @@ void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &pr
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return;
- bool result = base->put(key, value, &engine->currentStackFrame->jsFrame->thisObject);
+ bool result = base->put(
+ key, value, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
if (!result && engine->currentStackFrame->v4Function->isStrict())
engine->throwTypeError();
}
-ReturnedValue Runtime::method_loadSuperConstructor(ExecutionEngine *engine, const Value &t)
+ReturnedValue Runtime::LoadGlobalLookup::call(ExecutionEngine *engine, Function *f, int index)
+{
+ Lookup *l = runtimeLookup(f, index);
+ return l->globalGetter(l, engine);
+}
+
+ReturnedValue Runtime::LoadQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index)
+{
+ Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index);
+ return l->qmlContextPropertyGetter(l, engine, nullptr);
+}
+
+ReturnedValue Runtime::GetLookup::call(ExecutionEngine *engine, Function *f, const Value &base, int index)
+{
+ Lookup *l = runtimeLookup(f, index);
+ return l->getter(l, engine, base);
+}
+
+void Runtime::SetLookupSloppy::call(Function *f, const Value &base, int index, const Value &value)
+{
+ ExecutionEngine *engine = f->internalClass->engine;
+ QV4::Lookup *l = runtimeLookup(f, index);
+ l->setter(l, engine, const_cast<Value &>(base), value);
+}
+
+void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, const Value &value)
+{
+ ExecutionEngine *engine = f->internalClass->engine;
+ QV4::Lookup *l = runtimeLookup(f, index);
+ if (!l->setter(l, engine, const_cast<Value &>(base), value))
+ engine->throwTypeError();
+}
+
+ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t)
{
if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) {
return engine->throwReferenceError(QStringLiteral("super() already called."), QString(), 0, 0); // ### fix line number
@@ -1124,8 +1128,6 @@ ReturnedValue Runtime::method_loadSuperConstructor(ExecutionEngine *engine, cons
return c->asReturnedValue();
}
-#endif // V4_BOOTSTRAP
-
uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
{
Q_ASSERT(x.type() != y.type() || (x.isManaged() && (x.isString() != y.isString())));
@@ -1143,25 +1145,21 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y)
double dx = RuntimeHelpers::toNumber(x);
return dx == y.asDouble();
} else if (x.isBoolean()) {
- return Runtime::method_compareEqual(Value::fromDouble((double) x.booleanValue()), y);
+ return Runtime::CompareEqual::call(Value::fromDouble((double) x.booleanValue()), y);
} else if (y.isBoolean()) {
- return Runtime::method_compareEqual(x, Value::fromDouble((double) y.booleanValue()));
+ return Runtime::CompareEqual::call(x, Value::fromDouble((double) y.booleanValue()));
} else {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
Object *xo = x.objectValue();
Object *yo = y.objectValue();
if (yo && (x.isNumber() || x.isString())) {
Scope scope(yo->engine());
ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(yo, PREFERREDTYPE_HINT));
- return Runtime::method_compareEqual(x, py);
+ return Runtime::CompareEqual::call(x, py);
} else if (xo && (y.isNumber() || y.isString())) {
Scope scope(xo->engine());
ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT));
- return Runtime::method_compareEqual(px, y);
+ return Runtime::CompareEqual::call(px, y);
}
-#endif
}
return false;
@@ -1177,12 +1175,13 @@ Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y)
if (x.isNumber())
return y.isNumber() && x.asDouble() == y.asDouble();
- if (x.isManaged())
+ if (x.isManaged()) {
return y.isManaged() && x.cast<Managed>()->isEqualTo(y.cast<Managed>());
+ }
return false;
}
-QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r)
+QV4::Bool Runtime::CompareGreaterThan::call(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -1192,26 +1191,17 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return sr->lessThan(sl);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
- return Runtime::method_compareGreaterThan(pl, pr);
-#endif
+ return Runtime::CompareGreaterThan::call(pl, pr);
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1219,7 +1209,7 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r)
return dl > dr;
}
-QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r)
+QV4::Bool Runtime::CompareLessThan::call(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -1229,26 +1219,17 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return sl->lessThan(sr);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
- return Runtime::method_compareLessThan(pl, pr);
-#endif
+ return Runtime::CompareLessThan::call(pl, pr);
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1256,7 +1237,7 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r)
return dl < dr;
}
-QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r)
+QV4::Bool Runtime::CompareGreaterEqual::call(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -1266,26 +1247,17 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return !sl->lessThan(sr);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
- return Runtime::method_compareGreaterEqual(pl, pr);
-#endif
+ return Runtime::CompareGreaterEqual::call(pl, pr);
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1293,7 +1265,7 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r)
return dl >= dr;
}
-QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r)
+QV4::Bool Runtime::CompareLessEqual::call(const Value &l, const Value &r)
{
TRACE2(l, r);
if (l.isInteger() && r.isInteger())
@@ -1303,26 +1275,17 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r)
String *sl = l.stringValue();
String *sr = r.stringValue();
if (sl && sr) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- return false;
-#else
return !sr->lessThan(sl);
-#endif
}
Object *ro = r.objectValue();
Object *lo = l.objectValue();
if (ro || lo) {
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
QV4::ExecutionEngine *e = (lo ? lo : ro)->engine();
QV4::Scope scope(e);
QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue());
QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue());
- return Runtime::method_compareLessEqual(pl, pr);
-#endif
+ return Runtime::CompareLessEqual::call(pl, pr);
}
double dl = RuntimeHelpers::toNumber(l);
@@ -1330,22 +1293,21 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r)
return dl <= dr;
}
-#ifndef V4_BOOTSTRAP
-Bool Runtime::method_compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+Bool Runtime::CompareInstanceof::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
Scope scope(engine);
- ScopedValue v(scope, method_instanceof(engine, left, right));
+ ScopedValue v(scope, Instanceof::call(engine, left, right));
return v->booleanValue();
}
-uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const Value &right)
+uint Runtime::CompareIn::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
Scope scope(engine);
- ScopedValue v(scope, method_in(engine, left, right));
+ ScopedValue v(scope, In::call(engine, left, right));
return v->booleanValue();
}
@@ -1359,33 +1321,36 @@ static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engin
return engine->throwTypeError(msg);
}
-ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
+ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint index, Value argv[], int argc)
{
Scope scope(engine);
- Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index);
Value function = Value::fromReturnedValue(l->globalGetter(l, engine));
Value thisObject = Value::undefinedValue();
- if (!function.isFunctionObject())
+ if (!function.isFunctionObject()) {
return throwPropertyIsNotAFunctionTypeError(engine, &thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ }
return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
+ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index,
+ Value *argv, int argc)
{
Scope scope(engine);
ScopedValue thisObject(scope);
- Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index);
Value function = Value::fromReturnedValue(l->qmlContextPropertyGetter(l, engine, thisObject));
- if (!function.isFunctionObject())
+ if (!function.isFunctionObject()) {
return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ }
return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc)
+ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc)
{
Scope scope(engine);
ScopedValue thisObject(scope);
@@ -1404,7 +1369,7 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va
return function->call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
+ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
{
Scope scope(engine);
ScopedValue thisObject(scope);
@@ -1415,17 +1380,22 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
if (engine->hasException)
return Encode::undefined();
- if (!f)
- return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
- engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString());
+ if (!f) {
+ return throwPropertyIsNotAFunctionTypeError(
+ engine, thisObject, engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[nameIndex]->toQString());
+ }
return f->call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
+ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc)
{
+ const Value *base = &baseRef;
Scope scope(engine);
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedString name(
+ scope,
+ engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
ScopedObject lookupObject(scope, base);
if (!lookupObject) {
@@ -1437,7 +1407,7 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base,
}
if (base->isManaged()) {
- Managed *m = static_cast<Managed *>(base);
+ const Managed *m = static_cast<const Managed *>(base);
lookupObject = m->internalClass()->prototype;
Q_ASSERT(m->internalClass()->prototype);
} else {
@@ -1461,20 +1431,21 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base,
return f->call(base, argv, argc);
}
-ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)
+ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc)
{
- Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index);
// ok to have the value on the stack here
- Value f = Value::fromReturnedValue(l->getter(l, engine, *base));
+ Value f = Value::fromReturnedValue(l->getter(l, engine, base));
if (!f.isFunctionObject())
return engine->throwTypeError();
- return static_cast<FunctionObject &>(f).call(base, argv, argc);
+ return static_cast<FunctionObject &>(f).call(&base, argv, argc);
}
-ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)
+ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc)
{
+ const Value *base = &baseRef;
Scope scope(engine);
ScopedValue thisObject(scope, base->toObject(engine));
base = thisObject;
@@ -1483,14 +1454,14 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
if (engine->hasException)
return Encode::undefined();
- ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str));
+ ScopedFunctionObject f(scope, static_cast<const Object *>(base)->get(str));
if (!f)
return engine->throwTypeError();
return f->call(base, argv, argc);
}
-ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
+ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
@@ -1498,11 +1469,12 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu
return static_cast<const FunctionObject &>(func).call(&undef, argv, argc);
}
-ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)
+ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func,
+ const Value &thisObject, Value argv[], int argc)
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return static_cast<const FunctionObject &>(func).call(thisObject, argv, argc);
+ return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc);
}
struct CallArgs {
@@ -1528,11 +1500,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
}
// spread element
++i;
- it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1);
+ it = Runtime::GetIterator::call(scope.engine, argv[i], /* ForInIterator */ 1);
if (scope.engine->hasException)
return { nullptr, 0 };
while (1) {
- done = Runtime::method_iteratorNext(scope.engine, it, v);
+ done = Runtime::IteratorNext::call(scope.engine, it, v);
if (scope.engine->hasException)
return { nullptr, 0 };
Q_ASSERT(done->isBoolean());
@@ -1545,7 +1517,7 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
return { arguments, argCount };
}
-ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
+ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
{
Q_ASSERT(argc >= 1);
if (!function.isFunctionObject())
@@ -1559,7 +1531,7 @@ ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Valu
return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
}
-ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
+ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
{
if (!function.isFunctionObject())
return engine->throwTypeError();
@@ -1567,7 +1539,7 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu
return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc, &newTarget);
}
-ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
+ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
{
if (!function.isFunctionObject())
return engine->throwTypeError();
@@ -1580,7 +1552,7 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *engine)
+ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine)
{
// IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
// the jitted function, so it can safely do a tail call.
@@ -1603,20 +1575,21 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en
}
memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(engine, fo.function(), frame->jsFrame->args, argc, frame->callerCanHandleTailCall);
+ frame->init(engine, fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->callerCanHandleTailCall);
frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
frame->pendingTailCall = true;
return Encode::undefined();
}
-void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)
+void Runtime::ThrowException::call(ExecutionEngine *engine, const Value &value)
{
if (!value.isEmpty())
engine->throwError(value);
}
-ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &value)
+ReturnedValue Runtime::TypeofValue::call(ExecutionEngine *engine, const Value &value)
{
Scope scope(engine);
ScopedString res(scope);
@@ -1647,83 +1620,110 @@ ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &
return res.asReturnedValue();
}
-QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameIndex)
+QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name));
// typeof doesn't throw. clear any possible exception
scope.engine->hasException = false;
- return method_typeofValue(engine, prop);
+ return TypeofValue::call(engine, prop);
}
-ReturnedValue Runtime::method_createWithContext(ExecutionEngine *engine, Value *jsStackFrame)
+void Runtime::PushCallContext::call(CppStackFrame *frame)
{
- QV4::Value &accumulator = jsStackFrame[CallData::Accumulator];
- accumulator = accumulator.toObject(engine);
- if (engine->hasException)
- return Encode::undefined();
- Q_ASSERT(accumulator.isObject());
- const Object &obj = static_cast<const Object &>(accumulator);
- ExecutionContext *context = static_cast<ExecutionContext *>(jsStackFrame + CallData::Context);
- return context->newWithContext(obj.d())->asReturnedValue();
+ frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue();
}
-ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex)
+ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc)
{
- ExecutionEngine *e = parent->engine();
- return parent->newCatchContext(e->currentStackFrame, blockIndex,
- e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex])->asReturnedValue();
+ CallData *jsFrame = engine->currentStackFrame->jsFrame;
+ Value &newAcc = jsFrame->accumulator.asValue<Value>();
+ newAcc = Value::fromHeapObject(acc.toObject(engine));
+ if (!engine->hasException) {
+ Q_ASSERT(newAcc.isObject());
+ const Object &obj = static_cast<const Object &>(newAcc);
+ Value &context = jsFrame->context.asValue<Value>();
+ auto ec = static_cast<const ExecutionContext *>(&context);
+ context = ec->newWithContext(obj.d())->asReturnedValue();
+ }
+ return newAcc.asReturnedValue();
}
-ReturnedValue Runtime::method_createBlockContext(ExecutionContext *parent, int index)
+void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex)
{
- ExecutionEngine *e = parent->engine();
- return parent->newBlockContext(e->currentStackFrame, index)->asReturnedValue();
+ auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex];
+ engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue();
}
-ReturnedValue Runtime::method_cloneBlockContext(ExecutionContext *previous)
+void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index)
{
- return ExecutionContext::cloneBlockContext(static_cast<Heap::CallContext *>(previous->d()))->asReturnedValue();
+ engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
}
+void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
+{
+ auto frame = engine->currentStackFrame;
+ auto context = static_cast<Heap::CallContext *>(
+ Value::fromStaticValue(frame->jsFrame->context).m());
+ frame->jsFrame->context =
+ ExecutionContext::cloneBlockContext(engine, context)->asReturnedValue();
+}
-ReturnedValue Runtime::method_createScriptContext(ExecutionEngine *engine, int index)
+void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index)
{
Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext);
ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
engine->setScriptContext(c);
- return c;
+ engine->currentStackFrame->jsFrame->context = c;
}
-ReturnedValue Runtime::method_popScriptContext(ExecutionEngine *engine)
+void Runtime::PopScriptContext::call(ExecutionEngine *engine)
{
ReturnedValue root = engine->rootContext()->asReturnedValue();
engine->setScriptContext(root);
- return root;
+ engine->currentStackFrame->jsFrame->context = root;
}
-void Runtime::method_throwReferenceError(ExecutionEngine *engine, int nameIndex)
+void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
engine->throwReferenceError(name);
}
-void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
+void Runtime::ThrowOnNullOrUndefined::call(ExecutionEngine *engine, const Value &v)
+{
+ if (v.isNullOrUndefined())
+ engine->throwTypeError();
+}
+
+ReturnedValue Runtime::ConvertThisToObject::call(ExecutionEngine *engine, const Value &t)
+{
+ if (!t.isObject()) {
+ if (t.isNullOrUndefined()) {
+ return engine->globalObject->asReturnedValue();
+ } else {
+ return t.toObject(engine)->asReturnedValue();
+ }
+ }
+ return t.asReturnedValue();
+}
+
+void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable);
}
-ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length)
+ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length)
{
return engine->newArrayObject(values, length)->asReturnedValue();
}
-ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId, const QV4::Value *args, int argc)
+ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, QV4::Value args[], int argc)
{
Scope scope(engine);
Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]);
@@ -1755,7 +1755,8 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId
if (arg != ObjectLiteralArgument::Value) {
Q_ASSERT(args[2].isInteger());
int functionId = args[2].integerValue();
- QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
+ QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
+ ->runtimeFunctions[functionId];
Q_ASSERT(clos);
PropertyKey::FunctionNamePrefix prefix = PropertyKey::None;
@@ -1796,9 +1797,11 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId
return o.asReturnedValue();
}
-ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classIndex, const Value &superClass, const Value *computedNames)
+ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex,
+ const Value &superClass, Value computedNames[])
{
- const CompiledData::CompilationUnit *unit = engine->currentStackFrame->v4Function->compilationUnit;
+ const QV4::ExecutableCompilationUnit *unit
+ = engine->currentStackFrame->v4Function->executableCompilationUnit();
const QV4::CompiledData::Class *cls = unit->unitData()->classAt(classIndex);
Scope scope(engine);
@@ -1898,20 +1901,20 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde
return constructor->asReturnedValue();
}
-QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine)
+QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *engine)
{
Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_ArgumentsObject);
return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
}
-QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine)
+QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine)
{
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject);
return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
}
-QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, int argIndex)
+QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex)
{
const Value *values = engine->currentStackFrame->originalArguments + argIndex;
int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
@@ -1920,14 +1923,33 @@ QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine,
return engine->newArrayObject(values, nValues)->asReturnedValue();
}
-ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
+ReturnedValue Runtime::RegexpLiteral::call(ExecutionEngine *engine, int id)
{
- Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>());
+ const auto val
+ = engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id];
+ Heap::RegExpObject *ro = engine->newRegExpObject(Value::fromStaticValue(val).as<RegExp>());
return ro->asReturnedValue();
}
-#endif // V4_BOOTSTRAP
-ReturnedValue Runtime::method_uMinus(const Value &value)
+ReturnedValue Runtime::ToObject::call(ExecutionEngine *engine, const Value &obj)
+{
+ if (obj.isObject())
+ return obj.asReturnedValue();
+
+ return obj.toObject(engine)->asReturnedValue();
+}
+
+Bool Runtime::ToBoolean::call(const Value &obj)
+{
+ return obj.toBoolean();
+}
+
+ReturnedValue Runtime::ToNumber::call(ExecutionEngine *, const Value &v)
+{
+ return Encode(v.toNumber());
+}
+
+ReturnedValue Runtime::UMinus::call(const Value &value)
{
TRACE1(value);
@@ -1943,8 +1965,7 @@ ReturnedValue Runtime::method_uMinus(const Value &value)
// binary operators
-#ifndef V4_BOOTSTRAP
-ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right)
+ReturnedValue Runtime::Add::call(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -1956,7 +1977,7 @@ ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, co
return RuntimeHelpers::addHelper(engine, left, right);
}
-ReturnedValue Runtime::method_sub(const Value &left, const Value &right)
+ReturnedValue Runtime::Sub::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -1969,7 +1990,7 @@ ReturnedValue Runtime::method_sub(const Value &left, const Value &right)
return Value::fromDouble(lval - rval).asReturnedValue();
}
-ReturnedValue Runtime::method_mul(const Value &left, const Value &right)
+ReturnedValue Runtime::Mul::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -1982,7 +2003,7 @@ ReturnedValue Runtime::method_mul(const Value &left, const Value &right)
return Value::fromDouble(lval * rval).asReturnedValue();
}
-ReturnedValue Runtime::method_div(const Value &left, const Value &right)
+ReturnedValue Runtime::Div::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2003,7 +2024,7 @@ ReturnedValue Runtime::method_div(const Value &left, const Value &right)
return Value::fromDouble(lval / rval).asReturnedValue();
}
-ReturnedValue Runtime::method_mod(const Value &left, const Value &right)
+ReturnedValue Runtime::Mod::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2024,7 +2045,43 @@ ReturnedValue Runtime::method_mod(const Value &left, const Value &right)
return Value::fromDouble(std::fmod(lval, rval)).asReturnedValue();
}
-ReturnedValue Runtime::method_shl(const Value &left, const Value &right)
+ReturnedValue Runtime::Exp::call(const Value &base, const Value &exp)
+{
+ double b = base.toNumber();
+ double e = exp.toNumber();
+ if (qt_is_inf(e) && (b == 1 || b == -1))
+ return Encode(qt_qnan());
+ return Encode(pow(b,e));
+}
+
+ReturnedValue Runtime::BitAnd::call(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode((int)(lval & rval));
+}
+
+ReturnedValue Runtime::BitOr::call(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode((int)(lval | rval));
+}
+
+ReturnedValue Runtime::BitXor::call(const Value &left, const Value &right)
+{
+ TRACE2(left, right);
+
+ int lval = left.toInt32();
+ int rval = right.toInt32();
+ return Encode((int)(lval ^ rval));
+}
+
+ReturnedValue Runtime::Shl::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2033,7 +2090,7 @@ ReturnedValue Runtime::method_shl(const Value &left, const Value &right)
return Encode((int)(lval << rval));
}
-ReturnedValue Runtime::method_shr(const Value &left, const Value &right)
+ReturnedValue Runtime::Shr::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2042,7 +2099,7 @@ ReturnedValue Runtime::method_shr(const Value &left, const Value &right)
return Encode((int)(lval >> rval));
}
-ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
+ReturnedValue Runtime::UShr::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2053,37 +2110,35 @@ ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
return Encode(res);
}
-#endif // V4_BOOTSTRAP
-
-ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right)
+ReturnedValue Runtime::GreaterThan::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = method_compareGreaterThan(left, right);
+ bool r = CompareGreaterThan::call(left, right);
return Encode(r);
}
-ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right)
+ReturnedValue Runtime::LessThan::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = method_compareLessThan(left, right);
+ bool r = CompareLessThan::call(left, right);
return Encode(r);
}
-ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right)
+ReturnedValue Runtime::GreaterEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = method_compareGreaterEqual(left, right);
+ bool r = CompareGreaterEqual::call(left, right);
return Encode(r);
}
-ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right)
+ReturnedValue Runtime::LessEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = method_compareLessEqual(left, right);
+ bool r = CompareLessEqual::call(left, right);
return Encode(r);
}
@@ -2107,18 +2162,16 @@ struct LazyScope
}
};
-Bool Runtime::method_compareEqual(const Value &left, const Value &right)
+Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
Value lhs = left;
Value rhs = right;
-#ifndef V4_BOOTSTRAP
LazyScope scope;
Value *lhsGuard = nullptr;
Value *rhsGuard = nullptr;
-#endif
redo:
if (lhs.asReturnedValue() == rhs.asReturnedValue())
@@ -2148,7 +2201,6 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right)
case QV4::Value::QT_ManagedOrUndefined1:
case QV4::Value::QT_ManagedOrUndefined2:
case QV4::Value::QT_ManagedOrUndefined3: {
-#ifndef V4_BOOTSTRAP
// RHS: Managed
Heap::Base *l = lhs.m();
Heap::Base *r = rhs.m();
@@ -2166,7 +2218,6 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right)
lhs = lhsGuard->asReturnedValue();
break;
}
-#endif
return false;
}
case QV4::Value::QT_Empty:
@@ -2178,16 +2229,12 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right)
rhs = Value::fromDouble(rhs.int_32());
// fall through
default: // double
-#ifndef V4_BOOTSTRAP
if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false;
} else {
scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), lhs.m()->internalClass->engine);
lhs = lhsGuard->asReturnedValue();
}
-#else
- Q_UNIMPLEMENTED();
-#endif
}
goto redo;
case QV4::Value::QT_Empty:
@@ -2216,23 +2263,23 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right)
}
}
-ReturnedValue Runtime::method_equal(const Value &left, const Value &right)
+ReturnedValue Runtime::Equal::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = method_compareEqual(left, right);
+ bool r = CompareEqual::call(left, right);
return Encode(r);
}
-ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right)
+ReturnedValue Runtime::NotEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- bool r = !method_compareEqual(left, right);
+ bool r = !CompareEqual::call(left, right);
return Encode(r);
}
-ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right)
+ReturnedValue Runtime::StrictEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2240,7 +2287,7 @@ ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right)
return Encode(r);
}
-ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right)
+ReturnedValue Runtime::StrictNotEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
@@ -2248,21 +2295,21 @@ ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &rig
return Encode(r);
}
-Bool Runtime::method_compareNotEqual(const Value &left, const Value &right)
+Bool Runtime::CompareNotEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
- return !Runtime::method_compareEqual(left, right);
+ return !Runtime::CompareEqual::call(left, right);
}
-Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right)
+Bool Runtime::CompareStrictEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
return RuntimeHelpers::strictEqual(left, right);
}
-Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right)
+Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right)
{
TRACE2(left, right);
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 2be3ebf012..cb89b7e6c0 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -52,8 +52,6 @@
#include "qv4global_p.h"
#include "qv4value_p.h"
-#include "qv4context_p.h"
-#include "qv4engine_p.h"
#include "qv4math_p.h"
#include "qv4runtimeapi_p.h"
#include <QtCore/qnumeric.h>
@@ -114,20 +112,16 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
static Bool strictEqual(const Value &x, const Value &y);
static ReturnedValue addHelper(ExecutionEngine *engine, const Value &left, const Value &right);
-
- static ReturnedValue getTemplateObject(Function *function, int index);
};
// type conversion and testing
-#ifndef V4_BOOTSTRAP
inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, TypeHint typeHint)
{
if (!value.isObject())
return value.asReturnedValue();
return RuntimeHelpers::objectDefaultValue(&reinterpret_cast<const Object &>(value), typeHint);
}
-#endif
inline double RuntimeHelpers::toNumber(const Value &value)
{
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index ceec13a3bb..05ffb84d58 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -51,179 +51,449 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
typedef uint Bool;
-struct NoThrowEngine;
-namespace {
-template <typename T>
-struct ExceptionCheck {
- enum { NeedsCheck = 1 };
-};
-// push_catch and pop context methods shouldn't check for exceptions
-template <>
-struct ExceptionCheck<void (*)(QV4::NoThrowEngine *)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A>
-struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> {
- enum { NeedsCheck = 0 };
-};
-template <>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A, typename B>
-struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A, B)> {
- enum { NeedsCheck = 0 };
-};
-template <typename A, typename B, typename C>
-struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
- enum { NeedsCheck = 0 };
-};
-} // anonymous namespace
-
-#define FOR_EACH_RUNTIME_METHOD(F) \
- /* call */ \
- F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \
- F(ReturnedValue, callQmlContextPropertyLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \
- F(ReturnedValue, callName, (ExecutionEngine *engine, int nameIndex, Value *argv, int argc)) \
- F(ReturnedValue, callProperty, (ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)) \
- F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)) \
- F(ReturnedValue, callElement, (ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)) \
- F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \
- F(ReturnedValue, callWithReceiver, (ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)) \
- F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \
- F(ReturnedValue, callWithSpread, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \
- F(ReturnedValue, tailCall, (CppStackFrame *frame, ExecutionEngine *engine)) \
- \
- /* construct */ \
- F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, const Value &newTarget, Value *argv, int argc)) \
- F(ReturnedValue, constructWithSpread, (ExecutionEngine *engine, const Value &func, const Value &newTarget, Value *argv, int argc)) \
- \
- /* load & store */ \
- F(void, storeNameStrict, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
- F(void, storeNameSloppy, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
- F(void, storeProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \
- F(void, storeElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \
- F(void, storeElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)) \
- F(ReturnedValue, loadProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \
- F(ReturnedValue, loadName, (ExecutionEngine *engine, int nameIndex)) \
- F(ReturnedValue, loadElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \
- F(ReturnedValue, loadElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)) \
- F(ReturnedValue, loadSuperProperty, (ExecutionEngine *engine, const Value &property)) \
- F(void, storeSuperProperty, (ExecutionEngine *engine, const Value &property, const Value &value)) \
- F(ReturnedValue, loadSuperConstructor, (ExecutionEngine *engine, const Value &t)) \
- \
- /* typeof */ \
- F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \
- F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \
- \
- /* delete */ \
- F(bool, deleteProperty, (ExecutionEngine *engine, const Value &base, const Value &index)) \
- F(bool, deleteName, (ExecutionEngine *engine, int nameIndex)) \
- \
- /* exceptions & scopes */ \
- F(void, throwException, (ExecutionEngine *engine, const Value &value)) \
- F(ReturnedValue, createWithContext, (ExecutionEngine *, Value *jsStackFrame)) \
- F(ReturnedValue, createCatchContext, (ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex)) \
- F(ReturnedValue, createBlockContext, (ExecutionContext *parent, int index)) \
- F(ReturnedValue, createScriptContext, (ExecutionEngine *engine, int index)) \
- F(ReturnedValue, cloneBlockContext, (ExecutionContext *previous)) \
- F(ReturnedValue, popScriptContext, (ExecutionEngine *engine)) \
- F(void, throwReferenceError, (ExecutionEngine *engine, int nameIndex)) \
- \
- /* closures */ \
- F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \
- \
- /* function header */ \
- F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \
- F(ReturnedValue, createMappedArgumentsObject, (ExecutionEngine *engine)) \
- F(ReturnedValue, createUnmappedArgumentsObject, (ExecutionEngine *engine)) \
- F(ReturnedValue, createRestParameter, (ExecutionEngine *engine, int argIndex)) \
- \
- /* literals */ \
- F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \
- F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, int classId, const Value *args, int argc)) \
- F(ReturnedValue, createClass, (ExecutionEngine *engine, int classIndex, const Value &heritage, const Value *computedNames)) \
- \
- /* for-in, for-of and array destructuring */ \
- F(ReturnedValue, getIterator, (ExecutionEngine *engine, const Value &in, int iterator)) \
- F(ReturnedValue, iteratorNext, (ExecutionEngine *engine, const Value &iterator, Value *value)) \
- F(ReturnedValue, iteratorNextForYieldStar, (ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)) \
- F(ReturnedValue, iteratorClose, (ExecutionEngine *engine, const Value &iterator, const Value &done)) \
- F(ReturnedValue, destructureRestElement, (ExecutionEngine *engine, const Value &iterator)) \
- \
- /* unary operators */ \
- F(ReturnedValue, uMinus, (const Value &value)) \
- \
- /* binary operators */ \
- F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(ReturnedValue, sub, (const Value &left, const Value &right)) \
- F(ReturnedValue, mul, (const Value &left, const Value &right)) \
- F(ReturnedValue, div, (const Value &left, const Value &right)) \
- F(ReturnedValue, mod, (const Value &left, const Value &right)) \
- F(ReturnedValue, shl, (const Value &left, const Value &right)) \
- F(ReturnedValue, shr, (const Value &left, const Value &right)) \
- F(ReturnedValue, ushr, (const Value &left, const Value &right)) \
- F(ReturnedValue, greaterThan, (const Value &left, const Value &right)) \
- F(ReturnedValue, lessThan, (const Value &left, const Value &right)) \
- F(ReturnedValue, greaterEqual, (const Value &left, const Value &right)) \
- F(ReturnedValue, lessEqual, (const Value &left, const Value &right)) \
- F(ReturnedValue, equal, (const Value &left, const Value &right)) \
- F(ReturnedValue, notEqual, (const Value &left, const Value &right)) \
- F(ReturnedValue, strictEqual, (const Value &left, const Value &right)) \
- F(ReturnedValue, strictNotEqual, (const Value &left, const Value &right)) \
- \
- /* comparisons */ \
- F(Bool, compareGreaterThan, (const Value &l, const Value &r)) \
- F(Bool, compareLessThan, (const Value &l, const Value &r)) \
- F(Bool, compareGreaterEqual, (const Value &l, const Value &r)) \
- F(Bool, compareLessEqual, (const Value &l, const Value &r)) \
- F(Bool, compareEqual, (const Value &left, const Value &right)) \
- F(Bool, compareNotEqual, (const Value &left, const Value &right)) \
- F(Bool, compareStrictEqual, (const Value &left, const Value &right)) \
- F(Bool, compareStrictNotEqual, (const Value &left, const Value &right)) \
- \
- F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- \
- F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id))
struct Q_QML_PRIVATE_EXPORT Runtime {
- Runtime();
-
typedef ReturnedValue (*UnaryOperation)(const Value &value);
typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
- typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right);
+ typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *, const Value &left, const Value &right);
-#define DEFINE_RUNTIME_METHOD_ENUM(returnvalue, name, args) name,
- enum RuntimeMethods {
- FOR_EACH_RUNTIME_METHOD(DEFINE_RUNTIME_METHOD_ENUM)
- RuntimeMethodCount,
- InvalidRuntimeMethod = RuntimeMethodCount
+ enum class Throws { No, Yes };
+ enum class ChangesContext { No, Yes };
+ enum class Pure { No, Yes };
+ enum class LastArgumentIsOutputValue { No, Yes };
+
+ template<Throws t, ChangesContext c = ChangesContext::No, Pure p = Pure::No,
+ LastArgumentIsOutputValue out = LastArgumentIsOutputValue::No>
+ struct Method
+ {
+ static constexpr bool throws = t == Throws::Yes;
+ static constexpr bool changesContext = c == ChangesContext::Yes;
+ static constexpr bool pure = p == Pure::Yes;
+ static constexpr bool lastArgumentIsOutputValue = out == LastArgumentIsOutputValue::Yes;
+ };
+ using PureMethod = Method<Throws::No, ChangesContext::No, Pure::Yes>;
+ using IteratorMethod = Method<Throws::Yes, ChangesContext::No, Pure::No,
+ LastArgumentIsOutputValue::Yes>;
+
+ /* call */
+ struct Q_QML_PRIVATE_EXPORT CallGlobalLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallQmlContextPropertyLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallName : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, int, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallProperty : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, int, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallPropertyLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, uint, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallElement : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallValue : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallWithReceiver : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallPossiblyDirectEval : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CallWithSpread : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT TailCall : Method<Throws::Yes>
+ {
+ static ReturnedValue call(CppStackFrame *, ExecutionEngine *);
};
-#undef DEFINE_RUNTIME_METHOD_ENUM
- void *runtimeMethods[RuntimeMethodCount];
+ /* construct */
+ struct Q_QML_PRIVATE_EXPORT Construct : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT ConstructWithSpread : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
+ };
- static uint runtimeMethodOffset(RuntimeMethods method) { return method*QT_POINTER_SIZE; }
+ /* load & store */
+ struct Q_QML_PRIVATE_EXPORT StoreNameStrict : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, int, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StoreNameSloppy : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, int, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StoreProperty : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, const Value &, int, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StoreElement : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, const Value &, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadProperty : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadName : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadElement : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadSuperProperty : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StoreSuperProperty : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadSuperConstructor : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadGlobalLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Function *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT LoadQmlContextPropertyLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, uint);
+ };
+ struct Q_QML_PRIVATE_EXPORT GetLookup : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Function *, const Value &, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT SetLookupStrict : Method<Throws::Yes>
+ {
+ static void call(Function *, const Value &, int, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT SetLookupSloppy : Method<Throws::Yes>
+ {
+ static void call(Function *, const Value &, int, const Value &);
+ };
+
+ /* typeof */
+ struct Q_QML_PRIVATE_EXPORT TypeofValue : PureMethod
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT TypeofName : Method<Throws::No>
+ {
+ static ReturnedValue call(ExecutionEngine *, int);
+ };
+
+ /* delete */
+ struct Q_QML_PRIVATE_EXPORT DeleteProperty_NoThrow : Method<Throws::No>
+ {
+ static Bool call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT DeleteProperty : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Function *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT DeleteName_NoThrow : Method<Throws::No>
+ {
+ static Bool call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT DeleteName : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Function *, int);
+ };
+
+ /* exceptions & scopes */
+ struct Q_QML_PRIVATE_EXPORT ThrowException : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT PushCallContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(CppStackFrame *);
+ };
+ struct Q_QML_PRIVATE_EXPORT PushWithContext : Method<Throws::Yes, ChangesContext::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT PushCatchContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(ExecutionEngine *, int, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT PushBlockContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CloneBlockContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(ExecutionEngine *);
+ };
+ struct Q_QML_PRIVATE_EXPORT PushScriptContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT PopScriptContext : Method<Throws::No, ChangesContext::Yes>
+ {
+ static void call(ExecutionEngine *);
+ };
+ struct Q_QML_PRIVATE_EXPORT ThrowReferenceError : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT ThrowOnNullOrUndefined : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, const Value &);
+ };
+
+ /* closures */
+ struct Q_QML_PRIVATE_EXPORT Closure : Method<Throws::No>
+ {
+ static ReturnedValue call(ExecutionEngine *, int);
+ };
-#define RUNTIME_METHOD(returnvalue, name, args) \
- typedef returnvalue (*Method_##name)args; \
- enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \
- static returnvalue method_##name args;
- FOR_EACH_RUNTIME_METHOD(RUNTIME_METHOD)
-#undef RUNTIME_METHOD
+ /* Function header */
+ struct Q_QML_PRIVATE_EXPORT ConvertThisToObject : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT DeclareVar : Method<Throws::Yes>
+ {
+ static void call(ExecutionEngine *, Bool, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CreateMappedArgumentsObject : Method<Throws::No>
+ {
+ static ReturnedValue call(ExecutionEngine *);
+ };
+ struct Q_QML_PRIVATE_EXPORT CreateUnmappedArgumentsObject : Method<Throws::No>
+ {
+ static ReturnedValue call(ExecutionEngine *);
+ };
+ struct Q_QML_PRIVATE_EXPORT CreateRestParameter : PureMethod
+ {
+ static ReturnedValue call(ExecutionEngine *, int);
+ };
+
+ /* literals */
+ struct Q_QML_PRIVATE_EXPORT ArrayLiteral : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, Value[], uint);
+ };
+ struct Q_QML_PRIVATE_EXPORT ObjectLiteral : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, int, Value[], int);
+ };
+ struct Q_QML_PRIVATE_EXPORT CreateClass : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, int, const Value &, Value[]);
+ };
+
+ /* for-in, for-of and array destructuring */
+ struct Q_QML_PRIVATE_EXPORT GetIterator : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT IteratorNext : IteratorMethod
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, Value *);
+ };
+ struct Q_QML_PRIVATE_EXPORT IteratorNextForYieldStar : IteratorMethod
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value *);
+ };
+ struct Q_QML_PRIVATE_EXPORT IteratorClose : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT DestructureRestElement : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+
+ /* conversions */
+ struct Q_QML_PRIVATE_EXPORT ToObject : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT ToBoolean : PureMethod
+ {
+ static Bool call(const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT ToNumber : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &);
+ };
+ /* unary operators */
+ struct Q_QML_PRIVATE_EXPORT UMinus : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &);
+ };
+
+ /* binary operators */
+ struct Q_QML_PRIVATE_EXPORT Instanceof : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT In : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Add : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Sub : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Mul : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Div : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Mod : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Exp : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT BitAnd : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT BitOr : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT BitXor : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Shl : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Shr : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT UShr : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT GreaterThan : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LessThan : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT GreaterEqual : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT LessEqual : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT Equal : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT NotEqual : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StrictEqual : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT StrictNotEqual : Method<Throws::Yes>
+ {
+ static ReturnedValue call(const Value &, const Value &);
+ };
+
+ /* comparisons */
+ struct Q_QML_PRIVATE_EXPORT CompareGreaterThan : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareLessThan : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareGreaterEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareLessEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareNotEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareStrictEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareStrictNotEqual : Method<Throws::Yes>
+ {
+ static Bool call(const Value &, const Value &);
+ };
+
+ struct Q_QML_PRIVATE_EXPORT CompareInstanceof : Method<Throws::Yes>
+ {
+ static Bool call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_PRIVATE_EXPORT CompareIn : Method<Throws::Yes>
+ {
+ static Bool call(ExecutionEngine *, const Value &, const Value &);
+ };
+
+ struct Q_QML_PRIVATE_EXPORT RegexpLiteral : PureMethod
+ {
+ static ReturnedValue call(ExecutionEngine *, int);
+ };
+ struct Q_QML_PRIVATE_EXPORT GetTemplateObject : PureMethod
+ {
+ static ReturnedValue call(Function *, int);
+ };
struct StackOffsets {
static const int tailCall_function = -1;
@@ -234,7 +504,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
};
static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");
-static_assert(offsetof(Runtime, runtimeMethods) == 0, "JIT expects this to be the first member");
static_assert(sizeof(Runtime::BinaryOperation) == sizeof(void*), "JIT expects a function pointer to fit into a regular pointer, for cross-compilation offset translation");
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
index 9866966936..162d75db63 100644
--- a/src/qml/jsruntime/qv4runtimecodegen.cpp
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -37,10 +37,12 @@
**
****************************************************************************/
+#include "qv4engine_p.h"
#include "qv4runtimecodegen_p.h"
-#include "qv4compilerscanfunctions_p.h"
+#include <private/qv4compilerscanfunctions_p.h>
using namespace QV4;
+using namespace QQmlJS;
void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
@@ -58,7 +60,7 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
scan(ast);
scan.leaveEnvironment();
- if (hasError)
+ if (hasError())
return;
int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
@@ -67,17 +69,19 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
{
- if (hasError)
+ if (hasError())
return;
- hasError = true;
+
+ Codegen::throwSyntaxError(loc, detail);
engine->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
{
- if (hasError)
+ if (hasError())
return;
- hasError = true;
+
+ Codegen::throwReferenceError(loc, detail);
engine->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h
index 006a6a3cde..71aaf1fb55 100644
--- a/src/qml/jsruntime/qv4runtimecodegen_p.h
+++ b/src/qml/jsruntime/qv4runtimecodegen_p.h
@@ -66,11 +66,11 @@ public:
void generateFromFunctionExpression(const QString &fileName,
const QString &sourceCode,
- AST::FunctionExpression *ast,
+ QQmlJS::AST::FunctionExpression *ast,
Compiler::Module *module);
- void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override;
- void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override;
+ void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
+ void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
private:
ExecutionEngine *engine;
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 6cb2e95cdc..2fab9e4b7b 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -60,8 +60,9 @@
#include <QScopedValueRollback>
using namespace QV4;
+using namespace QQmlJS;
-Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer<CompiledData::CompilationUnit> &compilationUnit)
+Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer<ExecutableCompilationUnit> &compilationUnit)
: line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
, compilationUnit(compilationUnit), vmFunction(nullptr), parseAsBinding(true)
{
@@ -108,10 +109,10 @@ void Script::parse()
const auto diagnosticMessages = parser.diagnosticMessages();
for (const DiagnosticMessage &m : diagnosticMessages) {
if (m.isError()) {
- valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
+ valueScope.engine->throwSyntaxError(m.message, sourceFile, m.line, m.column);
return;
} else {
- qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
+ qWarning() << sourceFile << ':' << m.line << ':' << m.column
<< ": warning: " << m.message;
}
}
@@ -133,7 +134,7 @@ void Script::parse()
if (v4->hasException)
return;
- compilationUnit = cg.generateCompilationUnit();
+ compilationUnit = QV4::ExecutableCompilationUnit::create(cg.generateCompilationUnit());
vmFunction = compilationUnit->linkToEngine(v4);
}
@@ -172,10 +173,11 @@ Function *Script::function()
return vmFunction;
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator,
- const QString &fileName, const QString &finalUrl, const QString &source,
- QList<QQmlError> *reportedErrors,
- QV4::Compiler::ContextType contextType)
+QV4::CompiledData::CompilationUnit Script::precompile(
+ QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine,
+ Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl,
+ const QString &source, QList<QQmlError> *reportedErrors,
+ QV4::Compiler::ContextType contextType)
{
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
@@ -202,10 +204,16 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
Codegen cg(unitGenerator, /*strict mode*/false);
cg.generateFromProgram(fileName, finalUrl, source, program, module, contextType);
- errors = cg.qmlErrors();
- if (!errors.isEmpty()) {
- if (reportedErrors)
- *reportedErrors << errors;
+ if (cg.hasError()) {
+ if (reportedErrors) {
+ const auto v4Error = cg.error();
+ QQmlError error;
+ error.setUrl(cg.url());
+ error.setLine(v4Error.line);
+ error.setColumn(v4Error.column);
+ error.setDescription(v4Error.message);
+ reportedErrors->append(error);
+ }
return nullptr;
}
@@ -219,8 +227,9 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl, &cacheError)) {
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> jsUnit;
- jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit));
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> jsUnit
+ = QV4::ExecutableCompilationUnit::create(
+ QV4::CompiledData::CompilationUnit(cachedUnit));
return new QV4::Script(engine, qmlContext, jsUnit);
}
@@ -237,7 +246,6 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
- QmlIR::Document::removeScriptPragmas(sourceCode);
auto result = new QV4::Script(engine, qmlContext, /*parseAsBinding*/false, sourceCode, originalUrl.toString());
result->contextType = QV4::Compiler::ContextType::ScriptImportedByQML;
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index a1e9b83a8b..aecedea701 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -80,7 +80,7 @@ struct Q_QML_EXPORT Script {
if (qml)
qmlContext.set(engine, *qml);
}
- Script(ExecutionEngine *engine, QmlContext *qml, const QQmlRefPointer<CompiledData::CompilationUnit> &compilationUnit);
+ Script(ExecutionEngine *engine, QmlContext *qml, const QQmlRefPointer<ExecutableCompilationUnit> &compilationUnit);
~Script();
QString sourceFile;
int line;
@@ -92,7 +92,7 @@ struct Q_QML_EXPORT Script {
bool parsed;
QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Eval;
QV4::PersistentValue qmlContext;
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<ExecutableCompilationUnit> compilationUnit;
Function *vmFunction;
bool parseAsBinding;
@@ -101,8 +101,10 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QQmlRefPointer<CompiledData::CompilationUnit> precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator,
- const QString &fileName, const QString &finalUrl, const QString &source,
+ static QV4::CompiledData::CompilationUnit precompile(
+ QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine,
+ Compiler::JSUnitGenerator *unitGenerator, const QString &fileName,
+ const QString &finalUrl, const QString &source,
QList<QQmlError> *reportedErrors = nullptr,
QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Global);
static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 1eef12a491..77a98247ac 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -49,8 +49,10 @@
#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
+#if QT_CONFIG(qml_itemmodel)
#include <private/qqmlmodelindexvaluetype_p.h>
#include <QtCore/qabstractitemmodel.h>
+#endif
#include <algorithm>
@@ -75,6 +77,16 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
}
// F(elementType, elementTypeName, sequenceType, defaultValue)
+#if QT_CONFIG(qml_itemmodel)
+#define FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F) \
+ F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+ F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
+ F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
+ F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
+#else
+#define FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F)
+#endif
+
#define FOREACH_QML_SEQUENCE_TYPE(F) \
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
@@ -92,10 +104,7 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(QUrl, Url, QList<QUrl>, QUrl()) \
F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
- F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
- F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
- F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
- F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
+ FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F)
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
{
@@ -112,6 +121,7 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
return engine->newString(element.toString())->asReturnedValue();
}
+#if QT_CONFIG(qml_itemmodel)
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QModelIndex &element)
{
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(QMetaType::QModelIndex);
@@ -124,6 +134,7 @@ static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, co
const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(metaTypeId);
return QV4::QQmlValueTypeWrapper::create(engine, QVariant::fromValue(element), vtmo, metaTypeId);
}
+#endif
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
{
@@ -150,6 +161,7 @@ static QString convertElementToString(const QUrl &element)
return element.toString();
}
+#if QT_CONFIG(qml_itemmodel)
static QString convertElementToString(const QModelIndex &element)
{
return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
@@ -159,6 +171,7 @@ static QString convertElementToString(const QItemSelectionRange &element)
{
return reinterpret_cast<const QQmlItemSelectionRangeValueType *>(&element)->toString();
}
+#endif
static QString convertElementToString(qreal element)
{
@@ -192,6 +205,7 @@ template <> QUrl convertValueToElement(const Value &value)
return QUrl(value.toQString());
}
+#if QT_CONFIG(qml_itemmodel)
template <> QModelIndex convertValueToElement(const Value &value)
{
const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
@@ -207,6 +221,7 @@ template <> QItemSelectionRange convertValueToElement(const Value &value)
return v->toVariant().value<QItemSelectionRange>();
return QItemSelectionRange();
}
+#endif
template <> qreal convertValueToElement(const Value &value)
{
@@ -667,6 +682,7 @@ typedef QQmlSequence<QVector<QUrl> > QQmlUrlVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList);
typedef QQmlSequence<std::vector<QUrl> > QQmlUrlStdVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList);
+#if QT_CONFIG(qml_itemmodel)
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList);
typedef QQmlSequence<QVector<QModelIndex> > QQmlQModelIndexVectorList;
@@ -675,6 +691,7 @@ typedef QQmlSequence<std::vector<QModelIndex> > QQmlQModelIndexStdVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList);
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList);
+#endif
typedef QQmlSequence<QList<bool> > QQmlBoolList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolList);
typedef QQmlSequence<QList<qreal> > QQmlRealList;
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index da71215bed..886dfaa521 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct SequencePrototype : public QV4::Object
+struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
{
V4_PROTOTYPE(arrayPrototype)
void init();
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
deleted file mode 100644
index 50871a4d87..0000000000
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4serialize_p.h"
-
-#include <private/qv8engine_p.h>
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#include <private/qqmllistmodelworkeragent_p.h>
-#endif
-
-#include <private/qv4value_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4regexpobject_p.h>
-#if QT_CONFIG(qml_sequence_object)
-#include <private/qv4sequenceobject_p.h>
-#endif
-#include <private/qv4objectproto_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-// We allow the following JavaScript types to be passed between the main and
-// the secondary thread:
-// + undefined
-// + null
-// + Boolean
-// + String
-// + Function
-// + Array
-// + "Simple" Objects
-// + Number
-// + Date
-// + RegExp
-// <quint8 type><quint24 size><data>
-
-enum Type {
- WorkerUndefined,
- WorkerNull,
- WorkerTrue,
- WorkerFalse,
- WorkerString,
- WorkerFunction,
- WorkerArray,
- WorkerObject,
- WorkerInt32,
- WorkerUint32,
- WorkerNumber,
- WorkerDate,
- WorkerRegexp,
-#if QT_CONFIG(qml_list_model)
- WorkerListModel,
-#endif
-#if QT_CONFIG(qml_sequence_object)
- WorkerSequence
-#endif
-};
-
-static inline quint32 valueheader(Type type, quint32 size = 0)
-{
- return quint8(type) << 24 | (size & 0xFFFFFF);
-}
-
-static inline Type headertype(quint32 header)
-{
- return (Type)(header >> 24);
-}
-
-static inline quint32 headersize(quint32 header)
-{
- return header & 0xFFFFFF;
-}
-
-static inline void push(QByteArray &data, quint32 value)
-{
- data.append((const char *)&value, sizeof(quint32));
-}
-
-static inline void push(QByteArray &data, double value)
-{
- data.append((const char *)&value, sizeof(double));
-}
-
-static inline void push(QByteArray &data, void *ptr)
-{
- data.append((const char *)&ptr, sizeof(void *));
-}
-
-static inline void reserve(QByteArray &data, int extra)
-{
- data.reserve(data.size() + extra);
-}
-
-static inline quint32 popUint32(const char *&data)
-{
- quint32 rv = *((const quint32 *)data);
- data += sizeof(quint32);
- return rv;
-}
-
-static inline double popDouble(const char *&data)
-{
- double rv = *((const double *)data);
- data += sizeof(double);
- return rv;
-}
-
-static inline void *popPtr(const char *&data)
-{
- void *rv = *((void *const *)data);
- data += sizeof(void *);
- return rv;
-}
-
-// XXX TODO: Check that worker script is exception safe in the case of
-// serialization/deserialization failures
-
-#define ALIGN(size) (((size) + 3) & ~3)
-void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine *engine)
-{
- QV4::Scope scope(engine);
-
- if (v.isEmpty()) {
- Q_ASSERT(!"Serialize: got empty value");
- } else if (v.isUndefined()) {
- push(data, valueheader(WorkerUndefined));
- } else if (v.isNull()) {
- push(data, valueheader(WorkerNull));
- } else if (v.isBoolean()) {
- push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse));
- } else if (v.isString()) {
- const QString &qstr = v.toQString();
- int length = qstr.length();
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- int utf16size = ALIGN(length * sizeof(quint16));
-
- reserve(data, utf16size + sizeof(quint32));
- push(data, valueheader(WorkerString, length));
-
- int offset = data.size();
- data.resize(data.size() + utf16size);
- char *buffer = data.data() + offset;
-
- memcpy(buffer, qstr.constData(), length*sizeof(QChar));
- } else if (v.as<FunctionObject>()) {
- // XXX TODO: Implement passing function objects between the main and
- // worker scripts
- push(data, valueheader(WorkerUndefined));
- } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) {
- uint length = array->getLength();
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- reserve(data, sizeof(quint32) + length * sizeof(quint32));
- push(data, valueheader(WorkerArray, length));
- ScopedValue val(scope);
- for (uint ii = 0; ii < length; ++ii)
- serialize(data, (val = array->get(ii)), engine);
- } else if (v.isInteger()) {
- reserve(data, 2 * sizeof(quint32));
- push(data, valueheader(WorkerInt32));
- push(data, (quint32)v.integerValue());
-// } else if (v.IsUint32()) {
-// reserve(data, 2 * sizeof(quint32));
-// push(data, valueheader(WorkerUint32));
-// push(data, v.Uint32Value());
- } else if (v.isNumber()) {
- reserve(data, sizeof(quint32) + sizeof(double));
- push(data, valueheader(WorkerNumber));
- push(data, v.asDouble());
- } else if (const QV4::DateObject *d = v.as<DateObject>()) {
- reserve(data, sizeof(quint32) + sizeof(double));
- push(data, valueheader(WorkerDate));
- push(data, d->date());
- } else if (const RegExpObject *re = v.as<RegExpObject>()) {
- quint32 flags = re->flags();
- QString pattern = re->source();
- int length = pattern.length() + 1;
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- int utf16size = ALIGN(length * sizeof(quint16));
-
- reserve(data, sizeof(quint32) + utf16size);
- push(data, valueheader(WorkerRegexp, flags));
- push(data, (quint32)length);
-
- int offset = data.size();
- data.resize(data.size() + utf16size);
- char *buffer = data.data() + offset;
-
- memcpy(buffer, pattern.constData(), length*sizeof(QChar));
- } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
- // XXX TODO: Generalize passing objects between the main thread and worker scripts so
- // that others can trivially plug in their elements.
-#if QT_CONFIG(qml_list_model)
- QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
- if (lm && lm->agent()) {
- QQmlListModelWorkerAgent *agent = lm->agent();
- agent->addref();
- push(data, valueheader(WorkerListModel));
- push(data, (void *)agent);
- return;
- }
-#else
- Q_UNUSED(qobjectWrapper);
-#endif
- // No other QObject's are allowed to be sent
- push(data, valueheader(WorkerUndefined));
- } else if (const Object *o = v.as<Object>()) {
-#if QT_CONFIG(qml_sequence_object)
- if (o->isListType()) {
- // valid sequence. we generate a length (sequence length + 1 for the sequence type)
- uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32();
- uint length = seqLength + 1;
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- reserve(data, sizeof(quint32) + length * sizeof(quint32));
- push(data, valueheader(WorkerSequence, length));
- serialize(data, QV4::Value::fromInt32(QV4::SequencePrototype::metaTypeForSequence(o)), engine); // sequence type
- ScopedValue val(scope);
- for (uint ii = 0; ii < seqLength; ++ii)
- serialize(data, (val = o->get(ii)), engine); // sequence elements
-
- return;
- }
-#endif
-
- // regular object
- QV4::ScopedValue val(scope, v);
- QV4::ScopedArrayObject properties(scope, QV4::ObjectPrototype::getOwnPropertyNames(engine, val));
- quint32 length = properties->getLength();
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- push(data, valueheader(WorkerObject, length));
-
- QV4::ScopedValue s(scope);
- for (quint32 ii = 0; ii < length; ++ii) {
- s = properties->get(ii);
- serialize(data, s, engine);
-
- QV4::String *str = s->as<String>();
- val = o->get(str);
- if (scope.hasException())
- scope.engine->catchException();
-
- serialize(data, val, engine);
- }
- return;
- } else {
- push(data, valueheader(WorkerUndefined));
- }
-}
-
-ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
-{
- quint32 header = popUint32(data);
- Type type = headertype(header);
-
- Scope scope(engine);
-
- switch (type) {
- case WorkerUndefined:
- return QV4::Encode::undefined();
- case WorkerNull:
- return QV4::Encode::null();
- case WorkerTrue:
- return QV4::Encode(true);
- case WorkerFalse:
- return QV4::Encode(false);
- case WorkerString:
- {
- quint32 size = headersize(header);
- QString qstr((const QChar *)data, size);
- data += ALIGN(size * sizeof(quint16));
- return QV4::Encode(engine->newString(qstr));
- }
- case WorkerFunction:
- Q_ASSERT(!"Unreachable");
- break;
- case WorkerArray:
- {
- quint32 size = headersize(header);
- ScopedArrayObject a(scope, engine->newArrayObject());
- ScopedValue v(scope);
- for (quint32 ii = 0; ii < size; ++ii) {
- v = deserialize(data, engine);
- a->put(ii, v);
- }
- return a.asReturnedValue();
- }
- case WorkerObject:
- {
- quint32 size = headersize(header);
- ScopedObject o(scope, engine->newObject());
- ScopedValue name(scope);
- ScopedString n(scope);
- ScopedValue value(scope);
- for (quint32 ii = 0; ii < size; ++ii) {
- name = deserialize(data, engine);
- value = deserialize(data, engine);
- n = name->asReturnedValue();
- o->put(n, value);
- }
- return o.asReturnedValue();
- }
- case WorkerInt32:
- return QV4::Encode((qint32)popUint32(data));
- case WorkerUint32:
- return QV4::Encode(popUint32(data));
- case WorkerNumber:
- return QV4::Encode(popDouble(data));
- case WorkerDate:
- return QV4::Encode(engine->newDateObject(QV4::Value::fromDouble(popDouble(data))));
- case WorkerRegexp:
- {
- quint32 flags = headersize(header);
- quint32 length = popUint32(data);
- QString pattern = QString((const QChar *)data, length - 1);
- data += ALIGN(length * sizeof(quint16));
- return Encode(engine->newRegExpObject(pattern, flags));
- }
-#if QT_CONFIG(qml_list_model)
- case WorkerListModel:
- {
- void *ptr = popPtr(data);
- QQmlListModelWorkerAgent *agent = (QQmlListModelWorkerAgent *)ptr;
- QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(engine, agent));
- // ### Find a better solution then the ugly property
- QQmlListModelWorkerAgent::VariantRef ref(agent);
- QVariant var = qVariantFromValue(ref);
- QV4::ScopedValue v(scope, scope.engine->fromVariant(var));
- QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref")));
- rv->as<Object>()->defineReadonlyProperty(s, v);
-
- agent->release();
- agent->setEngine(engine);
- return rv->asReturnedValue();
- }
-#endif
-#if QT_CONFIG(qml_sequence_object)
- case WorkerSequence:
- {
- ScopedValue value(scope);
- bool succeeded = false;
- quint32 length = headersize(header);
- quint32 seqLength = length - 1;
- value = deserialize(data, engine);
- int sequenceType = value->integerValue();
- ScopedArrayObject array(scope, engine->newArrayObject());
- array->arrayReserve(seqLength);
- for (quint32 ii = 0; ii < seqLength; ++ii) {
- value = deserialize(data, engine);
- array->arrayPut(ii, value);
- }
- array->setArrayLengthUnchecked(seqLength);
- QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded);
- return QV4::SequencePrototype::fromVariant(engine, seqVariant, &succeeded);
- }
-#endif
- }
- Q_ASSERT(!"Unreachable");
- return QV4::Encode::undefined();
-}
-
-QByteArray Serialize::serialize(const QV4::Value &value, ExecutionEngine *engine)
-{
- QByteArray rv;
- serialize(rv, value, engine);
- return rv;
-}
-
-ReturnedValue Serialize::deserialize(const QByteArray &data, ExecutionEngine *engine)
-{
- const char *stream = data.constData();
- return deserialize(stream, engine);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index 088ecbe30d..1664d1bd71 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -76,7 +76,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("add")))));
if (!adder)
return scope.engine->throwTypeError();
- ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true));
+ ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true));
CHECK_EXCEPTION();
if (!iter)
return a.asReturnedValue();
@@ -84,7 +84,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
Value *nextValue = scope.alloc(1);
ScopedValue done(scope);
forever {
- done = Runtime::method_iteratorNext(scope.engine, iter, nextValue);
+ done = Runtime::IteratorNext::call(scope.engine, iter, nextValue);
CHECK_EXCEPTION();
if (done->toBoolean())
return a.asReturnedValue();
@@ -92,7 +92,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
adder->call(a, nextValue, 1);
if (scope.engine->hasException) {
ScopedValue falsey(scope, Encode(false));
- return Runtime::method_iteratorClose(scope.engine, iter, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iter, falsey);
}
}
}
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index 44cfef9173..bf689a74bc 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -52,63 +52,13 @@
#include <private/qv4context_p.h>
#include <private/qv4enginebase_p.h>
-#ifndef V4_BOOTSTRAP
+#include <private/qv4calldata_p.h>
#include <private/qv4function_p.h>
-#endif
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct CallData
-{
- enum Offsets {
- Function = 0,
- Context = 1,
- Accumulator = 2,
- This = 3,
- NewTarget = 4,
- Argc = 5,
-
- LastOffset = Argc,
- OffsetCount = LastOffset + 1
- };
-
- Value function;
- Value context;
- Value accumulator;
- Value thisObject;
- Value newTarget;
- Value _argc;
-
- int argc() const {
- Q_ASSERT(_argc.isInteger());
- return _argc.int_32();
- }
-
- void setArgc(int argc) {
- Q_ASSERT(argc >= 0);
- _argc.setInt_32(argc);
- }
-
- inline ReturnedValue argument(int i) const {
- return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue();
- }
-
- Value args[1];
-
- static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); }
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
-Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value));
-Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value));
-
struct Q_QML_EXPORT CppStackFrame {
EngineBase *engine;
Value *savedStackTop;
@@ -155,7 +105,6 @@ struct Q_QML_EXPORT CppStackFrame {
engine->jsStackTop = savedStackTop;
}
-#ifndef V4_BOOTSTRAP
static uint requiredJSStackFrameSize(uint nRegisters) {
return CallData::HeaderSize() + nRegisters;
}
@@ -198,7 +147,6 @@ struct Q_QML_EXPORT CppStackFrame {
*v = Value::emptyValue().asReturnedValue();
}
}
-#endif
QString source() const;
QString function() const;
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 68d65f2e24..223f4a4769 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -39,19 +39,15 @@
#include "qv4string_p.h"
#include "qv4value_p.h"
-#ifndef V4_BOOTSTRAP
#include "qv4identifiertable_p.h"
#include "qv4runtime_p.h"
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
-#endif
#include <QtCore/QHash>
#include <QtCore/private/qnumeric_p.h>
using namespace QV4;
-#ifndef V4_BOOTSTRAP
-
void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
{
StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
@@ -254,10 +250,3 @@ qint64 String::virtualGetLength(const Managed *m)
{
return static_cast<const String *>(m)->d()->length();
}
-
-#endif // V4_BOOTSTRAP
-
-uint String::toArrayIndex(const QString &str)
-{
- return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length());
-}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index fbd4f5f550..52fe09cd72 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -54,6 +54,7 @@
#include "qv4managed_p.h"
#include <QtCore/private/qnumeric_p.h>
#include "qv4enginebase_p.h"
+#include <private/qv4stringtoarrayindex_p.h>
QT_BEGIN_NAMESPACE
@@ -104,7 +105,6 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
static void markObjects(Heap::Base *that, MarkStack *markStack);
-#ifndef V4_BOOTSTRAP
const VTable *vtable() const {
return internalClass->vtable;
}
@@ -140,11 +140,9 @@ struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
private:
static void append(const String *data, QChar *ch);
-#endif
};
Q_STATIC_ASSERT(std::is_trivial< String >::value);
-#ifndef V4_BOOTSTRAP
struct ComplexString : String {
void init(String *l, String *n);
void init(String *ref, int from, int len);
@@ -162,12 +160,10 @@ inline
int String::length() const {
return text ? text->size : static_cast<const ComplexString *>(this)->len;
}
-#endif
}
struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
-#ifndef V4_BOOTSTRAP
V4_MANAGED(StringOrSymbol, Managed)
V4_NEEDS_DESTROY
enum {
@@ -184,11 +180,9 @@ public:
inline QString toQString() const {
return d()->toQString();
}
-#endif
};
struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
-#ifndef V4_BOOTSTRAP
V4_MANAGED(String, StringOrSymbol)
Q_MANAGED_TYPE(String)
V4_INTERNALCLASS(String)
@@ -239,43 +233,13 @@ struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
protected:
static bool virtualIsEqualTo(Managed *that, Managed *o);
static qint64 virtualGetLength(const Managed *m);
-#endif
-
-public:
- static uint toArrayIndex(const QString &str);
-
-private:
- static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
- static inline uint toUInt(const char *ch) { return static_cast<unsigned char>(*ch); }
-
- template <typename T>
- static inline uint toArrayIndex(const T *ch, const T *end)
- {
- uint i = toUInt(ch) - '0';
- if (i > 9)
- return UINT_MAX;
- ++ch;
- // reject "01", "001", ...
- if (i == 0 && ch != end)
- return UINT_MAX;
-
- while (ch < end) {
- uint x = toUInt(ch) - '0';
- if (x > 9)
- return UINT_MAX;
- if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
- return UINT_MAX;
- ++ch;
- }
- return i;
- }
public:
template <typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
// array indices get their number as hash value
- uint h = toArrayIndex(ch, end);
+ uint h = stringToArrayIndex(ch, end);
if (h != UINT_MAX) {
if (subtype)
*subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
@@ -283,17 +247,16 @@ public:
}
while (ch < end) {
- h = 31 * h + toUInt(ch);
+ h = 31 * h + charToUInt(ch);
++ch;
}
if (subtype)
- *subtype = (toUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
+ *subtype = (charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
return h;
}
};
-#ifndef V4_BOOTSTRAP
struct ComplexString : String {
typedef QV4::Heap::ComplexString Data;
QV4::Heap::ComplexString *d_unchecked() const { return static_cast<QV4::Heap::ComplexString *>(m()); }
@@ -332,8 +295,6 @@ inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v)
{
return v.toString(e)->asReturnedValue();
}
-#endif
-
}
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 6afa6d36d6..9b4a2d575e 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -45,7 +45,7 @@
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
#include "qv4symbol_p.h"
-#include "qv4alloca_p.h"
+#include <private/qv4alloca_p.h>
#include "qv4jscall_p.h"
#include "qv4stringiterator_p.h"
#include <QtCore/QDateTime>
@@ -152,13 +152,14 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
if (attributes != Attr_Invalid)
return attributes;
- const StringObject *s = static_cast<const StringObject *>(m);
- uint slen = s->d()->string->toQString().length();
- uint index = id.asArrayIndex();
- if (index < slen) {
- if (p)
- p->value = s->getIndex(index);
- return Attr_NotConfigurable|Attr_NotWritable;
+ if (id.isArrayIndex()) {
+ const uint index = id.asArrayIndex();
+ const auto s = static_cast<const StringObject *>(m);
+ if (index < uint(s->d()->string->toQString().length())) {
+ if (p)
+ p->value = s->getIndex(index);
+ return Attr_NotConfigurable|Attr_NotWritable;
+ }
}
return Object::virtualGetOwnProperty(m, id, p);
}
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index faf7934c06..7d33167762 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -214,7 +214,7 @@ template <typename T>
ReturnedValue atomicLoad(char *data)
{
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
- T val = QAtomicOps<T>::load(*mem);
+ T val = QAtomicOps<T>::loadRelaxed(*mem);
return typeToValue(val);
}
@@ -223,7 +223,7 @@ ReturnedValue atomicStore(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
- QAtomicOps<T>::store(*mem, value);
+ QAtomicOps<T>::storeRelaxed(*mem, value);
return typeToValue(value);
}
@@ -459,24 +459,23 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type
ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
- uint index = id.asArrayIndex();
- if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ const bool isArrayIndex = id.isArrayIndex();
+ if (!isArrayIndex && !id.isCanonicalNumericIndexString())
return Object::virtualGet(m, id, receiver, hasProperty);
- // fall through, with index == UINT_MAX it'll do the right thing.
Scope scope(static_cast<const Object *>(m)->engine());
Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m));
if (a->d()->buffer->isDetachedBuffer())
return scope.engine->throwTypeError();
- if (index >= a->length()) {
+ if (!isArrayIndex || id.asArrayIndex() >= a->length()) {
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
uint bytesPerElement = a->d()->type->bytesPerElement;
- uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
+ uint byteOffset = a->d()->byteOffset + id.asArrayIndex() * bytesPerElement;
Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
if (hasProperty)
@@ -486,27 +485,22 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val
bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id)
{
- uint index = id.asArrayIndex();
- if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ const bool isArrayIndex = id.isArrayIndex();
+ if (!isArrayIndex && !id.isCanonicalNumericIndexString())
return Object::virtualHasProperty(m, id);
- // fall through, with index == UINT_MAX it'll do the right thing.
const TypedArray *a = static_cast<const TypedArray *>(m);
if (a->d()->buffer->isDetachedBuffer()) {
a->engine()->throwTypeError();
return false;
}
- if (index >= a->length())
- return false;
- return true;
+ return isArrayIndex && id.asArrayIndex() < a->length();
}
PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
{
- uint index = id.asArrayIndex();
- if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ if (!id.isArrayIndex() && !id.isCanonicalNumericIndexString())
return Object::virtualGetOwnProperty(m, id, p);
- // fall through, with index == UINT_MAX it'll do the right thing.
bool hasProperty = false;
ReturnedValue v = virtualGet(m, id, m, &hasProperty);
@@ -517,10 +511,9 @@ PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyK
bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
- uint index = id.asArrayIndex();
- if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ const bool isArrayIndex = id.isArrayIndex();
+ if (!isArrayIndex && !id.isCanonicalNumericIndexString())
return Object::virtualPut(m, id, value, receiver);
- // fall through, with index == UINT_MAX it'll do the right thing.
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
@@ -531,6 +524,10 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
if (a->d()->buffer->isDetachedBuffer())
return scope.engine->throwTypeError();
+ if (!isArrayIndex)
+ return false;
+
+ const uint index = id.asArrayIndex();
if (index >= a->length())
return false;
@@ -547,11 +544,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
{
- uint index = id.asArrayIndex();
- if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
- return Object::virtualDefineOwnProperty(m, id, p, attrs);
- // fall through, with index == UINT_MAX it'll do the right thing.
+ if (!id.isArrayIndex()) {
+ return !id.isCanonicalNumericIndexString()
+ && Object::virtualDefineOwnProperty(m, id, p, attrs);
+ }
+ const uint index = id.asArrayIndex();
TypedArray *a = static_cast<TypedArray *>(m);
if (index >= a->length() || attrs.isAccessor())
return false;
@@ -1595,7 +1593,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const Function
R += separator;
v = instance->get(k);
- v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
+ v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
s = v->toString(scope.engine);
if (scope.hasException())
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index cbc153bb86..d29b060b9e 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -36,16 +36,14 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <qv4engine_p.h>
+
#include <qv4runtime_p.h>
-#include <qv4string_p.h>
#include <qv4propertykey_p.h>
-#ifndef V4_BOOTSTRAP
+#include <qv4string_p.h>
#include <qv4symbol_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <private/qv4mm_p.h>
-#endif
#include <wtf/MathExtras.h>
@@ -83,12 +81,8 @@ bool Value::toBooleanImpl(Value val)
Heap::Base *b = val.m();
if (!b)
return false;
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
-#else
if (b->internalClass->vtable->isString)
return static_cast<Heap::String *>(b)->length() > 0;
-#endif
return true;
}
@@ -103,10 +97,6 @@ double Value::toNumberImpl(Value val)
case QV4::Value::Undefined_Type:
return std::numeric_limits<double>::quiet_NaN();
case QV4::Value::Managed_Type:
-#ifdef V4_BOOTSTRAP
- Q_UNIMPLEMENTED();
- Q_FALLTHROUGH();
-#else
if (String *s = val.stringValue())
return RuntimeHelpers::stringToNumber(s->toQString());
if (val.isSymbol()) {
@@ -114,16 +104,15 @@ double Value::toNumberImpl(Value val)
m.engine()->throwTypeError();
return 0;
}
- {
- Q_ASSERT(val.isObject());
- Scope scope(val.objectValue()->engine());
- ScopedValue protectThis(scope, val);
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
+ {
+ Q_ASSERT(val.isObject());
+ Scope scope(val.objectValue()->engine());
+ ScopedValue protectThis(scope, val);
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
if (scope.engine->hasException)
return 0;
return prim->toNumber();
}
-#endif
case QV4::Value::Null_Type:
case QV4::Value::Boolean_Type:
case QV4::Value::Integer_Type:
@@ -133,7 +122,6 @@ double Value::toNumberImpl(Value val)
}
}
-#ifndef V4_BOOTSTRAP
QString Value::toQStringNoThrow() const
{
switch (type()) {
@@ -248,7 +236,6 @@ QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
ScopedStringOrSymbol s(scope, v);
return s->toPropertyKey();
}
-#endif // V4_BOOTSTRAP
bool Value::sameValue(Value other) const {
if (_val == other._val)
@@ -285,7 +272,6 @@ bool Value::sameValueZero(Value other) const {
return false;
}
-#ifndef V4_BOOTSTRAP
Heap::String *Value::toString(ExecutionEngine *e, Value val)
{
return RuntimeHelpers::convertToString(e, val);
@@ -327,4 +313,3 @@ uint Value::asArrayLength(bool *ok) const
}
return idx;
}
-#endif // V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index ce85e48b72..4e901721cb 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -57,8 +57,10 @@
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
#include <private/qv4internalclass_p.h>
+#include <private/qv4staticvalue_p.h>
#include <private/qnumeric_p.h>
+#include <private/qv4calldata_p.h>
QT_BEGIN_NAMESPACE
@@ -68,84 +70,23 @@ namespace Heap {
struct Base;
}
-struct Q_QML_PRIVATE_EXPORT Value
+struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
{
- /*
- We use 8 bytes for a value and a different variant of NaN boxing. A Double
- NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
- signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
- processor, and are thus free for us to store other data. We keep pointers in there for
- managed objects, and encode the other types using the free space given to use by the unused
- bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
- only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
- pointers.)
-
- We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
- get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
- managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
- the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
- set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
- used to encode Null/Int/Bool.
-
- Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
-
- Specific bit-sequences:
- 0 = always 0
- 1 = always 1
- x = stored value
- a,b,c,d = specific bit values, see notes
-
- 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
- 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
- ------------------------------------------------------------------------+--------------
- 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
- 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
- a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
- dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
- 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
- 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
- 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
- 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
-
- Notes:
- - a: xor-ed signbit, always 1 for NaN
- - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
- - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
- - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
- and JS
- - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
- - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
- so: (val >> (64-15)) == 1
- - Null, Bool, and Int have bit 48 set, indicating integer-convertible
- - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
- any non double results in a NaN
- - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
- 63) are zero. No need to shift.
- */
-
- quint64 _val;
-
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 &rawValueRef() { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR quint64 rawValue() const { return _val; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setRawValue(quint64 raw) { _val = raw; }
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- static inline int valueOffset() { return 0; }
- static inline int tagOffset() { return 4; }
-#else // !Q_LITTLE_ENDIAN
- static inline int valueOffset() { return 4; }
- static inline int tagOffset() { return 0; }
-#endif
- static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 value() const { return _val & quint64(~quint32(0)); }
- QML_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> 32; }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTag(quint32 tag) { setTagValue(tag, value()); }
+ using HeapBasePtr = Heap::Base *;
+ using ManagedPtr = Managed *;
+
+ Value() = default;
+ constexpr Value(quint64 val) : StaticValue(val) {}
+
+ static constexpr Value fromStaticValue(StaticValue staticValue)
+ {
+ return {staticValue._val};
+ }
#if QT_POINTER_SIZE == 8
- QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
- Heap::Base *b;
+ HeapBasePtr b;
#ifdef __ia64
// Restore bits 49-47 to bits 63-61, undoing the workaround explained in
// setM below.
@@ -159,7 +100,7 @@ struct Q_QML_PRIVATE_EXPORT Value
#endif
return b;
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b)
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
memcpy(&_val, &b, 8);
#ifdef __ia64
@@ -171,15 +112,15 @@ struct Q_QML_PRIVATE_EXPORT Value
#endif
}
#elif QT_POINTER_SIZE == 4
- QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
- Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32));
- Heap::Base *b;
+ Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
+ HeapBasePtr b;
quint32 v = value();
memcpy(&b, &v, 4);
return b;
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::Base *b)
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
quint32 v;
memcpy(&v, &b, 4);
@@ -189,190 +130,11 @@ struct Q_QML_PRIVATE_EXPORT Value
# error "unsupported pointer size"
#endif
- QML_NEARLY_ALWAYS_INLINE constexpr int int_32() const
- {
- return int(value());
- }
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
- {
- setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
- }
- QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
-
- QML_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
- {
- setTagValue(quint32(ValueTypeInternal::Empty), 0);
- }
-
- // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
- // and use negative numbers here
- enum QuickType {
- QT_ManagedOrUndefined = 0,
- QT_ManagedOrUndefined1 = 1,
- QT_ManagedOrUndefined2 = 2,
- QT_ManagedOrUndefined3 = 3,
- QT_Empty = 4,
- QT_Null = 5,
- QT_Bool = 6,
- QT_Int = 7
- // all other values are doubles
- };
-
- enum Type {
- Undefined_Type = 0,
- Managed_Type = 1,
- Empty_Type = 4,
- Null_Type = 5,
- Boolean_Type = 6,
- Integer_Type = 7,
- Double_Type = 8
- };
-
- inline Type type() const {
- int t = quickType();
- if (t < QT_Empty)
- return _val ? Managed_Type : Undefined_Type;
- if (t > QT_Int)
- return Double_Type;
- return static_cast<Type>(t);
- }
-
- // Shared between 32-bit and 64-bit encoding
- enum {
- Tag_Shift = 32
- };
-
- // Used only by 64-bit encoding
- static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
- enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-15,
- IsIntegerOrBool_Shift = 64-16,
- QuickType_Shift = 64 - 17,
- IsPositiveIntShift = 31
- };
-
- static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
-
- enum class ValueTypeInternal_64 {
- Empty = Immediate_Mask_64 | 0,
- Null = Immediate_Mask_64 | 0x08000u,
- Boolean = Immediate_Mask_64 | 0x10000u,
- Integer = Immediate_Mask_64 | 0x18000u
- };
-
- // Used only by 32-bit encoding
- enum Masks {
- SilentNaNBit = 0x00040000,
- NotDouble_Mask = 0x7ffa0000,
- };
- static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
-
- enum class ValueTypeInternal_32 {
- Empty = Immediate_Mask_32 | 0,
- Null = Immediate_Mask_32 | 0x08000u,
- Boolean = Immediate_Mask_32 | 0x10000u,
- Integer = Immediate_Mask_32 | 0x18000u
- };
-
- enum {
- Managed_Type_Internal = 0
- };
-
- using ValueTypeInternal = ValueTypeInternal_64;
-
- enum {
- NaN_Mask = 0x7ff80000,
- };
-
- inline quint64 quickType() const { return (_val >> QuickType_Shift); }
-
- // used internally in property
- inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
- inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
- inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
- inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
- inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
- inline bool isNumber() const { return quickType() >= QT_Int; }
-
- inline bool isUndefined() const { return _val == 0; }
- inline bool isDouble() const { return (_val >> IsDouble_Shift); }
- inline bool isManaged() const { return _val && ((_val >> IsManagedOrUndefined_Shift) == 0); }
- inline bool isManagedOrUndefined() const { return ((_val >> IsManagedOrUndefined_Shift) == 0); }
-
- inline bool isIntOrBool() const {
- return (_val >> IsIntegerOrBool_Shift) == 3;
- }
-
- inline bool integerCompatible() const {
- Q_ASSERT(!isEmpty());
- return (_val >> IsIntegerConvertible_Shift) == 1;
- }
- static inline bool integerCompatible(Value a, Value b) {
- return a.integerCompatible() && b.integerCompatible();
- }
- static inline bool bothDouble(Value a, Value b) {
- return a.isDouble() && b.isDouble();
- }
- inline bool isNaN() const { return (tag() & 0x7ffc0000 ) == 0x00040000; }
-
- inline bool isPositiveInt() const {
-#if QT_POINTER_SIZE == 4
- return isInteger() && int_32() >= 0;
-#else
- return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
-#endif
- }
-
- QML_NEARLY_ALWAYS_INLINE double doubleValue() const {
- Q_ASSERT(isDouble());
- double d;
- Value v = *this;
- v._val ^= NaNEncodeMask;
- memcpy(&d, &v._val, 8);
- return d;
- }
- QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
- if (qt_is_nan(d))
- d = qt_qnan();
- memcpy(&_val, &d, 8);
- _val ^= NaNEncodeMask;
- Q_ASSERT(isDouble());
- }
inline bool isString() const;
inline bool isStringOrSymbol() const;
inline bool isSymbol() const;
inline bool isObject() const;
inline bool isFunctionObject() const;
- inline bool isInt32() {
- if (tag() == quint32(ValueTypeInternal::Integer))
- return true;
- if (isDouble()) {
- double d = doubleValue();
- if (isInt32(d)) {
- setInt_32(int(d));
- return true;
- }
- }
- return false;
- }
- QML_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
- int i = int(d);
- return (i == d && !(d == 0 && std::signbit(d)));
- }
- double asDouble() const {
- if (tag() == quint32(ValueTypeInternal::Integer))
- return int_32();
- return doubleValue();
- }
-
- bool booleanValue() const {
- return int_32();
- }
- int integerValue() const {
- return int_32();
- }
QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
if (!isString())
@@ -394,16 +156,16 @@ struct Q_QML_PRIVATE_EXPORT Value
return nullptr;
return reinterpret_cast<Object*>(const_cast<Value *>(this));
}
- QML_NEARLY_ALWAYS_INLINE Managed *managed() const {
+ QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const {
if (!isManaged())
return nullptr;
return reinterpret_cast<Managed*>(const_cast<Value *>(this));
}
- QML_NEARLY_ALWAYS_INLINE Heap::Base *heapObject() const {
+ QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const {
return isManagedOrUndefined() ? m() : nullptr;
}
- static inline Value fromHeapObject(Heap::Base *m)
+ static inline Value fromHeapObject(HeapBasePtr m)
{
Value v;
v.setM(m);
@@ -446,12 +208,6 @@ struct Q_QML_PRIVATE_EXPORT Value
static Heap::Object *toObject(ExecutionEngine *e, Value val);
inline bool isPrimitive() const;
- inline bool tryIntegerConversion() {
- bool b = integerCompatible();
- if (b)
- setTagValue(quint32(ValueTypeInternal::Integer), value());
- return b;
- }
template <typename T>
const T *as() const {
@@ -485,13 +241,12 @@ struct Q_QML_PRIVATE_EXPORT Value
return static_cast<const T *>(managed());
}
-#ifndef V4_BOOTSTRAP
uint asArrayLength(bool *ok) const;
-#endif
- ReturnedValue *data_ptr() { return &_val; }
- constexpr ReturnedValue asReturnedValue() const { return _val; }
- static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; }
+ static constexpr Value fromReturnedValue(ReturnedValue val)
+ {
+ return fromStaticValue(StaticValue::fromReturnedValue(val));
+ }
// As per ES specs
bool sameValue(Value other) const;
@@ -499,21 +254,45 @@ struct Q_QML_PRIVATE_EXPORT Value
inline void mark(MarkStack *markStack);
- inline static constexpr Value emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
- static inline constexpr Value fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
- static inline constexpr Value fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
- inline static constexpr Value undefinedValue() { return { 0 }; }
- static inline constexpr Value nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
- static inline Value fromDouble(double d);
- static inline Value fromUInt32(uint i);
-
- static double toInteger(double d);
- static int toInt32(double d);
- static unsigned int toUInt32(double d);
+ static double toInteger(double d) { return StaticValue::toInteger(d); }
+ static int toInt32(double d) { return StaticValue::toInt32(d); }
+ static unsigned int toUInt32(double d) { return StaticValue::toUInt32(d); }
+ inline static constexpr Value emptyValue()
+ {
+ return fromStaticValue(StaticValue::emptyValue());
+ }
+ static inline constexpr Value fromBoolean(bool b)
+ {
+ return fromStaticValue(StaticValue::fromBoolean(b));
+ }
+ static inline constexpr Value fromInt32(int i)
+ {
+ return fromStaticValue(StaticValue::fromInt32(i));
+ }
+ inline static constexpr Value undefinedValue()
+ {
+ return fromStaticValue(StaticValue::undefinedValue());
+ }
+ static inline constexpr Value nullValue()
+ {
+ return fromStaticValue(StaticValue::nullValue());
+ }
+ static inline Value fromDouble(double d)
+ {
+ return fromStaticValue(StaticValue::fromDouble(d));
+ }
+ static inline Value fromUInt32(uint i)
+ {
+ return fromStaticValue(StaticValue::fromUInt32(i));
+ }
Value &operator =(const ScopedValue &v);
- Value &operator=(ReturnedValue v) { _val = v; return *this; }
- Value &operator=(Managed *m) {
+ Value &operator=(ReturnedValue v)
+ {
+ StaticValue::operator=(v);
+ return *this;
+ }
+ Value &operator=(ManagedPtr m) {
if (!m) {
setM(nullptr);
} else {
@@ -521,7 +300,7 @@ struct Q_QML_PRIVATE_EXPORT Value
}
return *this;
}
- Value &operator=(Heap::Base *o) {
+ Value &operator=(HeapBasePtr o) {
setM(o);
return *this;
}
@@ -529,43 +308,88 @@ struct Q_QML_PRIVATE_EXPORT Value
template<typename T>
Value &operator=(const Scoped<T> &t);
};
-Q_STATIC_ASSERT(std::is_trivial< Value >::value);
+Q_STATIC_ASSERT(std::is_trivial<Value>::value);
+Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
+
+template<>
+inline StaticValue &StaticValue::operator=<Value>(const Value &value)
+{
+ _val = value._val;
+ return *this;
+}
+
+template<typename Managed>
+inline StaticValue &StaticValue::operator=(const Managed &m)
+{
+ *static_cast<Value *>(this) = m;
+ return *this;
+}
+
+template<>
+inline Value &StaticValue::asValue<Value>()
+{
+ return *static_cast<Value *>(this);
+}
+
+template<>
+inline const Value &StaticValue::asValue<Value>() const
+{
+ return *static_cast<const Value *>(this);
+}
+
+template<>
+inline Value *CallData::argValues<Value>()
+{
+ return static_cast<Value *>(static_cast<StaticValue *>(args));
+}
+
+template<>
+inline const Value *CallData::argValues<Value>() const
+{
+ return static_cast<const Value *>(static_cast<const StaticValue *>(args));
+}
+
+template<typename HeapBase>
+inline Encode::Encode(HeapBase *o)
+{
+ val = Value::fromHeapObject(o).asReturnedValue();
+}
inline void Value::mark(MarkStack *markStack)
{
- Heap::Base *o = heapObject();
+ HeapBasePtr o = heapObject();
if (o)
o->mark(markStack);
}
inline bool Value::isString() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isString;
}
bool Value::isStringOrSymbol() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isStringOrSymbol;
}
bool Value::isSymbol() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
}
inline bool Value::isObject() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isObject;
}
inline bool Value::isFunctionObject() const
{
- Heap::Base *b = heapObject();
+ HeapBasePtr b = heapObject();
return b && b->internalClass->vtable->isFunctionObject;
}
@@ -595,151 +419,12 @@ inline ReturnedValue Value::convertedToNumber() const
inline
ReturnedValue Heap::Base::asReturnedValue() const
{
- return Value::fromHeapObject(const_cast<Heap::Base *>(this)).asReturnedValue();
-}
-
-inline Value Value::fromDouble(double d)
-{
- Value v;
- v.setDouble(d);
- return v;
-}
-
-inline Value Value::fromUInt32(uint i)
-{
- Value v;
- if (i < INT_MAX) {
- v.setTagValue(quint32(ValueTypeInternal::Integer), i);
- } else {
- v.setDouble(i);
- }
- return v;
-}
-
-struct Double {
- quint64 d;
-
- Double(double dbl) {
- memcpy(&d, &dbl, sizeof(double));
- }
-
- int sign() const {
- return (d >> 63) ? -1 : 1;
- }
-
- bool isDenormal() const {
- return static_cast<int>((d << 1) >> 53) == 0;
- }
-
- int exponent() const {
- return static_cast<int>((d << 1) >> 53) - 1023;
- }
-
- quint64 significant() const {
- quint64 m = (d << 12) >> 12;
- if (!isDenormal())
- m |= (static_cast<quint64>(1) << 52);
- return m;
- }
-
- static int toInt32(double d) {
- int i = static_cast<int>(d);
- if (i == d)
- return i;
- return Double(d).toInt32();
- }
-
- int toInt32() {
- int e = exponent() - 52;
- if (e < 0) {
- if (e <= -53)
- return 0;
- return sign() * static_cast<int>(significant() >> -e);
- } else {
- if (e > 31)
- return 0;
- return sign() * (static_cast<int>(significant()) << e);
- }
- }
-};
-
-inline double Value::toInteger(double d)
-{
- if (std::isnan(d))
- return +0;
- else if (!d || std::isinf(d))
- return d;
- return d >= 0 ? std::floor(d) : std::ceil(d);
-}
-
-inline int Value::toInt32(double value)
-{
- return Double::toInt32(value);
-}
-
-inline unsigned int Value::toUInt32(double d)
-{
- return static_cast<uint>(toInt32(d));
+ return Value::fromHeapObject(const_cast<Value::HeapBasePtr>(this)).asReturnedValue();
}
// For source compat with older code in other modules
using Primitive = Value;
-struct Encode {
- static constexpr ReturnedValue undefined() {
- return Value::undefinedValue().asReturnedValue();
- }
- static constexpr ReturnedValue null() {
- return Value::nullValue().asReturnedValue();
- }
-
- explicit constexpr Encode(bool b)
- : val(Value::fromBoolean(b).asReturnedValue())
- {
- }
- explicit Encode(double d) {
- val = Value::fromDouble(d).asReturnedValue();
- }
- explicit constexpr Encode(int i)
- : val(Value::fromInt32(i).asReturnedValue())
- {
- }
- explicit Encode(uint i) {
- val = Value::fromUInt32(i).asReturnedValue();
- }
- explicit constexpr Encode(ReturnedValue v)
- : val(v)
- {
- }
- constexpr Encode(Value v)
- : val(v.asReturnedValue())
- {
- }
-
- explicit Encode(Heap::Base *o) {
- val = Value::fromHeapObject(o).asReturnedValue();
- }
-
- explicit Encode(Value *o) {
- Q_ASSERT(o);
- val = o->asReturnedValue();
- }
-
- static ReturnedValue smallestNumber(double d) {
- if (Value::isInt32(d))
- return Encode(static_cast<int>(d));
- else
- return Encode(d);
- }
-
- constexpr operator ReturnedValue() const {
- return val;
- }
- quint64 val;
-private:
- explicit Encode(void *);
-};
-
template<typename T>
ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
@@ -796,8 +481,8 @@ inline double Value::toInteger() const
template <size_t o>
struct HeapValue : Value {
static Q_CONSTEXPR size_t offset = o;
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ HeapBasePtr base() {
+ HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
Q_ASSERT(base->inUse());
return base;
}
@@ -805,7 +490,7 @@ struct HeapValue : Value {
void set(EngineBase *e, const Value &newVal) {
WriteBarrier::write(e, base(), data_ptr(), newVal.asReturnedValue());
}
- void set(EngineBase *e, Heap::Base *b) {
+ void set(EngineBase *e, HeapBasePtr b) {
WriteBarrier::write(e, base(), data_ptr(), b->asReturnedValue());
}
};
@@ -817,8 +502,9 @@ struct ValueArray {
uint alloc;
Value values[1];
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Value::HeapBasePtr base() {
+ Value::HeapBasePtr base = reinterpret_cast<Value::HeapBasePtr>(this)
+ - (offset/sizeof(Heap::Base));
Q_ASSERT(base->inUse());
return base;
}
@@ -826,7 +512,7 @@ struct ValueArray {
void set(EngineBase *e, uint index, Value v) {
WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
}
- void set(EngineBase *e, uint index, Heap::Base *b) {
+ void set(EngineBase *e, uint index, Value::HeapBasePtr b) {
WriteBarrier::write(e, base(), values[index].data_ptr(), Value::fromHeapObject(b).asReturnedValue());
}
inline const Value &operator[] (uint index) const {
@@ -855,12 +541,12 @@ struct ValueArray {
const Value *end = v + alloc;
if (alloc > 32*1024) {
// drain from time to time to avoid overflows in the js stack
- Heap::Base **currentBase = markStack->top;
+ Value::HeapBasePtr *currentBase = markStack->top;
while (v < end) {
v->mark(markStack);
++v;
if (markStack->top >= currentBase + 32*1024) {
- Heap::Base **oldBase = markStack->base;
+ Value::HeapBasePtr *oldBase = markStack->base;
markStack->base = currentBase;
markStack->drain();
markStack->base = oldBase;
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index e4d8bcaafc..e117e509ab 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -41,7 +41,6 @@
#include "qv4functionobject_p.h"
#include "qv4objectproto_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qv8engine_p.h>
#include <private/qv4qobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 4ce8d97ee5..27d518f5c6 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -38,11 +38,11 @@
****************************************************************************/
#include "qv4vme_moth_p.h"
-#include "qv4instr_moth_p.h"
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
+#include <private/qv4instr_moth_p.h>
#include <private/qv4value_p.h>
#include <private/qv4debugging_p.h>
#include <private/qv4function_p.h>
@@ -56,17 +56,20 @@
#include <private/qv4profiling_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4generatorobject_p.h>
+#include <private/qv4alloca_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
-#include "qv4alloca_p.h"
-
+#if QT_CONFIG(qml_jit)
#include <private/qv4baselinejit_p.h>
+#endif
#include <qtqml_tracepoints_p.h>
#undef COUNT_INSTRUCTIONS
+enum { ShowWhenDeoptimiationHappens = 0 };
+
extern "C" {
// This is the interface to Qt Creator's (new) QML debugger.
@@ -202,7 +205,7 @@ int qt_v4DebuggerHook(const char *json)
return ProtocolVersion; // Version number.
}
- int version = ob.value(QLatin1Literal("version")).toString().toInt();
+ int version = ob.value(QLatin1String("version")).toString().toInt();
if (version != ProtocolVersion) {
return -WrongProtocol;
}
@@ -345,73 +348,9 @@ static struct InstrCount {
#undef CHECK_EXCEPTION
#endif
#define CHECK_EXCEPTION \
- if (engine->hasException) \
+ if (engine->hasException || engine->isInterrupted.loadAcquire()) \
goto handleUnwind
-static inline void traceJumpTakesTruePath(bool truePathTaken, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= truePathTaken ? quint8(ObservedTraceValues::TruePathTaken)
- : quint8(ObservedTraceValues::FalsePathTaken);
-#else
- Q_UNUSED(truePathTaken);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceValue(ReturnedValue acc, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- switch (Primitive::fromReturnedValue(acc).type()) {
- case QV4::Value::Integer_Type:
- *traceInfo |= quint8(ObservedTraceValues::Integer);
- break;
- case QV4::Value::Boolean_Type:
- *traceInfo |= quint8(ObservedTraceValues::Boolean);
- break;
- case QV4::Value::Double_Type:
- *traceInfo |= quint8(ObservedTraceValues::Double);
- break;
- default:
- *traceInfo |= quint8(ObservedTraceValues::Other);
- break;
- }
-#else
- Q_UNUSED(acc);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceDoubleValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Double);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceOtherValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Other);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
{
Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
@@ -425,7 +364,7 @@ static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
static inline const QV4::Value &constant(Function *function, int index)
{
- return function->compilationUnit->constants[index];
+ return function->compilationUnit->constants[index].asValue<Value>();
}
static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
@@ -491,7 +430,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
if (debugger == nullptr) {
if (function->jittedCode == nullptr) {
if (engine->canJIT(function))
@@ -499,16 +438,20 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
else
++function->interpreterCallCount;
}
- if (function->jittedCode != nullptr)
- return function->jittedCode(frame, engine);
}
-#endif // V4_ENABLE_JIT
+#endif // QT_CONFIG(qml_jit)
// interpreter
if (debugger)
debugger->enteringFunction();
- ReturnedValue result = interpret(frame, engine, function->codeData);
+ ReturnedValue result;
+ if (function->jittedCode != nullptr && debugger == nullptr) {
+ result = function->jittedCode(frame, engine);
+ } else {
+ // interpreter
+ result = interpret(frame, engine, function->codeData);
+ }
if (debugger)
debugger->leavingFunction(result);
@@ -519,15 +462,10 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
{
QV4::Function *function = frame->v4Function;
- QV4::Value &accumulator = frame->jsFrame->accumulator;
+ QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
- if (function->tracingEnabled()) {
- for (int i = 0; i < int(function->nFormals); ++i)
- traceValue(frame->jsFrame->argument(i), function, i);
- }
-
MOTH_JUMP_TABLE;
for (;;) {
@@ -586,7 +524,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -599,7 +536,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadScopedLocal)
auto cc = getScope(stack, scope);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -613,88 +549,73 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(LoadRuntimeString)
MOTH_BEGIN_INSTR(MoveRegExp)
- STACK_VALUE(destReg) = Runtime::method_regexpLiteral(engine, regExpId);
+ STACK_VALUE(destReg) = Runtime::RegexpLiteral::call(engine, regExpId);
MOTH_END_INSTR(MoveRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
- acc = Runtime::method_closure(engine, value);
+ acc = Runtime::Closure::call(engine, value);
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
STORE_IP();
- acc = Runtime::method_loadName(engine, name);
+ acc = Runtime::LoadName::call(engine, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
STORE_IP();
- QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
acc = l->globalGetter(l, engine);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
STORE_IP();
- QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
acc = l->qmlContextPropertyGetter(l, engine, nullptr);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameStrict)
STORE_IP();
STORE_ACC();
- Runtime::method_storeNameStrict(engine, name, accumulator);
+ Runtime::StoreNameStrict::call(engine, name, accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(StoreNameSloppy)
STORE_IP();
STORE_ACC();
- Runtime::method_storeNameSloppy(engine, name, accumulator);
+ Runtime::StoreNameSloppy::call(engine, name, accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreNameSloppy)
MOTH_BEGIN_INSTR(LoadElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- acc = Runtime::method_loadElement_traced(engine, STACK_VALUE(base), accumulator, function->traceInfo(traceSlot));
- traceValue(acc, function, traceSlot);
-#else
- Q_UNUSED(traceSlot);
- acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator);
-#endif
+ acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- Runtime::method_storeElement_traced(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator, function->traceInfo(traceSlot));
-#else
- Q_UNUSED(traceSlot);
- Runtime::method_storeElement(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
-#endif
+ Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_loadProperty(engine, accumulator, name);
+ acc = Runtime::LoadProperty::call(engine, accumulator, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
STORE_IP();
STORE_ACC();
- QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
if (accumulator.isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2")
@@ -706,20 +627,19 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = l->getter(l, engine, accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
STORE_IP();
STORE_ACC();
- Runtime::method_storeProperty(engine, STACK_VALUE(base), name, accumulator);
+ Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(SetLookup)
STORE_IP();
STORE_ACC();
- QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict())
engine->throwTypeError();
CHECK_EXCEPTION;
@@ -727,14 +647,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadSuperProperty)
STORE_IP();
- acc = Runtime::method_loadSuperProperty(engine, STACK_VALUE(property));
+ acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property));
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadSuperProperty)
MOTH_BEGIN_INSTR(StoreSuperProperty)
STORE_IP();
STORE_ACC();
- Runtime::method_storeSuperProperty(engine, STACK_VALUE(property), accumulator);
+ Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreSuperProperty)
@@ -765,7 +685,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
STORE_ACC();
- acc = Runtime::method_iteratorNextForYieldStar(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
+ acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
CHECK_EXCEPTION;
MOTH_END_INSTR(IteratorNextForYieldStar)
@@ -779,7 +699,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
Value undef = Value::undefinedValue();
acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
@@ -791,19 +710,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
- acc = Runtime::method_callProperty(engine, stack + base, name, stack + argv, argc);
+ acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
STORE_IP();
- Lookup *l = function->compilationUnit->runtimeLookups + lookupIndex;
+ Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
if (stack[base].isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2")
@@ -826,49 +743,42 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
- acc = Runtime::method_callElement(engine, stack + base, STACK_VALUE(index), stack + argv, argc);
+ acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
- acc = Runtime::method_callName(engine, name, stack + argv, argc);
+ acc = Runtime::CallName::call(engine, name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
STORE_IP();
- acc = Runtime::method_callPossiblyDirectEval(engine, stack + argv, argc);
+ acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
STORE_IP();
- acc = Runtime::method_callGlobalLookup(engine, index, stack + argv, argc);
+ acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
STORE_IP();
- acc = Runtime::method_callQmlContextPropertyLookup(engine, index, stack + argv, argc);
+ acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
STORE_IP();
- acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
+ acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(TailCall)
@@ -877,21 +787,21 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
*engine->jsAlloca(1) = Primitive::fromInt32(argv);
*engine->jsAlloca(1) = STACK_VALUE(thisObject);
*engine->jsAlloca(1) = STACK_VALUE(func);
- return Runtime::method_tailCall(frame, engine);
+ return Runtime::TailCall::call(frame, engine);
CHECK_EXCEPTION;
MOTH_END_INSTR(TailCall)
MOTH_BEGIN_INSTR(Construct)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_construct(engine, STACK_VALUE(func), ACC, stack + argv, argc);
+ acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(Construct)
MOTH_BEGIN_INSTR(ConstructWithSpread)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_constructWithSpread(engine, STACK_VALUE(func), ACC, stack + argv, argc);
+ acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(ConstructWithSpread)
@@ -918,7 +828,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
if (ACC.isEmpty()) {
STORE_IP();
- Runtime::method_throwReferenceError(engine, name);
+ Runtime::ThrowReferenceError::call(engine, name);
goto handleUnwind;
}
MOTH_END_INSTR(DeadTemporalZoneCheck)
@@ -926,7 +836,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(ThrowException)
STORE_IP();
STORE_ACC();
- Runtime::method_throwException(engine, accumulator);
+ Runtime::ThrowException::call(engine, accumulator);
goto handleUnwind;
MOTH_END_INSTR(ThrowException)
@@ -944,40 +854,36 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(SetException)
MOTH_BEGIN_INSTR(PushCatchContext)
- ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, index, name);
+ Runtime::PushCatchContext::call(engine, index, name);
MOTH_END_INSTR(PushCatchContext)
MOTH_BEGIN_INSTR(CreateCallContext)
- stack[CallData::Context] = ExecutionContext::newCallContext(frame);
+ Runtime::PushCallContext::call(frame);
MOTH_END_INSTR(CreateCallContext)
MOTH_BEGIN_INSTR(PushWithContext)
STORE_IP();
STORE_ACC();
- auto ctx = Runtime::method_createWithContext(engine, stack);
+ acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]);
CHECK_EXCEPTION;
- STACK_VALUE(CallData::Context) = ctx;
MOTH_END_INSTR(PushWithContext)
MOTH_BEGIN_INSTR(PushBlockContext)
STORE_ACC();
- ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- STACK_VALUE(CallData::Context) = Runtime::method_createBlockContext(c, index);
+ Runtime::PushBlockContext::call(engine, index);
MOTH_END_INSTR(PushBlockContext)
MOTH_BEGIN_INSTR(CloneBlockContext)
STORE_ACC();
- ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- STACK_VALUE(CallData::Context) = Runtime::method_cloneBlockContext(c);
+ Runtime::CloneBlockContext::call(engine);
MOTH_END_INSTR(CloneBlockContext)
MOTH_BEGIN_INSTR(PushScriptContext)
- STACK_VALUE(CallData::Context) = Runtime::method_createScriptContext(engine, index);
+ Runtime::PushScriptContext::call(engine, index);
MOTH_END_INSTR(PushScriptContext)
MOTH_BEGIN_INSTR(PopScriptContext)
- STACK_VALUE(CallData::Context) = Runtime::method_popScriptContext(engine);
+ Runtime::PopScriptContext::call(engine);
MOTH_END_INSTR(PopScriptContext)
MOTH_BEGIN_INSTR(PopContext)
@@ -988,14 +894,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(GetIterator)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_getIterator(engine, accumulator, iterator);
+ acc = Runtime::GetIterator::call(engine, accumulator, iterator);
CHECK_EXCEPTION;
MOTH_END_INSTR(GetIterator)
MOTH_BEGIN_INSTR(IteratorNext)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_iteratorNext(engine, accumulator, &STACK_VALUE(value));
+ acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
STACK_VALUE(done) = acc;
CHECK_EXCEPTION;
MOTH_END_INSTR(IteratorNext)
@@ -1003,98 +909,74 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(IteratorClose)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_iteratorClose(engine, accumulator, STACK_VALUE(done));
+ acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done));
CHECK_EXCEPTION;
MOTH_END_INSTR(IteratorClose)
MOTH_BEGIN_INSTR(DestructureRestElement)
STORE_IP();
STORE_ACC();
- acc = Runtime::method_destructureRestElement(engine, ACC);
+ acc = Runtime::DestructureRestElement::call(engine, ACC);
CHECK_EXCEPTION;
MOTH_END_INSTR(DestructureRestElement)
MOTH_BEGIN_INSTR(DeleteProperty)
- if (!Runtime::method_deleteProperty(engine, STACK_VALUE(base), STACK_VALUE(index))) {
- if (function->isStrict()) {
- STORE_IP();
- engine->throwTypeError();
- goto handleUnwind;
- }
- acc = Encode(false);
- } else {
- acc = Encode(true);
- }
+ acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(DeleteProperty)
MOTH_BEGIN_INSTR(DeleteName)
- if (!Runtime::method_deleteName(engine, name)) {
- if (function->isStrict()) {
- STORE_IP();
- QString n = function->compilationUnit->runtimeStrings[name]->toQString();
- engine->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(n));
- goto handleUnwind;
- }
- acc = Encode(false);
- } else {
- acc = Encode(true);
- }
+ acc = Runtime::DeleteName::call(engine, function, name);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(DeleteName)
MOTH_BEGIN_INSTR(TypeofName)
- acc = Runtime::method_typeofName(engine, name);
+ acc = Runtime::TypeofName::call(engine, name);
MOTH_END_INSTR(TypeofName)
MOTH_BEGIN_INSTR(TypeofValue)
STORE_ACC();
- acc = Runtime::method_typeofValue(engine, accumulator);
+ acc = Runtime::TypeofValue::call(engine, accumulator);
MOTH_END_INSTR(TypeofValue)
MOTH_BEGIN_INSTR(DeclareVar)
- Runtime::method_declareVar(engine, isDeletable, varName);
+ Runtime::DeclareVar::call(engine, isDeletable, varName);
MOTH_END_INSTR(DeclareVar)
MOTH_BEGIN_INSTR(DefineArray)
QV4::Value *arguments = stack + args;
- acc = Runtime::method_arrayLiteral(engine, arguments, argc);
+ acc = Runtime::ArrayLiteral::call(engine, arguments, argc);
MOTH_END_INSTR(DefineArray)
MOTH_BEGIN_INSTR(DefineObjectLiteral)
QV4::Value *arguments = stack + args;
- acc = Runtime::method_objectLiteral(engine, internalClassId, arguments, argc);
+ acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc);
MOTH_END_INSTR(DefineObjectLiteral)
MOTH_BEGIN_INSTR(CreateClass)
- acc = Runtime::method_createClass(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
+ acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
MOTH_END_INSTR(CreateClass)
MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
- acc = Runtime::method_createMappedArgumentsObject(engine);
+ acc = Runtime::CreateMappedArgumentsObject::call(engine);
MOTH_END_INSTR(CreateMappedArgumentsObject)
MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
- acc = Runtime::method_createUnmappedArgumentsObject(engine);
+ acc = Runtime::CreateUnmappedArgumentsObject::call(engine);
MOTH_END_INSTR(CreateUnmappedArgumentsObject)
MOTH_BEGIN_INSTR(CreateRestParameter)
- acc = Runtime::method_createRestParameter(engine, argIndex);
+ acc = Runtime::CreateRestParameter::call(engine, argIndex);
MOTH_END_INSTR(CreateRestParameter)
MOTH_BEGIN_INSTR(ConvertThisToObject)
- Value *t = &stack[CallData::This];
- if (!t->isObject()) {
- if (t->isNullOrUndefined()) {
- *t = engine->globalObject->asReturnedValue();
- } else {
- STORE_ACC();
- *t = t->toObject(engine)->asReturnedValue();
- CHECK_EXCEPTION;
- }
- }
+ STORE_ACC();
+ stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(ConvertThisToObject)
MOTH_BEGIN_INSTR(LoadSuperConstructor)
- acc = Runtime::method_loadSuperConstructor(engine, stack[CallData::Function]);
+ acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]);
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadSuperConstructor)
@@ -1114,7 +996,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = ACC.int_32();
else
takeJump = ACC.toBoolean();
- traceJumpTakesTruePath(takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpTrue)
@@ -1125,7 +1006,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = !ACC.int_32();
else
takeJump = !ACC.toBoolean();
- traceJumpTakesTruePath(!takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpFalse)
@@ -1140,6 +1020,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
code += offset;
MOTH_END_INSTR(JumpNotUndefined)
+ MOTH_BEGIN_INSTR(CheckException)
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)
@@ -1176,7 +1060,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(left.int_32() == ACC.int_32());
} else {
STORE_ACC();
- acc = Encode(bool(Runtime::method_compareEqual(left, accumulator)));
+ acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpEq)
@@ -1187,7 +1071,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(bool(left.int_32() != ACC.int_32()));
} else {
STORE_ACC();
- acc = Encode(bool(!Runtime::method_compareEqual(left, accumulator)));
+ acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpNe)
@@ -1200,7 +1084,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(left.asDouble() > ACC.asDouble());
} else {
STORE_ACC();
- acc = Encode(bool(Runtime::method_compareGreaterThan(left, accumulator)));
+ acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpGt)
@@ -1213,7 +1097,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(left.asDouble() >= ACC.asDouble());
} else {
STORE_ACC();
- acc = Encode(bool(Runtime::method_compareGreaterEqual(left, accumulator)));
+ acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpGe)
@@ -1226,7 +1110,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(left.asDouble() < ACC.asDouble());
} else {
STORE_ACC();
- acc = Encode(bool(Runtime::method_compareLessThan(left, accumulator)));
+ acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpLt)
@@ -1239,7 +1123,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(left.asDouble() <= ACC.asDouble());
} else {
STORE_ACC();
- acc = Encode(bool(Runtime::method_compareLessEqual(left, accumulator)));
+ acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpLe)
@@ -1249,7 +1133,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = Encode(true);
} else {
STORE_ACC();
- acc = Encode(bool(RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator)));
+ acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpStrictEqual)
@@ -1257,7 +1141,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(CmpStrictNotEqual)
if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
STORE_ACC();
- acc = Encode(!RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator));
+ acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
} else {
acc = Encode(false);
@@ -1266,13 +1150,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(CmpIn)
STORE_ACC();
- acc = Runtime::method_in(engine, STACK_VALUE(lhs), accumulator);
+ acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(CmpIn)
MOTH_BEGIN_INSTR(CmpInstanceOf)
STORE_ACC();
- acc = Runtime::method_instanceof(engine, STACK_VALUE(lhs), ACC);
+ acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC);
CHECK_EXCEPTION;
MOTH_END_INSTR(CmpInstanceOf)
@@ -1296,17 +1180,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
int a = ACC.int_32();
if (a == 0 || a == std::numeric_limits<int>::min()) {
acc = Encode(-static_cast<double>(a));
- traceDoubleValue(function, traceSlot);
} else {
- acc = sub_int32(0, ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(0, ACC.int_32());
}
} else if (ACC.isDouble()) {
acc ^= (1ull << 63); // simply flip sign bit
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(-ACC.toNumberImpl());
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(UMinus)
@@ -1317,57 +1198,49 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Increment)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = add_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = add_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() + 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() + 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = sub_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = sub_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() - 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() - 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = add_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = add_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() + ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
- acc = Runtime::method_add(engine, left, accumulator);
+ acc = Runtime::Add::call(engine, left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(Sub)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = sub_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() - ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
- acc = Runtime::method_sub(left, accumulator);
+ acc = Runtime::Sub::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Sub)
@@ -1376,7 +1249,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
double base = left.toNumber();
double exp = ACC.toNumber();
if (qIsInf(exp) && (base == 1 || base == -1))
- acc = Encode(qSNaN());
+ acc = Encode(qQNaN());
else
acc = Encode(pow(base,exp));
MOTH_END_INSTR(Exp)
@@ -1384,29 +1257,26 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Mul)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = mul_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = mul_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() * ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
- acc = Runtime::method_mul(left, accumulator);
+ acc = Runtime::Mul::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
STORE_ACC();
- acc = Runtime::method_div(STACK_VALUE(lhs), accumulator);
+ acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
STORE_ACC();
- acc = Runtime::method_mod(STACK_VALUE(lhs), accumulator);
+ acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(BitAnd)
@@ -1493,7 +1363,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(ThrowOnNullOrUndefined)
MOTH_BEGIN_INSTR(GetTemplateObject)
- acc = RuntimeHelpers::getTemplateObject(function, index);
+ acc = Runtime::GetTemplateObject::call(function, index);
MOTH_END_INSTR(GetTemplateObject)
MOTH_BEGIN_INSTR(Debug)
@@ -1504,7 +1374,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(Debug)
handleUnwind:
- Q_ASSERT(engine->hasException || frame->unwindLevel);
+ // We do start the exception handler in case of isInterrupted. The exception handler will
+ // immediately abort, due to the same isInterrupted. We don't skip the exception handler
+ // because the current behavior is easier to implement in the JIT.
+ Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel);
if (!frame->unwindHandler) {
acc = Encode::undefined();
return acc;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 8a76e60f20..b3944f5454 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -52,6 +52,7 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index aff1ae82d7..9dda104cd1 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -58,7 +58,7 @@ namespace QV4 {
struct Lookup;
-struct OwnPropertyKeyIterator {
+struct Q_QML_PRIVATE_EXPORT OwnPropertyKeyIterator {
virtual ~OwnPropertyKeyIterator() = 0;
virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0;
};
@@ -90,8 +90,8 @@ struct VTable
typedef bool (*ResolveLookupSetter)(Object *, ExecutionEngine *, Lookup *, const Value &);
const VTable * const parent;
- quint32 inlinePropertyOffset : 16;
- quint32 nInlineProperties : 16;
+ quint16 inlinePropertyOffset;
+ quint16 nInlineProperties;
quint8 isExecutionContext;
quint8 isString;
quint8 isObject;
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
index 7956e4a9a1..0bc8e90d27 100644
--- a/src/qml/memory/memory.pri
+++ b/src/qml/memory/memory.pri
@@ -1,15 +1,11 @@
INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
-!qmldevtools_build {
SOURCES += \
$$PWD/qv4mm.cpp \
HEADERS += \
$$PWD/qv4mm_p.h \
$$PWD/qv4mmdefs_p.h \
- $$PWD/qv4writebarrier_p.h
-}
-
-HEADERS += \
+ $$PWD/qv4writebarrier_p.h \
$$PWD/qv4heap_p.h
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 07af5a6f7a..d7cfa193e6 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -234,7 +234,7 @@ struct QQmlQPointer {
}
T *data() const {
- return d == nullptr || d->strongref.load() == 0 ? nullptr : qObject;
+ return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : qObject;
}
operator T*() const { return data(); }
inline T* operator->() const { return data(); }
@@ -247,7 +247,7 @@ struct QQmlQPointer {
}
bool isNull() const Q_DECL_NOTHROW
{
- return d == nullptr || qObject == nullptr || d->strongref.load() == 0;
+ return d == nullptr || qObject == nullptr || d->strongref.loadRelaxed() == 0;
}
private:
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index cac68bdcaf..c7f52eac6b 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -46,6 +46,7 @@
#include <QtCore/qalgorithms.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qloggingcategory.h>
+#include <private/qv4alloca_p.h>
#include <qqmlengine.h>
#include "PageReservation.h"
#include "PageAllocation.h"
@@ -59,10 +60,10 @@
#include <iostream>
#include <cstdlib>
#include <algorithm>
-#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
#include "qv4mapobject_p.h"
#include "qv4setobject_p.h"
+#include "qv4writebarrier_p.h"
//#define MM_STATS
@@ -111,7 +112,11 @@ enum {
struct MemorySegment {
enum {
+#ifdef Q_OS_RTEMS
+ NumChunks = sizeof(quint64),
+#else
NumChunks = 8*sizeof(quint64),
+#endif
SegmentSize = NumChunks*Chunk::ChunkSize,
};
@@ -846,7 +851,7 @@ MarkStack::MarkStack(ExecutionEngine *engine)
{
base = (Heap::Base **)engine->gcStack->base();
top = base;
- limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4;
+ limit = base + engine->maxGCStackSize()/sizeof(Heap::Base)*3/4;
}
void MarkStack::drain()
@@ -999,12 +1004,12 @@ bool MemoryManager::shouldRunGC() const
return false;
}
-size_t dumpBins(BlockAllocator *b, bool printOutput = true)
+static size_t dumpBins(BlockAllocator *b, const char *title)
{
const QLoggingCategory &stats = lcGcAllocatorStats();
size_t totalSlotMem = 0;
- if (printOutput)
- qDebug(stats) << "Slot map:";
+ if (title)
+ qDebug(stats) << "Slot map for" << title << "allocator:";
for (uint i = 0; i < BlockAllocator::NumBins; ++i) {
uint nEntries = 0;
HeapItem *h = b->freeBins[i];
@@ -1013,7 +1018,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
totalSlotMem += h->freeData.availableSlots;
h = h->freeData.next;
}
- if (printOutput)
+ if (title)
qDebug(stats) << " number of entries in slot" << i << ":" << nEntries;
}
SDUMP() << " large slot map";
@@ -1023,7 +1028,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
h = h->freeData.next;
}
- if (printOutput)
+ if (title)
qDebug(stats) << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
return totalSlotMem*Chunk::SlotSize;
}
@@ -1064,7 +1069,8 @@ void MemoryManager::runGC()
size_t oldChunks = blockAllocator.chunks.size();
qDebug(stats) << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks";
qDebug(stats) << "Fragmented memory before GC" << (totalMem - usedBefore);
- dumpBins(&blockAllocator);
+ dumpBins(&blockAllocator, "Block");
+ dumpBins(&icAllocator, "InternalClass");
QElapsedTimer t;
t.start();
@@ -1082,7 +1088,8 @@ void MemoryManager::runGC()
qDebug(stats) << " new unmanaged heap:" << unmanagedHeapSize;
qDebug(stats) << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
}
- size_t memInBins = dumpBins(&blockAllocator);
+ size_t memInBins = dumpBins(&blockAllocator, "Block")
+ + dumpBins(&icAllocator, "InternalClasss");
qDebug(stats) << "Marked object in" << markTime << "us.";
qDebug(stats) << " " << markStackSize << "objects marked";
qDebug(stats) << "Sweeped object in" << sweepTime << "us.";
@@ -1104,7 +1111,8 @@ void MemoryManager::runGC()
qDebug(stats) << "Used memory after GC:" << usedAfter;
qDebug(stats) << "Freed up bytes :" << (usedBefore - usedAfter);
qDebug(stats) << "Freed up chunks :" << (oldChunks - blockAllocator.chunks.size());
- size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
+ size_t lost = blockAllocator.allocatedMem() + icAllocator.allocatedMem()
+ - memInBins - usedAfter;
if (lost)
qDebug(stats) << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
if (largeItemsBefore || largeItemsAfter) {
@@ -1126,7 +1134,9 @@ void MemoryManager::runGC()
if (aggressiveGC) {
// ensure we don't 'loose' any memory
Q_ASSERT(blockAllocator.allocatedMem()
- == blockAllocator.usedMem() + dumpBins(&blockAllocator, false));
+ == blockAllocator.usedMem() + dumpBins(&blockAllocator, nullptr));
+ Q_ASSERT(icAllocator.allocatedMem()
+ == icAllocator.usedMem() + dumpBins(&icAllocator, nullptr));
}
usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep + icAllocator.usedSlotsAfterLastSweep;
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
index 8b04aa6cb1..c65cfc0269 100644
--- a/src/qml/memory/qv4writebarrier_p.h
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -51,7 +51,6 @@
//
#include <private/qv4global_p.h>
-#include <private/qv4enginebase_p.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +59,7 @@ QT_BEGIN_NAMESPACE
#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
namespace QV4 {
+struct EngineBase;
namespace WriteBarrier {
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri
index 2c0175c94b..e15730f5d1 100644
--- a/src/qml/parser/parser.pri
+++ b/src/qml/parser/parser.pri
@@ -4,11 +4,9 @@ HEADERS += \
$$PWD/qqmljsastvisitor_p.h \
$$PWD/qqmljsengine_p.h \
$$PWD/qqmljslexer_p.h \
- $$PWD/qqmljsmemorypool_p.h \
$$PWD/qqmljsglobal_p.h \
$$PWD/qqmljskeywords_p.h \
$$PWD/qqmljsengine_p.h \
- $$PWD/qqmljsglobal_p.h \
$$PWD/qqmljssourcelocation_p.h
SOURCES += \
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 4ad9057ced..8ac7633ae0 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -58,6 +58,7 @@
%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--"
%token T_NEW "new" T_NOT "!" T_NOT_EQ "!="
%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|"
+%token T_VERSION_NUMBER "version number"
%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+"
%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?"
%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
@@ -245,6 +246,7 @@
#include <private/qqmljsgrammar_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmljsengine_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
@@ -297,6 +299,9 @@ public:
AST::ExportsList *ExportsList;
AST::ExportClause *ExportClause;
AST::ExportDeclaration *ExportDeclaration;
+ AST::TypeAnnotation *TypeAnnotation;
+ AST::TypeArgumentList *TypeArgumentList;
+ AST::Type *Type;
AST::UiProgram *UiProgram;
AST::UiHeaderItemList *UiHeaderItemList;
@@ -314,6 +319,7 @@ public:
AST::UiArrayMemberList *UiArrayMemberList;
AST::UiQualifiedId *UiQualifiedId;
AST::UiEnumMemberList *UiEnumMemberList;
+ AST::UiVersionSpecifier *UiVersionSpecifier;
};
public:
@@ -365,7 +371,7 @@ public:
inline DiagnosticMessage diagnosticMessage() const
{
for (const DiagnosticMessage &d : diagnostic_messages) {
- if (d.kind != DiagnosticMessage::Warning)
+ if (d.type != QtWarningMsg)
return d;
}
@@ -376,10 +382,10 @@ public:
{ return diagnosticMessage().message; }
inline int errorLineNumber() const
- { return diagnosticMessage().loc.startLine; }
+ { return diagnosticMessage().line; }
inline int errorColumnNumber() const
- { return diagnosticMessage().loc.startColumn; }
+ { return diagnosticMessage().column; }
protected:
bool parse(int startToken);
@@ -403,13 +409,26 @@ protected:
void pushToken(int token);
int lookaheadToken(Lexer *lexer);
+ static DiagnosticMessage compileError(const AST::SourceLocation &location,
+ const QString &message, QtMsgType kind = QtCriticalMsg)
+ {
+ DiagnosticMessage error;
+ error.line = location.startLine;
+ error.column = location.startColumn;
+ error.message = message;
+ error.type = kind;
+ return error;
+ }
+
void syntaxError(const AST::SourceLocation &location, const char *message) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, QLatin1String(message)));
+ diagnostic_messages.append(compileError(location, QLatin1String(message)));
}
void syntaxError(const AST::SourceLocation &location, const QString &message) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, message));
+ diagnostic_messages.append(compileError(location, message));
}
+ bool ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnTypeAnnotation, AST::FormalParameterList *formals);
+
protected:
Engine *driver;
MemoryPool *pool;
@@ -580,6 +599,21 @@ int Parser::lookaheadToken(Lexer *lexer)
return yytoken;
}
+bool Parser::ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnValueAnnotation, AST::FormalParameterList *formals)
+{
+ for (auto formal = formals; formal; formal = formal->next) {
+ if (formal->element && formal->element->typeAnnotation) {
+ syntaxError(formal->element->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in function parameters in JavaScript functions");
+ return false;
+ }
+ }
+ if (returnValueAnnotation) {
+ syntaxError(returnValueAnnotation->firstSourceLocation(), "Type annotations are not permitted for the return value of JavaScript functions");
+ return false;
+ }
+ return true;
+}
+
//#define PARSER_DEBUG
bool Parser::parse(int startToken)
@@ -769,8 +803,10 @@ UiHeaderItemList: UiHeaderItemList UiImport;
PragmaId: JsIdentifier;
-UiPragma: T_PRAGMA PragmaId T_AUTOMATIC_SEMICOLON;
-UiPragma: T_PRAGMA PragmaId T_SEMICOLON;
+Semicolon: T_AUTOMATIC_SEMICOLON;
+Semicolon: T_SEMICOLON;
+
+UiPragma: T_PRAGMA PragmaId Semicolon;
/.
case $rule_number: {
AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2));
@@ -782,28 +818,52 @@ UiPragma: T_PRAGMA PragmaId T_SEMICOLON;
ImportId: MemberExpression;
-UiImport: UiImportHead T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_SEMICOLON;
+UiImport: UiImportHead Semicolon;
/.
case $rule_number: {
sym(1).UiImport->semicolonToken = loc(2);
} break;
./
-UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON;
+UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER;
/.
case $rule_number: {
- sym(1).UiImport->versionToken = loc(2);
+ auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval);
+ version->majorToken = loc(1);
+ version->minorToken = loc(3);
+ sym(1).UiVersionSpecifier = version;
+ } break;
+./
+
+
+UiVersionSpecifier: T_VERSION_NUMBER;
+/.
+ case $rule_number: {
+ auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0);
+ version->majorToken = loc(1);
+ sym(1).UiVersionSpecifier = version;
+ } break;
+./
+
+UiImport: UiImportHead UiVersionSpecifier Semicolon;
+/.
+ case $rule_number: {
+ auto versionToken = loc(2);
+ auto version = sym(2).UiVersionSpecifier;
+ sym(1).UiImport->version = version;
+ if (version->minorToken.isValid()) {
+ versionToken.length += version->minorToken.length + (version->minorToken.offset - versionToken.offset - versionToken.length);
+ }
+ sym(1).UiImport->versionToken = versionToken;
sym(1).UiImport->semicolonToken = loc(3);
} break;
./
-UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_SEMICOLON;
+UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier Semicolon;
/.
case $rule_number: {
sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->version = sym(2).UiVersionSpecifier;
sym(1).UiImport->asToken = loc(3);
sym(1).UiImport->importIdToken = loc(4);
sym(1).UiImport->importId = stringRef(4);
@@ -811,8 +871,7 @@ UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_SEMICOLON;
} break;
./
-UiImport: UiImportHead T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiImport: UiImportHead T_AS QmlIdentifier T_SEMICOLON;
+UiImport: UiImportHead T_AS QmlIdentifier Semicolon;
/.
case $rule_number: {
sym(1).UiImport->asToken = loc(2);
@@ -840,7 +899,7 @@ UiImportHead: T_IMPORT ImportId;
if (node) {
node->importToken = loc(1);
} else {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ diagnostic_messages.append(compileError(loc(1),
QLatin1String("Expected a qualified name id or a string literal")));
return false; // ### remove me
@@ -1045,6 +1104,17 @@ UiParameterListOpt: UiParameterList;
} break;
./
+UiParameterList: QmlIdentifier T_COLON UiPropertyType;
+/.
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1));
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ node->propertyTypeToken = loc(3);
+ sym(1).Node = node;
+ } break;
+./
+
UiParameterList: UiPropertyType QmlIdentifier;
/.
case $rule_number: {
@@ -1055,6 +1125,18 @@ UiParameterList: UiPropertyType QmlIdentifier;
} break;
./
+UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
+/.
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3));
+ node->propertyTypeToken = loc(5);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+ } break;
+./
+
UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
/.
case $rule_number: {
@@ -1066,8 +1148,7 @@ UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
} break;
./
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
@@ -1081,8 +1162,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEM
} break;
./
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON;
+UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
@@ -1095,8 +1175,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON;
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1110,8 +1189,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1127,8 +1205,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1140,8 +1217,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
@@ -1155,8 +1231,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1171,8 +1246,13 @@ UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlId
sym(1).Node = node;
} break;
./
+OptionalSemicolon: | Semicolon;
+/.
+/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
+ and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
+ ./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
@@ -1184,7 +1264,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1198,7 +1278,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScr
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1212,7 +1292,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScri
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1238,7 +1318,7 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1266,7 +1346,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1289,7 +1369,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
@@ -1314,13 +1394,21 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON Expre
} break;
./
-UiObjectMember: FunctionDeclaration;
+UiObjectMember: FunctionDeclarationWithTypes;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
} break;
./
+UiObjectMember: GeneratorExpression;
+/.
+ case $rule_number: {
+ auto node = new (pool) AST::UiSourceElement(sym(1).Node);
+ sym(1).Node = node;
+ } break;
+./
+
UiObjectMember: VariableStatement;
/.
case $rule_number: {
@@ -1332,8 +1420,8 @@ UiQualifiedId: MemberExpression;
/.
case $rule_number: {
if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
- QLatin1String("Ignored annotation")));
+ diagnostic_messages.append(compileError(mem->lbracketToken,
+ QLatin1String("Ignored annotation"), QtWarningMsg));
sym(1).Expression = mem->base;
}
@@ -1343,7 +1431,7 @@ UiQualifiedId: MemberExpression;
} else {
sym(1).UiQualifiedId = 0;
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ diagnostic_messages.append(compileError(loc(1),
QLatin1String("Expected a qualified name id")));
return false; // ### recover
@@ -1430,6 +1518,63 @@ IdentifierReference: JsIdentifier;
BindingIdentifier: IdentifierReference;
--------------------------------------------------------------------------------------------------------
+-- Types
+--------------------------------------------------------------------------------------------------------
+
+TypeArguments: Type;
+/.
+ case $rule_number: {
+ sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type);
+ } break;
+./
+
+TypeArguments: TypeArguments T_COMMA Type;
+/.
+ case $rule_number: {
+ sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type);
+ } break;
+./
+
+Type: UiQualifiedId T_LT TypeArguments T_GT;
+/.
+ case $rule_number: {
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish());
+ } break;
+./
+
+Type: T_RESERVED_WORD;
+/.
+ case $rule_number: {
+ AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
+ id->identifierToken = loc(1);
+ sym(1).Type = new (pool) AST::Type(id->finish());
+ } break;
+./
+
+Type: UiQualifiedId;
+/.
+ case $rule_number: {
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
+ } break;
+./
+
+TypeAnnotation: T_COLON Type;
+/.
+ case $rule_number: {
+ sym(1).TypeAnnotation = new (pool) AST::TypeAnnotation(sym(2).Type);
+ sym(1).TypeAnnotation->colonToken = loc(1);
+ } break;
+./
+
+TypeAnnotationOpt: TypeAnnotation;
+TypeAnnotationOpt: ;
+/.
+ case $rule_number: {
+ sym(1).TypeAnnotation = nullptr;
+ } break;
+./
+
+--------------------------------------------------------------------------------------------------------
-- Expressions
--------------------------------------------------------------------------------------------------------
@@ -1590,7 +1735,7 @@ RegularExpressionLiteral: T_DIVIDE_EQ;
scan_regexp: {
bool rx = lexer->scanRegExp(prefix);
if (!rx) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ diagnostic_messages.append(compileError(location(lexer), lexer->errorMessage()));
return false;
}
@@ -2759,8 +2904,7 @@ StatementListItem: Statement;
} break;
./
-StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_AUTOMATIC_SEMICOLON;
-StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_SEMICOLON;
+StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration Semicolon;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::StatementList(sym(3).FunctionDeclaration);
@@ -2810,14 +2954,20 @@ VarDeclaration: Var VariableDeclarationList;
VarDeclaration_In: Var VariableDeclarationList_In;
/.
case $rule_number: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(sym(1).scope));
+ AST::VariableDeclarationList *declarations = sym(2).VariableDeclarationList->finish(sym(1).scope);
+ for (auto it = declarations; it; it = it->next) {
+ if (it->declaration && it->declaration->typeAnnotation) {
+ syntaxError(it->declaration->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations");
+ return false;
+ }
+ }
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(declarations);
node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
-VariableStatement: VarDeclaration_In T_AUTOMATIC_SEMICOLON;
-VariableStatement: VarDeclaration_In T_SEMICOLON;
+VariableStatement: VarDeclaration_In Semicolon;
BindingList: LexicalBinding_In;
/. case $rule_number: Q_FALLTHROUGH(); ./
@@ -2847,22 +2997,22 @@ VariableDeclarationList_In: VariableDeclarationList_In T_COMMA VariableDeclarati
} break;
./
-LexicalBinding: BindingIdentifier InitializerOpt;
+LexicalBinding: BindingIdentifier TypeAnnotationOpt InitializerOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-LexicalBinding_In: BindingIdentifier InitializerOpt_In;
+LexicalBinding_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/. case $rule_number: Q_FALLTHROUGH(); ./
-VariableDeclaration: BindingIdentifier InitializerOpt;
+VariableDeclaration: BindingIdentifier TypeAnnotationOpt InitializerOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-VariableDeclaration_In: BindingIdentifier InitializerOpt_In;
+VariableDeclaration_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/.
case $rule_number: {
- auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression);
+ auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression);
node->identifierToken = loc(1);
sym(1).Node = node;
// if initializer is an anonymous function expression, we need to assign identifierref as it's name
- if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression))
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression))
f->name = stringRef(1);
- if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
+ if (auto *c = asAnonymousClassDefinition(sym(3).Expression))
c->name = stringRef(1);
} break;
./
@@ -3012,15 +3162,15 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In;
} break;
./
-BindingElement: BindingIdentifier InitializerOpt_In;
+BindingElement: BindingIdentifier TypeAnnotationOpt InitializerOpt_In;
/.
case $rule_number: {
- AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression);
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression);
node->identifierToken = loc(1);
// if initializer is an anonymous function expression, we need to assign identifierref as it's name
- if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression))
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression))
f->name = stringRef(1);
- if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
+ if (auto *c = asAnonymousClassDefinition(sym(3).Expression))
c->name = stringRef(1);
sym(1).Node = node;
} break;
@@ -3037,7 +3187,7 @@ BindingElement: BindingPattern InitializerOpt_In;
BindingRestElement: T_ELLIPSIS BindingIdentifier;
/.
case $rule_number: {
- AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), nullptr, AST::PatternElement::RestElement);
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), /*type annotation*/nullptr, nullptr, AST::PatternElement::RestElement);
node->identifierToken = loc(2);
sym(1).Node = node;
} break;
@@ -3087,8 +3237,7 @@ ExpressionStatementLookahead: ;
} break;
./
-ExpressionStatement: Expression_In T_AUTOMATIC_SEMICOLON;
-ExpressionStatement: Expression_In T_SEMICOLON;
+ExpressionStatement: Expression_In Semicolon;
/.
case $rule_number: {
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
@@ -3121,9 +3270,8 @@ IfStatement: T_IF T_LPAREN Expression_In T_RPAREN Statement;
./
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_AUTOMATIC_SEMICOLON;
IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_COMPATIBILITY_SEMICOLON; -- for JSC/V8 compatibility
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN T_SEMICOLON;
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression_In T_RPAREN Semicolon;
/.
case $rule_number: {
AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
@@ -3227,12 +3375,16 @@ IterationStatement: T_FOR T_LPAREN ForDeclaration InOrOf Expression_In T_RPAREN
} break;
./
-ForDeclaration: LetOrConst BindingIdentifier;
+ForDeclaration: LetOrConst BindingIdentifier TypeAnnotationOpt;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ForDeclaration: Var BindingIdentifier;
+ForDeclaration: Var BindingIdentifier TypeAnnotationOpt;
/.
case $rule_number: {
- auto *node = new (pool) AST::PatternElement(stringRef(2), nullptr);
+ if (auto typeAnnotation = sym(3).TypeAnnotation) {
+ syntaxError(typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations");
+ return false;
+ }
+ auto *node = new (pool) AST::PatternElement(stringRef(2), sym(3).TypeAnnotation, nullptr);
node->identifierToken = loc(2);
node->scope = sym(1).scope;
node->isForDeclaration = true;
@@ -3252,8 +3404,7 @@ ForDeclaration: Var BindingPattern;
} break;
./
-ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON;
-ContinueStatement: T_CONTINUE T_SEMICOLON;
+ContinueStatement: T_CONTINUE Semicolon;
/.
case $rule_number: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
@@ -3263,8 +3414,7 @@ ContinueStatement: T_CONTINUE T_SEMICOLON;
} break;
./
-ContinueStatement: T_CONTINUE IdentifierReference T_AUTOMATIC_SEMICOLON;
-ContinueStatement: T_CONTINUE IdentifierReference T_SEMICOLON;
+ContinueStatement: T_CONTINUE IdentifierReference Semicolon;
/.
case $rule_number: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
@@ -3275,8 +3425,7 @@ ContinueStatement: T_CONTINUE IdentifierReference T_SEMICOLON;
} break;
./
-BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON;
-BreakStatement: T_BREAK T_SEMICOLON;
+BreakStatement: T_BREAK Semicolon;
/.
case $rule_number: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
@@ -3286,8 +3435,7 @@ BreakStatement: T_BREAK T_SEMICOLON;
} break;
./
-BreakStatement: T_BREAK IdentifierReference T_AUTOMATIC_SEMICOLON;
-BreakStatement: T_BREAK IdentifierReference T_SEMICOLON;
+BreakStatement: T_BREAK IdentifierReference Semicolon;
/.
case $rule_number: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
@@ -3298,8 +3446,7 @@ BreakStatement: T_BREAK IdentifierReference T_SEMICOLON;
} break;
./
-ReturnStatement: T_RETURN ExpressionOpt_In T_AUTOMATIC_SEMICOLON;
-ReturnStatement: T_RETURN ExpressionOpt_In T_SEMICOLON;
+ReturnStatement: T_RETURN ExpressionOpt_In Semicolon;
/.
case $rule_number: {
if (!functionNestingLevel) {
@@ -3423,8 +3570,7 @@ LabelledItem: ExpressionStatementLookahead T_FORCE_DECLARATION FunctionDeclarati
} break;
./
-ThrowStatement: T_THROW Expression_In T_AUTOMATIC_SEMICOLON;
-ThrowStatement: T_THROW Expression_In T_SEMICOLON;
+ThrowStatement: T_THROW Expression_In Semicolon;
/.
case $rule_number: {
AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
@@ -3501,8 +3647,7 @@ CatchParameter: BindingPattern;
} break;
./
-DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON; -- automatic semicolon
-DebuggerStatement: T_DEBUGGER T_SEMICOLON;
+DebuggerStatement: T_DEBUGGER Semicolon;
/.
case $rule_number: {
AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
@@ -3519,59 +3664,85 @@ DebuggerStatement: T_DEBUGGER T_SEMICOLON;
-- otherwise conflict.
Function: T_FUNCTION %prec REDUCE_HERE;
-FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
sym(1).Node = node;
} break;
./
+FunctionDeclarationWithTypes: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ sym(6).TypeAnnotation);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
+ sym(1).Node = node;
+ } break;
+./
FunctionDeclaration_Default: FunctionDeclaration;
-FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
sym(1).Node = node;
} break;
./
-FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
if (! stringRef(2).isNull())
node->identifierToken = loc(2);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
sym(1).Node = node;
} break;
./
-FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ /*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
sym(1).Node = node;
} break;
./
@@ -3681,7 +3852,7 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun
ArrowParameters: BindingIdentifier;
/.
case $rule_number: {
- AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), nullptr, AST::PatternElement::Binding);
+ AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), /*type annotation*/nullptr, nullptr, AST::PatternElement::Binding);
e->identifierToken = loc(1);
sym(1).FormalParameterList = (new (pool) AST::FormalParameterList(nullptr, e))->finish(pool);
} break;
@@ -3715,30 +3886,34 @@ ConciseBodyLookahead: ;
} break;
./
-MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(7).StatementList);
f->functionToken = sym(1).PropertyName->firstSourceLocation();
f->lparenToken = loc(2);
f->rparenToken = loc(4);
- f->lbraceToken = loc(5);
- f->rbraceToken = loc(7);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
-MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(5);
- f->lbraceToken = loc(6);
- f->rbraceToken = loc(8);
+ f->lbraceToken = loc(7);
+ f->rbraceToken = loc(9);
f->isGenerator = true;
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Method);
node->colonToken = loc(2);
@@ -3747,30 +3922,34 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R
./
-MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(6).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, /*formals*/nullptr))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(7).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(4);
- f->lbraceToken = loc(5);
- f->rbraceToken = loc(7);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Getter);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
-MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList))
+ return false;
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList);
f->functionToken = sym(2).PropertyName->firstSourceLocation();
f->lparenToken = loc(3);
f->rparenToken = loc(5);
- f->lbraceToken = loc(6);
- f->rbraceToken = loc(8);
+ f->lbraceToken = loc(7);
+ f->rbraceToken = loc(9);
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Setter);
node->colonToken = loc(2);
sym(1).Node = node;
@@ -4077,13 +4256,10 @@ ModuleItemList: ModuleItemList ModuleItem;
} break;
./
-ModuleItem: ImportDeclaration T_AUTOMATIC_SEMICOLON;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ImportDeclaration T_SEMICOLON;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ExportDeclaration T_AUTOMATIC_SEMICOLON;
+
+ModuleItem: ImportDeclaration Semicolon;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ModuleItem: ExportDeclaration T_SEMICOLON;
+ModuleItem: ExportDeclaration Semicolon;
/.
case $rule_number: {
sym(1).StatementList = new (pool) AST::StatementList(sym(1).Node);
@@ -4420,7 +4596,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
yylloc.length = 0;
//const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'");
- //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+ //diagnostic_messages.append(compileError(yyloc, msg, QtWarningMsg));
first_token = &token_buffer[0];
last_token = &token_buffer[1];
@@ -4457,7 +4633,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
msg = QCoreApplication::translate("QQmlParser", "Syntax error");
else
msg = QCoreApplication::translate("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ diagnostic_messages.append(compileError(token_buffer[0].loc, msg));
action = errorState;
goto _Lcheck_token;
@@ -4488,7 +4664,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
qDebug() << "Parse error, trying to recover (2).";
#endif
const QString msg = QCoreApplication::translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ diagnostic_messages.append(compileError(token_buffer[0].loc, msg));
pushToken(*tk);
goto _Lcheck_token;
@@ -4503,7 +4679,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
int a = t_action(errorState, tk);
if (a > 0 && t_action(a, yytoken)) {
const QString msg = QCoreApplication::translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ diagnostic_messages.append(compileError(token_buffer[0].loc, msg));
pushToken(tk);
goto _Lcheck_token;
@@ -4511,7 +4687,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
}
const QString msg = QCoreApplication::translate("QQmlParser", "Syntax error");
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ diagnostic_messages.append(compileError(token_buffer[0].loc, msg));
}
return false;
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 2b1a999b38..b63b2191b9 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -131,7 +131,7 @@ FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *po
}
AST::PatternElement *binding = nullptr;
if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
- binding = new (pool) AST::PatternElement(idExpr->name, rhs);
+ binding = new (pool) AST::PatternElement(idExpr->name, /*type annotation*/nullptr, rhs);
binding->identifierToken = idExpr->identifierToken;
} else if (AST::Pattern *p = expr->patternCast()) {
SourceLocation loc;
@@ -960,6 +960,7 @@ void FunctionDeclaration::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
+ accept(typeAnnotation, visitor);
accept(body, visitor);
}
@@ -970,6 +971,7 @@ void FunctionExpression::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
+ accept(typeAnnotation, visitor);
accept(body, visitor);
}
@@ -981,9 +983,9 @@ FunctionExpression *FunctionExpression::asFunctionDefinition()
return this;
}
-QStringList FormalParameterList::formals() const
+BoundNames FormalParameterList::formals() const
{
- QStringList formals;
+ BoundNames formals;
int i = 0;
for (const FormalParameterList *it = this; it; it = it->next) {
if (it->element) {
@@ -991,18 +993,18 @@ QStringList FormalParameterList::formals() const
int duplicateIndex = formals.indexOf(name);
if (duplicateIndex >= 0) {
// change the name of the earlier argument to enforce the lookup semantics from the spec
- formals[duplicateIndex] += QLatin1String("#") + QString::number(i);
+ formals[duplicateIndex].id += QLatin1String("#") + QString::number(i);
}
- formals += name;
+ formals += {name, it->element->typeAnnotation};
}
++i;
}
return formals;
}
-QStringList FormalParameterList::boundNames() const
+BoundNames FormalParameterList::boundNames() const
{
- QStringList names;
+ BoundNames names;
for (const FormalParameterList *it = this; it; it = it->next) {
if (it->element)
it->element->boundNames(&names);
@@ -1270,6 +1272,35 @@ void UiQualifiedId::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+void Type::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(typeId, visitor);
+ accept(typeArguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (TypeArgumentList *it = this; it; it = it->next)
+ accept(it->typeId, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeAnnotation::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(type, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
void UiImport::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -1340,13 +1371,14 @@ void PatternElement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(bindingTarget, visitor);
+ accept(typeAnnotation, visitor);
accept(initializer, visitor);
}
visitor->endVisit(this);
}
-void PatternElement::boundNames(QStringList *names)
+void PatternElement::boundNames(BoundNames *names)
{
if (bindingTarget) {
if (PatternElementList *e = elementList())
@@ -1354,7 +1386,7 @@ void PatternElement::boundNames(QStringList *names)
else if (PatternPropertyList *p = propertyList())
p->boundNames(names);
} else {
- names->append(bindingIdentifier.toString());
+ names->append({bindingIdentifier.toString(), typeAnnotation});
}
}
@@ -1371,7 +1403,7 @@ void PatternElementList::accept0(Visitor *visitor)
}
}
-void PatternElementList::boundNames(QStringList *names)
+void PatternElementList::boundNames(BoundNames *names)
{
for (PatternElementList *it = this; it; it = it->next) {
if (it->element)
@@ -1384,13 +1416,14 @@ void PatternProperty::accept0(Visitor *visitor)
if (visitor->visit(this)) {
accept(name, visitor);
accept(bindingTarget, visitor);
+ accept(typeAnnotation, visitor);
accept(initializer, visitor);
}
visitor->endVisit(this);
}
-void PatternProperty::boundNames(QStringList *names)
+void PatternProperty::boundNames(BoundNames *names)
{
PatternElement::boundNames(names);
}
@@ -1406,7 +1439,7 @@ void PatternPropertyList::accept0(Visitor *visitor)
}
}
-void PatternPropertyList::boundNames(QStringList *names)
+void PatternPropertyList::boundNames(BoundNames *names)
{
for (PatternPropertyList *it = this; it; it = it->next)
it->property->boundNames(names);
@@ -1475,6 +1508,37 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast()
return this;
}
+void UiVersionSpecifier::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+ visitor->endVisit(this);
+}
+
+QString Type::toString() const
+{
+ QString result;
+ toString(&result);
+ return result;
+}
+
+void Type::toString(QString *out) const
+{
+ for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) {
+ out->append(it->name);
+
+ if (it->next)
+ out->append(QLatin1Char('.'));
+ }
+
+ if (typeArguments) {
+ out->append(QLatin1Char('<'));
+ if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId)
+ subType->toString(out);
+ out->append(QLatin1Char('>'));
+ };
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index b81553776d..39194068bf 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -53,7 +53,8 @@
#include "qqmljsastvisitor_p.h"
#include "qqmljsglobal_p.h"
-#include "qqmljsmemorypool_p.h"
+
+#include <private/qqmljsmemorypool_p.h>
#include <QtCore/qstring.h>
@@ -233,7 +234,9 @@ public:
Kind_PatternElementList,
Kind_PatternProperty,
Kind_PatternPropertyList,
-
+ Kind_Type,
+ Kind_TypeArgumentList,
+ Kind_TypeAnnotation,
Kind_UiArrayBinding,
Kind_UiImport,
@@ -251,7 +254,8 @@ public:
Kind_UiSourceElement,
Kind_UiHeaderItemList,
Kind_UiEnumDeclaration,
- Kind_UiEnumMemberList
+ Kind_UiEnumMemberList,
+ Kind_UiVersionSpecifier
};
inline Node() {}
@@ -303,6 +307,131 @@ public:
int kind = Kind_Undefined;
};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(const QStringRef &name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = nullptr;
+ return head;
+ }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return identifierToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+// attributes
+ UiQualifiedId *next;
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT Type: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Type)
+
+ Type(UiQualifiedId *typeId, Node *typeArguments = nullptr)
+ : typeId(typeId)
+ , typeArguments(typeArguments)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return typeId->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); }
+
+ QString toString() const;
+ void toString(QString *out) const;
+
+// attributes
+ UiQualifiedId *typeId;
+ Node *typeArguments; // TypeArgumentList
+};
+
+
+class QML_PARSER_EXPORT TypeArgumentList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeArgumentList)
+
+ TypeArgumentList(Type *typeId)
+ : typeId(typeId)
+ , next(nullptr)
+ { kind = K; }
+
+ TypeArgumentList(TypeArgumentList *previous, Type *typeId)
+ : typeId(typeId)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return typeId->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() : typeId->lastSourceLocation(); }
+
+ inline TypeArgumentList *finish()
+ {
+ TypeArgumentList *front = next;
+ next = nullptr;
+ return front;
+ }
+
+// attributes
+ Type *typeId;
+ TypeArgumentList *next;
+};
+
+class QML_PARSER_EXPORT TypeAnnotation: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeAnnotation)
+
+ TypeAnnotation(Type *type)
+ : type(type)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return colonToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return type->lastSourceLocation(); }
+
+// attributes
+ Type *type;
+ SourceLocation colonToken;
+};
class QML_PARSER_EXPORT ExpressionNode: public Node
{
public:
@@ -492,7 +621,30 @@ public:
SourceLocation literalToken;
};
-class QML_PARSER_EXPORT StringLiteral: public LeftHandSideExpression
+class QML_PARSER_EXPORT UiVersionSpecifier : public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiVersionSpecifier)
+
+ UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override { return majorToken; }
+
+ SourceLocation lastSourceLocation() const override
+ {
+ return minorToken.isValid() ? minorToken : majorToken;
+ }
+
+ // attributes:
+ int majorVersion;
+ int minorVersion;
+ SourceLocation majorToken;
+ SourceLocation minorToken;
+};
+
+class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(StringLiteral)
@@ -681,6 +833,34 @@ public:
SourceLocation propertyNameToken;
};
+struct QML_PARSER_EXPORT BoundName
+{
+ QString id;
+ TypeAnnotation *typeAnnotation = nullptr;
+ BoundName(const QString &id, TypeAnnotation *typeAnnotation)
+ : id(id), typeAnnotation(typeAnnotation)
+ {}
+ BoundName() = default;
+ QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
+};
+
+struct BoundNames : public QVector<BoundName>
+{
+ int indexOf(const QString &name, int from = 0) const
+ {
+ auto found = std::find_if(constBegin() + from, constEnd(),
+ [name](const BoundName &it) { return it.id == name; });
+ if (found == constEnd())
+ return -1;
+ return found - constBegin();
+ }
+
+ bool contains(const QString &name) const
+ {
+ return indexOf(name) != -1;
+ }
+};
+
class QML_PARSER_EXPORT PatternElement : public Node
{
public:
@@ -705,8 +885,9 @@ public:
: initializer(i), type(t)
{ kind = K; }
- PatternElement(const QStringRef &n, ExpressionNode *i = nullptr, Type t = Binding)
+ PatternElement(const QStringRef &n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
: bindingIdentifier(n), initializer(i), type(t)
+ , typeAnnotation(typeAnnotation)
{
Q_ASSERT(t >= RestElement);
kind = K;
@@ -726,7 +907,7 @@ public:
{ return identifierToken.isValid() ? identifierToken : (bindingTarget ? bindingTarget->firstSourceLocation() : initializer->firstSourceLocation()); }
SourceLocation lastSourceLocation() const override
- { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : identifierToken); }
+ { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : (typeAnnotation ? typeAnnotation->lastSourceLocation() : identifierToken)); }
ExpressionNode *destructuringTarget() const { return bindingTarget; }
Pattern *destructuringPattern() const { return bindingTarget ? bindingTarget->patternCast() : nullptr; }
@@ -736,7 +917,7 @@ public:
bool isVariableDeclaration() const { return scope != VariableScope::NoScope; }
bool isLexicallyScoped() const { return scope == VariableScope::Let || scope == VariableScope::Const; }
- virtual void boundNames(QStringList *names);
+ virtual void boundNames(BoundNames *names);
// attributes
SourceLocation identifierToken;
@@ -744,6 +925,7 @@ public:
ExpressionNode *bindingTarget = nullptr;
ExpressionNode *initializer = nullptr;
Type type = Literal;
+ TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
@@ -773,7 +955,7 @@ public:
void accept0(Visitor *visitor) override;
- void boundNames(QStringList *names);
+ void boundNames(BoundNames *names);
SourceLocation firstSourceLocation() const override
{ return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); }
@@ -796,7 +978,7 @@ public:
{ kind = K; }
PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr)
- : PatternElement(n, i), name(name)
+ : PatternElement(n, /*type annotation*/nullptr, i), name(name)
{ kind = K; }
PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr)
@@ -813,7 +995,7 @@ public:
return loc.isValid() ? loc : name->lastSourceLocation();
}
- void boundNames(QStringList *names) override;
+ void boundNames(BoundNames *names) override;
bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
// attributes
@@ -841,7 +1023,7 @@ public:
void accept0(Visitor *visitor) override;
- void boundNames(QStringList *names);
+ void boundNames(BoundNames *names);
inline PatternPropertyList *finish ()
{
@@ -2131,8 +2313,9 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public:
QQMLJS_DECLARE_AST_NODE(FunctionExpression)
- FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b):
- name (n), formals (f), body (b)
+ FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ name (n), formals (f), body (b),
+ typeAnnotation(typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2151,6 +2334,7 @@ public:
bool isGenerator = false;
FormalParameterList *formals;
StatementList *body;
+ TypeAnnotation *typeAnnotation;
SourceLocation functionToken;
SourceLocation identifierToken;
SourceLocation lparenToken;
@@ -2164,8 +2348,8 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public:
QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
- FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b):
- FunctionExpression(n, f, b)
+ FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ FunctionExpression(n, f, b, typeAnnotation)
{ kind = K; }
void accept0(Visitor *visitor) override;
@@ -2235,9 +2419,9 @@ public:
return false;
}
- QStringList formals() const;
+ BoundNames formals() const;
- QStringList boundNames() const;
+ BoundNames boundNames() const;
void accept0(Visitor *visitor) override;
@@ -2786,44 +2970,6 @@ public:
SourceLocation semicolonToken;
};
-class QML_PARSER_EXPORT UiQualifiedId: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
-
- UiQualifiedId(const QStringRef &name)
- : next(this), name(name)
- { kind = K; }
-
- UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
- : name(name)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
- }
-
- UiQualifiedId *finish()
- {
- UiQualifiedId *head = next;
- next = nullptr;
- return head;
- }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return identifierToken; }
-
- SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
-
-// attributes
- UiQualifiedId *next;
- QStringRef name;
- SourceLocation identifierToken;
-};
-
class QML_PARSER_EXPORT UiImport: public Node
{
public:
@@ -2855,6 +3001,7 @@ public:
SourceLocation asToken;
SourceLocation importIdToken;
SourceLocation semicolonToken;
+ UiVersionSpecifier *version = nullptr;
};
class QML_PARSER_EXPORT UiObjectMember: public Node
@@ -3090,10 +3237,10 @@ public:
void accept0(Visitor *) override;
SourceLocation firstSourceLocation() const override
- { return propertyTypeToken; }
+ { return colonToken.isValid() ? identifierToken : propertyTypeToken; }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
+ { return next ? next->lastSourceLocation() : (colonToken.isValid() ? propertyTypeToken : identifierToken); }
inline UiParameterList *finish ()
{
@@ -3109,6 +3256,7 @@ public:
SourceLocation commaToken;
SourceLocation propertyTypeToken;
SourceLocation identifierToken;
+ SourceLocation colonToken;
};
class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
@@ -3203,7 +3351,7 @@ public:
SourceLocation firstSourceLocation() const override
{
- if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->firstSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->firstSourceLocation();
@@ -3213,7 +3361,7 @@ public:
SourceLocation lastSourceLocation() const override
{
- if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ if (FunctionExpression *funDecl = sourceElement->asFunctionDefinition())
return funDecl->lastSourceLocation();
else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
return varStmt->lastSourceLocation();
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index e9caa918d5..05226fd043 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -158,6 +158,9 @@ class NestedExpression;
class ClassExpression;
class ClassDeclaration;
class ClassElementList;
+class TypeArgumentList;
+class Type;
+class TypeAnnotation;
// ui elements
class UiProgram;
@@ -178,8 +181,10 @@ class UiQualifiedId;
class UiHeaderItemList;
class UiEnumDeclaration;
class UiEnumMemberList;
+class UiVersionSpecifier;
-} } // namespace AST
+} // namespace AST
+} // namespace QQmlJS
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 9115449a46..7146cd00ac 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -111,6 +111,7 @@ public:
virtual bool visit(UiQualifiedId *) { return true; }
virtual bool visit(UiEnumDeclaration *) { return true; }
virtual bool visit(UiEnumMemberList *) { return true; }
+ virtual bool visit(UiVersionSpecifier *) { return true; }
virtual void endVisit(UiProgram *) {}
virtual void endVisit(UiImport *) {}
@@ -129,6 +130,7 @@ public:
virtual void endVisit(UiQualifiedId *) {}
virtual void endVisit(UiEnumDeclaration *) {}
virtual void endVisit(UiEnumMemberList *) { }
+ virtual void endVisit(UiVersionSpecifier *) {}
// QQmlJS
virtual bool visit(ThisExpression *) { return true; }
@@ -401,6 +403,15 @@ public:
virtual bool visit(DebuggerStatement *) { return true; }
virtual void endVisit(DebuggerStatement *) {}
+ virtual bool visit(Type *) { return true; }
+ virtual void endVisit(Type *) {}
+
+ virtual bool visit(TypeArgumentList *) { return true; }
+ virtual void endVisit(TypeArgumentList *) {}
+
+ virtual bool visit(TypeAnnotation *) { return true; }
+ virtual void endVisit(TypeAnnotation *) {}
+
virtual void throwRecursionDepthError() = 0;
quint16 recursionDepth() const { return m_recursionDepth; }
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index b7f7da9478..8a3e2db6a1 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -52,9 +52,10 @@
//
#include "qqmljsglobal_p.h"
-#include "qqmljsmemorypool_p.h"
#include "qqmljssourcelocation_p.h"
+#include <private/qqmljsmemorypool_p.h>
+
#include <QtCore/qstring.h>
#include <QtCore/qset.h>
@@ -91,28 +92,6 @@ public:
}
};
-
-class QML_PARSER_EXPORT DiagnosticMessage
-{
-public:
- enum Kind { Hint, Warning, Error };
-
- DiagnosticMessage() {}
-
- DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
- : kind(kind), loc(loc), message(message) {}
-
- bool isWarning() const
- { return kind == Warning; }
-
- bool isError() const
- { return kind == Error; }
-
- Kind kind = Error;
- AST::SourceLocation loc;
- QString message;
-};
-
class QML_PARSER_EXPORT Engine
{
Lexer *_lexer;
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index c53b13f64d..1e0ac72bd1 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -39,12 +39,15 @@
#include "qqmljslexer_p.h"
#include "qqmljsengine_p.h"
-#include "qqmljsmemorypool_p.h"
#include "qqmljskeywords_p.h"
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmljsmemorypool_p.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
+#include <QtCore/QScopedValueRollback>
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
@@ -269,16 +272,29 @@ int Lexer::lex()
++_bracesCount;
Q_FALLTHROUGH();
case T_SEMICOLON:
+ _importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
case T_QUESTION:
case T_COLON:
case T_TILDE:
_delimited = true;
break;
+ case T_AUTOMATIC_SEMICOLON:
+ case T_AS:
+ _importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
default:
if (isBinop(_tokenKind))
_delimited = true;
break;
+ case T_IMPORT:
+ if (qmlMode() || (_handlingDirectives && previousTokenKind == T_DOT))
+ _importState = ImportState::SawImport;
+ if (isBinop(_tokenKind))
+ _delimited = true;
+ break;
+
case T_IF:
case T_FOR:
case T_WHILE:
@@ -618,6 +634,8 @@ again:
return T_DIVIDE_;
case '.':
+ if (_importState == ImportState::SawImport)
+ return T_DOT;
if (isDecimalDigit(_char.unicode()))
return scanNumber(ch);
if (_char == QLatin1Char('.')) {
@@ -728,7 +746,10 @@ again:
case '7':
case '8':
case '9':
- return scanNumber(ch);
+ if (_importState == ImportState::SawImport)
+ return scanVersionNumber(ch);
+ else
+ return scanNumber(ch);
default: {
uint c = ch.unicode();
@@ -1146,6 +1167,26 @@ int Lexer::scanNumber(QChar ch)
return T_NUMERIC_LITERAL;
}
+int Lexer::scanVersionNumber(QChar ch)
+{
+ if (ch == QLatin1Char('0')) {
+ _tokenValue = 0;
+ return T_VERSION_NUMBER;
+ }
+
+ int acc = 0;
+ acc += ch.digitValue();
+
+ while (_char.isDigit()) {
+ acc *= 10;
+ acc += _char.digitValue();
+ scanChar(); // consume the digit
+ }
+
+ _tokenValue = acc;
+ return T_VERSION_NUMBER;
+}
+
bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
{
_tokenText.resize(0);
@@ -1402,6 +1443,13 @@ static inline bool isUriToken(int token)
bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
{
+ auto setError = [error, this](QString message) {
+ error->message = std::move(message);
+ error->line = tokenStartLine();
+ error->column = tokenStartColumn();
+ };
+
+ QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true);
Q_ASSERT(!_qmlMode);
lex(); // fetch the first token
@@ -1422,9 +1470,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
if (! (directiveName == QLatin1String("pragma") ||
directiveName == QLatin1String("import"))) {
- error->message = QCoreApplication::translate("QQmlParser", "Syntax error");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser", "Syntax error"));
return false; // not a valid directive name
}
@@ -1432,9 +1478,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
if (directiveName == QLatin1String("pragma")) {
// .pragma library
if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library"))) {
- error->message = QCoreApplication::translate("QQmlParser", "Syntax error");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser", "Syntax error"));
return false; // expected `library
}
@@ -1456,20 +1500,15 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
pathOrUri = tokenText();
if (!pathOrUri.endsWith(QLatin1String("js"))) {
- error->message = QCoreApplication::translate("QQmlParser","Imported file must be a script");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser","Imported file must be a script"));
return false;
}
} else if (_tokenKind == T_IDENTIFIER) {
- // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
-
+ // .import T_IDENTIFIER (. T_IDENTIFIER)* T_VERSION_NUMBER . T_VERSION_NUMBER as T_IDENTIFIER
while (true) {
if (!isUriToken(_tokenKind)) {
- error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
@@ -1477,9 +1516,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
lex();
if (tokenStartLine() != lineNumber) {
- error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
if (_tokenKind != QQmlJSGrammar::T_DOT)
@@ -1489,21 +1526,30 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
lex();
if (tokenStartLine() != lineNumber) {
- error->message = QCoreApplication::translate("QQmlParser","Invalid module URI");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
}
- if (_tokenKind != T_NUMERIC_LITERAL) {
- error->message = QCoreApplication::translate("QQmlParser","Module import requires a version");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ if (_tokenKind != T_VERSION_NUMBER) {
+ setError(QCoreApplication::translate("QQmlParser","Module import requires a version"));
return false; // expected the module version number
}
version = tokenText();
+ lex();
+ if (_tokenKind != T_DOT) {
+ setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing dot)"));
+ return false; // expected the module version number
+ }
+ version += QLatin1Char('.');
+
+ lex();
+ if (_tokenKind != T_VERSION_NUMBER) {
+ setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing number)"));
+ return false; // expected the module version number
+ }
+ version += tokenText();
}
//
@@ -1511,34 +1557,27 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
//
if (! (lex() == T_AS && tokenStartLine() == lineNumber)) {
if (fileImport)
- error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier");
+ setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier"));
else
- error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier");
+ setError(QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"));
if (tokenStartLine() != lineNumber) {
- error->loc.startLine = lineNumber;
- error->loc.startColumn = column;
- } else {
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ error->line = lineNumber;
+ error->line = column;
}
return false; // expected `as'
}
if (lex() != T_IDENTIFIER || tokenStartLine() != lineNumber) {
if (fileImport)
- error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier");
+ setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier"));
else
- error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"));
return false; // expected module name
}
const QString module = tokenText();
if (!module.at(0).isUpper()) {
- error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser","Invalid import qualifier"));
return false;
}
@@ -1549,9 +1588,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
if (tokenStartLine() != lineNumber) {
- error->message = QCoreApplication::translate("QQmlParser", "Syntax error");
- error->loc.startLine = tokenStartLine();
- error->loc.startColumn = tokenStartColumn();
+ setError(QCoreApplication::translate("QQmlParser", "Syntax error"));
return false; // the directives cannot span over multiple lines
}
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index 51152bfd6e..e2ee4ae351 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
class Engine;
-class DiagnosticMessage;
+struct DiagnosticMessage;
class Directives;
class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar
@@ -124,6 +124,11 @@ public:
StaticIsKeyword = 0x4
};
+ enum class ImportState {
+ SawImport,
+ NoQmlImport
+ };
+
public:
Lexer(Engine *engine);
@@ -188,6 +193,7 @@ private:
inline void scanChar();
int scanToken();
int scanNumber(QChar ch);
+ int scanVersionNumber(QChar ch);
enum ScanStringMode {
SingleQuote = '\'',
DoubleQuote = '"',
@@ -242,6 +248,7 @@ private:
int _tokenLength;
int _tokenLine;
int _tokenColumn;
+ ImportState _importState = ImportState::NoQmlImport;
bool _validTokenText;
bool _prohibitAutomaticSemicolon;
@@ -253,6 +260,7 @@ private:
bool _skipLinefeed = false;
int _generatorLevel = 0;
bool _staticIsKeyword = false;
+ bool _handlingDirectives = false;
};
} // end of namespace QQmlJS
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index df3085a28e..3c889244f4 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -19,31 +19,6 @@ gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks
DEFINES += QT_NO_FOREACH
-!build_pass {
- # Create a header containing a hash that describes this library. For a
- # released version of Qt, we'll use the .tag file that is updated by git
- # archive with the commit hash. For unreleased versions, we'll ask git
- # describe. Note that it won't update unless qmake is run again, even if
- # the commit change also changed something in this library.
- tagFile = $$PWD/../../.tag
- tag =
- exists($$tagFile) {
- tag = $$cat($$tagFile, singleline)
- QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
- }
- !equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
- QML_COMPILE_HASH = $$tag
- } else:exists($$PWD/../../.git) {
- commit = $$system(git rev-parse HEAD)
- QML_COMPILE_HASH = $$commit
- }
- compile_hash_contents = \
- "// Generated file, DO NOT EDIT" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
- write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
-}
-
exists("qqml_enable_gcov") {
QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
LIBS_PRIVATE += -lgcov
@@ -64,16 +39,21 @@ greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \
WERROR += -Wno-error=unused-const-variable
HEADERS += qtqmlglobal.h \
- qtqmlglobal_p.h
+ qtqmlglobal_p.h \
+ qtqmlcompilerglobal.h \
+ qtqmlcompilerglobal_p.h
#modules
+include(common/common.pri)
include(util/util.pri)
include(memory/memory.pri)
include(parser/parser.pri)
include(compiler/compiler.pri)
include(jsapi/jsapi.pri)
include(jsruntime/jsruntime.pri)
-include(jit/jit.pri)
+qtConfig(qml-jit) {
+ include(jit/jit.pri)
+}
include(qml/qml.pri)
include(debugger/debugger.pri)
include(qmldirparser/qmldirparser.pri)
@@ -83,6 +63,7 @@ qtConfig(qml-animation) {
include(types/types.pri)
include(../3rdparty/masm/masm-defs.pri)
include(../3rdparty/masm/masm.pri)
+include(../3rdparty/llvm/llvm.pri)
MODULE_PLUGIN_TYPES = \
qmltooling
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index ade05a596b..eadba394b4 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -3,6 +3,7 @@ HEADERS += \
$$PWD/qintrusivelist_p.h \
$$PWD/qpodvector_p.h \
$$PWD/qhashedstring_p.h \
+ $$PWD/qprimefornumbits_p.h \
$$PWD/qqmlrefcount_p.h \
$$PWD/qfieldlist_p.h \
$$PWD/qqmlthread_p.h \
@@ -11,12 +12,14 @@ HEADERS += \
$$PWD/qrecyclepool_p.h \
$$PWD/qflagpointer_p.h \
$$PWD/qlazilyallocated_p.h \
- $$PWD/qqmlnullablevalue_p.h
+ $$PWD/qqmlnullablevalue_p.h \
+ $$PWD/qstringhash_p.h \
+ $$PWD/qlinkedstringhash_p.h
SOURCES += \
$$PWD/qintrusivelist.cpp \
$$PWD/qhashedstring.cpp \
- $$PWD/qqmlthread.cpp \
+ $$PWD/qqmlthread.cpp
# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
# clock_gettime() is implemented in librt on these systems
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 117670dbfc..7a8fdd0a14 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -39,82 +39,7 @@
#include "qhashedstring_p.h"
-
-
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
-*/
-const int MinNumBits = 4;
-
-/*
- The prime_deltas array is a table of selected prime values, even
- though it doesn't look like one. The primes we are using are 1,
- 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
- surrounding of a power of two.
-
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-void QStringHashData::rehashToSize(int size)
-{
- short bits = qMax(MinNumBits, (int)numBits);
- while (primeForNumBits(bits) < size) bits++;
-
- if (bits > numBits)
- rehashToBits(bits);
-}
-
-void QStringHashData::rehashToBits(short bits)
-{
- numBits = qMax(MinNumBits, (int)bits);
-
- int nb = primeForNumBits(numBits);
- if (nb == numBuckets && buckets)
- return;
-
-#ifdef QSTRINGHASH_LINK_DEBUG
- if (linkCount)
- qFatal("QStringHash: Illegal attempt to rehash a linked hash.");
-#endif
-
- QStringHashNode **newBuckets = new QStringHashNode *[nb];
- ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
-
- // Preserve the existing order within buckets so that items with the
- // same key will retain the same find/findNext order
- for (int i = 0; i < numBuckets; ++i) {
- QStringHashNode *bucket = buckets[i];
- if (bucket)
- rehashNode(newBuckets, nb, bucket);
- }
-
- delete [] buckets;
- buckets = newBuckets;
- numBuckets = nb;
-}
-
-void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
-{
- QStringHashNode *next = node->next.data();
- if (next)
- rehashNode(newBuckets, nb, next);
-
- int bucket = node->hash % nb;
- node->next = newBuckets[bucket];
- newBuckets[bucket] = node;
-}
+QT_BEGIN_NAMESPACE
// Copy of QString's qMemCompare
bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
@@ -228,3 +153,4 @@ QString QHashedCStringRef::toUtf16() const
return rv;
}
+QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 2d6c25bdd3..b9f3f81219 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -63,9 +63,6 @@
QT_BEGIN_NAMESPACE
-// Enable this to debug hash linking assumptions.
-// #define QSTRINGHASH_LINK_DEBUG
-
class QHashedStringRef;
class Q_QML_PRIVATE_EXPORT QHashedString : public QString
{
@@ -174,854 +171,6 @@ private:
mutable quint32 m_hash = 0;
};
-class QStringHashData;
-class Q_AUTOTEST_EXPORT QStringHashNode
-{
-public:
- QStringHashNode()
- : ckey(nullptr)
- {
- }
-
- QStringHashNode(const QHashedString &key)
- : length(key.length()), hash(key.hash()), symbolId(0)
- {
- strData = const_cast<QHashedString &>(key).data_ptr();
- setQString(true);
- strData->ref.ref();
- }
-
- QStringHashNode(const QHashedCStringRef &key)
- : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
- {
- }
-
- QStringHashNode(const QStringHashNode &o)
- : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
- {
- setQString(o.isQString());
- if (isQString()) { strData->ref.ref(); }
- }
-
- ~QStringHashNode()
- {
- if (isQString()) { if (!strData->ref.deref()) free(strData); }
- }
-
- QFlagPointer<QStringHashNode> next;
-
- qint32 length = 0;
- quint32 hash = 0;
- quint32 symbolId = 0;
-
- union {
- const char *ckey;
- QStringData *strData;
- };
-
- inline QHashedString key() const
- {
- if (isQString())
- return QHashedString(QString((QChar *)strData->data(), length), hash);
-
- return QHashedString(QString::fromLatin1(ckey, length), hash);
- }
-
- bool isQString() const { return next.flag(); }
- void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
-
- inline char *cStrData() const { return (char *)ckey; }
- inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
-
- inline bool equals(const QV4::Value &string) const {
- QString s = string.toQStringNoThrow();
- if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == s;
- } else {
- return QLatin1String(cStrData(), length) == s;
- }
- }
-
- inline bool equals(const QV4::String *string) const {
- if (length != string->d()->length() || hash != string->hashValue())
- return false;
- if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == string->toQString();
- } else {
- return QLatin1String(cStrData(), length) == string->toQString();
- }
- }
-
- inline bool equals(const QHashedStringRef &string) const {
- return length == string.length() &&
- hash == string.hash() &&
- (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
- QHashedString::compare(string.constData(), cStrData(), length));
- }
-
- inline bool equals(const QHashedCStringRef &string) const {
- return length == string.length() &&
- hash == string.hash() &&
- (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length):
- QHashedString::compare(string.constData(), cStrData(), length));
- }
-};
-
-class Q_AUTOTEST_EXPORT QStringHashData
-{
-public:
- QStringHashData() {}
-
- QStringHashNode **buckets = nullptr;
- int numBuckets = 0;
- int size = 0;
- short numBits = 0;
-#ifdef QSTRINGHASH_LINK_DEBUG
- int linkCount = 0;
-#endif
-
- struct IteratorData {
- IteratorData() {}
- QStringHashNode *n = nullptr;
- void *p = nullptr;
- };
- void rehashToBits(short);
- void rehashToSize(int);
- void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
-
-private:
- QStringHashData(const QStringHashData &);
- QStringHashData &operator=(const QStringHashData &);
-};
-
-// For a supplied key type, in what form do we need to keep a hashed version?
-template<typename T>
-struct HashedForm {};
-
-template<> struct HashedForm<QString> { typedef QHashedString Type; };
-template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
-template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
-template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
-template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
-template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
-template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
-template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
-
-class QStringHashBase
-{
-public:
- static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
- static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
- static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
- static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
- static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
- static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
-
- static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
- static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
-
- static const QString &toQString(const QString &s) { return s; }
- static const QString &toQString(const QHashedString &s) { return s; }
- static QString toQString(const QV4::String *s) { return s->toQString(); }
- static QString toQString(const QHashedStringRef &s) { return s.toString(); }
-
- static QString toQString(const QLatin1String &s) { return QString(s); }
- static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
-
- static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
- static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
- static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
-
- template<typename K>
- static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
-};
-
-template<class T>
-class QStringHash : public QStringHashBase
-{
-public:
- typedef QHashedString key_type;
- typedef T mapped_type;
-
- struct Node : public QStringHashNode {
- Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
- Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
- Node(const Node &o) : QStringHashNode(o), value(o.value) {}
- Node() {}
- T value;
- };
- struct NewedNode : public Node {
- NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
- NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
- NewedNode(const Node &o) : Node(o), nextNewed(nullptr) {}
- NewedNode *nextNewed;
- };
- struct ReservedNodePool
- {
- ReservedNodePool() : nodes(nullptr) {}
- ~ReservedNodePool() { delete [] nodes; }
- int count = 0;
- int used = 0;
- Node *nodes;
- };
-
- QStringHashData data;
- NewedNode *newedNodes;
- ReservedNodePool *nodePool;
- const QStringHash<T> *link;
-
- template<typename K>
- inline Node *findNode(const K &) const;
-
- inline Node *createNode(const Node &o);
-
- template<typename K>
- inline Node *createNode(const K &, const T &);
-
- inline Node *insertNode(Node *, quint32);
-
- inline void initializeNode(Node *, const QHashedString &key);
- inline void initializeNode(Node *, const QHashedCStringRef &key);
-
- template<typename K>
- inline Node *takeNode(const K &key, const T &value);
-
- inline Node *takeNode(const Node &o);
-
- inline void copy(const QStringHash<T> &);
-
- void copyNode(const QStringHashNode *otherNode);
-
- inline QStringHashData::IteratorData iterateFirst() const;
- static inline QStringHashData::IteratorData iterateNext(const QStringHashData::IteratorData &);
-
-public:
- inline QStringHash();
- inline QStringHash(const QStringHash &);
- inline ~QStringHash();
-
- QStringHash &operator=(const QStringHash<T> &);
-
- void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
- void linkAndReserve(const QStringHash<T> &other, int additionalReserve);
-
- inline bool isEmpty() const;
- inline void clear();
- inline int count() const;
-
- inline int numBuckets() const;
- inline bool isLinked() const;
-
- class ConstIterator {
- public:
- inline ConstIterator();
- inline ConstIterator(const QStringHashData::IteratorData &);
-
- inline ConstIterator &operator++();
-
- inline bool operator==(const ConstIterator &o) const;
- inline bool operator!=(const ConstIterator &o) const;
-
- template<typename K>
- inline bool equals(const K &) const;
-
- inline QHashedString key() const;
- inline const T &value() const;
- inline const T &operator*() const;
-
- inline Node *node() const;
- private:
- QStringHashData::IteratorData d;
- };
-
- template<typename K>
- inline void insert(const K &, const T &);
-
- inline void insert(const ConstIterator &);
-
- template<typename K>
- inline T *value(const K &) const;
-
- inline T *value(const QV4::String *string) const;
- inline T *value(const ConstIterator &) const;
-
- template<typename K>
- inline bool contains(const K &) const;
-
- template<typename K>
- inline T &operator[](const K &);
-
- inline ConstIterator begin() const;
- inline ConstIterator end() const;
-
- inline ConstIterator iterator(Node *n) const;
-
- template<typename K>
- inline ConstIterator find(const K &) const;
-
- inline void reserve(int);
-};
-
-template<class T>
-QStringHash<T>::QStringHash()
-: newedNodes(nullptr), nodePool(nullptr), link(nullptr)
-{
-}
-
-template<class T>
-QStringHash<T>::QStringHash(const QStringHash<T> &other)
-: newedNodes(nullptr), nodePool(nullptr), link(nullptr)
-{
- data.numBits = other.data.numBits;
- data.size = other.data.size;
- reserve(other.count());
- copy(other);
-}
-
-template<class T>
-QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
-{
- if (&other == this)
- return *this;
-
- clear();
-
- data.numBits = other.data.numBits;
- data.size = other.data.size;
- reserve(other.count());
- copy(other);
-
- return *this;
-}
-
-template<class T>
-void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
-{
- clear();
- data.numBits = other.data.numBits;
- reserve(other.count() + additionalReserve);
- copy(other);
-}
-
-template<class T>
-void QStringHash<T>::linkAndReserve(const QStringHash<T> &other, int additionalReserve)
-{
- clear();
-
- if (other.count()) {
- data.size = other.data.size;
- data.rehashToSize(other.count() + additionalReserve);
-
- if (data.numBuckets == other.data.numBuckets) {
- nodePool = new ReservedNodePool;
- nodePool->count = additionalReserve;
- nodePool->used = 0;
- nodePool->nodes = new Node[additionalReserve];
-
-#ifdef QSTRINGHASH_LINK_DEBUG
- data.linkCount++;
- const_cast<QStringHash<T>&>(other).data.linkCount++;
-#endif
-
- for (int ii = 0; ii < data.numBuckets; ++ii)
- data.buckets[ii] = (Node *)other.data.buckets[ii];
-
- link = &other;
- return;
- }
-
- data.size = 0;
- }
-
- data.numBits = other.data.numBits;
- reserve(other.count() + additionalReserve);
- copy(other);
-}
-
-template<class T>
-QStringHash<T>::~QStringHash()
-{
- clear();
-}
-
-template<class T>
-void QStringHash<T>::clear()
-{
-#ifdef QSTRINGHASH_LINK_DEBUG
- if (link) {
- data.linkCount--;
- const_cast<QStringHash<T> *>(link)->data.linkCount--;
- }
-
- if (data.linkCount)
- qFatal("QStringHash: Illegal attempt to clear a linked hash.");
-#endif
-
- // Delete the individually allocated nodes
- NewedNode *n = newedNodes;
- while (n) {
- NewedNode *c = n;
- n = c->nextNewed;
- delete c;
- }
- // Delete the pool allocated nodes
- if (nodePool) delete nodePool;
- delete [] data.buckets;
-
- data.buckets = nullptr;
- data.numBuckets = 0;
- data.numBits = 0;
- data.size = 0;
-
- newedNodes = nullptr;
- nodePool = nullptr;
- link = nullptr;
-}
-
-template<class T>
-bool QStringHash<T>::isEmpty() const
-{
- return data.size== 0;
-}
-
-template<class T>
-int QStringHash<T>::count() const
-{
- return data.size;
-}
-
-template<class T>
-int QStringHash<T>::numBuckets() const
-{
- return data.numBuckets;
-}
-
-template<class T>
-bool QStringHash<T>::isLinked() const
-{
- return link != 0;
-}
-
-template<class T>
-void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
-{
- node->length = key.length();
- node->hash = key.hash();
- node->strData = const_cast<QHashedString &>(key).data_ptr();
- node->strData->ref.ref();
- node->setQString(true);
-}
-
-template<class T>
-void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
-{
- node->length = key.length();
- node->hash = key.hash();
- node->ckey = key.constData();
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
-{
- if (nodePool && nodePool->used != nodePool->count) {
- Node *rv = nodePool->nodes + nodePool->used++;
- initializeNode(rv, hashedString(key));
- rv->value = value;
- return rv;
- } else {
- NewedNode *rv = new NewedNode(hashedString(key), value);
- rv->nextNewed = newedNodes;
- newedNodes = rv;
- return rv;
- }
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
-{
- if (nodePool && nodePool->used != nodePool->count) {
- Node *rv = nodePool->nodes + nodePool->used++;
- rv->length = o.length;
- rv->hash = o.hash;
- if (o.isQString()) {
- rv->strData = o.strData;
- rv->strData->ref.ref();
- rv->setQString(true);
- } else {
- rv->ckey = o.ckey;
- }
- rv->symbolId = o.symbolId;
- rv->value = o.value;
- return rv;
- } else {
- NewedNode *rv = new NewedNode(o);
- rv->nextNewed = newedNodes;
- newedNodes = rv;
- return rv;
- }
-}
-
-template<class T>
-void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
-{
- // Copy the predecessor before the successor
- QStringHashNode *next = otherNode->next.data();
- if (next)
- copyNode(next);
-
- Node *mynode = takeNode(*(const Node *)otherNode);
- int bucket = mynode->hash % data.numBuckets;
- mynode->next = data.buckets[bucket];
- data.buckets[bucket] = mynode;
-}
-
-template<class T>
-void QStringHash<T>::copy(const QStringHash<T> &other)
-{
- Q_ASSERT(data.size == 0);
-
- data.size = other.data.size;
-
- // Ensure buckets array is created
- data.rehashToBits(data.numBits);
-
- // Preserve the existing order within buckets
- for (int i = 0; i < other.data.numBuckets; ++i) {
- QStringHashNode *bucket = other.data.buckets[i];
- if (bucket)
- copyNode(bucket);
- }
-}
-
-template<class T>
-QStringHashData::IteratorData
-QStringHash<T>::iterateNext(const QStringHashData::IteratorData &d)
-{
- QStringHash<T> *This = (QStringHash<T> *)d.p;
- Node *node = (Node *)d.n;
-
- if (This->nodePool && node >= This->nodePool->nodes &&
- node < (This->nodePool->nodes + This->nodePool->used)) {
- node--;
- if (node < This->nodePool->nodes)
- node = nullptr;
- } else {
- NewedNode *nn = (NewedNode *)node;
- node = nn->nextNewed;
-
- if (node == nullptr && This->nodePool && This->nodePool->used)
- node = This->nodePool->nodes + This->nodePool->used - 1;
- }
-
- if (node == nullptr && This->link)
- return This->link->iterateFirst();
-
- QStringHashData::IteratorData rv;
- rv.n = node;
- rv.p = d.p;
- return rv;
-}
-
-template<class T>
-QStringHashData::IteratorData QStringHash<T>::iterateFirst() const
-{
- Node *n = nullptr;
- if (newedNodes)
- n = newedNodes;
- else if (nodePool && nodePool->used)
- n = nodePool->nodes + nodePool->used - 1;
-
- if (n == nullptr && link)
- return link->iterateFirst();
-
- QStringHashData::IteratorData rv;
- rv.n = n;
- rv.p = const_cast<QStringHash<T> *>(this);
- return rv;
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::iterator(Node *n) const
-{
- if (!n)
- return ConstIterator();
-
- const QStringHash<T> *container = this;
-
- if (link) {
- // This node could be in the linked hash
- if ((n >= nodePool->nodes) && (n < (nodePool->nodes + nodePool->used))) {
- // The node is in this hash
- } else if ((n >= link->nodePool->nodes) && (n < (link->nodePool->nodes + link->nodePool->used))) {
- // The node is in the linked hash
- container = link;
- } else {
- const NewedNode *ln = link->newedNodes;
- while (ln) {
- if (ln == n) {
- // This node is in the linked hash's newed list
- container = link;
- break;
- }
- ln = ln->nextNewed;
- }
- }
- }
-
- QStringHashData::IteratorData rv;
- rv.n = n;
- rv.p = const_cast<QStringHash<T> *>(container);
- return ConstIterator(rv);
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
-{
- Node *n = takeNode(o);
- return insertNode(n, n->hash);
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
-{
- Node *n = takeNode(key, value);
- return insertNode(n, hashOf(key));
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
-{
- if (data.size >= data.numBuckets)
- data.rehashToBits(data.numBits + 1);
-
- int bucket = hash % data.numBuckets;
- n->next = data.buckets[bucket];
- data.buckets[bucket] = n;
-
- data.size++;
-
- return n;
-}
-
-template<class T>
-template<class K>
-void QStringHash<T>::insert(const K &key, const T &value)
-{
- // If this is a linked hash, we can't rely on owning the node, so we always
- // create a new one.
- Node *n = link?nullptr:findNode(key);
- if (n) n->value = value;
- else createNode(key, value);
-}
-
-template<class T>
-void QStringHash<T>::insert(const ConstIterator &iter)
-{
- insert(iter.key(), iter.value());
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
-{
- QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:nullptr;
-
- typename HashedForm<K>::Type hashedKey(hashedString(key));
- while (node && !node->equals(hashedKey))
- node = (*node->next);
-
- return (Node *)node;
-}
-
-template<class T>
-template<class K>
-T *QStringHash<T>::value(const K &key) const
-{
- Node *n = findNode(key);
- return n?&n->value:nullptr;
-}
-
-template<class T>
-T *QStringHash<T>::value(const ConstIterator &iter) const
-{
- Node *n = iter.node();
- return value(n->key());
-}
-
-template<class T>
-T *QStringHash<T>::value(const QV4::String *string) const
-{
- Node *n = findNode(string);
- return n?&n->value:nullptr;
-}
-
-template<class T>
-template<class K>
-bool QStringHash<T>::contains(const K &key) const
-{
- return nullptr != value(key);
-}
-
-template<class T>
-template<class K>
-T &QStringHash<T>::operator[](const K &key)
-{
- Node *n = findNode(key);
- if (n) return n->value;
- else return createNode(key, T())->value;
-}
-
-template<class T>
-void QStringHash<T>::reserve(int n)
-{
- if (nodePool || 0 == n)
- return;
-
- nodePool = new ReservedNodePool;
- nodePool->count = n;
- nodePool->used = 0;
- nodePool->nodes = new Node[n];
-
- data.rehashToSize(n);
-}
-
-template<class T>
-QStringHash<T>::ConstIterator::ConstIterator()
-{
-}
-
-template<class T>
-QStringHash<T>::ConstIterator::ConstIterator(const QStringHashData::IteratorData &d)
-: d(d)
-{
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator &QStringHash<T>::ConstIterator::operator++()
-{
- d = QStringHash<T>::iterateNext(d);
- return *this;
-}
-
-template<class T>
-bool QStringHash<T>::ConstIterator::operator==(const ConstIterator &o) const
-{
- return d.n == o.d.n;
-}
-
-template<class T>
-bool QStringHash<T>::ConstIterator::operator!=(const ConstIterator &o) const
-{
- return d.n != o.d.n;
-}
-
-template<class T>
-template<typename K>
-bool QStringHash<T>::ConstIterator::equals(const K &key) const
-{
- return d.n->equals(key);
-}
-
-template<class T>
-QHashedString QStringHash<T>::ConstIterator::key() const
-{
- Node *n = (Node *)d.n;
- return n->key();
-}
-template<class T>
-const T &QStringHash<T>::ConstIterator::value() const
-{
- Node *n = (Node *)d.n;
- return n->value;
-}
-
-template<class T>
-const T &QStringHash<T>::ConstIterator::operator*() const
-{
- Node *n = (Node *)d.n;
- return n->value;
-}
-
-template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::ConstIterator::node() const
-{
- Node *n = (Node *)d.n;
- return n;
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
-{
- return ConstIterator(iterateFirst());
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
-{
- return ConstIterator();
-}
-
-template<class T>
-template<class K>
-typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
-{
- return iterator(findNode(key));
-}
-
-template<class T>
-class QStringMultiHash : public QStringHash<T>
-{
-public:
- typedef typename QStringHash<T>::ConstIterator ConstIterator;
-
- template<typename K>
- inline void insert(const K &, const T &);
-
- inline void insert(const ConstIterator &);
-
- inline ConstIterator findNext(const ConstIterator &) const;
-};
-
-template<class T>
-template<class K>
-void QStringMultiHash<T>::insert(const K &key, const T &value)
-{
- // Always create a new node
- QStringHash<T>::createNode(key, value);
-}
-
-template<class T>
-void QStringMultiHash<T>::insert(const ConstIterator &iter)
-{
- // Always create a new node
- QStringHash<T>::createNode(iter.key(), iter.value());
-}
-
-template<class T>
-typename QStringHash<T>::ConstIterator QStringMultiHash<T>::findNext(const ConstIterator &iter) const
-{
- QStringHashNode *node = iter.node();
- if (node) {
- QHashedString key(node->key());
-
- while ((node = *node->next)) {
- if (node->equals(key)) {
- return QStringHash<T>::iterator(static_cast<typename QStringHash<T>::Node *>(node));
- }
- }
- }
-
- return ConstIterator();
-}
-
inline uint qHash(const QHashedString &string)
{
return uint(string.hash());
diff --git a/src/qml/qml/ftw/qlinkedstringhash_p.h b/src/qml/qml/ftw/qlinkedstringhash_p.h
new file mode 100644
index 0000000000..67ced7fbbf
--- /dev/null
+++ b/src/qml/qml/ftw/qlinkedstringhash_p.h
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLINKEDSTRINGHASH_P_H
+#define QLINKEDSTRINGHASH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qstringhash_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<class T>
+class QLinkedStringHash : private QStringHash<T>
+{
+public:
+ using typename QStringHash<T>::Node;
+ using typename QStringHash<T>::NewedNode;
+ using typename QStringHash<T>::ReservedNodePool;
+ using typename QStringHash<T>::mapped_type;
+
+ using ConstIteratorData = QStringHashData::IteratorData<const QLinkedStringHash>;
+ using ConstIterator = typename QStringHash<T>::template Iterator<ConstIteratorData, const T>;
+
+ void linkAndReserve(const QLinkedStringHash<T> &other, int additionalReserve)
+ {
+ clear();
+
+ if (other.count()) {
+ data.size = other.data.size;
+ data.rehashToSize(other.count() + additionalReserve);
+
+ if (data.numBuckets == other.data.numBuckets) {
+ nodePool = new ReservedNodePool;
+ nodePool->count = additionalReserve;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[additionalReserve];
+
+ for (int ii = 0; ii < data.numBuckets; ++ii)
+ data.buckets[ii] = (Node *)other.data.buckets[ii];
+
+ link = &other;
+ return;
+ }
+
+ data.size = 0;
+ }
+
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+ }
+
+ inline bool isLinked() const
+ {
+ return link != 0;
+ }
+
+ void clear()
+ {
+ QStringHash<T>::clear();
+ link = nullptr;
+ }
+
+ template<typename K>
+ void insert(const K &key, const T &value)
+ {
+ // If this is a linked hash, we can't rely on owning the node, so we always
+ // create a new one.
+ Node *n = link ? nullptr : QStringHash<T>::findNode(key);
+ if (n)
+ n->value = value;
+ else
+ QStringHash<T>::createNode(key, value);
+ }
+
+ template<typename K>
+ inline ConstIterator find(const K &key) const
+ {
+ return iterator(QStringHash<T>::findNode(key));
+ }
+
+ ConstIterator begin() const
+ {
+ return ConstIterator(
+ QStringHash<T>::template iterateFirst<const QLinkedStringHash<T>,
+ ConstIteratorData>(this));
+ }
+
+ ConstIterator end() const { return ConstIterator(); }
+
+ inline T *value(const ConstIterator &iter) { return value(iter.node()->key()); }
+
+ using QStringHash<T>::value;
+ using QStringHash<T>::reserve;
+ using QStringHash<T>::copy;
+
+protected:
+ friend QStringHash<T>;
+ using QStringHash<T>::data;
+ using QStringHash<T>::nodePool;
+
+ using QStringHash<T>::createNode;
+
+ inline ConstIteratorData iterateFirst() const
+ {
+ const ConstIteratorData rv
+ = QStringHash<T>::template iterateFirst<const QLinkedStringHash<T>,
+ ConstIteratorData>(this);
+ return (rv.n == nullptr && link) ? link->iterateFirst() : rv;
+ }
+
+ static inline ConstIteratorData iterateNext(const ConstIteratorData &d)
+ {
+ const QLinkedStringHash<T> *self = d.p;
+ const ConstIteratorData rv = QStringHash<T>::iterateNext(d);
+ return (rv.n == nullptr && self->link) ? self->link->iterateFirst() : rv;
+ }
+
+ inline ConstIterator iterator(Node *n) const
+ {
+ if (!n)
+ return ConstIterator();
+
+ const QLinkedStringHash<T> *container = this;
+
+ if (link) {
+ // This node could be in the linked hash
+ if ((n >= nodePool->nodes) && (n < (nodePool->nodes + nodePool->used))) {
+ // The node is in this hash
+ } else if ((n >= link->nodePool->nodes)
+ && (n < (link->nodePool->nodes + link->nodePool->used))) {
+ // The node is in the linked hash
+ container = link;
+ } else {
+ const NewedNode *ln = link->newedNodes;
+ while (ln) {
+ if (ln == n) {
+ // This node is in the linked hash's newed list
+ container = link;
+ break;
+ }
+ ln = ln->nextNewed;
+ }
+ }
+ }
+
+
+ ConstIteratorData rv;
+ rv.n = n;
+ rv.p = container;
+ return ConstIterator(rv);
+ }
+
+ const QLinkedStringHash<T> *link = nullptr;
+};
+
+template<class T>
+class QLinkedStringMultiHash : public QLinkedStringHash<T>
+{
+public:
+ using ConstIterator = typename QLinkedStringHash<T>::ConstIterator;
+
+ template<typename K>
+ inline void insert(const K &key, const T &value)
+ {
+ // Always create a new node
+ QLinkedStringHash<T>::createNode(key, value);
+ }
+
+ inline void insert(const ConstIterator &iter)
+ {
+ // Always create a new node
+ QLinkedStringHash<T>::createNode(iter.key(), iter.value());
+ }
+
+ inline ConstIterator findNext(const ConstIterator &iter) const
+ {
+ if (auto *node = iter.node()) {
+ QHashedString key(node->key());
+ while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(*node->next))) {
+ if (node->equals(key))
+ return QLinkedStringHash<T>::iterator(node);
+ }
+ }
+
+ return ConstIterator();
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QLINKEDSTRINGHASH_P_H
diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h
new file mode 100644
index 0000000000..6e9acbf7fd
--- /dev/null
+++ b/src/qml/qml/ftw/qprimefornumbits_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPRIMEFORNUMBITS_P_H
+#define QPRIMEFORNUMBITS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The qPrimeForNumBits() function returns the prime associated to a
+ power of two. For example, qPrimeForNumBits(8) returns 257.
+*/
+
+inline int qPrimeForNumBits(int numBits)
+{
+ static constexpr const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+ };
+
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+QT_END_NAMESPACE
+
+#endif // QPRIMEFORNUMBITS_P_H
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
index d32a08e0f5..b4f8acad49 100644
--- a/src/qml/qml/ftw/qqmlrefcount_p.h
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -60,18 +60,18 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlRefCount
{
+ Q_DISABLE_COPY_MOVE(QQmlRefCount)
public:
inline QQmlRefCount();
- inline virtual ~QQmlRefCount();
- inline void addref();
- inline void release();
+ inline void addref() const;
+ inline void release() const;
inline int count() const;
protected:
- inline virtual void destroy();
+ inline virtual ~QQmlRefCount();
private:
- QAtomicInt refCount;
+ mutable QAtomicInt refCount;
};
template<class T>
@@ -113,30 +113,25 @@ QQmlRefCount::QQmlRefCount()
QQmlRefCount::~QQmlRefCount()
{
- Q_ASSERT(refCount.load() == 0);
+ Q_ASSERT(refCount.loadRelaxed() == 0);
}
-void QQmlRefCount::addref()
+void QQmlRefCount::addref() const
{
- Q_ASSERT(refCount.load() > 0);
+ Q_ASSERT(refCount.loadRelaxed() > 0);
refCount.ref();
}
-void QQmlRefCount::release()
+void QQmlRefCount::release() const
{
- Q_ASSERT(refCount.load() > 0);
+ Q_ASSERT(refCount.loadRelaxed() > 0);
if (!refCount.deref())
- destroy();
+ delete this;
}
int QQmlRefCount::count() const
{
- return refCount.load();
-}
-
-void QQmlRefCount::destroy()
-{
- delete this;
+ return refCount.loadRelaxed();
}
template<class T>
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
new file mode 100644
index 0000000000..f9435b4919
--- /dev/null
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -0,0 +1,807 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTRINGHASH_P_H
+#define QSTRINGHASH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qhashedstring_p.h>
+#include <private/qprimefornumbits_p.h>
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStringHashData;
+class QStringHashNode
+{
+public:
+ QStringHashNode()
+ : ckey(nullptr)
+ {
+ }
+
+ QStringHashNode(const QHashedString &key)
+ : length(key.length()), hash(key.hash()), symbolId(0)
+ {
+ strData = const_cast<QHashedString &>(key).data_ptr();
+ setQString(true);
+ strData->ref.ref();
+ }
+
+ QStringHashNode(const QHashedCStringRef &key)
+ : length(key.length()), hash(key.hash()), symbolId(0), ckey(key.constData())
+ {
+ }
+
+ QStringHashNode(const QStringHashNode &o)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ {
+ setQString(o.isQString());
+ if (isQString()) { strData->ref.ref(); }
+ }
+
+ ~QStringHashNode()
+ {
+ if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ }
+
+ QFlagPointer<QStringHashNode> next;
+
+ qint32 length = 0;
+ quint32 hash = 0;
+ quint32 symbolId = 0;
+
+ union {
+ const char *ckey;
+ QStringData *strData;
+ };
+
+ inline QHashedString key() const
+ {
+ if (isQString())
+ return QHashedString(QString((QChar *)strData->data(), length), hash);
+
+ return QHashedString(QString::fromLatin1(ckey, length), hash);
+ }
+
+ bool isQString() const { return next.flag(); }
+ void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+
+ inline char *cStrData() const { return (char *)ckey; }
+ inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
+
+ inline bool equals(const QV4::Value &string) const {
+ QString s = string.toQStringNoThrow();
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == s;
+ } else {
+ return QLatin1String(cStrData(), length) == s;
+ }
+ }
+
+ inline bool equals(const QV4::String *string) const {
+ if (length != string->d()->length() || hash != string->hashValue())
+ return false;
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == string->toQString();
+ } else {
+ return QLatin1String(cStrData(), length) == string->toQString();
+ }
+ }
+
+ inline bool equals(const QHashedStringRef &string) const {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+
+ inline bool equals(const QHashedCStringRef &string) const {
+ return length == string.length() &&
+ hash == string.hash() &&
+ (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length):
+ QHashedString::compare(string.constData(), cStrData(), length));
+ }
+};
+
+class QStringHashData
+{
+ Q_DISABLE_COPY_MOVE(QStringHashData)
+public:
+ QStringHashData() = default;
+ ~QStringHashData() = default;
+
+ /*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+ */
+ enum { MinNumBits = 4 };
+
+ QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash
+ int numBuckets = 0;
+ int size = 0;
+ short numBits = 0;
+
+ template<typename StringHash>
+ struct IteratorData {
+ IteratorData(QStringHashNode *n = nullptr, StringHash *p = nullptr) : n(n), p(p) {}
+
+ template<typename OtherData>
+ IteratorData(const OtherData &other) : n(other.n), p(other.p) {}
+
+ QStringHashNode *n;
+ StringHash *p;
+ };
+
+ void rehashToBits(short bits)
+ {
+ numBits = qMax(short(MinNumBits), bits);
+
+ int nb = qPrimeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ QStringHashNode **newBuckets = new QStringHashNode *[nb];
+ ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
+
+ // Preserve the existing order within buckets so that items with the
+ // same key will retain the same find/findNext order
+ for (int i = 0; i < numBuckets; ++i) {
+ QStringHashNode *bucket = buckets[i];
+ if (bucket)
+ rehashNode(newBuckets, nb, bucket);
+ }
+
+ delete [] buckets;
+ buckets = newBuckets;
+ numBuckets = nb;
+ }
+
+ void rehashToSize(int size)
+ {
+ short bits = qMax(short(MinNumBits), numBits);
+ while (qPrimeForNumBits(bits) < size)
+ bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits);
+ }
+
+ void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
+ {
+ QStringHashNode *next = node->next.data();
+ if (next)
+ rehashNode(newBuckets, nb, next);
+
+ int bucket = node->hash % nb;
+ node->next = newBuckets[bucket];
+ newBuckets[bucket] = node;
+ }
+};
+
+// For a supplied key type, in what form do we need to keep a hashed version?
+template<typename T>
+struct HashedForm {};
+
+template<> struct HashedForm<QString> { typedef QHashedString Type; };
+template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
+template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
+template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
+template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
+template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
+template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
+template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
+
+class QStringHashBase
+{
+public:
+ static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
+ static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
+ static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
+ static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
+ static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
+ static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
+
+ static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
+ static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
+
+ static const QString &toQString(const QString &s) { return s; }
+ static const QString &toQString(const QHashedString &s) { return s; }
+ static QString toQString(const QV4::String *s) { return s->toQString(); }
+ static QString toQString(const QHashedStringRef &s) { return s.toString(); }
+
+ static QString toQString(const QLatin1String &s) { return QString(s); }
+ static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
+
+ static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
+ static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
+ static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
+
+ template<typename K>
+ static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
+};
+
+template<class T>
+class QStringHash : public QStringHashBase
+{
+public:
+ typedef QHashedString key_type;
+ typedef T mapped_type;
+
+ using MutableIteratorData = QStringHashData::IteratorData<QStringHash<T>>;
+ using ConstIteratorData = QStringHashData::IteratorData<const QStringHash<T>>;
+
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const QHashedCStringRef &key, const T &value) : QStringHashNode(key), value(value) {}
+ Node(const Node &o) : QStringHashNode(o), value(o.value) {}
+ Node() {}
+ T value;
+ };
+ struct NewedNode : public Node {
+ NewedNode(const QHashedString &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
+ NewedNode(const QHashedCStringRef &key, const T &value) : Node(key, value), nextNewed(nullptr) {}
+ NewedNode(const Node &o) : Node(o), nextNewed(nullptr) {}
+ NewedNode *nextNewed;
+ };
+ struct ReservedNodePool
+ {
+ ReservedNodePool() : nodes(nullptr) {}
+ ~ReservedNodePool() { delete [] nodes; }
+ int count = 0;
+ int used = 0;
+ Node *nodes;
+ };
+
+ QStringHashData data;
+ NewedNode *newedNodes;
+ ReservedNodePool *nodePool;
+
+ template<typename K>
+ inline Node *findNode(const K &) const;
+
+ inline Node *createNode(const Node &o);
+
+ template<typename K>
+ inline Node *createNode(const K &, const T &);
+
+ inline Node *insertNode(Node *, quint32);
+
+ inline void initializeNode(Node *, const QHashedString &key);
+ inline void initializeNode(Node *, const QHashedCStringRef &key);
+
+ template<typename K>
+ inline Node *takeNode(const K &key, const T &value);
+
+ inline Node *takeNode(const Node &o);
+
+ inline void copy(const QStringHash<T> &);
+
+ void copyNode(const QStringHashNode *otherNode);
+
+ template<typename StringHash, typename Data>
+ static inline Data iterateFirst(StringHash *self);
+
+ template<typename Data>
+ static inline Data iterateNext(const Data &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ void copyAndReserve(const QStringHash<T> &other, int additionalReserve);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline int numBuckets() const;
+
+ template<typename Data, typename Value>
+ class Iterator {
+ public:
+ inline Iterator() = default;
+ inline Iterator(const Data &d) : d(d) {}
+
+ inline Iterator &operator++()
+ {
+ d = QStringHash<T>::iterateNext(d);
+ return *this;
+ }
+
+ inline bool operator==(const Iterator &o) const { return d.n == o.d.n; }
+ inline bool operator!=(const Iterator &o) const { return d.n != o.d.n; }
+
+ template<typename K>
+ inline bool equals(const K &key) const { return d.n->equals(key); }
+
+ inline QHashedString key() const { return static_cast<Node *>(d.n)->key(); }
+ inline Value &value() const { return static_cast<Node *>(d.n)->value; }
+ inline Value &operator*() const { return static_cast<Node *>(d.n)->value; }
+
+ Node *node() const { return static_cast<Node *>(d.n); }
+ private:
+ Data d;
+ };
+
+ using MutableIterator = Iterator<MutableIteratorData, T>;
+ using ConstIterator = Iterator<ConstIteratorData, const T>;
+
+ template<typename K>
+ inline void insert(const K &, const T &);
+ inline void insert(const MutableIterator &);
+ inline void insert(const ConstIterator &);
+
+ template<typename K>
+ inline T *value(const K &) const;
+ inline T *value(const QV4::String *string) const;
+ inline T *value(const MutableIterator &) const;
+ inline T *value(const ConstIterator &) const;
+
+ template<typename K>
+ inline bool contains(const K &) const;
+
+ template<typename K>
+ inline T &operator[](const K &);
+
+ inline MutableIterator begin();
+ inline ConstIterator begin() const;
+ inline ConstIterator constBegin() const { return begin(); }
+
+ inline MutableIterator end();
+ inline ConstIterator end() const;
+ inline ConstIterator constEnd() const { return end(); }
+
+ template<typename K>
+ inline MutableIterator find(const K &);
+
+ template<typename K>
+ inline ConstIterator find(const K &) const;
+
+ inline void reserve(int);
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+: newedNodes(nullptr), nodePool(nullptr)
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: newedNodes(nullptr), nodePool(nullptr)
+{
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+
+ data.numBits = other.data.numBits;
+ data.size = other.data.size;
+ reserve(other.count());
+ copy(other);
+
+ return *this;
+}
+
+template<class T>
+void QStringHash<T>::copyAndReserve(const QStringHash<T> &other, int additionalReserve)
+{
+ clear();
+ data.numBits = other.data.numBits;
+ reserve(other.count() + additionalReserve);
+ copy(other);
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+ // Delete the individually allocated nodes
+ NewedNode *n = newedNodes;
+ while (n) {
+ NewedNode *c = n;
+ n = c->nextNewed;
+ delete c;
+ }
+ // Delete the pool allocated nodes
+ if (nodePool) delete nodePool;
+ delete [] data.buckets;
+
+ data.buckets = nullptr;
+ data.numBuckets = 0;
+ data.numBits = 0;
+ data.size = 0;
+
+ newedNodes = nullptr;
+ nodePool = nullptr;
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.size== 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+int QStringHash<T>::numBuckets() const
+{
+ return data.numBuckets;
+}
+
+template<class T>
+void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
+{
+ node->length = key.length();
+ node->hash = key.hash();
+ node->strData = const_cast<QHashedString &>(key).data_ptr();
+ node->strData->ref.ref();
+ node->setQString(true);
+}
+
+template<class T>
+void QStringHash<T>::initializeNode(Node *node, const QHashedCStringRef &key)
+{
+ node->length = key.length();
+ node->hash = key.hash();
+ node->ckey = key.constData();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const K &key, const T &value)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ initializeNode(rv, hashedString(key));
+ rv->value = value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(hashedString(key), value);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
+{
+ if (nodePool && nodePool->used != nodePool->count) {
+ Node *rv = nodePool->nodes + nodePool->used++;
+ rv->length = o.length;
+ rv->hash = o.hash;
+ if (o.isQString()) {
+ rv->strData = o.strData;
+ rv->strData->ref.ref();
+ rv->setQString(true);
+ } else {
+ rv->ckey = o.ckey;
+ }
+ rv->symbolId = o.symbolId;
+ rv->value = o.value;
+ return rv;
+ } else {
+ NewedNode *rv = new NewedNode(o);
+ rv->nextNewed = newedNodes;
+ newedNodes = rv;
+ return rv;
+ }
+}
+
+template<class T>
+void QStringHash<T>::copyNode(const QStringHashNode *otherNode)
+{
+ // Copy the predecessor before the successor
+ QStringHashNode *next = otherNode->next.data();
+ if (next)
+ copyNode(next);
+
+ Node *mynode = takeNode(*(const Node *)otherNode);
+ int bucket = mynode->hash % data.numBuckets;
+ mynode->next = data.buckets[bucket];
+ data.buckets[bucket] = mynode;
+}
+
+template<class T>
+void QStringHash<T>::copy(const QStringHash<T> &other)
+{
+ Q_ASSERT(data.size == 0);
+
+ data.size = other.data.size;
+
+ // Ensure buckets array is created
+ data.rehashToBits(data.numBits);
+
+ // Preserve the existing order within buckets
+ for (int i = 0; i < other.data.numBuckets; ++i) {
+ QStringHashNode *bucket = other.data.buckets[i];
+ if (bucket)
+ copyNode(bucket);
+ }
+}
+
+template<class T>
+template<typename Data>
+Data QStringHash<T>::iterateNext(const Data &d)
+{
+ auto *This = d.p;
+ Node *node = (Node *)d.n;
+
+ if (This->nodePool && node >= This->nodePool->nodes &&
+ node < (This->nodePool->nodes + This->nodePool->used)) {
+ node--;
+ if (node < This->nodePool->nodes)
+ node = nullptr;
+ } else {
+ NewedNode *nn = (NewedNode *)node;
+ node = nn->nextNewed;
+
+ if (node == nullptr && This->nodePool && This->nodePool->used)
+ node = This->nodePool->nodes + This->nodePool->used - 1;
+ }
+
+ Data rv;
+ rv.n = node;
+ rv.p = d.p;
+ return rv;
+}
+
+template<class T>
+template<typename StringHash, typename Data>
+Data QStringHash<T>::iterateFirst(StringHash *self)
+{
+ typename StringHash::Node *n = nullptr;
+ if (self->newedNodes)
+ n = self->newedNodes;
+ else if (self->nodePool && self->nodePool->used)
+ n = self->nodePool->nodes + self->nodePool->used - 1;
+
+ Data rv;
+ rv.n = n;
+ rv.p = self;
+ return rv;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const Node &o)
+{
+ Node *n = takeNode(o);
+ return insertNode(n, n->hash);
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const K &key, const T &value)
+{
+ Node *n = takeNode(key, value);
+ return insertNode(n, hashOf(key));
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::insertNode(Node *n, quint32 hash)
+{
+ if (data.size >= data.numBuckets)
+ data.rehashToBits(data.numBits + 1);
+
+ int bucket = hash % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+template<class K>
+void QStringHash<T>::insert(const K &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n)
+ n->value = value;
+ else
+ createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const MutableIterator &iter)
+{
+ insert(iter.key(), iter.value());
+}
+
+template<class T>
+void QStringHash<T>::insert(const ConstIterator &iter)
+{
+ insert(iter.key(), iter.value());
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
+{
+ QStringHashNode *node = data.numBuckets?data.buckets[hashOf(key) % data.numBuckets]:nullptr;
+
+ typename HashedForm<K>::Type hashedKey(hashedString(key));
+ while (node && !node->equals(hashedKey))
+ node = (*node->next);
+
+ return (Node *)node;
+}
+
+template<class T>
+template<class K>
+T *QStringHash<T>::value(const K &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:nullptr;
+}
+
+template<typename T>
+T *QStringHash<T>::value(const MutableIterator &iter) const
+{
+ return value(iter.node()->key());
+}
+
+template<class T>
+T *QStringHash<T>::value(const ConstIterator &iter) const
+{
+ return value(iter.node()->key());
+}
+
+template<class T>
+T *QStringHash<T>::value(const QV4::String *string) const
+{
+ Node *n = findNode(string);
+ return n?&n->value:nullptr;
+}
+
+template<class T>
+template<class K>
+bool QStringHash<T>::contains(const K &key) const
+{
+ return nullptr != value(key);
+}
+
+template<class T>
+template<class K>
+T &QStringHash<T>::operator[](const K &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key, T())->value;
+}
+
+template<class T>
+void QStringHash<T>::reserve(int n)
+{
+ if (nodePool || 0 == n)
+ return;
+
+ nodePool = new ReservedNodePool;
+ nodePool->count = n;
+ nodePool->used = 0;
+ nodePool->nodes = new Node[n];
+
+ data.rehashToSize(n);
+}
+
+template<class T>
+typename QStringHash<T>::MutableIterator QStringHash<T>::begin()
+{
+ return MutableIterator(iterateFirst<QStringHash<T>, MutableIteratorData>(this));
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::begin() const
+{
+ return ConstIterator(iterateFirst<const QStringHash<T>, ConstIteratorData>(this));
+}
+
+template<class T>
+typename QStringHash<T>::MutableIterator QStringHash<T>::end()
+{
+ return MutableIterator();
+}
+
+template<class T>
+typename QStringHash<T>::ConstIterator QStringHash<T>::end() const
+{
+ return ConstIterator();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::MutableIterator QStringHash<T>::find(const K &key)
+{
+ Node *n = findNode(key);
+ return n ? MutableIterator(MutableIteratorData(n, this)) : MutableIterator();
+}
+
+template<class T>
+template<class K>
+typename QStringHash<T>::ConstIterator QStringHash<T>::find(const K &key) const
+{
+ Node *n = findNode(key);
+ return n ? ConstIterator(ConstIteratorData(n, this)) : ConstIterator();
+}
+
+QT_END_NAMESPACE
+
+#endif // QSTRINGHASH_P_H
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index ca13ce9211..2e9c6f3de6 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -1,5 +1,14 @@
SOURCES += \
+ $$PWD/qqml.cpp \
+ $$PWD/qqmldatablob.cpp \
+ $$PWD/qqmldirdata.cpp \
+ $$PWD/qqmlerror.cpp \
$$PWD/qqmlopenmetaobject.cpp \
+ $$PWD/qqmlscriptblob.cpp \
+ $$PWD/qqmlscriptdata.cpp \
+ $$PWD/qqmltypedata.cpp \
+ $$PWD/qqmltypeloaderqmldircontent.cpp \
+ $$PWD/qqmltypeloaderthread.cpp \
$$PWD/qqmlvmemetaobject.cpp \
$$PWD/qqmlengine.cpp \
$$PWD/qqmlexpression.cpp \
@@ -14,14 +23,21 @@ SOURCES += \
$$PWD/qqmlvme.cpp \
$$PWD/qqmlboundsignal.cpp \
$$PWD/qqmlmetatype.cpp \
+ $$PWD/qqmlmetatypedata.cpp \
$$PWD/qqmlstringconverters.cpp \
+ $$PWD/qqmltype.cpp \
+ $$PWD/qqmltypemodule.cpp \
+ $$PWD/qqmltypemoduleversion.cpp \
$$PWD/qqmlparserstatus.cpp \
$$PWD/qqmltypeloader.cpp \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlvaluetype.cpp \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
+ $$PWD/qqmlmetaobject.cpp \
$$PWD/qqmlnotifier.cpp \
+ $$PWD/qqmlobjectorgadget.cpp \
+ $$PWD/qqmlstaticmetaobject.cpp \
$$PWD/qqmltypenotavailable.cpp \
$$PWD/qqmltypenamecache.cpp \
$$PWD/qqmlscriptstring.cpp \
@@ -44,13 +60,26 @@ SOURCES += \
$$PWD/qqmlfileselector.cpp \
$$PWD/qqmlobjectcreator.cpp \
$$PWD/qqmldelayedcallqueue.cpp \
- $$PWD/qqmlloggingcategory.cpp
+ $$PWD/qqmlloggingcategory.cpp \
+ $$PWD/qqmlirloader.cpp \
+ $$PWD/qqmlpropertyresolver.cpp \
+ $$PWD/qqmltypecompiler.cpp \
+ $$PWD/qqmlpropertycachecreator.cpp \
+ $$PWD/qqmlpropertyvalidator.cpp
HEADERS += \
+ $$PWD/qqmldatablob_p.h \
+ $$PWD/qqmldirdata_p.h \
$$PWD/qqmlglobal_p.h \
$$PWD/qqmlopenmetaobject_p.h \
+ $$PWD/qqmlscriptblob_p.h \
+ $$PWD/qqmlscriptdata_p.h \
+ $$PWD/qqmltypedata_p.h \
+ $$PWD/qqmltypeloaderqmldircontent_p.h \
+ $$PWD/qqmltypeloaderthread_p.h \
$$PWD/qqmlvmemetaobject_p.h \
$$PWD/qqml.h \
+ $$PWD/qqmlerror.h \
$$PWD/qqmlproperty.h \
$$PWD/qqmlcomponent.h \
$$PWD/qqmlcomponent_p.h \
@@ -68,6 +97,12 @@ HEADERS += \
$$PWD/qqmlexpression_p.h \
$$PWD/qqmlprivate.h \
$$PWD/qqmlmetatype_p.h \
+ $$PWD/qqmlmetatypedata_p.h \
+ $$PWD/qqmltype_p.h \
+ $$PWD/qqmltype_p_p.h \
+ $$PWD/qqmltypemodule_p.h \
+ $$PWD/qqmltypemodule_p_p.h \
+ $$PWD/qqmltypemoduleversion_p.h \
$$PWD/qqmlengine.h \
$$PWD/qqmlcontext.h \
$$PWD/qqmlexpression.h \
@@ -81,9 +116,17 @@ HEADERS += \
$$PWD/qqmldata_p.h \
$$PWD/qqmlvaluetype_p.h \
$$PWD/qqmlcleanup_p.h \
+ $$PWD/qqmlenumdata_p.h \
+ $$PWD/qqmlenumvalue_p.h \
$$PWD/qqmlpropertycache_p.h \
+ $$PWD/qqmlpropertycachemethodarguments_p.h \
+ $$PWD/qqmlpropertycachevector_p.h \
+ $$PWD/qqmlpropertydata_p.h \
$$PWD/qqmlpropertyindex_p.h \
+ $$PWD/qqmlmetaobject_p.h \
$$PWD/qqmlnotifier_p.h \
+ $$PWD/qqmlobjectorgadget_p.h \
+ $$PWD/qqmlstaticmetaobject_p.h \
$$PWD/qqmltypenotavailable_p.h \
$$PWD/qqmltypenamecache_p.h \
$$PWD/qqmlscriptstring.h \
@@ -110,7 +153,13 @@ HEADERS += \
$$PWD/qqmlfileselector.h \
$$PWD/qqmlobjectcreator_p.h \
$$PWD/qqmldelayedcallqueue_p.h \
- $$PWD/qqmlloggingcategory_p.h
+ $$PWD/qqmlloggingcategory_p.h \
+ $$PWD/qqmlirloader_p.h \
+ $$PWD/qqmlpropertyresolver_p.h \
+ $$PWD/qqmltypecompiler_p.h \
+ $$PWD/qqmlpropertycachecreator_p.h \
+ $$PWD/qqmlpropertyvalidator_p.h \
+ $$PWD/qqmlsourcecoordinate_p.h
qtConfig(qml-xml-http-request) {
HEADERS += \
@@ -129,5 +178,15 @@ qtConfig(qml-locale) {
$$PWD/qqmllocale.cpp
}
+qtConfig(qml-network) {
+ HEADERS += \
+ $$PWD/qqmltypeloadernetworkreplyproxy_p.h
+
+ SOURCES += \
+ $$PWD/qqmltypeloadernetworkreplyproxy.cpp
+}
+
+android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
new file mode 100644
index 0000000000..5b16a3c9e2
--- /dev/null
+++ b/src/qml/qml/qqml.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqml.h"
+
+#include <QtQml/qqmlprivate.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmlmetatypedata_p.h>
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypemodule_p_p.h>
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+void qmlClearTypeRegistrations() // Declared in qqml.h
+{
+ QQmlMetaType::clearTypeRegistrations();
+ QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types
+ qmlClearEnginePlugins();
+}
+
+//From qqml.h
+bool qmlProtectModule(const char *uri, int majVersion)
+{
+ return QQmlMetaType::protectModule(uri, majVersion);
+}
+
+//From qqml.h
+void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
+{
+ QQmlMetaType::registerModule(uri, versionMajor, versionMinor);
+}
+
+//From qqml.h
+int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ return QQmlMetaType::typeId(uri, versionMajor, versionMinor, qmlName);
+}
+
+// From qqmlprivate.h
+QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (!m_object) {
+ QQmlError error;
+ error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+
+ if (qeng->thread() != m_object->thread()) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+ if (alreadyCalled) {
+ QQmlError error;
+ error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
+ QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ return nullptr;
+ }
+ alreadyCalled = true;
+ qeng->setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ return m_object;
+};
+
+/*
+This method is "over generalized" to allow us to (potentially) register more types of things in
+the future without adding exported symbols.
+*/
+int QQmlPrivate::qmlregister(RegistrationType type, void *data)
+{
+ if (type == AutoParentRegistration) {
+ return QQmlMetaType::registerAutoParentFunction(
+ *reinterpret_cast<RegisterAutoParent *>(data));
+ } else if (type == QmlUnitCacheHookRegistration) {
+ return QQmlMetaType::registerUnitCacheHook(
+ *reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
+ }
+
+ QQmlType dtype;
+ if (type == TypeRegistration)
+ dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
+ else if (type == InterfaceRegistration)
+ dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data));
+ else if (type == SingletonRegistration)
+ dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
+ else if (type == CompositeRegistration)
+ dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
+ else if (type == CompositeSingletonRegistration)
+ dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
+ else
+ return -1;
+
+ if (!dtype.isValid())
+ return -1;
+
+ QQmlMetaType::registerUndeletableType(dtype);
+ return dtype.index();
+}
+
+void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
+{
+ switch (type) {
+ case AutoParentRegistration:
+ QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data));
+ break;
+ case QmlUnitCacheHookRegistration:
+ QQmlMetaType::removeCachedUnitLookupFunction(
+ reinterpret_cast<QmlUnitCacheLookupFunction>(data));
+ break;
+ case TypeRegistration:
+ case InterfaceRegistration:
+ case SingletonRegistration:
+ case CompositeRegistration:
+ case CompositeSingletonRegistration:
+ QQmlMetaType::unregisterType(data);
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 6bd66464b5..b2bf1f328f 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -102,7 +102,7 @@ class QQmlPropertyValueInterceptor;
void Q_QML_EXPORT qmlClearTypeRegistrations();
template<typename T>
-int qmlRegisterType()
+int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
QML_GETTYPENAMES
@@ -115,7 +115,7 @@ int qmlRegisterType()
nullptr,
QString(),
- nullptr, 0, 0, nullptr, &T::staticMetaObject,
+ uri, versionMajor, 0, nullptr, &T::staticMetaObject,
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -133,6 +133,14 @@ int qmlRegisterType()
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
+#if QT_DEPRECATED_SINCE(5, 14)
+template<typename T>
+QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
+{
+ return qmlRegisterAnonymousType<T>("", 1);
+}
+#endif
+
int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
template<typename T>
@@ -579,9 +587,13 @@ namespace QtQml {
Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *,
- const QMetaObject *, bool create);
+#if QT_DEPRECATED_SINCE(5, 14)
+ Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
+ QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+ Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
+ QObject *qmlAttachedPropertiesObject(
+ int *, const QObject *, const QMetaObject *, bool create);
+#endif
Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
const QMetaObject *);
Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
@@ -614,8 +626,6 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create);
}
-Q_QML_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor);
-
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
QJSValue (*callback)(QQmlEngine *, QJSEngine *))
{
@@ -624,13 +634,13 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
uri, versionMajor, versionMinor, typeName,
- callback, nullptr, nullptr, 0, 0
+ callback, nullptr, nullptr, 0, 0, {}
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
-enum { QmlCurrentSingletonTypeRegistrationVersion = 2 };
+enum { QmlCurrentSingletonTypeRegistrationVersion = 3 };
template <typename T>
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
QObject *(*callback)(QQmlEngine *, QJSEngine *))
@@ -642,12 +652,40 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
uri, versionMajor, versionMinor, typeName,
- nullptr, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0
+ nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+template <typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value
+ && !std::is_convertible<F, QObject *(*)(QQmlEngine *, QJSEngine *)>::value, void>::type* = nullptr>
+inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
+ F&& callback)
+{
+
+ QML_GETTYPENAMES
+
+ QQmlPrivate::RegisterSingletonType api = {
+ QmlCurrentSingletonTypeRegistrationVersion,
+
+ uri, versionMajor, versionMinor, typeName,
+
+ nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
+}
+
+template<typename T>
+inline auto qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor,
+ const char *typeName, T *cppObject) -> typename std::enable_if<std::is_base_of<QObject, T>::value, int>::type
+{
+ QQmlPrivate::RegisterSingletonFunctor registrationFunctor;
+ registrationFunctor.m_object = cppObject;
+ return qmlRegisterSingletonType<T>(uri, versionMajor, versionMinor, typeName, registrationFunctor);
+}
+
inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
if (url.isRelative()) {
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index facd79d211..adb036e2d0 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include <QtQml/qqmlfile.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QTranslator>
#include <QQmlComponent>
@@ -62,9 +63,6 @@ void QQmlApplicationEnginePrivate::cleanUp()
obj->disconnect(q);
qDeleteAll(objects);
-#if QT_CONFIG(translation)
- qDeleteAll(translators);
-#endif
}
void QQmlApplicationEnginePrivate::init()
@@ -75,10 +73,11 @@ void QQmlApplicationEnginePrivate::init()
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
#if QT_CONFIG(translation)
- QTranslator* qtTranslator = new QTranslator;
+ QTranslator* qtTranslator = new QTranslator(q);
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
QCoreApplication::installTranslator(qtTranslator);
- translators << qtTranslator;
+ else
+ delete qtTranslator;
#endif
new QQmlFileSelector(q,q);
QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true));
@@ -92,13 +91,12 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
- QTranslator *translator = new QTranslator;
- if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) {
+ Q_Q(QQmlApplicationEngine);
+ QTranslator *translator = new QTranslator(q);
+ if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm")))
QCoreApplication::installTranslator(translator);
- translators << translator;
- } else {
+ else
delete translator;
- }
#else
Q_UNUSED(rootFile)
#endif
@@ -133,7 +131,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
q->objectCreated(nullptr, c->url());
break;
case QQmlComponent::Ready: {
- auto newObj = c->create();
+ auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties);
objects << newObj;
QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
@@ -281,6 +279,22 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
+ Sets the \a initialProperties with which the QML component gets initialized after
+ it gets loaded.
+
+
+ \sa QQmlComponent::setInitialProperties
+ \sa QQmlApplicationEngine::load
+ \sa QQmlApplicationEngine::loadData
+ \since 5.14
+*/
+void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialProperties)
+{
+ Q_D(QQmlApplicationEngine);
+ d->initialProperties = initialProperties;
+}
+
+/*!
Loads the QML given in \a data. The object tree defined by \a data is
instantiated immediately.
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index bb5d6b5d68..2b4de91154 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -66,6 +66,7 @@ public:
public Q_SLOTS:
void load(const QUrl &url);
void load(const QString &filePath);
+ void setInitialProperties(const QVariantMap &initialProperties);
void loadData(const QByteArray &data, const QUrl &url = QUrl());
Q_SIGNALS:
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 6cf6828832..1279e400e8 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -59,7 +59,6 @@
QT_BEGIN_NAMESPACE
-class QTranslator;
class QFileSelector;
class Q_QML_PRIVATE_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate
{
@@ -74,10 +73,7 @@ public:
void loadTranslations(const QUrl &rootFile);
void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
-
-#if QT_CONFIG(translation)
- QList<QTranslator *> translators;
-#endif
+ QVariantMap initialProperties;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index b164517011..3a437eab8d 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -49,6 +49,7 @@
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
@@ -335,7 +336,7 @@ protected:
class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
public:
- QQmlTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
+ QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
setCompilationUnit(compilationUnit);
m_binding = binding;
@@ -356,7 +357,7 @@ public:
if (!isAddedToObject() || hasError())
return;
- const QString result = m_binding->valueAsString(m_compilationUnit.data());
+ const QString result = m_compilationUnit->bindingValueAsString(m_binding);
Q_ASSERT(targetObject());
@@ -378,7 +379,7 @@ private:
const QV4::CompiledData::Binding *m_binding;
};
-QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
+QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
{
QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding);
@@ -517,9 +518,9 @@ QString QQmlBinding::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- quint16 lineNumber = f->compiledFunction->location.line;
- quint16 columnNumber = f->compiledFunction->location.column;
- return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber));
+ uint lineNumber = f->compiledFunction->location.line;
+ uint columnNumber = f->compiledFunction->location.column;
+ return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
return QStringLiteral("[native code]");
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index f192de4342..7f96b4df9f 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -63,6 +63,7 @@
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qv4functionobject_p.h>
QT_BEGIN_NAMESPACE
@@ -79,7 +80,7 @@ public:
const QString &url = QString(), quint16 lineNumber = 0);
static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function,
QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope);
- static QQmlBinding *createTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, const QV4::CompiledData::Binding *binding,
+ static QQmlBinding *createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding,
QObject *obj, QQmlContextData *ctxt);
~QQmlBinding() override;
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index e5b78591e0..ff01e737ca 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -44,7 +44,6 @@
#include "qqmlengine_p.h"
#include "qqmlexpression_p.h"
#include "qqmlcontext_p.h"
-#include "qqmlmetatype_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
@@ -57,6 +56,7 @@
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
@@ -210,8 +210,6 @@ void QQmlBoundSignalExpression::evaluate(void **a)
} else if (type == QMetaType::Int) {
//### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
jsCall->args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
- } else if (type == qMetaTypeId<QQmlV4Handle>()) {
- jsCall->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]);
} else if (ep->isQObject(type)) {
if (!*reinterpret_cast<void* const *>(a[ii + 1]))
jsCall->args[ii] = QV4::Value::nullValue();
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 7ad9310160..b26b90d2aa 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -51,8 +51,6 @@
#include "qqmlincubator_p.h"
#include <private/qqmljavascriptexpression_p.h>
-#include <private/qv8engine_p.h>
-
#include <private/qv4functionobject_p.h>
#include <private/qv4script_p.h>
#include <private/qv4scopedvalue_p.h>
@@ -66,7 +64,6 @@
#include <QThreadStorage>
#include <QtCore/qdebug.h>
#include <qqmlinfo.h>
-#include "qqmlmemoryprofiler_p.h"
namespace {
QThreadStorage<int> creationDepth;
@@ -74,7 +71,7 @@ namespace {
QT_BEGIN_NAMESPACE
-class QQmlComponentExtension : public QV8Engine::Deletable
+class QQmlComponentExtension : public QV4::ExecutionEngine::Deletable
{
public:
QQmlComponentExtension(QV4::ExecutionEngine *v4);
@@ -353,6 +350,32 @@ void QQmlComponentPrivate::clear()
compilationUnit = nullptr;
}
+QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
+{
+ if (!engine) {
+ // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
+ qWarning("QQmlComponent: Must provide an engine before calling create");
+ return nullptr;
+ }
+ if (!context)
+ context = engine->rootContext();
+ return q->beginCreate(context);
+}
+
+bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
+{
+ QQmlProperty prop(component, name);
+ auto privProp = QQmlPropertyPrivate::get(prop);
+ if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ QQmlError error{};
+ error.setUrl(url);
+ error.setDescription(QLatin1String("Could not set property %1").arg(name));
+ state.errors.push_back(error);
+ return false;
+ } else
+ return true;
+}
+
/*!
\internal
*/
@@ -552,7 +575,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
/*!
\internal
*/
-QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationUnit *compilationUnit, int start, QObject *parent)
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit,
+ int start, QObject *parent)
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
@@ -781,20 +805,30 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
- QML_MEMORY_SCOPE_URL(url());
- if (!d->engine) {
- // ###Qt6: In Qt 6, it should be impossible for users to create a QQmlComponent without an engine, and we can remove this check
- qWarning("QQmlComponent: Must provide an engine before calling create");
- return nullptr;
- }
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv)
+ completeCreate();
+ return rv;
+}
- if (!context)
- context = d->engine->rootContext();
+/*!
+ Create an object instance of this component, and initialize its toplevel
+ properties with \a initialProperties. \a context specifies the context
+ where the object instance is to be created.
- QObject *rv = beginCreate(context);
- if (rv)
+ \sa QQmlComponent::create
+ \since 5.14
+*/
+QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
+{
+ Q_D(QQmlComponent);
+
+ QObject *rv = d->doBeginCreate(this, context);
+ if (rv) {
+ setInitialProperties(rv, initialProperties);
completeCreate();
+ }
return rv;
}
@@ -1070,6 +1104,26 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
+/*!
+ Set toplevel \a properties of the \a component.
+
+
+ This method provides advanced control over component instance creation.
+ In general, programmers should use
+ \l QQmlComponent::createWithInitialProperties to create a component.
+
+ Use this method after beginCreate and before completeCreate has been called.
+ If a provided property does not exist, a warning is issued.
+
+ \since 5.14
+*/
+void QQmlComponent::setInitialProperties(QObject *component, const QVariantMap &properties)
+{
+ Q_D(QQmlComponent);
+ for (auto it = properties.constBegin(); it != properties.constEnd(); ++it)
+ d->setInitialProperty(component, it.key(), it.value());
+}
+
/*
This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
arguments instead of QQmlContext which means we don't have to construct the rather weighty
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index 20199d0b21..f259c99b08 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -59,9 +59,7 @@ class QQmlComponentPrivate;
class QQmlComponentAttached;
namespace QV4 {
-namespace CompiledData {
-struct CompilationUnit;
-}
+class ExecutableCompilationUnit;
}
class Q_QML_EXPORT QQmlComponent : public QObject
@@ -102,6 +100,8 @@ public:
QUrl url() const;
virtual QObject *create(QQmlContext *context = nullptr);
+ QObject *createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context = nullptr);
+ void setInitialProperties(QObject *component, const QVariantMap &properties);
virtual QObject *beginCreate(QQmlContext *);
virtual void completeCreate();
@@ -128,7 +128,8 @@ protected:
Q_INVOKABLE void incubateObject(QQmlV4Function *);
private:
- QQmlComponent(QQmlEngine *, QV4::CompiledData::CompilationUnit *compilationUnit, int, QObject *parent);
+ QQmlComponent(QQmlEngine *, QV4::ExecutableCompilationUnit *compilationUnit, int,
+ QObject *parent);
Q_DISABLE_COPY(QQmlComponent)
friend class QQmlTypeData;
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 4d9e4c6c15..2170646b89 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -60,6 +60,7 @@
#include "qqmlerror.h"
#include "qqml.h"
#include <private/qqmlobjectcreator_p.h>
+#include <private/qqmltypedata_p.h>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -105,7 +106,7 @@ public:
qreal progress;
int start;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
struct ConstructionState {
ConstructionState()
@@ -142,6 +143,9 @@ public:
static QQmlComponentPrivate *get(QQmlComponent *c) {
return static_cast<QQmlComponentPrivate *>(QObjectPrivate::get(c));
}
+
+ QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
+ bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 3710cee162..af8deb085c 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -317,6 +317,12 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
d->propertyValues[idx] = value;
QMetaObject::activate(this, d->notifyIndex, idx, nullptr);
}
+
+ if (auto *obj = qvariant_cast<QObject *>(value)) {
+ connect(obj, &QObject::destroyed, this, [d, name](QObject *destroyed) {
+ d->dropDestroyedQObject(name, destroyed);
+ });
+ }
}
/*!
@@ -352,7 +358,7 @@ void QQmlContext::setContextProperties(const QVector<PropertyPair> &properties)
data->expressions = nullptr;
data->childContexts = nullptr;
- for (auto property : properties)
+ for (const auto &property : properties)
setContextProperty(property.name, property.value);
data->expressions = expressions;
@@ -438,23 +444,20 @@ QUrl QQmlContext::resolvedUrl(const QUrl &src)
QUrl QQmlContextData::resolvedUrl(const QUrl &src)
{
- QQmlContextData *ctxt = this;
-
QUrl resolved;
if (src.isRelative() && !src.isEmpty()) {
- if (ctxt) {
- while(ctxt) {
- if (ctxt->url().isValid())
- break;
- else
- ctxt = ctxt->parent;
- }
-
- if (ctxt)
- resolved = ctxt->url().resolved(src);
- else if (engine)
- resolved = engine->baseUrl().resolved(src);
- }
+ QQmlContextData *ctxt = this;
+ do {
+ if (ctxt->url().isValid())
+ break;
+ else
+ ctxt = ctxt->parent;
+ } while (ctxt);
+
+ if (ctxt)
+ resolved = ctxt->url().resolved(src);
+ else if (engine)
+ resolved = engine->baseUrl().resolved(src);
} else {
resolved = src;
}
@@ -527,6 +530,17 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind
}
}
+void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed)
+{
+ const int idx = data->propertyNames().value(name);
+ Q_ASSERT(idx >= 0);
+ if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed)
+ return;
+
+ propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr);
+ QMetaObject::activate(q_func(), notifyIndex, idx, nullptr);
+}
+
QQmlContextData::QQmlContextData()
: QQmlContextData(nullptr)
@@ -845,7 +859,7 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
return QQmlContextPrivate::get(asQQmlContext());
}
-void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex)
+void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
{
typeCompilationUnit = unit;
componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index 7e3cef8e1d..5f7316b00c 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -66,7 +66,7 @@
#include <private/qflagpointer_p.h>
#include <private/qqmlguard_p.h>
-#include <private/qv4compileddata_p.h>
+#include <private/qv4executablecompilationunit_p.h>
#include <private/qv4identifier_p.h>
QT_BEGIN_NAMESPACE
@@ -104,6 +104,8 @@ public:
static int context_count(QQmlListProperty<QObject> *);
static QObject *context_at(QQmlListProperty<QObject> *, int);
+
+ void dropDestroyedQObject(const QString &name, QObject *destroyed);
};
class QQmlComponentAttached;
@@ -152,12 +154,12 @@ public:
QQmlIncubatorPrivate *incubator;
// Compilation unit for contexts that belong to a compiled type.
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit;
// object index in CompiledData::Unit to component that created this context
int componentObjectIndex;
- void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex);
+ void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex);
// flag indicates whether the context owns the cache (after mutation) or not.
mutable QV4::IdentifierHash propertyNameCache;
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 5cf87f5264..a5f34dafdf 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -39,7 +39,7 @@
#include "qqmlcustomparser_p.h"
-#include <private/qqmltypecompiler_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qdebug.h>
@@ -100,7 +100,12 @@ void QQmlCustomParser::clearErrors()
*/
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
- exceptions << QQmlCompileError(location, description);
+ QQmlJS::DiagnosticMessage error;
+ error.line = location.line;
+ error.column = location.column;
+ error.message = description;
+
+ exceptions << error;
}
struct StaticQtMetaObject : public QObject
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index bf28bca447..df8cbc9072 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -51,10 +51,9 @@
// We mean it.
//
-#include "qqmlmetatype_p.h"
#include "qqmlerror.h"
#include "qqmlbinding_p.h"
-#include <private/qqmltypecompiler_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qxmlstream.h>
@@ -81,10 +80,10 @@ public:
void clearErrors();
Flags flags() const { return m_flags; }
- virtual void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
- virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
+ virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
+ virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
- QVector<QQmlCompileError> errors() const { return exceptions; }
+ QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; }
protected:
void error(const QV4::CompiledData::Binding *binding, const QString& description)
@@ -98,7 +97,7 @@ protected:
const QMetaObject *resolveType(const QString&) const;
private:
- QVector<QQmlCompileError> exceptions;
+ QVector<QQmlJS::DiagnosticMessage> exceptions;
QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index f4c03fc17c..299476f5c8 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -76,8 +76,8 @@ class QQmlDataExtended;
class QQmlNotifierEndpoint;
namespace QV4 {
+class ExecutableCompilationUnit;
namespace CompiledData {
-struct CompilationUnit;
struct Binding;
}
}
@@ -226,14 +226,14 @@ public:
~DeferredData();
unsigned int deferredIdx;
QMultiHash<int, const QV4::CompiledData::Binding *> bindings;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;//Not always the same as the other compilation unit
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;//Not always the same as the other compilation unit
QQmlContextData *context;//Could be either context or outerContext
Q_DISABLE_COPY(DeferredData);
};
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QVector<DeferredData *> deferredData;
- void deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, QQmlContextData *);
+ void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, QQmlContextData *);
void releaseDeferredData();
QV4::WeakValue jsWrapper;
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
new file mode 100644
index 0000000000..750fc6de50
--- /dev/null
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -0,0 +1,639 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmldatablob_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#include <QtQml/qqmlengine.h>
+
+#ifdef DATABLOB_DEBUG
+#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
+#else
+#define ASSERT_CALLBACK()
+#endif
+
+DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\class QQmlDataBlob
+\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
+\internal
+
+QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
+and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
+The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
+*/
+
+/*!
+\enum QQmlDataBlob::Status
+
+This enum describes the status of the data blob.
+
+\list
+\li Null The blob has not yet been loaded by a QQmlTypeLoader
+\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
+ invoked or has not yet returned.
+\li WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
+ This status only occurs after the QQmlDataBlob::setData() callback has been made, and when the
+ blob has outstanding dependencies.
+\li Complete The blob's data has been loaded and all dependencies are done.
+\li Error An error has been set on this blob.
+\endlist
+*/
+
+/*!
+\enum QQmlDataBlob::Type
+
+This enum describes the type of the data blob.
+
+\list
+\li QmlFile This is a QQmlTypeData
+\li JavaScriptFile This is a QQmlScriptData
+\li QmldirFile This is a QQmlQmldirData
+\endlist
+*/
+
+/*!
+Create a new QQmlDataBlob for \a url and of the provided \a type.
+*/
+QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
+: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
+ m_inCallback(false), m_isDone(false)
+{
+ //Set here because we need to get the engine from the manager
+ if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
+ m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
+ (QQmlAbstractUrlInterceptor::DataType)m_type);
+}
+
+/*! \internal */
+QQmlDataBlob::~QQmlDataBlob()
+{
+ Q_ASSERT(m_waitingOnMe.isEmpty());
+
+ cancelAllWaitingFor();
+}
+
+/*!
+ Must be called before loading can occur.
+*/
+void QQmlDataBlob::startLoading()
+{
+ Q_ASSERT(status() == QQmlDataBlob::Null);
+ m_data.setStatus(QQmlDataBlob::Loading);
+}
+
+/*!
+Returns the type provided to the constructor.
+*/
+QQmlDataBlob::Type QQmlDataBlob::type() const
+{
+ return m_type;
+}
+
+/*!
+Returns the blob's status.
+*/
+QQmlDataBlob::Status QQmlDataBlob::status() const
+{
+ return m_data.status();
+}
+
+/*!
+Returns true if the status is Null.
+*/
+bool QQmlDataBlob::isNull() const
+{
+ return status() == Null;
+}
+
+/*!
+Returns true if the status is Loading.
+*/
+bool QQmlDataBlob::isLoading() const
+{
+ return status() == Loading;
+}
+
+/*!
+Returns true if the status is WaitingForDependencies.
+*/
+bool QQmlDataBlob::isWaiting() const
+{
+ return status() == WaitingForDependencies ||
+ status() == ResolvingDependencies;
+}
+
+/*!
+Returns true if the status is Complete.
+*/
+bool QQmlDataBlob::isComplete() const
+{
+ return status() == Complete;
+}
+
+/*!
+Returns true if the status is Error.
+*/
+bool QQmlDataBlob::isError() const
+{
+ return status() == Error;
+}
+
+/*!
+Returns true if the status is Complete or Error.
+*/
+bool QQmlDataBlob::isCompleteOrError() const
+{
+ Status s = status();
+ return s == Error || s == Complete;
+}
+
+/*!
+Returns the data download progress from 0 to 1.
+*/
+qreal QQmlDataBlob::progress() const
+{
+ quint8 p = m_data.progress();
+ if (p == 0xFF) return 1.;
+ else return qreal(p) / qreal(0xFF);
+}
+
+/*!
+Returns the physical url of the data. Initially this is the same as
+finalUrl(), but if a URL interceptor is set, it will work on this URL
+and leave finalUrl() alone.
+
+\sa finalUrl()
+*/
+QUrl QQmlDataBlob::url() const
+{
+ return m_url;
+}
+
+QString QQmlDataBlob::urlString() const
+{
+ if (m_urlString.isEmpty())
+ m_urlString = m_url.toString();
+
+ return m_urlString;
+}
+
+/*!
+Returns the logical URL to be used for resolving further URLs referred to in
+the code.
+
+This is the blob url passed to the constructor. If a URL interceptor rewrites
+the URL, this one stays the same. If a network redirect happens while fetching
+the data, this url is updated to reflect the new location. Therefore, if both
+an interception and a redirection happen, the final url will indirectly
+incorporate the result of the interception, potentially breaking further
+lookups.
+
+\sa url()
+*/
+QUrl QQmlDataBlob::finalUrl() const
+{
+ return m_finalUrl;
+}
+
+/*!
+Returns the finalUrl() as a string.
+*/
+QString QQmlDataBlob::finalUrlString() const
+{
+ if (m_finalUrlString.isEmpty())
+ m_finalUrlString = m_finalUrl.toString();
+
+ return m_finalUrlString;
+}
+
+/*!
+Return the errors on this blob.
+
+May only be called from the load thread, or after the blob isCompleteOrError().
+*/
+QList<QQmlError> QQmlDataBlob::errors() const
+{
+ Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
+ return m_errors;
+}
+
+/*!
+Mark this blob as having \a errors.
+
+All outstanding dependencies will be cancelled. Requests to add new dependencies
+will be ignored. Entry into the Error state is irreversable.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::setError(const QQmlError &errors)
+{
+ ASSERT_CALLBACK();
+
+ QList<QQmlError> l;
+ l << errors;
+ setError(l);
+}
+
+/*!
+\overload
+*/
+void QQmlDataBlob::setError(const QList<QQmlError> &errors)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Error);
+ Q_ASSERT(m_errors.isEmpty());
+
+ m_errors = errors; // Must be set before the m_data fence
+ m_data.setStatus(Error);
+
+ if (dumpErrors()) {
+ qWarning().nospace() << "Errors for " << urlString();
+ for (int ii = 0; ii < errors.count(); ++ii)
+ qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
+ }
+ cancelAllWaitingFor();
+
+ if (!m_inCallback)
+ tryDone();
+}
+
+void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
+{
+ QQmlError e;
+ e.setColumn(error.column);
+ e.setLine(error.line);
+ e.setDescription(error.message);
+ e.setUrl(url());
+ setError(e);
+}
+
+void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors)
+{
+ QList<QQmlError> finalErrors;
+ finalErrors.reserve(errors.count());
+ for (const auto &error : errors) {
+ QQmlError e;
+ e.setColumn(error.column);
+ e.setLine(error.line);
+ e.setDescription(error.message);
+ e.setUrl(url());
+ finalErrors << e;
+ }
+ setError(finalErrors);
+}
+
+void QQmlDataBlob::setError(const QString &description)
+{
+ QQmlError e;
+ e.setDescription(description);
+ e.setUrl(url());
+ setError(e);
+}
+
+/*!
+Wait for \a blob to become complete or to error. If \a blob is already
+complete or in error, or this blob is already complete, this has no effect.
+
+The setError() method may only be called from within a QQmlDataBlob callback.
+*/
+void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
+{
+ ASSERT_CALLBACK();
+
+ Q_ASSERT(status() != Null);
+
+ if (!blob ||
+ blob->status() == Error || blob->status() == Complete ||
+ status() == Error || status() == Complete || m_isDone)
+ return;
+
+ for (const auto &existingDep: qAsConst(m_waitingFor))
+ if (existingDep.data() == blob)
+ return;
+
+ m_data.setStatus(WaitingForDependencies);
+
+ m_waitingFor.append(blob);
+ blob->m_waitingOnMe.append(this);
+}
+
+/*!
+\fn void QQmlDataBlob::dataReceived(const Data &data)
+
+Invoked when data for the blob is received. Implementors should use this callback
+to determine a blob's dependencies. Within this callback you may call setError()
+or addDependency().
+*/
+
+/*!
+Invoked once data has either been received or a network error occurred, and all
+dependencies are complete.
+
+You can set an error in this method, but you cannot add new dependencies. Implementors
+should use this callback to finalize processing of data.
+
+The default implementation does nothing.
+
+XXX Rename processData() or some such to avoid confusion between done() (processing thread)
+and completed() (main thread)
+*/
+void QQmlDataBlob::done()
+{
+}
+
+#if QT_CONFIG(qml_network)
+/*!
+Invoked if there is a network error while fetching this blob.
+
+The default implementation sets an appropriate QQmlError.
+*/
+void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
+{
+ Q_UNUSED(networkError);
+
+ QQmlError error;
+ error.setUrl(m_url);
+
+ const char *errorString = nullptr;
+ switch (networkError) {
+ default:
+ errorString = "Network error";
+ break;
+ case QNetworkReply::ConnectionRefusedError:
+ errorString = "Connection refused";
+ break;
+ case QNetworkReply::RemoteHostClosedError:
+ errorString = "Remote host closed the connection";
+ break;
+ case QNetworkReply::HostNotFoundError:
+ errorString = "Host not found";
+ break;
+ case QNetworkReply::TimeoutError:
+ errorString = "Timeout";
+ break;
+ case QNetworkReply::ProxyConnectionRefusedError:
+ case QNetworkReply::ProxyConnectionClosedError:
+ case QNetworkReply::ProxyNotFoundError:
+ case QNetworkReply::ProxyTimeoutError:
+ case QNetworkReply::ProxyAuthenticationRequiredError:
+ case QNetworkReply::UnknownProxyError:
+ errorString = "Proxy error";
+ break;
+ case QNetworkReply::ContentAccessDenied:
+ errorString = "Access denied";
+ break;
+ case QNetworkReply::ContentNotFoundError:
+ errorString = "File not found";
+ break;
+ case QNetworkReply::AuthenticationRequiredError:
+ errorString = "Authentication required";
+ break;
+ };
+
+ error.setDescription(QLatin1String(errorString));
+
+ setError(error);
+}
+#endif // qml_network
+
+/*!
+Called if \a blob, which was previously waited for, has an error.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called if \a blob, which was previously waited for, has completed.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
+{
+ Q_UNUSED(blob);
+}
+
+/*!
+Called when all blobs waited for have completed. This occurs regardless of
+whether they are in error, or complete state.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::allDependenciesDone()
+{
+ m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
+}
+
+/*!
+Called when the download progress of this blob changes. \a progress goes
+from 0 to 1.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::downloadProgressChanged(qreal progress)
+{
+ Q_UNUSED(progress);
+}
+
+/*!
+Invoked on the main thread sometime after done() was called on the load thread.
+
+You cannot modify the blobs state at all in this callback and cannot depend on the
+order or timeliness of these callbacks. Implementors should use this callback to notify
+dependencies on the main thread that the blob is done and not a lot else.
+
+This callback is only invoked if an asynchronous load for this blob is
+made. An asynchronous load is one in which the Asynchronous mode is
+specified explicitly, or one that is implicitly delayed due to a network
+operation.
+
+The default implementation does nothing.
+*/
+void QQmlDataBlob::completed()
+{
+}
+
+
+void QQmlDataBlob::tryDone()
+{
+ if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
+ m_isDone = true;
+ addref();
+
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
+#endif
+ done();
+
+ if (status() != Error)
+ m_data.setStatus(Complete);
+
+ notifyAllWaitingOnMe();
+
+ // Locking is not required here, as anyone expecting callbacks must
+ // already be protected against the blob being completed (as set above);
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlDataBlob: Dispatching completed");
+#endif
+ m_typeLoader->m_thread->callCompleted(this);
+
+ release();
+ }
+}
+
+void QQmlDataBlob::cancelAllWaitingFor()
+{
+ while (m_waitingFor.count()) {
+ QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
+
+ Q_ASSERT(blob->m_waitingOnMe.contains(this));
+
+ blob->m_waitingOnMe.removeOne(this);
+ }
+}
+
+void QQmlDataBlob::notifyAllWaitingOnMe()
+{
+ while (m_waitingOnMe.count()) {
+ QQmlDataBlob *blob = m_waitingOnMe.takeLast();
+
+ Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
+ [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
+
+ blob->notifyComplete(this);
+ }
+}
+
+void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
+{
+ Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
+
+ m_inCallback = true;
+
+ QQmlRefPointer<QQmlDataBlob> blobRef;
+ for (int i = 0; i < m_waitingFor.count(); ++i) {
+ if (m_waitingFor.at(i).data() == blob) {
+ blobRef = m_waitingFor.takeAt(i);
+ break;
+ }
+ }
+ Q_ASSERT(blobRef);
+
+ if (blob->status() == Error) {
+ dependencyError(blob);
+ } else if (blob->status() == Complete) {
+ dependencyComplete(blob);
+ }
+
+ if (!isError() && m_waitingFor.isEmpty())
+ allDependenciesDone();
+
+ m_inCallback = false;
+
+ tryDone();
+}
+
+QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
+{
+ error->clear();
+ if (hasInlineSourceCode)
+ return inlineSourceCode;
+
+ QFile f(fileInfo.absoluteFilePath());
+ if (!f.open(QIODevice::ReadOnly)) {
+ *error = f.errorString();
+ return QString();
+ }
+
+ const qint64 fileSize = fileInfo.size();
+
+ if (uchar *mappedData = f.map(0, fileSize)) {
+ QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
+ f.unmap(mappedData);
+ return source;
+ }
+
+ QByteArray data(fileSize, Qt::Uninitialized);
+ if (f.read(data.data(), data.length()) != data.length()) {
+ *error = f.errorString();
+ return QString();
+ }
+ return QString::fromUtf8(data);
+}
+
+QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
+{
+ if (hasInlineSourceCode)
+ return QDateTime();
+
+ return fileInfo.lastModified();
+}
+
+bool QQmlDataBlob::SourceCodeData::exists() const
+{
+ if (hasInlineSourceCode)
+ return true;
+ return fileInfo.exists();
+}
+
+bool QQmlDataBlob::SourceCodeData::isEmpty() const
+{
+ if (hasInlineSourceCode)
+ return inlineSourceCode.isEmpty();
+ return fileInfo.size() == 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
new file mode 100644
index 0000000000..0450e94c02
--- /dev/null
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDATABLOB_P_H
+#define QQMLDATABLOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qv4compileddata_p.h>
+
+#if QT_CONFIG(qml_network)
+#include <QtNetwork/qnetworkreply.h>
+#endif
+
+#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeLoader;
+class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+{
+public:
+ enum Status {
+ Null, // Prior to QQmlTypeLoader::load()
+ Loading, // Prior to data being received and dataReceived() being called
+ WaitingForDependencies, // While there are outstanding addDependency()s
+ ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
+ Complete, // Finished
+ Error // Error
+ };
+
+ enum Type { //Matched in QQmlAbstractUrlInterceptor
+ QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
+ JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
+ QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
+ };
+
+ QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
+ ~QQmlDataBlob() override;
+
+ void startLoading();
+
+ QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
+
+ Type type() const;
+
+ Status status() const;
+ bool isNull() const;
+ bool isLoading() const;
+ bool isWaiting() const;
+ bool isComplete() const;
+ bool isError() const;
+ bool isCompleteOrError() const;
+
+ qreal progress() const;
+
+ QUrl url() const;
+ QString urlString() const;
+ QUrl finalUrl() const;
+ QString finalUrlString() const;
+
+ QList<QQmlError> errors() const;
+
+ class SourceCodeData {
+ public:
+ QString readAll(QString *error) const;
+ QDateTime sourceTimeStamp() const;
+ bool exists() const;
+ bool isEmpty() const;
+ private:
+ friend class QQmlDataBlob;
+ friend class QQmlTypeLoader;
+ QString inlineSourceCode;
+ QFileInfo fileInfo;
+ bool hasInlineSourceCode = false;
+ };
+
+protected:
+ // Can be called from within callbacks
+ void setError(const QQmlError &);
+ void setError(const QList<QQmlError> &errors);
+ void setError(const QQmlJS::DiagnosticMessage &error);
+ void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
+ void setError(const QString &description);
+ void addDependency(QQmlDataBlob *);
+
+ // Callbacks made in load thread
+ virtual void dataReceived(const SourceCodeData &) = 0;
+ virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
+ virtual void done();
+#if QT_CONFIG(qml_network)
+ virtual void networkError(QNetworkReply::NetworkError);
+#endif
+ virtual void dependencyError(QQmlDataBlob *);
+ virtual void dependencyComplete(QQmlDataBlob *);
+ virtual void allDependenciesDone();
+
+ // Callbacks made in main thread
+ virtual void downloadProgressChanged(qreal);
+ virtual void completed();
+
+protected:
+ // Manager that is currently fetching data for me
+ QQmlTypeLoader *m_typeLoader;
+
+private:
+ friend class QQmlTypeLoader;
+ friend class QQmlTypeLoaderThread;
+
+ void tryDone();
+ void cancelAllWaitingFor();
+ void notifyAllWaitingOnMe();
+ void notifyComplete(QQmlDataBlob *);
+
+ struct ThreadData {
+ private:
+ enum {
+ StatusMask = 0x0000FFFF,
+ StatusShift = 0,
+ ProgressMask = 0x00FF0000,
+ ProgressShift = 16,
+ AsyncMask = 0x80000000,
+ NoMask = 0
+ };
+
+ public:
+ inline ThreadData()
+ : _p(0)
+ {
+ }
+
+ inline QQmlDataBlob::Status status() const
+ {
+ return QQmlDataBlob::Status((_p.loadRelaxed() & StatusMask) >> StatusShift);
+ }
+
+ inline void setStatus(QQmlDataBlob::Status status)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline bool isAsync() const
+ {
+ return _p.loadRelaxed() & AsyncMask;
+ }
+
+ inline void setIsAsync(bool v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ inline quint8 progress() const
+ {
+ return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
+ }
+
+ inline void setProgress(quint8 v)
+ {
+ while (true) {
+ int d = _p.loadRelaxed();
+ int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
+ if (d == nd || _p.testAndSetOrdered(d, nd)) return;
+ }
+ }
+
+ private:
+ QAtomicInt _p;
+ };
+ ThreadData m_data;
+
+ // m_errors should *always* be written before the status is set to Error.
+ // We use the status change as a memory fence around m_errors so that locking
+ // isn't required. Once the status is set to Error (or Complete), m_errors
+ // cannot be changed.
+ QList<QQmlError> m_errors;
+
+ Type m_type;
+
+ QUrl m_url;
+ QUrl m_finalUrl;
+ mutable QString m_urlString;
+ mutable QString m_finalUrlString;
+
+ // List of QQmlDataBlob's that are waiting for me to complete.
+protected:
+ QList<QQmlDataBlob *> m_waitingOnMe;
+private:
+
+ // List of QQmlDataBlob's that I am waiting for to complete.
+ QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
+
+ int m_redirectCount:30;
+ bool m_inCallback:1;
+ bool m_isDone:1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDATABLOB_P_H
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 61cb0a9065..02fde97b3d 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -38,12 +38,12 @@
****************************************************************************/
#include "qqmldelayedcallqueue_p.h"
-#include <private/qv8engine_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <private/qv4value_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QQmlError>
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
new file mode 100644
index 0000000000..de74dfdf9b
--- /dev/null
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmldirdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, QmldirFile, loader)
+{
+}
+
+const QString &QQmlQmldirData::content() const
+{
+ return m_content;
+}
+
+QQmlTypeLoader::Blob::PendingImportPtr QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+{
+ auto it = m_imports.find(blob);
+ if (it == m_imports.end())
+ return nullptr;
+ return *it;
+}
+
+void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, QQmlTypeLoader::Blob::PendingImportPtr import)
+{
+ m_imports[blob] = std::move(import);
+}
+
+int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
+{
+ QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
+ if (it == m_priorities.end())
+ return 0;
+ return *it;
+}
+
+void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
+{
+ m_priorities[blob] = priority;
+}
+
+void QQmlQmldirData::dataReceived(const SourceCodeData &data)
+{
+ QString error;
+ m_content = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+}
+
+void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
+{
+ Q_UNIMPLEMENTED();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
new file mode 100644
index 0000000000..34f1ff1678
--- /dev/null
+++ b/src/qml/qml/qqmldirdata_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLDIRDATA_P_H
+#define QQMLDIRDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ const QString &content() const;
+
+ PendingImportPtr import(QQmlTypeLoader::Blob *) const;
+ void setImport(QQmlTypeLoader::Blob *, PendingImportPtr);
+
+ int priority(QQmlTypeLoader::Blob *) const;
+ void setPriority(QQmlTypeLoader::Blob *, int);
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
+
+private:
+ QString m_content;
+ QHash<QQmlTypeLoader::Blob *, QQmlTypeLoader::Blob::PendingImportPtr> m_imports;
+ QHash<QQmlTypeLoader::Blob *, int> m_priorities;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDIRDATA_P_H
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 4c6a1b69d8..0fd07ea209 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -51,14 +51,15 @@
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlcomponent_p.h"
-#include "qqmldirparser_p.h"
#include "qqmlextensioninterface.h"
#include "qqmllist_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
+#include <private/qqmldirparser_p.h>
#include <private/qqmlboundsignal_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qstandardpaths.h>
#include <QtCore/qsettings.h>
#include <QtCore/qmetaobject.h>
@@ -86,19 +87,7 @@
#if QT_CONFIG(qml_animation)
#include <private/qqmltimer_p.h>
#endif
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#endif
#include <private/qqmlplatform_p.h>
-#include <private/qquickpackage_p.h>
-#if QT_CONFIG(qml_delegate_model)
-#include <private/qqmldelegatemodel_p.h>
-#endif
-#include <private/qqmlobjectmodel_p.h>
-#if QT_CONFIG(qml_worker_script)
-#include <private/qquickworkerscript_p.h>
-#endif
-#include <private/qqmlinstantiator_p.h>
#include <private/qqmlloggingcategory_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
@@ -116,13 +105,6 @@ Q_DECLARE_METATYPE(QQmlProperty)
QT_BEGIN_NAMESPACE
-void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
-{
- QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
- QQmlEnginePrivate::registerQtQuick2Types(uri, versionMajor, versionMinor);
- QQmlValueTypeFactory::registerValueTypes(uri, versionMajor, versionMinor);
-}
-
// Declared in qqml.h
int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
const char *uri, int versionMajor,
@@ -215,63 +197,56 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
bool QQmlEnginePrivate::qml_debugging_enabled = false;
bool QQmlEnginePrivate::s_designerMode = false;
-// these types are part of the QML language
-void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor)
+void QQmlEnginePrivate::defineModule()
{
- qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component");
- qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject");
- qmlRegisterType<QQmlBind>(uri, versionMajor, versionMinor,"Binding");
- qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
- qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, 0, "Connections", new QQmlConnectionsParser);
- if (!strcmp(uri, "QtQuick"))
- qmlRegisterCustomType<QQmlConnections,1>(uri, versionMajor, 7, "Connections", new QQmlConnectionsParser); //Only available in QtQuick >=2.7
- else
- qmlRegisterCustomType<QQmlConnections,1>(uri, versionMajor, 3, "Connections", new QQmlConnectionsParser); //Only available in QtQml >=2.3
-#if QT_CONFIG(qml_animation)
- qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer");
-#endif
- qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1
- qmlRegisterType<QQmlInstanceModel>();
+ const char uri[] = "QtQml";
- qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor, 8, "LoggingCategory"); //Only available in >=2.8
- qmlRegisterType<QQmlLoggingCategory,1>(uri, versionMajor, 12, "LoggingCategory"); //Only available in >=2.12
-}
+ qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component");
+ qmlRegisterType<QObject>(uri, 2, 0, "QtObject");
+ qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
+ qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding"); // Only available in >= 2.8
+ qmlRegisterType<QQmlBind, 14>(uri, 2, 14, "Binding");
+ // TODO: We won't need Connections to be a custom type anymore once we can drop the
+ // automatic signal handler inference from undeclared properties.
+ qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
+ qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3
-// These QtQuick types' implementation resides in the QtQml module
-void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor)
-{
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, versionMajor, versionMinor, "ListElement"); // Now in QtQml.Models, here for compatibility
- qmlRegisterCustomType<QQmlListModel>(uri, versionMajor, versionMinor, "ListModel", new QQmlListModelParser); // Now in QtQml.Models, here for compatibility
-#endif
-#if QT_CONFIG(qml_worker_script)
- qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
+#if QT_CONFIG(qml_animation)
+ qmlRegisterType<QQmlTimer>(uri, 2, 0, "Timer");
#endif
- qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package");
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, versionMajor, versionMinor, "VisualDataModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, versionMajor, versionMinor, "VisualDataGroup");
+
+ qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory"); // Only available in >= 2.8
+ qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory"); // Only available in >= 2.12
+
+#if QT_CONFIG(qml_locale)
+ qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
#endif
- qmlRegisterType<QQmlObjectModel>(uri, versionMajor, versionMinor, "VisualItemModel");
-#endif // < Qt 6
}
-void QQmlEnginePrivate::defineQtQuick2Module()
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+void QQmlEnginePrivate::registerQuickTypes()
{
- // register the base types into the QtQuick namespace
- registerBaseTypes("QtQuick",2,0);
+ // Don't add anything here. These are only for backwards compatibility.
- // register the QtQuick2 types which are implemented in the QtQml module.
- registerQtQuick2Types("QtQuick",2,0);
+ const char uri[] = "QtQuick";
+
+ qmlRegisterType<QQmlComponent>(uri, 2, 0, "Component");
+ qmlRegisterType<QObject>(uri, 2, 0, "QtObject");
+ qmlRegisterType<QQmlBind>(uri, 2, 0, "Binding");
+ qmlRegisterType<QQmlBind, 8>(uri, 2, 8, "Binding");
+ qmlRegisterCustomType<QQmlConnections>(uri, 2, 0, "Connections", new QQmlConnectionsParser);
+ qmlRegisterCustomType<QQmlConnections, 3>(uri, 2, 7, "Connections", new QQmlConnectionsParser);
+#if QT_CONFIG(qml_animation)
+ qmlRegisterType<QQmlTimer>(uri, 2, 0,"Timer");
+#endif
+ qmlRegisterType<QQmlLoggingCategory>(uri, 2, 8, "LoggingCategory");
+ qmlRegisterType<QQmlLoggingCategory, 12>(uri, 2, 12, "LoggingCategory");
#if QT_CONFIG(qml_locale)
- qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+ qmlRegisterUncreatableType<QQmlLocale>(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
#endif
-
- // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
- qmlRegisterModule("QtQuick", 2, QT_VERSION_MINOR);
}
+#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
bool QQmlEnginePrivate::designerMode()
{
@@ -841,19 +816,20 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
if (ddata->notifyList &&
- QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) {
+ QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) {
- if (!QObjectPrivate::get(object)->threadData->thread)
+ if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire())
return;
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
QList<QByteArray> parameterTypes = m.parameterTypes();
- int *types = (int *)malloc((parameterTypes.count() + 1) * sizeof(int));
- void **args = (void **) malloc((parameterTypes.count() + 1) *sizeof(void *));
+ QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
+ object, index,
+ parameterTypes.count() + 1));
- types[0] = 0; // return type
- args[0] = nullptr; // return value
+ void **args = ev->args();
+ int *types = ev->types();
for (int ii = 0; ii < parameterTypes.count(); ++ii) {
const QByteArray &typeName = parameterTypes.at(ii);
@@ -866,21 +842,16 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
- free(types);
- free(args);
return;
}
args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
}
- QMetaCallEvent *ev = new QMetaCallEvent(m.methodIndex(), 0, nullptr, object, index,
- parameterTypes.count() + 1, types, args);
-
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
- mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread);
- QCoreApplication::postEvent(mpo, ev);
+ mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
+ QCoreApplication::postEvent(mpo, ev.take());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
@@ -975,14 +946,10 @@ void QQmlEnginePrivate::init()
Q_Q(QQmlEngine);
if (baseModulesUninitialized) {
- qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component"); // required for the Compiler.
- registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
-#if QT_CONFIG(qml_locale)
- qmlRegisterUncreatableType<QQmlLocale>("QtQml", 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
-#endif
- // Auto-increment the import to stay in sync with ALL future QtQml minor versions from 5.11 onward
- qmlRegisterModule("QtQml", 2, QT_VERSION_MINOR);
+ // required for the Compiler.
+ qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
+ qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
QQmlData::init();
baseModulesUninitialized = false;
@@ -994,24 +961,13 @@ void QQmlEnginePrivate::init()
qRegisterMetaType<QQmlComponent::Status>();
qRegisterMetaType<QList<QObject*> >();
qRegisterMetaType<QList<int> >();
- qRegisterMetaType<QQmlV4Handle>();
qRegisterMetaType<QQmlBinding*>();
- v8engine()->setEngine(q);
+ q->handle()->setQmlEngine(q);
rootContext = new QQmlContext(q,true);
}
-#if QT_CONFIG(qml_worker_script)
-QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine()
-{
- Q_Q(QQmlEngine);
- if (!workerScriptEngine)
- workerScriptEngine = new QQuickWorkerScriptEngine(q);
- return workerScriptEngine;
-}
-#endif
-
/*!
\class QQmlEngine
\since 5.0
@@ -1091,7 +1047,7 @@ QQmlEngine::~QQmlEngine()
// XXX TODO: performance -- store list of singleton types separately?
QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
for (const QQmlType &currType : singletonTypes)
- currType.singletonInstanceInfo()->destroy(this);
+ d->destroySingletonInstance(currType);
delete d->rootContext;
d->rootContext = nullptr;
@@ -1214,6 +1170,13 @@ void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
}
}
+QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
+{
+ const QString providerIdLower = providerId.toLower();
+ QMutexLocker locker(&mutex);
+ return imageProviders.value(providerIdLower);
+}
+
#if QT_CONFIG(qml_network)
/*!
Sets the \a factory to use for creating QNetworkAccessManager(s).
@@ -1303,8 +1266,10 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const
void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider)
{
Q_D(QQmlEngine);
+ QString providerIdLower = providerId.toLower();
+ QSharedPointer<QQmlImageProviderBase> sp(provider);
QMutexLocker locker(&d->mutex);
- d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider));
+ d->imageProviders.insert(std::move(providerIdLower), std::move(sp));
}
/*!
@@ -1315,8 +1280,9 @@ void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBa
QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const
{
Q_D(const QQmlEngine);
+ const QString providerIdLower = providerId.toLower();
QMutexLocker locker(&d->mutex);
- return d->imageProviders.value(providerId.toLower()).data();
+ return d->imageProviders.value(providerIdLower).data();
}
/*!
@@ -1327,8 +1293,9 @@ QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) cons
void QQmlEngine::removeImageProvider(const QString &providerId)
{
Q_D(QQmlEngine);
+ const QString providerIdLower = providerId.toLower();
QMutexLocker locker(&d->mutex);
- d->imageProviders.take(providerId.toLower());
+ d->imageProviders.take(providerIdLower);
}
/*!
@@ -1436,23 +1403,13 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
+ Q_D(QQmlEngine);
QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
- QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo();
- info->init(this);
-
- if (QObject* o = info->qobjectApi(this))
- return this->newQObject(o);
- else {
- QJSValue value = info->scriptApi(this);
- if (!value.isUndefined())
- return value;
- }
-
- return QJSValue();
+ return d->singletonInstance<QJSValue>(type);
}
/*!
@@ -1669,6 +1626,7 @@ static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlDat
return rv;
}
+#if QT_DEPRECATED_SINCE(5, 14)
QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
{
QQmlData *data = QQmlData::get(object, create);
@@ -1696,6 +1654,7 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
return qmlAttachedPropertiesObjectById(*idCache, object, create);
}
+#endif
QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
const QMetaObject *attachedMetaObject)
@@ -1824,7 +1783,7 @@ void QQmlData::NotifyList::layout()
todo = nullptr;
}
-void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *context)
+void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *context)
{
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = objectIndex;
@@ -1832,7 +1791,7 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
- const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
@@ -2157,20 +2116,21 @@ void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError
dumpwarning(error);
}
-QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileName, const QList<DiagnosticMessage> &diagnosticMessages)
+QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
+ const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages)
{
QList<QQmlError> errors;
- for (const DiagnosticMessage &m : diagnosticMessages) {
+ for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message));
continue;
}
QQmlError error;
error.setUrl(QUrl(fileName));
error.setDescription(m.message);
- error.setLine(m.loc.startLine);
- error.setColumn(m.loc.startColumn);
+ error.setLine(m.line);
+ error.setColumn(m.column);
errors << error;
}
return errors;
@@ -2298,6 +2258,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths)
d->importDatabase.setPluginPathList(paths);
}
+#if QT_CONFIG(library)
/*!
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
@@ -2311,6 +2272,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Q_D(QQmlEngine);
return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors);
}
+#endif
/*!
\property QQmlEngine::offlineStoragePath
@@ -2365,6 +2327,17 @@ QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName)
return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
}
+// #### Qt 6: Remove this function, it exists only for binary compatibility.
+/*!
+ * \internal
+ */
+bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
+{
+ Q_UNUSED(name)
+ Q_UNUSED(fileName)
+ return false;
+}
+
QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
{
Q_Q(const QQmlEngine);
@@ -2461,7 +2434,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVe
}
}
-void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
+void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
{
compilationUnit->isRegisteredWithEngine = true;
@@ -2471,7 +2444,7 @@ void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::Compila
m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit);
}
-void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
+void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
{
compilationUnit->isRegisteredWithEngine = false;
@@ -2479,6 +2452,70 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::Compi
m_compositeTypes.remove(compilationUnit->metaTypeId);
}
+template<>
+QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
+{
+ Q_Q(QQmlEngine);
+
+ QJSValue value = singletonInstances.value(type);
+ if (!value.isUndefined()) {
+ return value;
+ }
+
+ QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ Q_ASSERT(siinfo != nullptr);
+
+ if (siinfo->scriptCallback) {
+ value = siinfo->scriptCallback(q, q);
+ if (value.isQObject()) {
+ QObject *o = value.toQObject();
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ }
+ singletonInstances.insert(type, value);
+
+ } else if (siinfo->qobjectCallback) {
+ QObject *o = siinfo->qobjectCallback(q, q);
+ if (!o) {
+ QQmlError error;
+ error.setMessageType(QtMsgType::QtCriticalMsg);
+ error.setDescription(QString::asprintf("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
+ qPrintable(QString::fromUtf8(type.typeName()))));
+ warning(error);
+ } else {
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(q, o);
+ }
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+ } else if (!siinfo->url.isEmpty()) {
+ QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ QObject *o = component.beginCreate(q->rootContext());
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+ component.completeCreate();
+ }
+
+ return value;
+}
+
+void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+{
+ Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+
+ QObject* o = singletonInstances.take(type).toQObject();
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
+ return;
+ delete o;
+ }
+}
+
bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
return typeLoader.isTypeLoaded(url);
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 871e6bd9b4..31fe3a1849 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -114,7 +114,9 @@ public:
bool addNamedBundle(const QString &name, const QString &fileName);
+#if QT_CONFIG(library)
bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
+#endif
#if QT_CONFIG(qml_network)
void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *);
@@ -175,12 +177,7 @@ Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId);
template<typename T>
T QQmlEngine::singletonInstance(int qmlTypeId) {
- QJSValue instance = singletonInstance<QJSValue>(qmlTypeId);
- if (!instance.isQObject())
- return nullptr;
-
- QObject *object = instance.toQObject();
- return qobject_cast<T>(object);
+ return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 92e56cd957..385ae02ce5 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -62,11 +62,11 @@
#include "qqmlcontext_p.h"
#include "qqmlexpression.h"
#include "qqmlproperty_p.h"
-#include "qqmlpropertycache_p.h"
#include "qqmlmetatype_p.h"
#include <private/qintrusivelist_p.h>
#include <private/qrecyclepool_p.h>
#include <private/qfieldlist_p.h>
+#include <private/qv4engine_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
@@ -77,7 +77,6 @@
#include <private/qobject_p.h>
-#include <private/qv8engine_p.h>
#include <private/qjsengine_p.h>
#include <private/qqmldirparser_p.h>
@@ -95,12 +94,12 @@ class QQmlTypeNameCache;
class QQmlComponentAttached;
class QQmlCleanup;
class QQmlDelayedError;
-class QQuickWorkerScriptEngine;
class QQmlObjectCreator;
class QDir;
class QQmlIncubator;
class QQmlProfiler;
class QQmlPropertyCapture;
+class QQmlMetaObject;
// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
// The inline method definitions are in qqmljavascriptexpression_p.h
@@ -150,12 +149,10 @@ public:
QQmlDelayedError *erroredBindings;
int inProgressCreations;
- QV8Engine *v8engine() const { return q_func()->handle()->v8Engine; }
QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); }
#if QT_CONFIG(qml_worker_script)
- QQuickWorkerScriptEngine *getWorkerScriptEngine();
- QQuickWorkerScriptEngine *workerScriptEngine;
+ QThread *workerScriptEngine;
#endif
QUrl baseUrl;
@@ -171,6 +168,8 @@ public:
mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
#endif
QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
+ QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
+
QQmlAbstractUrlInterceptor* urlInterceptor;
@@ -223,12 +222,16 @@ public:
QQmlMetaObject metaObjectForType(int) const;
QQmlPropertyCache *propertyCacheForType(int);
QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
- void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
- void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
+ void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
+ template <typename T>
+ T singletonInstance(const QQmlType &type);
+ void destroySingletonInstance(const QQmlType &type);
+
void sendQuit();
void sendExit(int retCode = 0);
void warning(const QQmlError &);
@@ -238,7 +241,6 @@ public:
static void warning(QQmlEnginePrivate *, const QQmlError &);
static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
- inline static QV8Engine *getV8Engine(QQmlEngine *e);
inline static QV4::ExecutionEngine *getV4Engine(QQmlEngine *e);
inline static QQmlEnginePrivate *get(QQmlEngine *e);
inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
@@ -249,9 +251,10 @@ public:
static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
- static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
- static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
- static void defineQtQuick2Module();
+ static void defineModule();
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ static void registerQuickTypes();
+#endif
static bool designerMode();
static void activateDesignerMode();
@@ -261,9 +264,11 @@ public:
mutable QMutex networkAccessManagerMutex;
private:
+ QHash<QQmlType, QJSValue> singletonInstances;
+
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
// the threaded loader. Only access them through their respective accessor methods.
- QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
+ QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes;
static bool s_designerMode;
// These members is protected by the full QQmlEnginePrivate::mutex mutex
@@ -381,13 +386,6 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersi
return QQmlMetaType::propertyCache(type, minorVersion);
}
-QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
-{
- Q_ASSERT(e);
-
- return e->handle()->v8Engine;
-}
-
QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
{
Q_ASSERT(e);
@@ -434,6 +432,14 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
return get(qmlEngine);
}
+template<>
+Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
+
+template<typename T>
+T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
+ return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_P_H
diff --git a/src/qml/types/qqmlmodelsmodule_p.h b/src/qml/qml/qqmlenumdata_p.h
index 939ecc1500..df99c2c1bc 100644
--- a/src/qml/types/qqmlmodelsmodule_p.h
+++ b/src/qml/qml/qqmlenumdata_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Research In Motion.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLMODELSMODULE_H
-#define QQMLMODELSMODULE_H
+#ifndef QQMLENUMDATA_P_H
+#define QQMLENUMDATA_P_H
//
// W A R N I N G
@@ -51,17 +51,16 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <private/qqmlenumvalue_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlModelsModule
+struct QQmlEnumData
{
-public:
- static void defineModule();
- static void defineLabsModule();
+ QString name;
+ QVector<QQmlEnumValue> values;
};
QT_END_NAMESPACE
-#endif
+#endif // QQMLENUMDATA_P_H
diff --git a/src/qml/qml/qqmlenumvalue_p.h b/src/qml/qml/qqmlenumvalue_p.h
new file mode 100644
index 0000000000..ea0fc244cb
--- /dev/null
+++ b/src/qml/qml/qqmlenumvalue_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLENUMVALUE_P_H
+#define QQMLENUMVALUE_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/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQmlEnumValue
+{
+ QQmlEnumValue() {}
+ QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {}
+ QString namedValue;
+ int value = -1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLENUMVALUE_P_H
diff --git a/src/qml/qmldirparser/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 5e181f7e27..0b94ed3b49 100644
--- a/src/qml/qmldirparser/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -38,17 +38,17 @@
****************************************************************************/
#include "qqmlerror.h"
+#include "qqmlfile.h"
#include "qqmlsourcecoordinate_p.h"
+#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
-#ifndef QT_NO_QOBJECT
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -77,26 +77,14 @@ QT_BEGIN_NAMESPACE
\sa QQuickView::errors(), QQmlComponent::errors()
*/
-class QQmlErrorPrivate
+class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage
{
public:
- QQmlErrorPrivate();
-
+ QQmlErrorPrivate() { type = QtWarningMsg; }
QUrl url;
- QString description;
- quint16 line;
- quint16 column;
- QtMsgType messageType;
-#ifndef QT_NO_QOBJECT
QPointer<QObject> object;
-#endif
};
-QQmlErrorPrivate::QQmlErrorPrivate()
-: line(0), column(0), messageType(QtMsgType::QtWarningMsg)
-{
-}
-
/*!
Creates an empty error object.
*/
@@ -126,13 +114,11 @@ QQmlError &QQmlError::operator=(const QQmlError &other)
if (!d)
d = new QQmlErrorPrivate;
d->url = other.d->url;
- d->description = other.d->description;
+ d->message = other.d->message;
d->line = other.d->line;
d->column = other.d->column;
-#ifndef QT_NO_QOBJECT
d->object = other.d->object;
-#endif
- d->messageType = other.d->messageType;
+ d->type = other.d->type;
}
return *this;
}
@@ -179,7 +165,7 @@ void QQmlError::setUrl(const QUrl &url)
QString QQmlError::description() const
{
if (d)
- return d->description;
+ return d->message;
return QString();
}
@@ -190,7 +176,7 @@ void QQmlError::setDescription(const QString &description)
{
if (!d)
d = new QQmlErrorPrivate;
- d->description = description;
+ d->message = description;
}
/*!
@@ -199,7 +185,7 @@ void QQmlError::setDescription(const QString &description)
int QQmlError::line() const
{
if (d)
- return qmlSourceCoordinate(d->line);
+ return qmlConvertSourceCoordinate<quint32, int>(d->line);
return -1;
}
@@ -210,7 +196,7 @@ void QQmlError::setLine(int line)
{
if (!d)
d = new QQmlErrorPrivate;
- d->line = qmlSourceCoordinate(line);
+ d->line = qmlConvertSourceCoordinate<int, quint32>(line);
}
/*!
@@ -219,7 +205,7 @@ void QQmlError::setLine(int line)
int QQmlError::column() const
{
if (d)
- return qmlSourceCoordinate(d->column);
+ return qmlConvertSourceCoordinate<quint32, int>(d->column);
return -1;
}
@@ -230,10 +216,9 @@ void QQmlError::setColumn(int column)
{
if (!d)
d = new QQmlErrorPrivate;
- d->column = qmlSourceCoordinate(column);
+ d->column = qmlConvertSourceCoordinate<int, quint32>(column);
}
-#ifndef QT_NO_QOBJECT
/*!
Returns the nearest object where this error occurred.
Exceptions in bound property expressions set this to the object
@@ -256,7 +241,6 @@ void QQmlError::setObject(QObject *object)
d = new QQmlErrorPrivate;
d->object = object;
}
-#endif // QT_NO_QOBJECT
/*!
\since 5.9
@@ -266,7 +250,7 @@ void QQmlError::setObject(QObject *object)
QtMsgType QQmlError::messageType() const
{
if (d)
- return d->messageType;
+ return d->type;
return QtMsgType::QtWarningMsg;
}
@@ -280,7 +264,7 @@ void QQmlError::setMessageType(QtMsgType messageType)
{
if (!d)
d = new QQmlErrorPrivate;
- d->messageType = messageType;
+ d->type = messageType;
}
/*!
@@ -324,8 +308,8 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
QUrl url = error.url();
- if (error.line() > 0 && url.scheme() == QLatin1String("file")) {
- QString file = url.toLocalFile();
+ if (error.line() > 0 && (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc"))) {
+ QString file = QQmlFile::urlToLocalFileOrQrc(url);
QFile f(file);
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
diff --git a/src/qml/qmldirparser/qqmlerror.h b/src/qml/qml/qqmlerror.h
index f4221358e9..8ea493c11d 100644
--- a/src/qml/qmldirparser/qqmlerror.h
+++ b/src/qml/qml/qqmlerror.h
@@ -69,10 +69,8 @@ public:
int column() const;
void setColumn(int);
-#ifndef QT_NO_QOBJECT
QObject *object() const;
void setObject(QObject *);
-#endif
QtMsgType messageType() const;
void setMessageType(QtMsgType messageType);
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index ac2629979f..f6a5afb891 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -45,8 +45,8 @@
#include "qqmlcontext_p.h"
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
-#include <private/qv8engine_p.h>
#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <QtCore/qdebug.h>
@@ -352,7 +352,7 @@ QString QQmlExpression::sourceFile() const
int QQmlExpression::lineNumber() const
{
Q_D(const QQmlExpression);
- return qmlSourceCoordinate(d->line);
+ return qmlConvertSourceCoordinate<quint16, int>(d->line);
}
/*!
@@ -362,7 +362,7 @@ int QQmlExpression::lineNumber() const
int QQmlExpression::columnNumber() const
{
Q_D(const QQmlExpression);
- return qmlSourceCoordinate(d->column);
+ return qmlConvertSourceCoordinate<quint16, int>(d->column);
}
/*!
@@ -373,8 +373,8 @@ void QQmlExpression::setSourceLocation(const QString &url, int line, int column)
{
Q_D(QQmlExpression);
d->url = url;
- d->line = qmlSourceCoordinate(line);
- d->column = qmlSourceCoordinate(column);
+ d->line = qmlConvertSourceCoordinate<int, quint16>(line);
+ d->column = qmlConvertSourceCoordinate<int, quint16>(column);
}
/*!
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 1d60c518c4..acebb6bac3 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -149,7 +149,8 @@ QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString
return QVariant();
}
-QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, QQmlV4Handle obj, QV4::ExecutionEngine *e, bool *ok)
+QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, const QV4::Value &obj,
+ QV4::ExecutionEngine *e, bool *ok)
{
QVariant v;
@@ -225,63 +226,53 @@ bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_
bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; }
bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; }
bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, QVariant *) { return false; }
+bool QQmlValueTypeProvider::variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *) { return false; }
bool QQmlValueTypeProvider::equal(int, const void *, const QVariant&) { return false; }
bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; }
bool QQmlValueTypeProvider::read(const QVariant&, void *, int) { return false; }
bool QQmlValueTypeProvider::write(int, const void *, QVariant&) { return false; }
-Q_GLOBAL_STATIC(QQmlValueTypeProvider, nullValueTypeProvider)
-static QQmlValueTypeProvider *valueTypeProvider = nullptr;
+struct ValueTypeProviderList {
+ QQmlValueTypeProvider nullProvider;
+ QQmlValueTypeProvider *head = &nullProvider;
+};
-static QQmlValueTypeProvider **getValueTypeProvider(void)
-{
- if (valueTypeProvider == nullptr) {
- valueTypeProvider = nullValueTypeProvider;
- }
-
- return &valueTypeProvider;
-}
+Q_GLOBAL_STATIC(ValueTypeProviderList, valueTypeProviders)
Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *newProvider)
{
- static QQmlValueTypeProvider **providerPtr = getValueTypeProvider();
- newProvider->next = *providerPtr;
- *providerPtr = newProvider;
+ if (ValueTypeProviderList *providers = valueTypeProviders()) {
+ newProvider->next = providers->head;
+ providers->head = newProvider;
+ }
}
Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *oldProvider)
{
- if (oldProvider == nullValueTypeProvider) {
- // don't remove the null provider
- // we get here when the QtQml library is being unloaded
- return;
- }
-
- // the only entry with next = 0 is the null provider
- Q_ASSERT(oldProvider->next);
+ if (ValueTypeProviderList *providers = valueTypeProviders()) {
+ QQmlValueTypeProvider *prev = providers->head;
+ if (prev == oldProvider) {
+ providers->head = oldProvider->next;
+ return;
+ }
- QQmlValueTypeProvider *prev = valueTypeProvider;
- if (prev == oldProvider) {
- valueTypeProvider = oldProvider->next;
- return;
- }
+ // singly-linked list removal
+ for (; prev; prev = prev->next) {
+ if (prev->next != oldProvider)
+ continue; // this is not the provider you're looking for
+ prev->next = oldProvider->next;
+ return;
+ }
- // singly-linked list removal
- for ( ; prev; prev = prev->next) {
- if (prev->next != oldProvider)
- continue; // this is not the provider you're looking for
- prev->next = oldProvider->next;
- return;
+ qWarning("QQml_removeValueTypeProvider: was asked to remove provider %p but it was not found", oldProvider);
}
-
- qWarning("QQml_removeValueTypeProvider: was asked to remove provider %p but it was not found", oldProvider);
}
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider(void)
+Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider()
{
- static QQmlValueTypeProvider **providerPtr = getValueTypeProvider();
- return *providerPtr;
+ if (ValueTypeProviderList *providers = valueTypeProviders())
+ return providers->head;
+ return nullptr;
}
QQmlColorProvider::~QQmlColorProvider() {}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 818537560c..3c540a6124 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -53,9 +53,8 @@
#include <private/qtqmlglobal_p.h>
#include <QtCore/QObject>
-#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlmetaobject_p.h>
#include <private/qmetaobject_p.h>
-#include <private/qv8engine_p.h>
QT_BEGIN_NAMESPACE
@@ -91,7 +90,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \
-{ \
+do { \
SenderType *sender = (Sender); \
ReceiverType *receiver = (Receiver); \
const char *signal = (Signal); \
@@ -99,11 +98,11 @@ QT_BEGIN_NAMESPACE
static int signalIdx = -1; \
static int methodIdx = -1; \
if (signalIdx < 0) { \
- Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \
+ Q_ASSERT((int(*signal) - '0') == QSIGNAL_CODE); \
signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \
} \
if (methodIdx < 0) { \
- int code = ((int)(*method) - '0'); \
+ int code = (int(*method) - '0'); \
Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \
if (code == QSLOT_CODE) \
methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \
@@ -112,7 +111,7 @@ QT_BEGIN_NAMESPACE
} \
Q_ASSERT(signalIdx != -1 && methodIdx != -1); \
QMetaObject::connect(sender, signalIdx, receiver, methodIdx, Qt::DirectConnection); \
-}
+} while (0)
/*!
Disconnect \a Signal of \a Sender from \a Method of \a Receiver. \a Signal must be
@@ -130,7 +129,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
#define qmlobject_disconnect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \
-{ \
+do { \
SenderType *sender = (Sender); \
ReceiverType *receiver = (Receiver); \
const char *signal = (Signal); \
@@ -138,11 +137,11 @@ QT_BEGIN_NAMESPACE
static int signalIdx = -1; \
static int methodIdx = -1; \
if (signalIdx < 0) { \
- Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \
+ Q_ASSERT((int(*signal) - '0') == QSIGNAL_CODE); \
signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \
} \
if (methodIdx < 0) { \
- int code = ((int)(*method) - '0'); \
+ int code = (int(*method) - '0'); \
Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \
if (code == QSLOT_CODE) \
methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \
@@ -151,7 +150,7 @@ QT_BEGIN_NAMESPACE
} \
Q_ASSERT(signalIdx != -1 && methodIdx != -1); \
QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \
-}
+} while (0)
/*!
This method is identical to qobject_cast<T>() except that it does not require lazy
@@ -233,7 +232,7 @@ public:
QVariant createVariantFromString(const QString &);
QVariant createVariantFromString(int, const QString &, bool *);
- QVariant createVariantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, bool*);
+ QVariant createVariantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, bool *);
bool equalValueType(int, const void *, const QVariant&);
bool storeValueType(int, const void *, void *, size_t);
@@ -250,7 +249,7 @@ private:
virtual bool variantFromString(const QString &, QVariant *);
virtual bool variantFromString(int, const QString &, QVariant *);
- virtual bool variantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, QVariant *);
+ virtual bool variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *);
virtual bool equal(int, const void *, const QVariant&);
virtual bool store(int, const void *, void *, size_t);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index ba8dce4b6e..8b5e11c890 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -54,6 +54,8 @@
#include <private/qqmltypenamecache_p.h>
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
+#include <private/qqmltypemodule_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
@@ -131,85 +133,6 @@ bool isPathAbsolute(const QString &path)
#endif
}
-/*
- \internal
-
- Fetches the QQmlType instance registered for \a urlString, creating a
- registration for it if it is not already registered, using the associated
- \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
- details.
-
- Errors (if there are any) are placed into \a errors, if it is nonzero. Note
- that errors are treated as fatal if \a errors is not set.
-*/
-QQmlType fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
- bool isCompositeSingleton, QList<QQmlError> *errors,
- int majorVersion=-1, int minorVersion=-1)
-{
- QUrl url(urlString); // ### unfortunate (costly) conversion
- QQmlType ret = QQmlMetaType::qmlType(url);
- if (ret.isValid())
- return ret;
-
- int dot = typeName.indexOf(QLatin1Char('.'));
- QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
-
- // We need a pointer, but we were passed a string. Take a copy so we
- // can guarentee it will live long enough to reach qmlregister.
- QByteArray buf(unqualifiedtype.toString().toUtf8());
-
- QQmlMetaTypeRegistrationFailureRecorder failureRecorder;
-
- // Register the type. Note that the URI parameters here are empty; for
- // file type imports, we do not place them in a URI as we don't
- // necessarily have a good and unique one (picture a library import,
- // which may be found in multiple plugin locations on disk), but there
- // are other reasons for this too.
- //
- // By not putting them in a URI, we prevent the types from being
- // registered on a QQmlTypeModule; this is important, as once types are
- // placed on there, they cannot be easily removed, meaning if the
- // developer subsequently loads a different import (meaning different
- // types) with the same URI (using, say, a different plugin path), it is
- // very undesirable that we continue to associate the types from the
- // "old" URI with that new module.
- //
- // Not having URIs also means that the types cannot be found by name
- // etc, the only way to look them up is through QQmlImports -- for
- // better or worse.
- if (isCompositeSingleton) {
- QQmlPrivate::RegisterCompositeSingletonType reg = {
- url,
- "", // uri
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::registerCompositeSingletonType(reg);
- } else {
- QQmlPrivate::RegisterCompositeType reg = {
- url,
- "", // uri
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::registerCompositeType(reg);
- }
-
- // This means that the type couldn't be found by URL, but could not be
- // registered either, meaning we most likely were passed some kind of bad
- // data.
- if (!ret.isValid()) {
- if (!errors) // Cannot list errors properly, just quit
- qFatal("%s", failureRecorder.failures().join('\n').toLatin1().constData());
- QQmlError error;
- error.setDescription(failureRecorder.failures().join('\n'));
- errors->prepend(error);
- }
- return ret;
-}
-
} // namespace
struct RegisteredPlugin {
@@ -219,6 +142,13 @@ struct RegisteredPlugin {
struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
QMutex mutex;
+
+ ~StringRegisteredPluginMap()
+ {
+ QMutexLocker lock(&mutex);
+ for (const RegisteredPlugin &plugin : qAsConst(*this))
+ delete plugin.loader;
+ }
};
Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
@@ -831,9 +761,9 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (candidate != end) {
if (!base) // ensure we have a componentUrl
componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
- QQmlType returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton,
- nullptr, candidate->majorVersion,
- candidate->minorVersion);
+ QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton,
+ nullptr, candidate->majorVersion,
+ candidate->minorVersion);
if (vmajor)
*vmajor = candidate->majorVersion;
if (vminor)
@@ -850,12 +780,12 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
typeStr + dotqml_string, // Type -> Type.qml
typeStr + dotuidotqml_string // Type -> Type.ui.qml
};
- for (uint i = 0; i < sizeof(urlsToTry) / sizeof(urlsToTry[0]); ++i) {
- exists = typeLoader->fileExists(localDirectoryPath, urlsToTry[i]);
+ for (const QString &urlToTry : urlsToTry) {
+ exists = typeLoader->fileExists(localDirectoryPath, urlToTry);
if (exists) {
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
// don't let function.qml confuse the use of "new Function(...)" for example.
- if (!QQml_isFileCaseCorrect(localDirectoryPath + urlsToTry[i])) {
+ if (!QQml_isFileCaseCorrect(localDirectoryPath + urlToTry)) {
exists = false;
if (errors) {
QQmlError caseError;
@@ -867,7 +797,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
#else
Q_UNUSED(errors);
#endif
- qmlUrl = url + urlsToTry[i];
+ qmlUrl = url + urlToTry;
break;
}
}
@@ -877,8 +807,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
- QQmlType returnType = fetchOrCreateTypeForUrl(
- qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
+ QQmlType returnType = QQmlMetaType::typeForUrl(
+ qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
if (type_return)
*type_return = returnType;
return returnType.isValid();
@@ -926,7 +856,10 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
+ *type_return = QQmlMetaType::typeForUrl(
+ resolveLocalUrl(s->imports.at(0)->url,
+ unqualifiedtype.toString() + QLatin1String(".qml")),
+ type, false, errors);
return type_return->isValid();
}
}
@@ -1099,13 +1032,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
return true;
}
-#if defined(QT_SHARED) || !QT_CONFIG(library)
-static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
-{
- return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why);
-}
-#endif
-
/*
Import an extension defined by a qmldir file.
@@ -1154,7 +1080,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
int dynamicPluginsFound = 0;
int staticPluginsFound = 0;
-#if defined(QT_SHARED)
+#if QT_CONFIG(library)
const auto qmldirPlugins = qmldir.plugins();
for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
@@ -1165,9 +1091,11 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// XXX TODO: should we leave the import plugin error alone?
// Here, we pop it off the top and coalesce it into this error's message.
// The reason is that the lower level may add url and line/column numbering information.
- QQmlError poppedError = errors->takeFirst();
QQmlError error;
- error.setDescription(msgCannotLoadPlugin(uri, poppedError.description()));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "plugin cannot be loaded for module \"%1\": %2")
+ .arg(uri, errors->takeFirst().description()));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
@@ -1175,7 +1103,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
}
}
-#endif // QT_SHARED
+#endif // QT_CONFIG(library)
if (dynamicPluginsFound < qmldirPluginCount) {
// Check if the missing plugins can be resolved statically. We do this by looking at
@@ -1823,6 +1751,16 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
addImportPath(QStringLiteral("qrc:/qt-project.org/imports"));
addImportPath(QCoreApplication::applicationDirPath());
+#if defined(Q_OS_ANDROID)
+ addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_BUNDLED_LIBS_PATH"))) {
+ const QString envImportPath = qEnvironmentVariable("QT_BUNDLED_LIBS_PATH");
+ QLatin1Char pathSep(':');
+ QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
+ for (int ii = paths.count() - 1; ii >= 0; --ii)
+ addPluginPath(paths.at(ii));
+ }
+#endif
}
QQmlImportDatabase::~QQmlImportDatabase()
@@ -1870,6 +1808,18 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
if (!resolvedPath.endsWith(Slash))
resolvedPath += Slash;
+#if defined(Q_OS_ANDROID)
+ if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') && qmldirPath.at(1) == QLatin1Char('/') &&
+ qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), Qt::CaseInsensitive)) {
+ QString pluginName = qmldirPath.mid(21) + Slash + baseName;
+ auto bundledPath = resolvedPath + QLatin1String("lib") + pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
+ }
+#endif
resolvedPath += prefix + baseName;
for (const QString &suffix : suffixes) {
const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
@@ -1924,9 +1874,15 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
QLatin1String(".so"),
QLatin1String(".bundle")
};
-# else // Unix
+#else // Unix
static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = { QLatin1String(".so") };
+ static const QStringList suffixes = {
+# if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+# endif
+ QLatin1String(".so")
+
+ };
#endif
return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
@@ -2030,7 +1986,9 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::setImportPathList: " << paths;
- fileImportPath = paths;
+ fileImportPath.clear();
+ for (auto it = paths.crbegin(); it != paths.crend(); ++it)
+ addImportPath(*it);
// Our existing cached paths may have been invalidated
clearDirCache();
@@ -2044,77 +2002,7 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b
{
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath;
-
- QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
- if (!iface) {
- if (errors) {
- QQmlError error;
- error.setDescription(tr("Module loaded for URI '%1' does not implement QQmlTypesExtensionInterface").arg(typeNamespace));
- errors->prepend(error);
- }
- return false;
- }
-
- const QByteArray bytes = uri.toUtf8();
- const char *moduleId = bytes.constData();
-
- QQmlMetaTypeRegistrationFailureRecorder failureRecorder;
- {
- // Create a scope for QWriteLocker to keep it as narrow as possible, and
- // to ensure that we release it before the call to initalizeEngine below
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
-
- if (!typeNamespace.isEmpty()) {
- // This is an 'identified' module
- if (typeNamespace != uri) {
- // The namespace for type registrations must match the URI for locating the module
- if (errors) {
- QQmlError error;
- error.setDescription(tr("Module namespace '%1' does not match import URI '%2'").arg(typeNamespace).arg(uri));
- errors->prepend(error);
- }
- return false;
- }
-
- if (QQmlMetaType::namespaceContainsRegistrations(typeNamespace, vmaj)) {
- // Other modules have already installed to this namespace
- if (errors) {
- QQmlError error;
- error.setDescription(tr("Namespace '%1' has already been used for type registration").arg(typeNamespace));
- errors->prepend(error);
- }
- return false;
- } else {
- QQmlMetaType::protectNamespace(typeNamespace);
- }
- } else {
- // This is not an identified module - provide a warning
- qWarning().nospace() << qPrintable(tr("Module '%1' does not contain a module identifier directive - it cannot be protected from external registrations.").arg(uri));
- }
-
- QQmlMetaType::setTypeRegistrationNamespace(typeNamespace);
-
- if (QQmlExtensionPlugin *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
- // basepath should point to the directory of the module, not the plugin file itself:
- QQmlExtensionPluginPrivate::get(plugin)->baseUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
- }
-
- iface->registerTypes(moduleId);
- QQmlMetaType::setTypeRegistrationNamespace(QString());
- } // QWriteLocker lock(QQmlMetaType::typeRegistrationLock())
-
- if (!failureRecorder.failures().isEmpty()) {
- if (errors) {
- for (const QString &failure : failureRecorder.failures()) {
- QQmlError error;
- error.setDescription(failure);
- errors->prepend(error);
- }
- }
- return false;
- }
-
- return true;
+ return QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors);
}
/*!
@@ -2169,13 +2057,13 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba
return true;
}
+#if QT_CONFIG(library)
/*!
\internal
*/
bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri,
const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
{
-#if QT_CONFIG(library)
QFileInfo fileInfo(filePath);
const QString absoluteFilePath = fileInfo.absoluteFilePath();
@@ -2253,20 +2141,14 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
}
return true;
-#else
- Q_UNUSED(filePath);
- Q_UNUSED(uri);
- Q_UNUSED(typeNamespace);
- Q_UNUSED(vmaj);
- Q_UNUSED(errors);
- return false;
-#endif
}
+#endif // QT_CONFIG(library)
+
void QQmlImportDatabase::clearDirCache()
{
- QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.begin();
- while (itr != qmldirCache.end()) {
+ QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.constBegin();
+ while (itr != qmldirCache.constEnd()) {
QmldirCache *cache = *itr;
do {
QmldirCache *nextCache = cache->next;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index f8c01ed876..ea9c2eafb5 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -44,9 +44,10 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
+#include <QtQml/qqmlerror.h>
#include <private/qqmldirparser_p.h>
-#include <private/qqmlmetatype_p.h>
-#include <private/qhashedstring_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qstringhash_p.h>
//
// W A R N I N G
@@ -211,7 +212,9 @@ public:
QQmlImportDatabase(QQmlEngine *);
~QQmlImportDatabase();
+#if QT_CONFIG(library)
bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
+#endif
QStringList importPathList(PathType type = LocalOrRemote) const;
void setImportPathList(const QStringList &paths);
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 39da550d63..bc06226cbf 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -42,7 +42,6 @@
#include "qqmlincubator_p.h"
#include "qqmlexpression_p.h"
-#include "qqmlmemoryprofiler_p.h"
#include "qqmlobjectcreator_p.h"
void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
@@ -272,8 +271,6 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!compilationUnit)
return;
- QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl());
-
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 676ba1a29a..57ec8249cb 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -87,7 +87,7 @@ public:
QPointer<QObject> result;
QQmlGuardedContextData rootContext;
QQmlEnginePrivate *enginePriv;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QScopedPointer<QQmlObjectCreator> creator;
int subComponentToCreate;
QQmlVMEGuard vmeGuard;
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index 6322302422..2bfd2d5bb4 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlDebug(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
\since 5.9
Prints debug messages that include the file and line number for the
@@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlInfo(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -119,7 +119,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QQmlInfo QtQml::qmlWarning(const QObject *object)
- \relates QQmlEngine
+ \relates QtQml
\since 5.9
Prints warning messages that include the file and line number for the
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
index 673125632e..faa112d4af 100644
--- a/src/qml/qml/qqmlinfo.h
+++ b/src/qml/qml/qqmlinfo.h
@@ -40,6 +40,7 @@
#ifndef QQMLINFO_H
#define QQMLINFO_H
+#include <QtQml/qtqmlglobal.h>
#include <QtCore/qdebug.h>
#include <QtCore/qurl.h>
#include <QtQml/qqmlerror.h>
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
new file mode 100644
index 0000000000..82cad8eba8
--- /dev/null
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlirloader_p.h"
+#include <private/qqmlirbuilder_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlIRLoader::QQmlIRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
+ : unit(qmlData)
+ , output(output)
+{
+ pool = output->jsParserEngine.pool();
+}
+
+void QQmlIRLoader::load()
+{
+ output->jsGenerator.stringTable.initializeFromBackingUnit(unit);
+
+ const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit();
+
+ for (quint32 i = 0; i < qmlUnit->nImports; ++i)
+ output->imports << qmlUnit->importAt(i);
+
+ if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
+ QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ p->location = QV4::CompiledData::Location();
+ p->type = QmlIR::Pragma::PragmaSingleton;
+ output->pragmas << p;
+ }
+
+ for (uint i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
+ QmlIR::Object *object = loadObject(serializedObject);
+ output->objects.append(object);
+ }
+}
+
+struct FakeExpression : public QQmlJS::AST::NullExpression
+{
+ FakeExpression(int start, int length)
+ : location(start, length)
+ {}
+
+ virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ { return location; }
+
+ virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ { return location; }
+
+private:
+ QQmlJS::AST::SourceLocation location;
+};
+
+QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+{
+ QmlIR::Object *object = pool->New<QmlIR::Object>();
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+
+ object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
+ object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
+ object->flags = serializedObject->flags;
+ object->id = serializedObject->id;
+ object->location = serializedObject->location;
+ object->locationOfIdProperty = serializedObject->locationOfIdProperty;
+
+ QVector<int> functionIndices;
+ functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
+
+ for (uint i = 0; i < serializedObject->nBindings; ++i) {
+ QmlIR::Binding *b = pool->New<QmlIR::Binding>();
+ *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
+ object->bindings->append(b);
+ if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ functionIndices.append(b->value.compiledScriptIndex);
+ b->value.compiledScriptIndex = functionIndices.count() - 1;
+
+ QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
+ foe->nameIndex = 0;
+
+ QQmlJS::AST::ExpressionNode *expr;
+
+ if (b->stringIndex != quint32(0)) {
+ const int start = output->code.length();
+ const QString script = output->stringAt(b->stringIndex);
+ const int length = script.length();
+ output->code.append(script);
+ expr = new (pool) FakeExpression(start, length);
+ } else
+ expr = new (pool) QQmlJS::AST::NullExpression();
+ foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
+ object->functionsAndExpressions->append(foe);
+ }
+ }
+
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+
+ for (uint i = 0; i < serializedObject->nSignals; ++i) {
+ const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
+ QmlIR::Signal *s = pool->New<QmlIR::Signal>();
+ s->nameIndex = serializedSignal->nameIndex;
+ s->location = serializedSignal->location;
+ s->parameters = pool->New<QmlIR::PoolList<QmlIR::Parameter> >();
+
+ for (uint i = 0; i < serializedSignal->nParameters; ++i) {
+ QmlIR::Parameter *p = pool->New<QmlIR::Parameter>();
+ *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
+ s->parameters->append(p);
+ }
+
+ object->qmlSignals->append(s);
+ }
+
+ for (uint i = 0; i < serializedObject->nEnums; ++i) {
+ const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i);
+ QmlIR::Enum *e = pool->New<QmlIR::Enum>();
+ e->nameIndex = serializedEnum->nameIndex;
+ e->location = serializedEnum->location;
+ e->enumValues = pool->New<QmlIR::PoolList<QmlIR::EnumValue> >();
+
+ for (uint i = 0; i < serializedEnum->nEnumValues; ++i) {
+ QmlIR::EnumValue *v = pool->New<QmlIR::EnumValue>();
+ *static_cast<QV4::CompiledData::EnumValue*>(v) = *serializedEnum->enumValueAt(i);
+ e->enumValues->append(v);
+ }
+
+ object->qmlEnums->append(e);
+ }
+
+ const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
+ for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
+ QmlIR::Property *p = pool->New<QmlIR::Property>();
+ *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
+ object->properties->append(p);
+ }
+
+ {
+ const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable();
+ for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) {
+ QmlIR::Alias *a = pool->New<QmlIR::Alias>();
+ *static_cast<QV4::CompiledData::Alias*>(a) = *serializedAlias;
+ object->aliases->append(a);
+ }
+ }
+
+ const quint32_le *functionIdx = serializedObject->functionOffsetTable();
+ for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
+ QmlIR::Function *f = pool->New<QmlIR::Function>();
+ const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
+
+ functionIndices.append(*functionIdx);
+ f->index = functionIndices.count() - 1;
+ f->location = compiledFunction->location;
+ f->nameIndex = compiledFunction->nameIndex;
+ f->returnType = compiledFunction->returnType;
+
+ f->formals.allocate(pool, int(compiledFunction->nFormals));
+ const QV4::CompiledData::Parameter *formalNameIdx = compiledFunction->formalsTable();
+ for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
+ *static_cast<QV4::CompiledData::Parameter*>(&f->formals[i]) = *formalNameIdx;
+
+ object->functions->append(f);
+ }
+
+ object->runtimeFunctionIndices.allocate(pool, functionIndices);
+
+ return object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlirloader_p.h b/src/qml/qml/qqmlirloader_p.h
new file mode 100644
index 0000000000..4812946ef0
--- /dev/null
+++ b/src/qml/qml/qqmlirloader_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLIRLOADER_P_H
+#define QQMLIRLOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qqmljsmemorypool_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlIR {
+struct Document;
+struct Object;
+}
+
+struct Q_QML_PRIVATE_EXPORT QQmlIRLoader {
+ QQmlIRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
+
+ void load();
+
+private:
+ QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
+
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
+
+ const QV4::CompiledData::Unit *unit;
+ QmlIR::Document *output;
+ QQmlJS::MemoryPool *pool;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLIRLOADER_P_H
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 9a3a5218e0..8661ebcc13 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -208,7 +208,10 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
}
Q_ASSERT(m_qmlScope.valueRef());
- QV4::ReturnedValue res = v4Function->call(&callData->thisObject, callData->args, callData->argc(), static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
+ QV4::ReturnedValue res = v4Function->call(
+ &(callData->thisObject.asValue<QV4::Value>()),
+ callData->argValues<QV4::Value>(), callData->argc(),
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, res);
@@ -392,10 +395,10 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
return;
m_qmlScope.set(qmlContext->engine(), *qmlContext);
m_v4Function = f;
- setCompilationUnit(m_v4Function->compilationUnit);
+ setCompilationUnit(m_v4Function->executableCompilationUnit());
}
-void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
{
m_compilationUnit = compilationUnit;
}
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 453c8ab8a8..eecee08062 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -153,7 +153,7 @@ protected:
void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line);
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
- void setCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ void setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
// We store some flag bits in the following flag pointers.
// activeGuards:flag1 - notifyOnValueChanged
@@ -178,11 +178,11 @@ private:
QQmlJavaScriptExpression *m_nextExpression;
QV4::PersistentValue m_qmlScope;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
QV4::Function *m_v4Function;
};
-class QQmlPropertyCapture
+class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture
{
public:
QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w)
diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h
index 04bab8d929..e182ced51d 100644
--- a/src/qml/qml/qqmllist_p.h
+++ b/src/qml/qml/qqmllist_p.h
@@ -52,7 +52,7 @@
//
#include "qqmllist.h"
-#include "qqmlpropertycache_p.h"
+#include "qqmlmetaobject_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 2f769c1aef..5349572921 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qqmllistwrapper_p.h"
-#include <private/qv8engine_p.h>
#include <private/qqmllist_p.h>
#include <private/qv4objectproto_p.h>
#include <qv4objectiterator_p.h>
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 2b17037df0..dca13ac8d4 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -662,7 +662,7 @@ LOCALE_STRING_PROPERTY(exponential)
LOCALE_STRING_PROPERTY(amText)
LOCALE_STRING_PROPERTY(pmText)
-class QV4LocaleDataDeletable : public QV8Engine::Deletable
+class QV4LocaleDataDeletable : public QV4::ExecutionEngine::Deletable
{
public:
QV4LocaleDataDeletable(QV4::ExecutionEngine *engine);
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index ece06e04b4..ee5d9af2e7 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -65,7 +65,7 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
- Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 1)
+ Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
public:
enum DefaultLogLevel {
diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp
new file mode 100644
index 0000000000..a967f46b12
--- /dev/null
+++ b/src/qml/qml/qqmlmetaobject.cpp
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlmetaobject_p.h"
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlpropertycachemethodarguments_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
+
+static bool isNamedEnumeratorInScope(const QMetaObject *resolvedMetaObject, const QByteArray &scope,
+ const QByteArray &name)
+{
+ for (int i = resolvedMetaObject->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = resolvedMetaObject->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return true;
+ }
+ return false;
+}
+
+static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scopedName)
+{
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = scopedName.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = scopedName.left(scopeIdx);
+ name = scopedName.mid(scopeIdx + 2);
+ } else {
+ name = scopedName;
+ }
+
+ if (scope == "Qt")
+ return isNamedEnumeratorInScope(StaticQtMetaObject::get(), scope, name);
+
+ if (isNamedEnumeratorInScope(metaObj, scope, name))
+ return true;
+
+ if (metaObj->d.relatedMetaObjects && !scope.isEmpty()) {
+ for (auto related = metaObj->d.relatedMetaObjects; *related; ++related) {
+ if (isNamedEnumeratorInScope(*related, scope, name))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Returns true if \a from is assignable to a property of type \a to
+bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
+{
+ Q_ASSERT(!from.isNull() && !to.isNull());
+
+ struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
+ return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+ } };
+
+ const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
+ if (tom == &QObject::staticMetaObject) return true;
+
+ if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
+ QQmlPropertyCache *fromp = from._m.asT1();
+ QQmlPropertyCache *top = to._m.asT1();
+
+ while (fromp) {
+ if (fromp == top) return true;
+ fromp = fromp->parent();
+ }
+ } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
+ QQmlPropertyCache *fromp = from._m.asT1();
+
+ while (fromp) {
+ const QMetaObject *fromm = fromp->metaObject();
+ if (fromm && I::equal(fromm, tom)) return true;
+ fromp = fromp->parent();
+ }
+ } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
+ const QMetaObject *fromm = from._m.asT2();
+
+ if (!tom) return false;
+
+ while (fromm) {
+ if (I::equal(fromm, tom)) return true;
+ fromm = fromm->superClass();
+ }
+ } else { // QMetaObject -> QMetaObject
+ const QMetaObject *fromm = from._m.asT2();
+
+ while (fromm) {
+ if (I::equal(fromm, tom)) return true;
+ fromm = fromm->superClass();
+ }
+ }
+
+ return false;
+}
+
+void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
+{
+ int offset;
+
+ switch (type) {
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ case QMetaObject::QueryPropertyDesignable:
+ case QMetaObject::QueryPropertyEditable:
+ case QMetaObject::QueryPropertyScriptable:
+ case QMetaObject::QueryPropertyStored:
+ case QMetaObject::QueryPropertyUser:
+ offset = (*metaObject)->propertyOffset();
+ while (*index < offset) {
+ *metaObject = (*metaObject)->superClass();
+ offset = (*metaObject)->propertyOffset();
+ }
+ break;
+ case QMetaObject::InvokeMetaMethod:
+ offset = (*metaObject)->methodOffset();
+ while (*index < offset) {
+ *metaObject = (*metaObject)->superClass();
+ offset = (*metaObject)->methodOffset();
+ }
+ break;
+ default:
+ offset = 0;
+ Q_UNIMPLEMENTED();
+ offset = INT_MAX;
+ }
+
+ *index -= offset;
+}
+
+QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
+{
+ if (_m.isNull()) return nullptr;
+ if (_m.isT1()) return _m.asT1();
+ else return e->cache(_m.asT2());
+}
+
+int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
+{
+ Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0);
+
+ int type = data.propType();
+
+ const char *propTypeName = nullptr;
+
+ if (type == QMetaType::UnknownType) {
+ // Find the return type name from the method info
+ QMetaMethod m;
+
+ if (_m.isT1()) {
+ QQmlPropertyCache *c = _m.asT1();
+ Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+ while (data.coreIndex() < c->methodIndexCacheStart)
+ c = c->_parent;
+
+ const QMetaObject *metaObject = c->createMetaObject();
+ Q_ASSERT(metaObject);
+ m = metaObject->method(data.coreIndex());
+ } else {
+ m = _m.asT2()->method(data.coreIndex());
+ }
+
+ type = m.returnType();
+ propTypeName = m.typeName();
+ }
+
+ if (QMetaType::sizeOf(type) <= int(sizeof(int))) {
+ if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration)
+ return QMetaType::Int;
+
+ if (isNamedEnumerator(metaObject(), propTypeName))
+ return QMetaType::Int;
+
+ if (type == QMetaType::UnknownType) {
+ if (unknownTypeError)
+ *unknownTypeError = propTypeName;
+ }
+ } // else we know that it's a known type, as sizeOf(UnknownType) == 0
+
+ return type;
+}
+
+int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
+{
+ Q_ASSERT(!_m.isNull() && index >= 0);
+
+ if (_m.isT1()) {
+ typedef QQmlPropertyCacheMethodArguments A;
+
+ QQmlPropertyCache *c = _m.asT1();
+ Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+ while (index < c->methodIndexCacheStart)
+ c = c->_parent;
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
+
+ if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid)
+ return static_cast<A *>(rv->arguments())->arguments;
+
+ const QMetaObject *metaObject = c->createMetaObject();
+ Q_ASSERT(metaObject);
+ QMetaMethod m = metaObject->method(index);
+
+ int argc = m.parameterCount();
+ if (!rv->arguments()) {
+ A *args = c->createArgumentsObject(argc, m.parameterNames());
+ rv->setArguments(args);
+ }
+ A *args = static_cast<A *>(rv->arguments());
+
+ QList<QByteArray> argTypeNames; // Only loaded if needed
+
+ for (int ii = 0; ii < argc; ++ii) {
+ int type = m.parameterType(ii);
+
+ if (QMetaType::sizeOf(type) > int(sizeof(int))) {
+ // Cannot be passed as int
+ // We know that it's a known type, as sizeOf(UnknownType) == 0
+ } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
+ type = QMetaType::Int;
+ } else {
+ if (argTypeNames.isEmpty())
+ argTypeNames = m.parameterTypes();
+ if (isNamedEnumerator(metaObject, argTypeNames.at(ii))) {
+ type = QMetaType::Int;
+ } else if (type == QMetaType::UnknownType){
+ if (unknownTypeError)
+ *unknownTypeError = argTypeNames.at(ii);
+ return nullptr;
+ }
+
+ }
+ args->arguments[ii + 1] = type;
+ }
+ args->argumentsValid = true;
+ return static_cast<A *>(rv->arguments())->arguments;
+
+ } else {
+ QMetaMethod m = _m.asT2()->method(index);
+ return methodParameterTypes(m, argStorage, unknownTypeError);
+
+ }
+}
+
+int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const
+{
+ Q_ASSERT(argStorage);
+
+ int argc = m.parameterCount();
+ argStorage->resize(argc + 1);
+ argStorage->operator[](0) = argc;
+ QList<QByteArray> argTypeNames; // Only loaded if needed
+
+ for (int ii = 0; ii < argc; ++ii) {
+ int type = m.parameterType(ii);
+ if (QMetaType::sizeOf(type) > int(sizeof(int))) {
+ // Cannot be passed as int
+ // We know that it's a known type, as sizeOf(UnknownType) == 0
+ } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
+ type = QMetaType::Int;
+ } else {
+ if (argTypeNames.isEmpty())
+ argTypeNames = m.parameterTypes();
+ if (isNamedEnumerator(_m.asT2(), argTypeNames.at(ii))) {
+ type = QMetaType::Int;
+ } else if (type == QMetaType::UnknownType) {
+ if (unknownTypeError)
+ *unknownTypeError = argTypeNames.at(ii);
+ return nullptr;
+ }
+ }
+ argStorage->operator[](ii + 1) = type;
+ }
+
+ return argStorage->data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject_p.h b/src/qml/qml/qqmlmetaobject_p.h
new file mode 100644
index 0000000000..65d6361b90
--- /dev/null
+++ b/src/qml/qml/qqmlmetaobject_p.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLMETAOBJECT_P_H
+#define QQMLMETAOBJECT_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 <QtQml/qtqmlglobal.h>
+
+#include <private/qflagpointer_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
+// This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
+// we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
+// QObject type used in assignment or when we don't have a QQmlEngine etc.
+//
+// This class does NOT reference the propertycache.
+class QQmlEnginePrivate;
+class QQmlPropertyData;
+class Q_QML_EXPORT QQmlMetaObject
+{
+public:
+ typedef QVarLengthArray<int, 9> ArgTypeStorage;
+
+ inline QQmlMetaObject();
+ inline QQmlMetaObject(QObject *);
+ inline QQmlMetaObject(const QMetaObject *);
+ inline QQmlMetaObject(QQmlPropertyCache *);
+ inline QQmlMetaObject(const QQmlMetaObject &);
+
+ inline QQmlMetaObject &operator=(const QQmlMetaObject &);
+
+ inline bool isNull() const;
+
+ inline const char *className() const;
+ inline int propertyCount() const;
+
+ inline bool hasMetaObject() const;
+ inline const QMetaObject *metaObject() const;
+
+ QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
+
+ int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
+ int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
+
+ static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
+
+ // static_metacall (on Gadgets) doesn't call the base implementation and therefore
+ // we need a helper to find the correct meta object and property/method index.
+ static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+
+protected:
+ QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
+ int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
+ QByteArray *unknownTypeError) const;
+
+};
+
+QQmlMetaObject::QQmlMetaObject()
+{
+}
+
+QQmlMetaObject::QQmlMetaObject(QObject *o)
+{
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
+ else _m = o->metaObject();
+ }
+}
+
+QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
+ : _m(m)
+{
+}
+
+QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
+ : _m(m)
+{
+}
+
+QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
+ : _m(o._m)
+{
+}
+
+QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
+{
+ _m = o._m;
+ return *this;
+}
+
+bool QQmlMetaObject::isNull() const
+{
+ return _m.isNull();
+}
+
+const char *QQmlMetaObject::className() const
+{
+ if (_m.isNull()) {
+ return nullptr;
+ } else if (_m.isT1()) {
+ return _m.asT1()->className();
+ } else {
+ return _m.asT2()->className();
+ }
+}
+
+int QQmlMetaObject::propertyCount() const
+{
+ if (_m.isNull()) {
+ return 0;
+ } else if (_m.isT1()) {
+ return _m.asT1()->propertyCount();
+ } else {
+ return _m.asT2()->propertyCount();
+ }
+}
+
+bool QQmlMetaObject::hasMetaObject() const
+{
+ return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
+}
+
+const QMetaObject *QQmlMetaObject::metaObject() const
+{
+ if (_m.isNull()) return nullptr;
+ if (_m.isT1()) return _m.asT1()->createMetaObject();
+ else return _m.asT2();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLMETAOBJECT_P_H
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 0f8a850584..c2674b402a 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -37,410 +37,78 @@
**
****************************************************************************/
-#include <QtQml/qqmlprivate.h>
#include "qqmlmetatype_p.h"
-#include <private/qqmlproxymetaobject_p.h>
-#include <private/qqmlcustomparser_p.h>
-#include <private/qhashedstring_p.h>
-#include <private/qqmlimport_p.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qbitarray.h>
-#include <QtCore/qreadwritelock.h>
-#include <QtCore/private/qmetaobject_p.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <qmetatype.h>
-#include <qobjectdefs.h>
-#include <qbytearray.h>
-#include <qreadwritelock.h>
-#include <qstring.h>
-#include <qstringlist.h>
-#include <qvector.h>
+#include <private/qqmlmetatypedata_p.h>
+#include <private/qqmltypemodule_p_p.h>
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qv4executablecompilationunit_p.h>
-#include <ctype.h>
-#include "qqmlcomponent.h"
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qloggingcategory.h>
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
QT_BEGIN_NAMESPACE
-struct QQmlMetaTypeData
+struct LockedData : private QQmlMetaTypeData
{
- QQmlMetaTypeData();
- ~QQmlMetaTypeData();
- void registerType(QQmlTypePrivate *priv);
- QList<QQmlType> types;
- QSet<QQmlType> undeletableTypes;
- typedef QHash<int, QQmlTypePrivate *> Ids;
- Ids idToType;
- typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
- Names nameToType;
- typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
- Files urlToType;
- Files urlToNonFileImportType; // For non-file imported composite and composite
- // singleton types. This way we can locate any
- // of them by url, even if it was registered as
- // a module via QQmlPrivate::RegisterCompositeType
- typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
- MetaObjects metaObjectToType;
- typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
- StringConverters stringConverters;
-
- struct VersionedUri {
- VersionedUri()
- : majorVersion(0) {}
- VersionedUri(const QHashedString &uri, int majorVersion)
- : uri(uri), majorVersion(majorVersion) {}
- bool operator==(const VersionedUri &other) const {
- return other.majorVersion == majorVersion && other.uri == uri;
- }
- QHashedString uri;
- int majorVersion;
- };
- typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
- TypeModules uriToModule;
-
- QBitArray objects;
- QBitArray interfaces;
- QBitArray lists;
-
- QList<QQmlPrivate::AutoParentFunction> parentFunctions;
- QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
-
- QSet<QString> protectedNamespaces;
-
- QString typeRegistrationNamespace;
-
- QHash<int, int> qmlLists;
-
- QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
- QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion);
- QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
-
- void startRecordingTypeRegFailures(QStringList *storage)
- { typeRegistrationFailures = storage; }
- void stopRecordingTypeRegFailures()
- { startRecordingTypeRegFailures(nullptr); }
- void recordTypeRegFailure(const QString &message)
- {
- if (typeRegistrationFailures)
- typeRegistrationFailures->append(message);
- else
- qWarning("%s", message.toUtf8().constData());
- }
-
-private:
- QStringList *typeRegistrationFailures = nullptr;
+ friend class QQmlMetaTypeDataPtr;
};
-struct EnumInfo {
- QStringList path;
- QString metaObjectName;
- QString enumName;
- QString enumKey;
- QString metaEnumScope;
- bool scoped;
-};
+Q_GLOBAL_STATIC(LockedData, metaTypeData)
+Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
-class QQmlTypeModulePrivate
+class QQmlMetaTypeDataPtr
{
+ Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
public:
- QQmlTypeModulePrivate()
- : minMinorVersion(INT_MAX), maxMinorVersion(0), locked(false) {}
-
- static QQmlTypeModulePrivate* get(QQmlTypeModule* q) { return q->d; }
+ QQmlMetaTypeDataPtr() : locker(metaTypeDataLock()), data(metaTypeData()) {}
+ ~QQmlMetaTypeDataPtr() = default;
- QQmlMetaTypeData::VersionedUri uri;
+ QQmlMetaTypeData &operator*() { return *data; }
+ QQmlMetaTypeData *operator->() { return data; }
+ operator QQmlMetaTypeData *() { return data; }
- int minMinorVersion;
- int maxMinorVersion;
- bool locked;
+ const QQmlMetaTypeData &operator*() const { return *data; }
+ const QQmlMetaTypeData *operator->() const { return data; }
+ operator const QQmlMetaTypeData *() const { return data; }
- void add(QQmlTypePrivate *);
- void remove(const QQmlTypePrivate *type);
-
- typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash;
- TypeHash typeHash;
-};
-
-Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
-Q_GLOBAL_STATIC_WITH_ARGS(QMutex, metaTypeDataLock, (QMutex::Recursive))
-
-static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
-{
- return v.uri.hash() ^ qHash(v.majorVersion);
-}
+ bool isValid() const { return data != nullptr; }
-QQmlMetaTypeRegistrationFailureRecorder::QQmlMetaTypeRegistrationFailureRecorder()
-{
- metaTypeData()->startRecordingTypeRegFailures(&_failures);
-}
-
-QQmlMetaTypeRegistrationFailureRecorder::~QQmlMetaTypeRegistrationFailureRecorder()
-{
- metaTypeData()->stopRecordingTypeRegFailures();
-}
-
-QQmlMetaTypeData::QQmlMetaTypeData()
-{
-}
-
-QQmlMetaTypeData::~QQmlMetaTypeData()
-{
- for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i)
- delete *i;
- for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end();
- it != end; ++it)
- (*it)->release();
-}
-
-class QQmlTypePrivate
-{
- Q_DISABLE_COPY(QQmlTypePrivate)
-public:
- QQmlTypePrivate(QQmlType::RegistrationType type);
- ~QQmlTypePrivate();
-
- void init() const;
- void initEnums(const QQmlPropertyCache *cache = nullptr) const;
- void insertEnums(const QMetaObject *metaObject) const;
- void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
-
- QAtomicInt refCount;
- QQmlType::RegistrationType regType;
-
- struct QQmlCppTypeData
- {
- int allocationSize;
- void (*newFunc)(void *);
- QString noCreationReason;
- int parserStatusCast;
- QObject *(*extFunc)(QObject *);
- const QMetaObject *extMetaObject;
- QQmlCustomParser *customParser;
- QQmlAttachedPropertiesFunc attachedPropertiesFunc;
- const QMetaObject *attachedPropertiesType;
- int propertyValueSourceCast;
- int propertyValueInterceptorCast;
- bool registerEnumClassesUnscoped;
- };
-
- struct QQmlSingletonTypeData
- {
- QQmlType::SingletonInstanceInfo *singletonInstanceInfo;
- };
-
- struct QQmlCompositeTypeData
- {
- QUrl url;
- };
-
- union extraData {
- QQmlCppTypeData* cd;
- QQmlSingletonTypeData* sd;
- QQmlCompositeTypeData* fd;
- } extraData;
-
- const char *iid;
- QHashedString module;
- QString name;
- QString elementName;
- int version_maj;
- int version_min;
- int typeId;
- int listId;
- int revision;
- mutable bool containsRevisionedAttributes;
- mutable QQmlType superType;
- const QMetaObject *baseMetaObject;
-
- int index;
- mutable volatile bool isSetup:1;
- mutable volatile bool isEnumFromCacheSetup:1;
- mutable volatile bool isEnumFromBaseSetup:1;
- mutable bool haveSuperType:1;
- mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
- mutable QStringHash<int> enums;
- mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
- mutable QList<QStringHash<int>*> scopedEnums;
-
- struct PropertyCacheByMinorVersion
- {
- PropertyCacheByMinorVersion() : cache(nullptr), minorVersion(-1) {}
- explicit PropertyCacheByMinorVersion(QQmlPropertyCache *pc, int ver) : cache(pc), minorVersion(ver) {}
- QQmlPropertyCachePtr cache;
- int minorVersion;
- };
- QVector<PropertyCacheByMinorVersion> propertyCaches;
- QQmlPropertyCache *propertyCacheForMinorVersion(int minorVersion) const;
- void setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache);
private:
- void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const;
- void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const;
+ QMutexLocker locker;
+ LockedData *data = nullptr;
};
-void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
+static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
+ const QQmlPrivate::RegisterInterface &type)
{
- for (int i = 0; i < types.count(); ++i) {
- if (!types.at(i).isValid()) {
- types[i] = QQmlType(priv);
- priv->index = i;
- return;
- }
- }
- types.append(QQmlType(priv));
- priv->index = types.count() - 1;
-}
-
-void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
-{
- if (scriptCallback && scriptApi(e).isUndefined()) {
- QJSValue value = scriptCallback(e, e);
- if (value.isQObject()) {
- QObject *o = value.toQObject();
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- }
- setScriptApi(e, value);
- } else if (qobjectCallback && !qobjectApi(e)) {
- QObject *o = qobjectCallback(e, e);
- setQObjectApi(e, o);
- if (!o) {
- qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName));
- }
- // if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(e, o);
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- } else if (!url.isEmpty() && !qobjectApi(e)) {
- QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
- QObject *o = component.beginCreate(e->rootContext());
- setQObjectApi(e, o);
- if (o)
- component.completeCreate();
- }
-}
-
-void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
-{
- // cleans up the engine-specific singleton instances if they exist.
- scriptApis.remove(e);
- QObject *o = qobjectApis.take(e);
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
- return;
- delete o;
- }
-}
-
-void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
-{
- qobjectApis.insert(e, o);
-}
-
-QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
-{
- return qobjectApis.value(e);
-}
-
-void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v)
-{
- scriptApis.insert(e, v);
-}
-
-QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
-{
- return scriptApis.value(e);
-}
-
-QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
-: refCount(1), regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
- containsRevisionedAttributes(false), baseMetaObject(nullptr),
- index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false),
- haveSuperType(false)
-{
- switch (type) {
- case QQmlType::CppType:
- extraData.cd = new QQmlCppTypeData;
- extraData.cd->allocationSize = 0;
- extraData.cd->newFunc = nullptr;
- extraData.cd->parserStatusCast = -1;
- extraData.cd->extFunc = nullptr;
- extraData.cd->extMetaObject = nullptr;
- extraData.cd->customParser = nullptr;
- extraData.cd->attachedPropertiesFunc = nullptr;
- extraData.cd->attachedPropertiesType = nullptr;
- extraData.cd->propertyValueSourceCast = -1;
- extraData.cd->propertyValueInterceptorCast = -1;
- extraData.cd->registerEnumClassesUnscoped = true;
- break;
- case QQmlType::SingletonType:
- case QQmlType::CompositeSingletonType:
- extraData.sd = new QQmlSingletonTypeData;
- extraData.sd->singletonInstanceInfo = nullptr;
- break;
- case QQmlType::InterfaceType:
- extraData.cd = nullptr;
- break;
- case QQmlType::CompositeType:
- extraData.fd = new QQmlCompositeTypeData;
- break;
- default: qFatal("QQmlTypePrivate Internal Error.");
- }
-}
-
-QQmlTypePrivate::~QQmlTypePrivate()
-{
- qDeleteAll(scopedEnums);
- switch (regType) {
- case QQmlType::CppType:
- delete extraData.cd->customParser;
- delete extraData.cd;
- break;
- case QQmlType::SingletonType:
- case QQmlType::CompositeSingletonType:
- delete extraData.sd->singletonInstanceInfo;
- delete extraData.sd;
- break;
- case QQmlType::CompositeType:
- delete extraData.fd;
- break;
- default: //Also InterfaceType, because it has no extra data
- break;
- }
-}
-
-QQmlType::QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &interface)
- : d(new QQmlTypePrivate(InterfaceType))
-{
- d->iid = interface.iid;
- d->typeId = interface.typeId;
- d->listId = interface.listId;
+ auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
+ d->iid = type.iid;
+ d->typeId = type.typeId;
+ d->listId = type.listId;
d->isSetup = true;
d->version_maj = 0;
d->version_min = 0;
data->registerType(d);
+ return d;
}
-QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
- : d(new QQmlTypePrivate(SingletonType))
+static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterSingletonType &type)
{
+ auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
data->registerType(d);
- d->elementName = elementName;
- d->module = QString::fromUtf8(type.uri);
-
+ d->setName(QString::fromUtf8(type.uri), elementName);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
- if (type.qobjectApi) {
+ if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
if (type.version >= 1) // static metaobject added in version 1
d->baseMetaObject = type.instanceMetaObject;
if (type.version >= 2) // typeId added in version 2
@@ -449,37 +117,26 @@ QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQm
d->revision = type.revision;
}
- d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo;
+ d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ if (type.version >= 3) {
+ d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
+ } else {
+ d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ }
d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
d->extraData.sd->singletonInstanceInfo->instanceMetaObject
- = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : nullptr;
-}
-
-QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeSingletonType &type)
- : d(new QQmlTypePrivate(CompositeSingletonType))
-{
- data->registerType(d);
-
- d->elementName = elementName;
- d->module = QString::fromUtf8(type.uri);
-
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
+ = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
- d->extraData.sd->singletonInstanceInfo = new SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ return d;
}
-QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterType &type)
- : d(new QQmlTypePrivate(CppType))
+static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterType &type)
{
+ QQmlTypePrivate *d = new QQmlTypePrivate(QQmlType::CppType);
data->registerType(d);
-
- d->elementName = elementName;
- d->module = QString::fromUtf8(type.uri);
+ d->setName(QString::fromUtf8(type.uri), elementName);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
@@ -509,141 +166,41 @@ QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQm
if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false"))
d->extraData.cd->registerEnumClassesUnscoped = false;
}
+
+ return d;
}
-QQmlType::QQmlType(QQmlMetaTypeData *data, const QString &elementName, const QQmlPrivate::RegisterCompositeType &type)
- : d(new QQmlTypePrivate(CompositeType))
+static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterCompositeType &type)
{
+ auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
data->registerType(d);
-
- d->elementName = elementName;
-
- d->module = QString::fromUtf8(type.uri);
+ d->setName(QString::fromUtf8(type.uri), elementName);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ return d;
}
-QQmlType::QQmlType()
- : d(nullptr)
-{
-}
-
-QQmlType::QQmlType(const QQmlType &other)
- : d(other.d)
-{
- if (d)
- d->refCount.ref();
-}
-
-QQmlType &QQmlType::operator =(const QQmlType &other)
-{
- if (d != other.d) {
- if (d && !d->refCount.deref())
- delete d;
- d = other.d;
- if (d)
- d->refCount.ref();
- }
- return *this;
-}
-
-QQmlType::QQmlType(QQmlTypePrivate *priv)
- : d(priv)
-{
- if (d)
- d->refCount.ref();
-}
-
-QQmlType::~QQmlType()
-{
- if (d && !d->refCount.deref())
- delete d;
-}
-
-QHashedString QQmlType::module() const
-{
- if (!d)
- return QHashedString();
- return d->module;
-}
-
-int QQmlType::majorVersion() const
-{
- if (!d)
- return -1;
- return d->version_maj;
-}
-
-int QQmlType::minorVersion() const
+static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterCompositeSingletonType &type)
{
- if (!d)
- return -1;
- return d->version_min;
-}
-
-bool QQmlType::availableInVersion(int vmajor, int vminor) const
-{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
- return false;
- return vmajor == d->version_maj && vminor >= d->version_min;
-}
-
-bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
-{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
- return false;
- return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
-}
-
-// returns the nearest _registered_ super class
-QQmlType QQmlType::superType() const
-{
- if (!d)
- return QQmlType();
- if (!d->haveSuperType && d->baseMetaObject) {
- const QMetaObject *mo = d->baseMetaObject->superClass();
- while (mo && !d->superType.isValid()) {
- d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min);
- mo = mo->superClass();
- }
- d->haveSuperType = true;
- }
-
- return d->superType;
-}
+ auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
+ data->registerType(d);
+ d->setName(QString::fromUtf8(type.uri), elementName);
-QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
-{
- Q_ASSERT(isComposite());
- if (!engine || !d)
- return QQmlType();
- QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
- if (td.isNull() || !td->isComplete())
- return QQmlType();
- QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
- const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
- return QQmlMetaType::qmlType(mo);
-}
+ d->version_maj = type.versionMajor;
+ d->version_min = type.versionMinor;
-QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const
-{
- // similar logic to resolveCompositeBaseType
- Q_ASSERT(isComposite());
- if (!engine)
- return nullptr;
- QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
- if (td.isNull() || !td->isComplete())
- return nullptr;
- QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
- return compilationUnit->rootPropertyCache().data();
+ d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
+ d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
+ d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ return d;
}
-static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
{
// Set classname
builder.setClassName(ignoreEnd->className());
@@ -710,918 +267,10 @@ static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
-static bool isPropertyRevisioned(const QMetaObject *mo, int index)
-{
- int i = index;
- i -= mo->propertyOffset();
- if (i < 0 && mo->d.superdata)
- return isPropertyRevisioned(mo->d.superdata, index);
-
- const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
- if (i >= 0 && i < mop->propertyCount) {
- int handle = mop->propertyData + 3*i;
- int flags = mo->d.data[handle + 2];
-
- return (flags & Revisioned);
- }
-
- return false;
-}
-
-void QQmlTypePrivate::init() const
-{
- if (isSetup)
- return;
-
- QMutexLocker lock(metaTypeDataLock());
- if (isSetup)
- return;
-
- const QMetaObject *mo = baseMetaObject;
- if (!mo) {
- // version 0 singleton type without metaobject information
- return;
- }
-
- if (regType == QQmlType::CppType) {
- // Setup extended meta object
- // XXX - very inefficient
- if (extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject, extraData.cd->extMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = mo;
- QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
- }
-
- mo = mo->d.superdata;
- while(mo) {
- QQmlTypePrivate *t = metaTypeData()->metaObjectToType.value(mo);
- if (t) {
- if (t->regType == QQmlType::CppType) {
- if (t->extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = baseMetaObject;
- if (!metaObjects.isEmpty())
- metaObjects.constLast().metaObject->d.superdata = mmo;
- QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
- }
- }
- mo = mo->d.superdata;
- }
-
- for (int ii = 0; ii < metaObjects.count(); ++ii) {
- metaObjects[ii].propertyOffset =
- metaObjects.at(ii).metaObject->propertyOffset();
- metaObjects[ii].methodOffset =
- metaObjects.at(ii).metaObject->methodOffset();
- }
-
- // Check for revisioned details
- {
- const QMetaObject *mo = nullptr;
- if (metaObjects.isEmpty())
- mo = baseMetaObject;
- else
- mo = metaObjects.constFirst().metaObject;
-
- for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
- if (isPropertyRevisioned(mo, ii))
- containsRevisionedAttributes = true;
- }
-
- for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
- if (mo->method(ii).revision() != 0)
- containsRevisionedAttributes = true;
- }
- }
-
- isSetup = true;
- lock.unlock();
-}
-
-void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const
-{
- if ((isEnumFromBaseSetup || !baseMetaObject)
- && (isEnumFromCacheSetup || !cache)) {
- return;
- }
-
- init();
-
- QMutexLocker lock(metaTypeDataLock());
-
- if (!isEnumFromCacheSetup && cache) {
- insertEnumsFromPropertyCache(cache);
- isEnumFromCacheSetup = true;
- }
-
- if (!isEnumFromBaseSetup && baseMetaObject) { // could be singleton type without metaobject
- insertEnums(baseMetaObject);
- isEnumFromBaseSetup = true;
- }
-}
-
-void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
-{
- // Add any enum values defined by 'related' classes
- if (metaObject->d.relatedMetaObjects) {
- const auto *related = metaObject->d.relatedMetaObjects;
- if (related) {
- while (*related)
- insertEnums(*related++);
- }
- }
-
- QSet<QString> localEnums;
- const QMetaObject *localMetaObject = nullptr;
-
- // Add any enum values defined by this class, overwriting any inherited values
- for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- const bool isScoped = e.isScoped();
- QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr;
-
- // We allow enums in sub-classes to overwrite enums from base-classes, such as
- // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin).
- // This is acceptable because the _use_ of the enum from the QML side requires qualification
- // anyway, i.e. ListView.Center vs. Item.Center.
- // However if a class defines two enums with the same value, then that must produce a warning
- // because it represents a valid conflict.
- if (e.enclosingMetaObject() != localMetaObject) {
- localEnums.clear();
- localMetaObject = e.enclosingMetaObject();
- }
-
- for (int jj = 0; jj < e.keyCount(); ++jj) {
- const QString key = QString::fromUtf8(e.key(jj));
- const int value = e.value(jj);
- if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
- if (localEnums.contains(key)) {
- auto existingEntry = enums.find(key);
- if (existingEntry != enums.end() && existingEntry.value() != value) {
- qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
- createEnumConflictReport(metaObject, key);
- }
- } else {
- localEnums.insert(key);
- }
- enums.insert(key, value);
- }
- if (isScoped)
- scoped->insert(key, value);
- }
-
- if (isScoped) {
- scopedEnums << scoped;
- scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
- }
- }
-}
-
-void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const
-{
- path.append(QString::fromUtf8(metaObject->className()));
-
- if (metaObject->d.relatedMetaObjects) {
- const auto *related = metaObject->d.relatedMetaObjects;
- if (related) {
- while (*related)
- createListOfPossibleConflictingItems(*related++, enumInfoList, path);
- }
- }
-
- for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
- const auto e = metaObject->enumerator(ii);
-
- for (int jj = 0; jj < e.keyCount(); ++jj) {
- const QString key = QString::fromUtf8(e.key(jj));
-
- EnumInfo enumInfo;
- enumInfo.metaObjectName = QString::fromUtf8(metaObject->className());
- enumInfo.enumName = QString::fromUtf8(e.name());
- enumInfo.enumKey = key;
- enumInfo.scoped = e.isScoped();
- enumInfo.path = path;
- enumInfo.metaEnumScope = QString::fromUtf8(e.scope());
- enumInfoList.append(enumInfo);
- }
- }
-}
-
-void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const
-{
- QList<EnumInfo> enumInfoList;
-
- if (baseMetaObject) // prefer baseMetaObject if available
- metaObject = baseMetaObject;
-
- if (!metaObject) { // If there is no metaObject at all return early
- qWarning() << "No meta object information available. Skipping conflict analysis.";
- return;
- }
-
- createListOfPossibleConflictingItems(metaObject, enumInfoList, QStringList());
-
- qWarning().noquote() << QLatin1String("Possible conflicting items:");
- // find items with conflicting key
- for (const auto i : enumInfoList) {
- if (i.enumKey == conflictingKey)
- qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
- << i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
- }
-}
-
-void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
-{
- const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
-
- while (cache && cache->metaObject() != cppMetaObject) {
-
- int count = cache->qmlEnumCount();
- for (int ii = 0; ii < count; ++ii) {
- QStringHash<int> *scoped = new QStringHash<int>();
- QQmlEnumData *enumData = cache->qmlEnum(ii);
-
- for (int jj = 0; jj < enumData->values.count(); ++jj) {
- const QQmlEnumValue &value = enumData->values.at(jj);
- enums.insert(value.namedValue, value.value);
- scoped->insert(value.namedValue, value.value);
- }
- scopedEnums << scoped;
- scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
- }
- cache = cache->parent();
- }
- insertEnums(cppMetaObject);
-}
-
-
-QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const
-{
- for (int i = 0; i < propertyCaches.count(); ++i)
- if (propertyCaches.at(i).minorVersion == minorVersion)
- return propertyCaches.at(i).cache.data();
- return nullptr;
-}
-
-void QQmlTypePrivate::setPropertyCacheForMinorVersion(int minorVersion, QQmlPropertyCache *cache)
-{
- for (int i = 0; i < propertyCaches.count(); ++i) {
- if (propertyCaches.at(i).minorVersion == minorVersion) {
- propertyCaches[i].cache = cache;
- return;
- }
- }
- propertyCaches.append(PropertyCacheByMinorVersion(cache, minorVersion));
-}
-
-QByteArray QQmlType::typeName() const
-{
- if (d) {
- if (d->regType == SingletonType || d->regType == CompositeSingletonType)
- return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
- else if (d->baseMetaObject)
- return d->baseMetaObject->className();
- }
- return QByteArray();
-}
-
-QString QQmlType::elementName() const
-{
- if (!d)
- return QString();
- return d->elementName;
-}
-
-QString QQmlType::qmlTypeName() const
-{
- if (!d)
- return QString();
- if (d->name.isEmpty()) {
- if (!d->module.isEmpty())
- d->name = static_cast<QString>(d->module) + QLatin1Char('/') + d->elementName;
- else
- d->name = d->elementName;
- }
-
- return d->name;
-}
-
-QObject *QQmlType::create() const
-{
- if (!d || !isCreatable())
- return nullptr;
-
- d->init();
-
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
- d->extraData.cd->newFunc(rv);
-
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
-
- return rv;
-}
-
-void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
-{
- if (!d || !isCreatable())
- return;
-
- d->init();
-
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
- d->extraData.cd->newFunc(rv);
-
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
-
- *out = rv;
- *memory = ((char *)rv) + d->extraData.cd->allocationSize;
-}
-
-QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
-{
- if (!d)
- return nullptr;
- if (d->regType != SingletonType && d->regType != CompositeSingletonType)
- return nullptr;
- return d->extraData.sd->singletonInstanceInfo;
-}
-
-QQmlCustomParser *QQmlType::customParser() const
-{
- if (!d)
- return nullptr;
- if (d->regType != CppType)
- return nullptr;
- return d->extraData.cd->customParser;
-}
-
-QQmlType::CreateFunc QQmlType::createFunction() const
-{
- if (!d || d->regType != CppType)
- return nullptr;
- return d->extraData.cd->newFunc;
-}
-
-QString QQmlType::noCreationReason() const
-{
- if (!d || d->regType != CppType)
- return QString();
- return d->extraData.cd->noCreationReason;
-}
-
-bool QQmlType::isCreatable() const
-{
- return d && d->regType == CppType && d->extraData.cd->newFunc;
-}
-
-QQmlType::ExtensionFunc QQmlType::extensionFunction() const
-{
- if (!d || d->regType != CppType)
- return nullptr;
- return d->extraData.cd->extFunc;
-}
-
-bool QQmlType::isExtendedType() const
-{
- if (!d)
- return false;
- d->init();
-
- return !d->metaObjects.isEmpty();
-}
-
-bool QQmlType::isSingleton() const
-{
- return d && (d->regType == SingletonType || d->regType == CompositeSingletonType);
-}
-
-bool QQmlType::isInterface() const
-{
- return d && d->regType == InterfaceType;
-}
-
-bool QQmlType::isComposite() const
-{
- return d && (d->regType == CompositeType || d->regType == CompositeSingletonType);
-}
-
-bool QQmlType::isCompositeSingleton() const
-{
- return d && d->regType == CompositeSingletonType;
-}
-
-int QQmlType::typeId() const
-{
- return d ? d->typeId : -1;
-}
-
-int QQmlType::qListTypeId() const
-{
- return d ? d->listId : -1;
-}
-
-const QMetaObject *QQmlType::metaObject() const
-{
- if (!d)
- return nullptr;
- d->init();
-
- if (d->metaObjects.isEmpty())
- return d->baseMetaObject;
- else
- return d->metaObjects.constFirst().metaObject;
-
-}
-
-const QMetaObject *QQmlType::baseMetaObject() const
-{
- return d ? d->baseMetaObject : nullptr;
-}
-
-bool QQmlType::containsRevisionedAttributes() const
-{
- if (!d)
- return false;
- d->init();
-
- return d->containsRevisionedAttributes;
-}
-
-int QQmlType::metaObjectRevision() const
-{
- return d ? d->revision : -1;
-}
-
-QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
-{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesFunc;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
- return base.attachedPropertiesFunction(engine);
-}
-
-const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
-{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
- return base.attachedPropertiesType(engine);
-}
-
-/*
-This is the id passed to qmlAttachedPropertiesById(). This is different from the index
-for the case that a single class is registered under two or more names (eg. Item in
-Qt 4.7 and QtQuick 1.0).
-*/
-int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
-{
- if (!d)
- return -1;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType ? d->index : -1;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = resolveCompositeBaseType(engine);
- return base.attachedPropertiesId(engine);
-}
-
-int QQmlType::parserStatusCast() const
-{
- if (!d || d->regType != CppType)
- return -1;
- return d->extraData.cd->parserStatusCast;
-}
-
-int QQmlType::propertyValueSourceCast() const
-{
- if (!d || d->regType != CppType)
- return -1;
- return d->extraData.cd->propertyValueSourceCast;
-}
-
-int QQmlType::propertyValueInterceptorCast() const
-{
- if (!d || d->regType != CppType)
- return -1;
- return d->extraData.cd->propertyValueInterceptorCast;
-}
-
-const char *QQmlType::interfaceIId() const
-{
- if (!d || d->regType != InterfaceType)
- return nullptr;
- return d->iid;
-}
-
-int QQmlType::index() const
-{
- return d ? d->index : -1;
-}
-
-QUrl QQmlType::sourceUrl() const
-{
- if (d) {
- if (d->regType == CompositeType)
- return d->extraData.fd->url;
- else if (d->regType == CompositeSingletonType)
- return d->extraData.sd->singletonInstanceInfo->url;
- }
- return QUrl();
-}
-
-int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
-
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
-
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
-{
- Q_UNUSED(engine)
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
-{
- Q_UNUSED(engine)
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : nullptr;
- *ok = true;
-
- d->initEnums(cache);
-
- int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
-}
-
-void QQmlType::refHandle(QQmlTypePrivate *priv)
-{
- if (priv)
- priv->refCount.ref();
-}
-
-void QQmlType::derefHandle(QQmlTypePrivate *priv)
-{
- if (priv && !priv->refCount.deref())
- delete priv;
-}
-
-int QQmlType::refCount(QQmlTypePrivate *priv)
-{
- if (priv)
- return priv->refCount;
- return -1;
-}
-
-namespace {
-template <typename QQmlTypeContainer>
-void removeQQmlTypePrivate(QQmlTypeContainer &container, const QQmlTypePrivate *reference)
-{
- for (typename QQmlTypeContainer::iterator it = container.begin(); it != container.end();) {
- if (*it == reference)
- it = container.erase(it);
- else
- ++it;
- }
-}
-
-struct IsQQmlTypePrivate
-{
- const QQmlTypePrivate *reference;
- explicit IsQQmlTypePrivate(const QQmlTypePrivate *ref) : reference(ref) {}
-
- bool operator()(const QQmlTypePrivate *priv) const { return reference == priv; }
-};
-}
-
-QQmlTypeModule::QQmlTypeModule()
-: d(new QQmlTypeModulePrivate)
-{
-}
-
-QQmlTypeModule::~QQmlTypeModule()
-{
- delete d; d = nullptr;
-}
-
-QString QQmlTypeModule::module() const
-{
- return d->uri.uri;
-}
-
-int QQmlTypeModule::majorVersion() const
-{
- return d->uri.majorVersion;
-}
-
-int QQmlTypeModule::minimumMinorVersion() const
-{
- return d->minMinorVersion;
-}
-
-int QQmlTypeModule::maximumMinorVersion() const
-{
- return d->maxMinorVersion;
-}
-
-void QQmlTypeModulePrivate::add(QQmlTypePrivate *type)
-{
- int minVersion = type->version_min;
- minMinorVersion = qMin(minMinorVersion, minVersion);
- maxMinorVersion = qMax(maxMinorVersion, minVersion);
-
- QList<QQmlTypePrivate *> &list = typeHash[type->elementName];
- for (int ii = 0; ii < list.count(); ++ii) {
- Q_ASSERT(list.at(ii));
- if (list.at(ii)->version_min < minVersion) {
- list.insert(ii, type);
- return;
- }
- }
- list.append(type);
-}
-
-void QQmlTypeModulePrivate::remove(const QQmlTypePrivate *type)
-{
- for (TypeHash::ConstIterator elementIt = typeHash.begin(); elementIt != typeHash.end();) {
- QList<QQmlTypePrivate *> &list = const_cast<QList<QQmlTypePrivate *> &>(elementIt.value());
-
- removeQQmlTypePrivate(list, type);
-
-#if 0
- if (list.isEmpty())
- elementIt = typeHash.erase(elementIt);
- else
- ++elementIt;
-#else
- ++elementIt;
-#endif
- }
-}
-
-QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const
-{
- QMutexLocker lock(metaTypeDataLock());
-
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
-}
-
-QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
-{
- QMutexLocker lock(metaTypeDataLock());
-
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
-}
-
-void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
-{
- QMutexLocker lock(metaTypeDataLock());
- for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
- typeCandidates != end; ++typeCandidates) {
- for (auto type: typeCandidates.value()) {
- if (type->regType == QQmlType::CompositeSingletonType)
- callback(QQmlType(type));
- }
- }
-}
-
-QQmlTypeModuleVersion::QQmlTypeModuleVersion()
-: m_module(nullptr), m_minor(0)
-{
-}
-
-QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
-: m_module(module), m_minor(minor)
-{
- Q_ASSERT(m_module);
- Q_ASSERT(m_minor >= 0);
-}
-
-QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
-: m_module(o.m_module), m_minor(o.m_minor)
-{
-}
-
-QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
-{
- m_module = o.m_module;
- m_minor = o.m_minor;
- return *this;
-}
-
-QQmlTypeModule *QQmlTypeModuleVersion::module() const
-{
- return m_module;
-}
-
-int QQmlTypeModuleVersion::minorVersion() const
-{
- return m_minor;
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
-void qmlClearTypeRegistrations() // Declared in qqml.h
+void QQmlMetaType::clearTypeRegistrations()
{
//Only cleans global static, assumed no running engine
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
delete *i;
@@ -1630,44 +279,35 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
data->idToType.clear();
data->nameToType.clear();
data->urlToType.clear();
+ data->typePropertyCaches.clear();
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->uriToModule.clear();
data->undeletableTypes.clear();
-
- QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types
-#if QT_CONFIG(library)
- qmlClearEnginePlugins();
-#endif
-}
-
-static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
-{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
- data->parentFunctions.removeOne(function);
}
-static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent)
+int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
data->parentFunctions.append(autoparent.function);
return data->parentFunctions.count() - 1;
}
-QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface)
+void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
{
- if (interface.version > 0)
- qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+ QQmlMetaTypeDataPtr data;
+ data->parentFunctions.removeOne(function);
+}
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
+{
+ if (type.version > 0)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
- QQmlType type(data, interface);
- QQmlTypePrivate *priv = type.priv();
+ QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *priv = createQQmlType(data, type);
Q_ASSERT(priv);
data->idToType.insert(priv->typeId, priv);
@@ -1676,14 +316,14 @@ QQmlType registerInterface(const QQmlPrivate::RegisterInterface &interface)
if (!priv->elementName.isEmpty())
data->nameToType.insert(priv->elementName, priv);
- if (data->interfaces.size() <= interface.typeId)
- data->interfaces.resize(interface.typeId + 16);
- if (data->lists.size() <= interface.listId)
- data->lists.resize(interface.listId + 16);
- data->interfaces.setBit(interface.typeId, true);
- data->lists.setBit(interface.listId, true);
+ if (data->interfaces.size() <= type.typeId)
+ data->interfaces.resize(type.typeId + 16);
+ if (data->lists.size() <= type.listId)
+ data->lists.resize(type.listId + 16);
+ data->interfaces.setBit(type.typeId, true);
+ data->lists.setBit(type.listId, true);
- return type;
+ return QQmlType(priv);
}
QString registrationTypeString(QQmlType::RegistrationType typeType)
@@ -1701,7 +341,8 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
}
// NOTE: caller must hold a QMutexLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName, int majorVersion = -1)
+bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
+ const char *uri, const QString &typeName, int majorVersion = -1)
{
if (!typeName.isEmpty()) {
if (typeName.at(0).isLower()) {
@@ -1736,7 +377,7 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
versionedUri.uri = nameSpace;
versionedUri.majorVersion = majorVersion;
if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (QQmlTypeModulePrivate::get(qqtm)->locked){
+ if (qqtm->isLocked()){
QString failure(QCoreApplication::translate("qmlRegisterType",
"Cannot install %1 '%2' into protected module '%3' version '%4'"));
data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
@@ -1755,8 +396,7 @@ QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMe
QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
QQmlTypeModule *module = data->uriToModule.value(versionedUri);
if (!module) {
- module = new QQmlTypeModule;
- module->d->uri = versionedUri;
+ module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
data->uriToModule.insert(versionedUri, module);
}
return module;
@@ -1792,47 +432,47 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data);
Q_ASSERT(module);
- module->d->add(type);
+ module->add(type);
}
}
-QQmlType registerType(const QQmlPrivate::RegisterType &type)
+QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
+
QString elementName = QString::fromUtf8(type.elementName);
if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
return QQmlType();
- QQmlType dtype(data, elementName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
- addTypeToData(dtype.priv(), data);
+ addTypeToData(priv, data);
if (!type.typeId)
- data->idToType.insert(dtype.typeId(), dtype.priv());
+ data->idToType.insert(priv->typeId, priv);
- return dtype;
+ return QQmlType(priv);
}
-QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
+QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
+
QString typeName = QString::fromUtf8(type.typeName);
if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
return QQmlType();
- QQmlType dtype(data, typeName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
- addTypeToData(dtype.priv(), data);
+ addTypeToData(priv, data);
- return dtype;
+ return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
{
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
+
QString typeName = QString::fromUtf8(type.typeName);
bool fileImport = false;
if (*(type.uri) == '\0')
@@ -1840,21 +480,20 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, typeName))
return QQmlType();
- QQmlType dtype(data, typeName, type);
-
- addTypeToData(dtype.priv(), data);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), dtype.priv());
+ files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
- return dtype;
+ return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
+
QString typeName = QString::fromUtf8(type.typeName);
bool fileImport = false;
if (*(type.uri) == '\0')
@@ -1862,16 +501,16 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor))
return QQmlType();
- QQmlType dtype(data, typeName, type);
- addTypeToData(dtype.priv(), data);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), dtype.priv());
+ files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
- return dtype;
+ return QQmlType(priv);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
+void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
{
QByteArray name = compilationUnit->rootPropertyCache()->className();
@@ -1894,125 +533,61 @@ void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationU
compilationUnit->metaTypeId = ptr_type;
compilationUnit->listMetaTypeId = lst_type;
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *d = metaTypeData();
- d->qmlLists.insert(lst_type, ptr_type);
+ QQmlMetaTypeDataPtr data;
+ data->qmlLists.insert(lst_type, ptr_type);
}
-void QQmlMetaType::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit)
+void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
{
int ptr_type = compilationUnit->metaTypeId;
int lst_type = compilationUnit->listMetaTypeId;
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *d = metaTypeData();
- d->qmlLists.remove(lst_type);
+ QQmlMetaTypeDataPtr data;
+ data->qmlLists.remove(lst_type);
QMetaType::unregisterType(ptr_type);
QMetaType::unregisterType(lst_type);
}
-int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
+int QQmlMetaType::registerUnitCacheHook(
+ const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
{
if (hookRegistration.version > 0)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeDataPtr data;
data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit;
return 0;
}
-/*
-This method is "over generalized" to allow us to (potentially) register more types of things in
-the future without adding exported symbols.
-*/
-int QQmlPrivate::qmlregister(RegistrationType type, void *data)
-{
- if (type == AutoParentRegistration)
- return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
- else if (type == QmlUnitCacheHookRegistration)
- return registerQmlUnitCacheHook(*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
-
- QQmlType dtype;
- if (type == TypeRegistration)
- dtype = registerType(*reinterpret_cast<RegisterType *>(data));
- else if (type == InterfaceRegistration)
- dtype = registerInterface(*reinterpret_cast<RegisterInterface *>(data));
- else if (type == SingletonRegistration)
- dtype = registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
- else if (type == CompositeRegistration)
- dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
- else if (type == CompositeSingletonRegistration)
- dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
- else
- return -1;
-
- if (!dtype.isValid())
- return -1;
-
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *typeData = metaTypeData();
- typeData->undeletableTypes.insert(dtype);
-
- return dtype.index();
-}
-
-void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
-{
- switch (type) {
- case AutoParentRegistration:
- unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data));
- break;
- case QmlUnitCacheHookRegistration:
- QQmlMetaType::removeCachedUnitLookupFunction(
- reinterpret_cast<QmlUnitCacheLookupFunction>(data));
- break;
- case TypeRegistration:
- case InterfaceRegistration:
- case SingletonRegistration:
- case CompositeRegistration:
- case CompositeSingletonRegistration:
- qmlUnregisterType(data);
- break;
- }
-}
-
-//From qqml.h
-bool qmlProtectModule(const char *uri, int majVersion)
+bool QQmlMetaType::protectModule(const char *uri, int majVersion)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::VersionedUri versionedUri;
versionedUri.uri = QString::fromUtf8(uri);
versionedUri.majorVersion = majVersion;
if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
- QQmlTypeModulePrivate::get(qqtm)->locked = true;
+ qqtm->lock();
return true;
}
return false;
}
-//From qqml.h
-void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
+void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
Q_ASSERT(module);
- QQmlTypeModulePrivate *p = QQmlTypeModulePrivate::get(module);
- p->minMinorVersion = qMin(p->minMinorVersion, versionMinor);
- p->maxMinorVersion = qMax(p->maxMinorVersion, versionMinor);
+ module->addMinorVersion(versionMinor);
}
-//From qqml.h
-int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
if (!module)
@@ -2025,34 +600,218 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q
return type.index();
}
-bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion)
+void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
{
- const QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
+ data->undeletableTypes.insert(dtype);
+}
+static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
+ int majorVersion)
+{
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
- for (const QQmlType &type : data->types)
+ for (const QQmlType &type : data->types) {
if (type.module() == nameSpace && type.majorVersion() == majorVersion)
return true;
+ }
return false;
}
-void QQmlMetaType::protectNamespace(const QString &uri)
+class QQmlMetaTypeRegistrationFailureRecorder
+{
+ Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
+public:
+ QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
+ : data(data)
+ {
+ data->setTypeRegistrationFailures(failures);
+ }
+
+ ~QQmlMetaTypeRegistrationFailureRecorder()
+ {
+ data->setTypeRegistrationFailures(nullptr);
+ }
+
+ QQmlMetaTypeData *data = nullptr;
+};
+
+
+bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
+ const QString &uri, const QString &typeNamespace, int vmaj,
+ QList<QQmlError> *errors)
{
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
+ if (!iface) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
+ "QQmlTypesExtensionInterface").arg(typeNamespace));
+ errors->prepend(error);
+ }
+ return false;
+ }
+
+ if (!typeNamespace.isEmpty() && typeNamespace != uri) {
+ // This is an 'identified' module
+ // The namespace for type registrations must match the URI for locating the module
+ if (errors) {
+ QQmlError error;
+ error.setDescription(
+ QStringLiteral("Module namespace '%1' does not match import URI '%2'")
+ .arg(typeNamespace).arg(uri));
+ errors->prepend(error);
+ }
+ return false;
+ }
+
+ QStringList failures;
+ QQmlMetaTypeDataPtr data;
+ {
+ QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
+ if (!typeNamespace.isEmpty()) {
+ // This is an 'identified' module
+ if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) {
+ // Other modules have already installed to this namespace
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("Namespace '%1' has already been used "
+ "for type registration")
+ .arg(typeNamespace));
+ errors->prepend(error);
+ }
+ return false;
+ }
+
+ data->protectedNamespaces.insert(uri);
+ } else {
+ // This is not an identified module - provide a warning
+ qWarning().nospace() << qPrintable(
+ QStringLiteral("Module '%1' does not contain a module identifier directive - "
+ "it cannot be protected from external registrations.").arg(uri));
+ }
+
+ if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
+ // basepath should point to the directory of the module, not the plugin file itself:
+ QQmlExtensionPluginPrivate::get(plugin)->baseUrl
+ = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
+ }
+
+ data->typeRegistrationNamespace = typeNamespace;
+ const QByteArray bytes = uri.toUtf8();
+ const char *moduleId = bytes.constData();
+ iface->registerTypes(moduleId);
+ data->typeRegistrationNamespace.clear();
+ }
+
+ if (!failures.isEmpty()) {
+ if (errors) {
+ for (const QString &failure : qAsConst(failures)) {
+ QQmlError error;
+ error.setDescription(failure);
+ errors->prepend(error);
+ }
+ }
+ return false;
+ }
- data->protectedNamespaces.insert(uri);
+ return true;
}
-void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
+/*
+ \internal
+
+ Fetches the QQmlType instance registered for \a urlString, creating a
+ registration for it if it is not already registered, using the associated
+ \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
+ details.
+
+ Errors (if there are any) are placed into \a errors, if it is nonzero.
+ Otherwise errors are printed as warnings.
+*/
+QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
+ const QHashedStringRef &qualifiedType,
+ bool isCompositeSingleton, QList<QQmlError> *errors,
+ int majorVersion, int minorVersion)
{
- QQmlMetaTypeData *data = metaTypeData();
+ // ### unfortunate (costly) conversion
+ const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
- data->typeRegistrationNamespace = uri;
+ QQmlMetaTypeDataPtr data;
+ {
+ QQmlType ret(data->urlToType.value(url));
+ if (ret.isValid() && ret.sourceUrl() == url)
+ return ret;
+ }
+ {
+ QQmlType ret(data->urlToNonFileImportType.value(url));
+ if (ret.isValid() && ret.sourceUrl() == url)
+ return ret;
+ }
+
+ const int dot = qualifiedType.indexOf(QLatin1Char('.'));
+ const QString typeName = dot < 0
+ ? qualifiedType.toString()
+ : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
+
+ QStringList failures;
+ QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ const QQmlType::RegistrationType registrationType = isCompositeSingleton
+ ? QQmlType::CompositeSingletonType
+ : QQmlType::CompositeType;
+ if (checkRegistration(registrationType, data, nullptr, typeName, majorVersion)) {
+ auto *priv = new QQmlTypePrivate(registrationType);
+ priv->setName(QString(), typeName);
+ priv->version_maj = majorVersion;
+ priv->version_min = minorVersion;
+
+ if (isCompositeSingleton) {
+ priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
+ priv->extraData.sd->singletonInstanceInfo->url = url;
+ priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
+ } else {
+ priv->extraData.fd->url = url;
+ }
+
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ data->urlToType.insertMulti(url, priv);
+ return QQmlType(priv);
+ }
+
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (errors) {
+ QQmlError error;
+ error.setDescription(failures.join('\n'));
+ errors->prepend(error);
+ } else {
+ qWarning("%s", failures.join('\n').toLatin1().constData());
+ }
+ return QQmlType();
}
-QMutex *QQmlMetaType::typeRegistrationLock()
+QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
{
return metaTypeDataLock();
}
@@ -2062,8 +821,7 @@ QMutex *QQmlMetaType::typeRegistrationLock()
*/
bool QQmlMetaType::isAnyModule(const QString &uri)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
iter != data->uriToModule.cend(); ++iter) {
@@ -2079,14 +837,13 @@ bool QQmlMetaType::isAnyModule(const QString &uri)
*/
bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::VersionedUri versionedUri;
versionedUri.uri = uri;
versionedUri.majorVersion = majVersion;
if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
- return QQmlTypeModulePrivate::get(qqtm)->locked;
+ return qqtm->isLocked();
return false;
}
@@ -2100,9 +857,7 @@ bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
{
Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
- QMutexLocker lock(metaTypeDataLock());
-
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
// first, check Types
QQmlTypeModule *tm =
@@ -2115,15 +870,13 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version
QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
}
QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
return data->parentFunctions;
}
@@ -2144,8 +897,7 @@ bool QQmlMetaType::isQObject(int userType)
if (userType == QMetaType::QObjectStar)
return true;
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
}
@@ -2154,8 +906,7 @@ bool QQmlMetaType::isQObject(int userType)
*/
int QQmlMetaType::listType(int id)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id);
if (iter != data->qmlLists.cend())
return *iter;
@@ -2166,10 +917,10 @@ int QQmlMetaType::listType(int id)
return 0;
}
+#if QT_DEPRECATED_SINCE(5, 14)
int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
it != end && it.key() == mo; ++it) {
@@ -2185,16 +936,15 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr
{
if (id < 0)
return nullptr;
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
return data->types.at(id).attachedPropertiesFunction(engine);
}
+#endif
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
const QMetaObject *mo)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
QQmlType type(data->metaObjectToType.value(mo));
return type.attachedPropertiesFunction(engine);
@@ -2259,8 +1009,7 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
if (userType == QMetaType::QObjectStar)
return Object;
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
if (data->qmlLists.contains(userType))
return List;
else if (userType < data->objects.size() && data->objects.testBit(userType))
@@ -2276,17 +1025,20 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
*/
bool QQmlMetaType::isInterface(int userType)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
}
const char *QQmlMetaType::interfaceIId(int userType)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
- QQmlType type(data->idToType.value(userType));
- lock.unlock();
+
+ QQmlTypePrivate *typePrivate = nullptr;
+ {
+ QQmlMetaTypeDataPtr data;
+ typePrivate = data->idToType.value(userType);
+ }
+
+ QQmlType type(typePrivate);
if (type.isInterface() && type.typeId() == userType)
return type.interfaceIId();
else
@@ -2295,8 +1047,7 @@ const char *QQmlMetaType::interfaceIId(int userType)
bool QQmlMetaType::isList(int userType)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
if (data->qmlLists.contains(userType))
return true;
return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
@@ -2319,9 +1070,7 @@ bool QQmlMetaType::isList(int userType)
*/
void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
{
- QMutexLocker lock(metaTypeDataLock());
-
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
if (data->stringConverters.contains(type))
return;
data->stringConverters.insert(type, converter);
@@ -2333,9 +1082,7 @@ void QQmlMetaType::registerCustomStringConverter(int type, StringConverter conve
*/
QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
{
- QMutexLocker lock(metaTypeDataLock());
-
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
return data->stringConverters.value(type);
}
@@ -2362,8 +1109,7 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major,
QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
{
Q_ASSERT(version_major >= 0 && version_minor >= 0);
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
while (it != data->nameToType.cend() && it.key() == name) {
@@ -2383,9 +1129,7 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString
*/
QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
+ const QQmlMetaTypeDataPtr data;
return QQmlType(data->metaObjectToType.value(metaObject));
}
@@ -2397,8 +1141,7 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
{
Q_ASSERT(version_major >= 0 && version_minor >= 0);
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
@@ -2418,8 +1161,7 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin
*/
QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
if (category == TypeIdCategory::MetaType) {
QQmlTypePrivate *type = data->idToType.value(typeId);
@@ -2442,8 +1184,7 @@ QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports /* = false */)
{
const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl);
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QQmlType type(data->urlToType.value(url));
if (!type.isValid() && includeNonFileImports)
@@ -2455,221 +1196,87 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion)
-{
- if (QQmlPropertyCache *rv = propertyCaches.value(metaObject))
- return rv;
-
- if (!metaObject->superClass()) {
- QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
- propertyCaches.insert(metaObject, rv);
- return rv;
- }
- QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion);
- QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion);
- propertyCaches.insert(metaObject, rv);
- return rv;
-}
-
QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
return data->propertyCache(metaObject, minorVersion);
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
-{
- Q_ASSERT(type.isValid());
-
- if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(minorVersion))
- return pc;
-
- QVector<QQmlType> types;
-
- int maxMinorVersion = 0;
-
- const QMetaObject *metaObject = type.metaObject();
-
- while (metaObject) {
- QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
- if (t.isValid()) {
- maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
- types << t;
- } else {
- types << QQmlType();
- }
-
- metaObject = metaObject->superClass();
- }
-
- if (QQmlPropertyCache *pc = type.key()->propertyCacheForMinorVersion(maxMinorVersion)) {
- const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, pc);
- return pc;
- }
-
- QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion);
-
- bool hasCopied = false;
-
- for (int ii = 0; ii < types.count(); ++ii) {
- QQmlType currentType = types.at(ii);
- if (!currentType.isValid())
- continue;
-
- int rev = currentType.metaObjectRevision();
- int moIndex = types.count() - 1 - ii;
-
- if (raw->allowedRevisionCache[moIndex] != rev) {
- if (!hasCopied) {
- raw = raw->copy();
- hasCopied = true;
- }
- raw->allowedRevisionCache[moIndex] = rev;
- }
- }
-
- // Test revision compatibility - the basic rule is:
- // * Anything that is excluded, cannot overload something that is not excluded *
-
- // Signals override:
- // * other signals and methods of the same name.
- // * properties named on<Signal Name>
- // * automatic <property name>Changed notify signals
-
- // Methods override:
- // * other methods of the same name
-
- // Properties override:
- // * other elements of the same name
-
-#if 0
- bool overloadError = false;
- QString overloadName;
-
- for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
- !overloadError && iter != raw->stringCache.end();
- ++iter) {
-
- QQmlPropertyData *d = *iter;
- if (raw->isAllowedInRevision(d))
- continue; // Not excluded - no problems
-
- // check that a regular "name" overload isn't happening
- QQmlPropertyData *current = d;
- while (!overloadError && current) {
- current = d->overrideData(current);
- if (current && raw->isAllowedInRevision(current))
- overloadError = true;
- }
- }
-
- if (overloadError) {
- if (hasCopied) raw->release();
-
- error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
- return 0;
- }
-#endif
-
- const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(minorVersion, raw);
-
- if (hasCopied)
- raw->release();
-
- if (minorVersion != maxMinorVersion)
- const_cast<QQmlTypePrivate*>(type.key())->setPropertyCacheForMinorVersion(maxMinorVersion, raw);
-
- return raw;
-}
-
QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
return data->propertyCache(type, minorVersion);
}
-void qmlUnregisterType(int typeIndex)
+void QQmlMetaType::unregisterType(int typeIndex)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
- {
- const QQmlType type = data->types.value(typeIndex);
- const QQmlTypePrivate *d = type.priv();
- if (d) {
- removeQQmlTypePrivate(data->idToType, d);
- removeQQmlTypePrivate(data->nameToType, d);
- removeQQmlTypePrivate(data->urlToType, d);
- removeQQmlTypePrivate(data->urlToNonFileImportType, d);
- removeQQmlTypePrivate(data->metaObjectToType, d);
- for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) {
- QQmlTypeModulePrivate *modulePrivate = (*module)->priv();
- modulePrivate->remove(d);
- }
- data->types[typeIndex] = QQmlType();
- data->undeletableTypes.remove(type);
- }
+ QQmlMetaTypeDataPtr data;
+ const QQmlType type = data->types.value(typeIndex);
+ if (const QQmlTypePrivate *d = type.priv()) {
+ removeQQmlTypePrivate(data->idToType, d);
+ removeQQmlTypePrivate(data->nameToType, d);
+ removeQQmlTypePrivate(data->urlToType, d);
+ removeQQmlTypePrivate(data->urlToNonFileImportType, d);
+ removeQQmlTypePrivate(data->metaObjectToType, d);
+ for (auto & module : data->uriToModule)
+ module->remove(d);
+ data->clearPropertyCachesForMinorVersion(typeIndex);
+ data->types[typeIndex] = QQmlType();
+ data->undeletableTypes.remove(type);
}
}
void QQmlMetaType::freeUnusedTypesAndCaches()
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
// in case this is being called during program exit, `data` might be destructed already
- if (!data)
+ if (!data.isValid())
return;
- {
- bool deletedAtLeastOneType;
- do {
- deletedAtLeastOneType = false;
- QList<QQmlType>::Iterator it = data->types.begin();
- while (it != data->types.end()) {
- const QQmlTypePrivate *d = (*it).priv();
- if (d && d->refCount == 1) {
- deletedAtLeastOneType = true;
-
- removeQQmlTypePrivate(data->idToType, d);
- removeQQmlTypePrivate(data->nameToType, d);
- removeQQmlTypePrivate(data->urlToType, d);
- removeQQmlTypePrivate(data->urlToNonFileImportType, d);
- removeQQmlTypePrivate(data->metaObjectToType, d);
-
- for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) {
- QQmlTypeModulePrivate *modulePrivate = (*module)->priv();
- modulePrivate->remove(d);
- }
-
- *it = QQmlType();
- } else {
- ++it;
- }
+ bool deletedAtLeastOneType;
+ do {
+ deletedAtLeastOneType = false;
+ QList<QQmlType>::Iterator it = data->types.begin();
+ while (it != data->types.end()) {
+ const QQmlTypePrivate *d = (*it).priv();
+ if (d && d->count() == 1) {
+ deletedAtLeastOneType = true;
+
+ removeQQmlTypePrivate(data->idToType, d);
+ removeQQmlTypePrivate(data->nameToType, d);
+ removeQQmlTypePrivate(data->urlToType, d);
+ removeQQmlTypePrivate(data->urlToNonFileImportType, d);
+ removeQQmlTypePrivate(data->metaObjectToType, d);
+
+ for (auto &module : data->uriToModule)
+ module->remove(d);
+
+ data->clearPropertyCachesForMinorVersion(d->index);
+ *it = QQmlType();
+ } else {
+ ++it;
}
- } while (deletedAtLeastOneType);
- }
-
- {
- bool deletedAtLeastOneCache;
- do {
- deletedAtLeastOneCache = false;
- QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
- while (it != data->propertyCaches.end()) {
-
- if ((*it)->count() == 1) {
- QQmlPropertyCache *pc = nullptr;
- qSwap(pc, *it);
- it = data->propertyCaches.erase(it);
- pc->release();
- deletedAtLeastOneCache = true;
- } else {
- ++it;
- }
+ }
+ } while (deletedAtLeastOneType);
+
+ bool deletedAtLeastOneCache;
+ do {
+ deletedAtLeastOneCache = false;
+ QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
+ while (it != data->propertyCaches.end()) {
+
+ if ((*it)->count() == 1) {
+ QQmlPropertyCache *pc = nullptr;
+ qSwap(pc, *it);
+ it = data->propertyCaches.erase(it);
+ pc->release();
+ deletedAtLeastOneCache = true;
+ } else {
+ ++it;
}
- } while (deletedAtLeastOneCache);
- }
+ }
+ } while (deletedAtLeastOneCache);
}
/*!
@@ -2677,8 +1284,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
*/
QList<QString> QQmlMetaType::qmlTypeNames()
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QList<QString> names;
names.reserve(data->nameToType.count());
@@ -2697,8 +1303,7 @@ QList<QString> QQmlMetaType::qmlTypeNames()
*/
QList<QQmlType> QQmlMetaType::qmlTypes()
{
- QMutexLocker lock(metaTypeDataLock());
- const QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QList<QQmlType> types;
for (QQmlTypePrivate *t : data->nameToType)
@@ -2712,9 +1317,7 @@ QList<QQmlType> QQmlMetaType::qmlTypes()
*/
QList<QQmlType> QQmlMetaType::qmlAllTypes()
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
+ const QQmlMetaTypeDataPtr data;
return data->types;
}
@@ -2723,8 +1326,7 @@ QList<QQmlType> QQmlMetaType::qmlAllTypes()
*/
QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
QList<QQmlType> retn;
for (const auto t : qAsConst(data->nameToType)) {
@@ -2737,13 +1339,12 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ const QQmlMetaTypeDataPtr data;
for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
QString error;
- if (!unit->qmlData->verifyHeader(QDateTime(), &error)) {
+ if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) {
qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
if (status)
*status = CachedUnitLookupError::VersionMismatch;
@@ -2763,15 +1364,13 @@ const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUr
void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
data->lookupCachedQmlUnit.prepend(handler);
}
void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
{
- QMutexLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
+ QQmlMetaTypeDataPtr data;
data->lookupCachedQmlUnit.removeAll(handler);
}
@@ -2817,4 +1416,38 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
return typeName;
}
+QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject *mo,
+ const QMetaObject *baseMetaObject,
+ QMetaObject *lastMetaObject)
+{
+ QList<QQmlProxyMetaObject::ProxyData> metaObjects;
+ mo = mo->d.superdata;
+
+ const QQmlMetaTypeDataPtr data;
+
+ while (mo) {
+ QQmlTypePrivate *t = data->metaObjectToType.value(mo);
+ if (t) {
+ if (t->regType == QQmlType::CppType) {
+ if (t->extraData.cd->extFunc) {
+ QMetaObjectBuilder builder;
+ clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = baseMetaObject;
+ if (!metaObjects.isEmpty())
+ metaObjects.constLast().metaObject->d.superdata = mmo;
+ else if (lastMetaObject)
+ lastMetaObject->d.superdata = mmo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
+ metaObjects << data;
+ }
+ }
+ }
+ mo = mo->d.superdata;
+ }
+
+ return metaObjects;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index abc79e50e2..6c2b0bb2a6 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -51,40 +51,44 @@
// We mean it.
//
-#include "qqml.h"
#include <private/qtqmlglobal_p.h>
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qbitarray.h>
-#include <QtQml/qjsvalue.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmlproxymetaobject_p.h>
QT_BEGIN_NAMESPACE
-class QQmlType;
-class QQmlEngine;
-class QQmlEnginePrivate;
-class QQmlCustomParser;
-class QQmlTypePrivate;
class QQmlTypeModule;
-class QHashedString;
-class QHashedStringRef;
-class QMutex;
-class QQmlPropertyCache;
-class QQmlCompiledData;
-
-namespace QV4 { struct String; }
+class QRecursiveMutex;
+class QQmlError;
-void Q_QML_PRIVATE_EXPORT qmlUnregisterType(int type);
+namespace QV4 { class ExecutableCompilationUnit; }
class Q_QML_PRIVATE_EXPORT QQmlMetaType
{
public:
+ static QQmlType registerType(const QQmlPrivate::RegisterType &type);
+ static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
+ static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type);
static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type);
+ static bool registerPluginTypes(QObject *instance, const QString &basePath,
+ const QString &uri, const QString &typeNamespace, int vmaj,
+ QList<QQmlError> *errors);
+ static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
+ bool isCompositeSingleton, QList<QQmlError> *errors,
+ int majorVersion = -1, int minorVersion = -1);
+
+ static void unregisterType(int type);
+
+ static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- static void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
- static void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit);
+ static void registerModule(const char *uri, int versionMajor, int versionMinor);
+ static bool protectModule(const char *uri, int majVersion);
+
+ static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
+
+ static void registerUndeletableType(const QQmlType &dtype);
static QList<QString> qmlTypeNames();
static QList<QQmlType> qmlTypes();
@@ -117,8 +121,12 @@ public:
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
static int listType(int);
- static int attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *);
- static QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *, int);
+#if QT_DEPRECATED_SINCE(5, 14)
+ static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine,
+ const QMetaObject *);
+ static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *,
+ int);
+#endif
static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
const QMetaObject *);
@@ -152,228 +160,38 @@ public:
static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
- static bool namespaceContainsRegistrations(const QString &, int majorVersion);
-
- static void protectNamespace(const QString &);
-
- static void setTypeRegistrationNamespace(const QString &);
-
- static QMutex *typeRegistrationLock();
+ static QRecursiveMutex *typeRegistrationLock();
static QString prettyTypeName(const QObject *object);
-};
-struct QQmlMetaTypeData;
-class QHashedCStringRef;
-class QQmlPropertyCache;
-class Q_QML_PRIVATE_EXPORT QQmlType
-{
-public:
- QQmlType();
- QQmlType(const QQmlType &other);
- QQmlType &operator =(const QQmlType &other);
- explicit QQmlType(QQmlTypePrivate *priv);
- ~QQmlType();
-
- bool operator ==(const QQmlType &other) const {
- return d == other.d;
+ template <typename QQmlTypeContainer>
+ static void removeQQmlTypePrivate(QQmlTypeContainer &container,
+ const QQmlTypePrivate *reference)
+ {
+ for (typename QQmlTypeContainer::iterator it = container.begin(); it != container.end();) {
+ if (*it == reference)
+ it = container.erase(it);
+ else
+ ++it;
+ }
}
- bool isValid() const { return d != nullptr; }
- const QQmlTypePrivate *key() const { return d; }
+ static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent);
+ static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function);
- QByteArray typeName() const;
- QString qmlTypeName() const;
- QString elementName() const;
+ static int registerUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration);
+ static void clearTypeRegistrations();
- QHashedString module() const;
- int majorVersion() const;
- int minorVersion() const;
-
- bool availableInVersion(int vmajor, int vminor) const;
- bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const;
-
- QObject *create() const;
- void create(QObject **, void **, size_t) const;
-
- typedef void (*CreateFunc)(void *);
- CreateFunc createFunction() const;
- QQmlCustomParser *customParser() const;
-
- bool isCreatable() const;
- typedef QObject *(*ExtensionFunc)(QObject *);
- ExtensionFunc extensionFunction() const;
- bool isExtendedType() const;
- QString noCreationReason() const;
-
- bool isSingleton() const;
- bool isInterface() const;
- bool isComposite() const;
- bool isCompositeSingleton() const;
-
- int typeId() const;
- int qListTypeId() const;
-
- const QMetaObject *metaObject() const;
- const QMetaObject *baseMetaObject() const;
- int metaObjectRevision() const;
- bool containsRevisionedAttributes() const;
-
- QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
- const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
- int attachedPropertiesId(QQmlEnginePrivate *engine) const;
-
- int parserStatusCast() const;
- const char *interfaceIId() const;
- int propertyValueSourceCast() const;
- int propertyValueInterceptorCast() const;
-
- int index() const;
-
- class Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
- {
- public:
- SingletonInstanceInfo()
- : scriptCallback(nullptr), qobjectCallback(nullptr), instanceMetaObject(nullptr) {}
-
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject;
- QString typeName;
- QUrl url; // used by composite singletons
-
- void setQObjectApi(QQmlEngine *, QObject *);
- QObject *qobjectApi(QQmlEngine *) const;
- void setScriptApi(QQmlEngine *, const QJSValue &);
- QJSValue scriptApi(QQmlEngine *) const;
-
- void init(QQmlEngine *);
- void destroy(QQmlEngine *);
-
- QHash<QQmlEngine *, QJSValue> scriptApis;
- QHash<QQmlEngine *, QObject *> qobjectApis;
- };
- SingletonInstanceInfo *singletonInstanceInfo() const;
-
- QUrl sourceUrl() const;
-
- int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const;
- int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const;
- int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
-
- int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
- int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
-
- QQmlTypePrivate *priv() const { return d; }
- static void refHandle(QQmlTypePrivate *priv);
- static void derefHandle(QQmlTypePrivate *priv);
- static int refCount(QQmlTypePrivate *priv);
-
- enum RegistrationType {
- CppType = 0,
- SingletonType = 1,
- InterfaceType = 2,
- CompositeType = 3,
- CompositeSingletonType = 4,
- AnyRegistrationType = 255
- };
+ static QList<QQmlProxyMetaObject::ProxyData> proxyData(const QMetaObject *mo,
+ const QMetaObject *baseMetaObject,
+ QMetaObject *lastMetaObject);
-private:
- QQmlType superType() const;
- QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
- int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
- QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
- friend class QQmlTypePrivate;
-
- friend QString registrationTypeString(RegistrationType);
- friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int);
- friend QQmlType registerType(const QQmlPrivate::RegisterType &);
- friend QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
- friend QQmlType registerInterface(const QQmlPrivate::RegisterInterface &);
- friend int registerQmlUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &);
- friend uint qHash(const QQmlType &t, uint seed);
- friend Q_QML_EXPORT void qmlClearTypeRegistrations();
- friend class QQmlMetaType;
-
- QQmlType(QQmlMetaTypeData *data, const QQmlPrivate::RegisterInterface &);
- QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterSingletonType &);
- QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterType &);
- QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeType &);
- QQmlType(QQmlMetaTypeData *data, const QString &, const QQmlPrivate::RegisterCompositeSingletonType &);
-
- QQmlTypePrivate *d;
+ static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
};
Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE);
-
-inline uint qHash(const QQmlType &t, uint seed = 0) { return qHash(reinterpret_cast<quintptr>(t.d), seed); }
-
-
-class QQmlTypeModulePrivate;
-class QQmlTypeModule
-{
-public:
- QString module() const;
- int majorVersion() const;
-
- int minimumMinorVersion() const;
- int maximumMinorVersion() const;
-
- QQmlType type(const QHashedStringRef &, int) const;
- QQmlType type(const QV4::String *, int) const;
-
- void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
-
- QQmlTypeModulePrivate *priv() { return d; }
-private:
- //Used by register functions and creates the QQmlTypeModule for them
- friend QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data);
- friend void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data);
- friend struct QQmlMetaTypeData;
- friend Q_QML_EXPORT void qmlClearTypeRegistrations();
- friend class QQmlTypeModulePrivate;
-
- QQmlTypeModule();
- ~QQmlTypeModule();
- QQmlTypeModulePrivate *d;
-};
-
-class QQmlTypeModuleVersion
-{
-public:
- QQmlTypeModuleVersion();
- QQmlTypeModuleVersion(QQmlTypeModule *, int);
- QQmlTypeModuleVersion(const QQmlTypeModuleVersion &);
- QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &);
-
- QQmlTypeModule *module() const;
- int minorVersion() const;
-
- QQmlType type(const QHashedStringRef &) const;
- QQmlType type(const QV4::String *) const;
-
-private:
- QQmlTypeModule *m_module;
- int m_minor;
-};
-
-class Q_AUTOTEST_EXPORT QQmlMetaTypeRegistrationFailureRecorder
-{
- QStringList _failures;
-
-public:
- QQmlMetaTypeRegistrationFailureRecorder();
- ~QQmlMetaTypeRegistrationFailureRecorder();
-
- QStringList failures() const
- { return _failures; }
-};
-
QT_END_NAMESPACE
#endif // QQMLMETATYPE_P_H
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
new file mode 100644
index 0000000000..775bc8bdb4
--- /dev/null
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlmetatypedata_p.h"
+
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypemodule_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlMetaTypeData::QQmlMetaTypeData()
+{
+}
+
+QQmlMetaTypeData::~QQmlMetaTypeData()
+{
+ for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i)
+ delete *i;
+ for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end();
+ it != end; ++it)
+ (*it)->release();
+
+ // Do this before the attached properties disappear.
+ types.clear();
+ undeletableTypes.clear();
+}
+
+// This expects a "fresh" QQmlTypePrivate and adopts its reference.
+void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
+{
+ for (int i = 0; i < types.count(); ++i) {
+ if (!types.at(i).isValid()) {
+ types[i] = QQmlType(priv);
+ priv->index = i;
+ priv->release();
+ return;
+ }
+ }
+ types.append(QQmlType(priv));
+ priv->index = types.count() - 1;
+ priv->release();
+}
+
+QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const
+{
+ return (index < typePropertyCaches.length())
+ ? typePropertyCaches.at(index).value(minorVersion).data()
+ : nullptr;
+}
+
+void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion,
+ QQmlPropertyCache *cache)
+{
+ if (index >= typePropertyCaches.length())
+ typePropertyCaches.resize(index + 1);
+ typePropertyCaches[index][minorVersion] = cache;
+}
+
+void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index)
+{
+ if (index < typePropertyCaches.length())
+ typePropertyCaches[index].clear();
+}
+
+QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion)
+{
+ if (QQmlPropertyCache *rv = propertyCaches.value(metaObject))
+ return rv;
+
+ if (!metaObject->superClass()) {
+ QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
+ propertyCaches.insert(metaObject, rv);
+ return rv;
+ }
+ QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion);
+ QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion);
+ propertyCaches.insert(metaObject, rv);
+ return rv;
+}
+
+QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
+{
+ Q_ASSERT(type.isValid());
+
+ if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), minorVersion))
+ return pc;
+
+ QVector<QQmlType> types;
+
+ int maxMinorVersion = 0;
+
+ const QMetaObject *metaObject = type.metaObject();
+
+ while (metaObject) {
+ QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
+ if (t.isValid()) {
+ maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
+ types << t;
+ } else {
+ types << QQmlType();
+ }
+
+ metaObject = metaObject->superClass();
+ }
+
+ if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), maxMinorVersion)) {
+ setPropertyCacheForMinorVersion(type.index(), minorVersion, pc);
+ return pc;
+ }
+
+ QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion);
+
+ bool hasCopied = false;
+
+ for (int ii = 0; ii < types.count(); ++ii) {
+ const QQmlType &currentType = types.at(ii);
+ if (!currentType.isValid())
+ continue;
+
+ int rev = currentType.metaObjectRevision();
+ int moIndex = types.count() - 1 - ii;
+
+ if (raw->allowedRevision(moIndex) != rev) {
+ if (!hasCopied) {
+ // TODO: The copy should be mutable, and the original should be const
+ // Considering this, the setAllowedRevision() below does not violate
+ // the immutability of already published property caches.
+ raw = raw->copy();
+ hasCopied = true;
+ }
+ raw->setAllowedRevision(moIndex, rev);
+ }
+ }
+
+ // Test revision compatibility - the basic rule is:
+ // * Anything that is excluded, cannot overload something that is not excluded *
+
+ // Signals override:
+ // * other signals and methods of the same name.
+ // * properties named on<Signal Name>
+ // * automatic <property name>Changed notify signals
+
+ // Methods override:
+ // * other methods of the same name
+
+ // Properties override:
+ // * other elements of the same name
+
+#if 0
+ bool overloadError = false;
+ QString overloadName;
+
+ for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
+ !overloadError && iter != raw->stringCache.end();
+ ++iter) {
+
+ QQmlPropertyData *d = *iter;
+ if (raw->isAllowedInRevision(d))
+ continue; // Not excluded - no problems
+
+ // check that a regular "name" overload isn't happening
+ QQmlPropertyData *current = d;
+ while (!overloadError && current) {
+ current = d->overrideData(current);
+ if (current && raw->isAllowedInRevision(current))
+ overloadError = true;
+ }
+ }
+
+ if (overloadError) {
+ if (hasCopied) raw->release();
+
+ error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
+ return 0;
+ }
+#endif
+
+ setPropertyCacheForMinorVersion(type.index(), minorVersion, raw);
+
+ if (hasCopied)
+ raw->release();
+
+ if (minorVersion != maxMinorVersion)
+ setPropertyCacheForMinorVersion(type.index(), maxMinorVersion, raw);
+
+ return raw;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
new file mode 100644
index 0000000000..5239b635ce
--- /dev/null
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLMETATYPEDATA_P_H
+#define QQMLMETATYPEDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltype_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qhashedstring_p.h>
+
+#include <QtCore/qset.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qbitarray.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypePrivate;
+struct QQmlMetaTypeData
+{
+ QQmlMetaTypeData();
+ ~QQmlMetaTypeData();
+ void registerType(QQmlTypePrivate *priv);
+ QList<QQmlType> types;
+ QSet<QQmlType> undeletableTypes;
+ typedef QHash<int, QQmlTypePrivate *> Ids;
+ Ids idToType;
+ typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
+ Names nameToType;
+ typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
+ Files urlToType;
+ Files urlToNonFileImportType; // For non-file imported composite and composite
+ // singleton types. This way we can locate any
+ // of them by url, even if it was registered as
+ // a module via QQmlPrivate::RegisterCompositeType
+ typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
+ MetaObjects metaObjectToType;
+ typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
+ StringConverters stringConverters;
+ QVector<QHash<int, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches;
+
+ struct VersionedUri {
+ VersionedUri()
+ : majorVersion(0) {}
+ VersionedUri(const QHashedString &uri, int majorVersion)
+ : uri(uri), majorVersion(majorVersion) {}
+ bool operator==(const VersionedUri &other) const {
+ return other.majorVersion == majorVersion && other.uri == uri;
+ }
+ QHashedString uri;
+ int majorVersion;
+ };
+ typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
+ TypeModules uriToModule;
+
+ QBitArray objects;
+ QBitArray interfaces;
+ QBitArray lists;
+
+ QList<QQmlPrivate::AutoParentFunction> parentFunctions;
+ QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
+
+ QSet<QString> protectedNamespaces;
+
+ QString typeRegistrationNamespace;
+
+ QHash<int, int> qmlLists;
+
+ QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
+
+ QQmlPropertyCache *propertyCacheForMinorVersion(int index, int minorVersion) const;
+ void setPropertyCacheForMinorVersion(int index, int minorVersion, QQmlPropertyCache *cache);
+ void clearPropertyCachesForMinorVersion(int index);
+
+ QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion);
+ QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
+
+ void setTypeRegistrationFailures(QStringList *failures)
+ {
+ m_typeRegistrationFailures = failures;
+ }
+
+ void recordTypeRegFailure(const QString &message)
+ {
+ if (m_typeRegistrationFailures)
+ m_typeRegistrationFailures->append(message);
+ else
+ qWarning("%s", message.toUtf8().constData());
+ }
+
+private:
+ QStringList *m_typeRegistrationFailures = nullptr;
+};
+
+inline uint qHash(const QQmlMetaTypeData::VersionedUri &v)
+{
+ return v.uri.hash() ^ qHash(v.majorVersion);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLMETATYPEDATA_P_H
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index 0706b8c0cf..1359586b31 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -118,8 +118,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
disconnect();
Q_ASSERT(engine);
- if (QObjectPrivate::get(source)->threadData->threadId.load() !=
- QObjectPrivate::get(engine)->threadData->threadId.load()) {
+ if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() !=
+ QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) {
QString sourceName;
QDebug(&sourceName) << source;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index e45515fbcf..a4270628e8 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,7 +55,9 @@
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmlscriptdata_p.h>
#include <private/qjsvalue_p.h>
+#include <private/qv4generatorobject_p.h>
#include <qtqml_tracepoints_p.h>
@@ -73,7 +75,7 @@ struct ActiveOCRestorer
};
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *creationContext,
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext,
QQmlIncubatorPrivate *incubator)
: phase(Startup)
, compilationUnit(compilationUnit)
@@ -100,7 +102,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR
}
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
: phase(Startup)
, compilationUnit(compilationUnit)
, propertyCaches(&compilationUnit->propertyCaches)
@@ -373,7 +375,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
propertyType = QMetaType::Int;
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
- QVariant value = binding->valueAsString(compilationUnit.data());
+ QVariant value = compilationUnit->bindingValueAsString(binding);
bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
Q_ASSERT(ok);
Q_UNUSED(ok);
@@ -406,7 +408,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
switch (propertyType) {
case QMetaType::QVariant: {
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = binding->valueAsNumber(compilationUnit->constants);
+ double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromInt32(int(n)));
@@ -438,11 +440,13 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &nullValue, propertyWriteFlags);
}
} else {
- QString stringValue = binding->valueAsString(compilationUnit.data());
+ QString stringValue = compilationUnit->bindingValueAsString(binding);
if (property->isVarProperty()) {
QV4::ScopedString s(scope, v4->newString(stringValue));
_vmeMetaObject->setVMEProperty(property->coreIndex(), s);
} else {
+ // ### Qt 6: Doing the conversion here where we don't know the eventual target type is rather strange
+ // and caused for instance QTBUG-78943
QVariant value = QQmlStringConverters::variantFromString(stringValue);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
@@ -451,25 +455,25 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
case QVariant::String: {
assertOrNull(binding->evaluatesToString());
- QString value = binding->valueAsString(compilationUnit.data());
+ QString value = compilationUnit->bindingValueAsString(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::StringList: {
assertOrNull(binding->evaluatesToString());
- QStringList value(binding->valueAsString(compilationUnit.data()));
+ QStringList value(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::ByteArray: {
assertType(QV4::CompiledData::Binding::Type_String);
- QByteArray value(binding->valueAsString(compilationUnit.data()).toUtf8());
+ QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Url: {
assertType(QV4::CompiledData::Binding::Type_String);
- QString string = binding->valueAsString(compilationUnit.data());
+ QString string = compilationUnit->bindingValueAsString(binding);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
@@ -481,7 +485,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
case QVariant::UInt: {
assertType(QV4::CompiledData::Binding::Type_Number);
- double d = binding->valueAsNumber(compilationUnit->constants);
+ double d = compilationUnit->bindingValueAsNumber(binding);
uint value = uint(d);
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
@@ -489,7 +493,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
case QVariant::Int: {
assertType(QV4::CompiledData::Binding::Type_Number);
- double d = binding->valueAsNumber(compilationUnit->constants);
+ double d = compilationUnit->bindingValueAsNumber(binding);
int value = int(d);
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
@@ -497,19 +501,19 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
case QMetaType::Float: {
assertType(QV4::CompiledData::Binding::Type_Number);
- float value = float(binding->valueAsNumber(compilationUnit->constants));
+ float value = float(compilationUnit->bindingValueAsNumber(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Double: {
assertType(QV4::CompiledData::Binding::Type_Number);
- double value = binding->valueAsNumber(compilationUnit->constants);
+ double value = compilationUnit->bindingValueAsNumber(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Color: {
bool ok = false;
- uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ uint colorValue = QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
struct { void *data[4]; } buffer;
if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
@@ -520,21 +524,21 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
#if QT_CONFIG(datestring)
case QVariant::Date: {
bool ok = false;
- QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Time: {
bool ok = false;
- QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::DateTime: {
bool ok = false;
- QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QDateTime value = QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
// ### VME compatibility :(
{
const qint64 date = value.date().toJulianDay();
@@ -548,42 +552,42 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
#endif // datestring
case QVariant::Point: {
bool ok = false;
- QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok).toPoint();
+ QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::PointF: {
bool ok = false;
- QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Size: {
bool ok = false;
- QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok).toSize();
+ QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::SizeF: {
bool ok = false;
- QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::Rect: {
bool ok = false;
- QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok).toRect();
+ QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
case QVariant::RectF: {
bool ok = false;
- QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
@@ -599,7 +603,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float xp;
float yp;
} vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
@@ -611,7 +615,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float yp;
float zy;
} vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
@@ -624,7 +628,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float zy;
float wp;
} vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
@@ -637,7 +641,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
float yp;
float zp;
} vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec));
+ bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
assertOrNull(ok);
Q_UNUSED(ok);
property->writeProperty(_qobject, &vec, propertyWriteFlags);
@@ -651,12 +655,12 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
if (property->propType() == qMetaTypeId<QList<qreal> >()) {
assertType(QV4::CompiledData::Binding::Type_Number);
QList<qreal> value;
- value.append(binding->valueAsNumber(compilationUnit->constants));
+ value.append(compilationUnit->bindingValueAsNumber(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QList<int> >()) {
assertType(QV4::CompiledData::Binding::Type_Number);
- double n = binding->valueAsNumber(compilationUnit->constants);
+ double n = compilationUnit->bindingValueAsNumber(binding);
QList<int> value;
value.append(int(n));
property->writeProperty(_qobject, &value, propertyWriteFlags);
@@ -669,7 +673,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
} else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
assertType(QV4::CompiledData::Binding::Type_String);
- QString urlString = binding->valueAsString(compilationUnit.data());
+ QString urlString = compilationUnit->bindingValueAsString(binding);
QUrl u = urlString.isEmpty() ? QUrl()
: compilationUnit->finalUrl().resolved(QUrl(urlString));
QList<QUrl> value;
@@ -679,7 +683,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else if (property->propType() == qMetaTypeId<QList<QString> >()) {
assertOrNull(binding->evaluatesToString());
QList<QString> value;
- value.append(binding->valueAsString(compilationUnit.data()));
+ value.append(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (property->propType() == qMetaTypeId<QJSValue>()) {
@@ -687,7 +691,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
value = QJSValue(binding->valueAsBoolean());
} else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = binding->valueAsNumber(compilationUnit->constants);
+ double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
value = QJSValue(int(n));
} else
@@ -695,14 +699,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
value = QJSValue::NullValue;
} else {
- value = QJSValue(binding->valueAsString(compilationUnit.data()));
+ value = QJSValue(compilationUnit->bindingValueAsString(binding));
}
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
}
// otherwise, try a custom type assignment
- QString stringValue = binding->valueAsString(compilationUnit.data());
+ QString stringValue = compilationUnit->bindingValueAsString(binding);
QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
Q_ASSERT(converter);
QVariant value = (*converter)(stringValue);
@@ -735,7 +739,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
if (_compiledObject->idNameIndex) {
const QQmlPropertyData *idProperty = propertyData.last();
@@ -816,7 +820,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
- QV4::CompiledData::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
+ QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
Q_ASSERT(tr);
QQmlType attachedType = tr->type;
if (!attachedType.isValid()) {
@@ -835,13 +839,14 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
// ### resolve this at compile time
if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
- QQmlScriptString ss(binding->valueAsScriptString(compilationUnit.data()), context->asQQmlContext(), _scopeObject);
+ QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
+ context->asQQmlContext(), _scopeObject);
ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
ss.d.data()->lineNumber = binding->location.line;
ss.d.data()->columnNumber = binding->location.column;
ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
- ss.d.data()->numberValue = binding->valueAsNumber(compilationUnit->constants);
+ ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::RemoveBindingOnAliasWrite;
@@ -938,7 +943,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
auto bindingTarget = _bindingTarget;
auto valueTypeProperty = _valueTypeProperty;
- auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool {
+ auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) mutable -> bool {
if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias())
return false;
@@ -1133,7 +1138,10 @@ void QQmlObjectCreator::setupFunctions()
if (!property->isVMEFunction())
continue;
- function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
+ if (runtimeFunction->isGenerator())
+ function = QV4::GeneratorFunction::create(qmlContext, runtimeFunction);
+ else
+ function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
_vmeMetaObject->setVmeMethod(property->coreIndex(), function);
}
}
@@ -1184,8 +1192,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
} else {
- QV4::CompiledData::ResolvedTypeReference *typeRef
- = resolvedType(obj->inheritedTypeNameIndex);
+ QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType type = typeRef->type;
@@ -1445,8 +1452,12 @@ void QQmlObjectCreator::clear()
return;
Q_ASSERT(phase != Startup);
- while (!sharedState->allCreatedObjects.isEmpty())
- delete sharedState->allCreatedObjects.pop();
+ while (!sharedState->allCreatedObjects.isEmpty()) {
+ auto object = sharedState->allCreatedObjects.pop();
+ if (engine->objectOwnership(object) != QQmlEngine::CppOwnership) {
+ delete object;
+ }
+ }
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 5aca60e2f0..ecdbcc56dd 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -53,17 +53,16 @@
#include <private/qqmlimport_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmltypecompiler_p.h>
#include <private/qfinitestack_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlprofiler_p.h>
+#include <private/qv4qmlcontext_p.h>
#include <qpointer.h>
QT_BEGIN_NAMESPACE
class QQmlAbstractBinding;
-struct QQmlTypeCompiler;
class QQmlInstantiationInterrupt;
class QQmlIncubatorPrivate;
@@ -85,7 +84,7 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
+ QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
@@ -94,17 +93,17 @@ public:
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
void clear();
- QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; }
+ QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
- QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() const { return &sharedState->finalizeCallbacks; }
+ QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; }
QList<QQmlError> errors;
QQmlContextData *parentContextData() const { return parentContext.contextData(); }
- QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; }
+ QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
private:
- QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
void init(QQmlContextData *parentContext);
@@ -125,7 +124,7 @@ private:
inline QV4::QmlContext *currentQmlContext();
Q_NEVER_INLINE void createQmlContext();
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
+ QV4::ResolvedTypeReference *resolvedType(int id) const
{
return compilationUnit->resolvedType(id);
}
@@ -141,7 +140,7 @@ private:
QQmlEngine *engine;
QV4::ExecutionEngine *v4;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
QQmlContextData *context;
diff --git a/src/qml/qml/qqmlobjectorgadget.cpp b/src/qml/qml/qqmlobjectorgadget.cpp
new file mode 100644
index 0000000000..1d4916d7d1
--- /dev/null
+++ b/src/qml/qml/qqmlobjectorgadget.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlobjectorgadget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
+{
+ if (ptr.isNull()) {
+ const QMetaObject *metaObject = _m.asT2();
+ metaObject->d.static_metacall(nullptr, type, index, argv);
+ }
+ else if (ptr.isT1()) {
+ QMetaObject::metacall(ptr.asT1(), type, index, argv);
+ }
+ else {
+ const QMetaObject *metaObject = _m.asT1()->metaObject();
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/util/qqmllistaccessor_p.h b/src/qml/qml/qqmlobjectorgadget_p.h
index bcd079adef..c5f5f58a3a 100644
--- a/src/qml/util/qqmllistaccessor_p.h
+++ b/src/qml/qml/qqmlobjectorgadget_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLLISTACCESSOR_H
-#define QQMLLISTACCESSOR_H
+#ifndef QQMLOBJECTORGADGET_P_H
+#define QQMLOBJECTORGADGET_P_H
//
// W A R N I N G
@@ -51,33 +51,33 @@
// We mean it.
//
-#include <QtCore/QVariant>
+#include <private/qqmlmetaobject_p.h>
QT_BEGIN_NAMESPACE
-class QQmlEngine;
-class Q_AUTOTEST_EXPORT QQmlListAccessor
+class QQmlObjectOrGadget: public QQmlMetaObject
{
public:
- QQmlListAccessor();
- ~QQmlListAccessor();
+ QQmlObjectOrGadget(QObject *obj)
+ : QQmlMetaObject(obj),
+ ptr(obj)
+ {}
+ QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
+ : QQmlMetaObject(propertyCache)
+ , ptr(gadget)
+ {}
- QVariant list() const;
- void setList(const QVariant &, QQmlEngine * = nullptr);
-
- bool isValid() const;
-
- int count() const;
- QVariant at(int) const;
-
- enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer };
- Type type() const { return m_type; }
+ void metacall(QMetaObject::Call type, int index, void **argv) const;
private:
- Type m_type;
- QVariant d;
+ QBiPointer<QObject, void> ptr;
+
+protected:
+ QQmlObjectOrGadget(const QMetaObject* metaObject)
+ : QQmlMetaObject(metaObject)
+ {}
};
QT_END_NAMESPACE
-#endif // QQMLLISTACCESSOR_H
+#endif // QQMLOBJECTORGADGET_P_H
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index fc798a2c23..fe0946c6de 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -41,7 +41,6 @@
#include <private/qqmlpropertycache_p.h>
#include <private/qqmldata_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#include <private/qv8engine_p.h>
#include <qqmlengine.h>
#include <qdebug.h>
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 8a45de9f76..bfd3611fb8 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -51,11 +51,14 @@
// We mean it.
//
+#include <functional>
+
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
#include <QtCore/qurl.h>
+#include <QPointer>
QT_BEGIN_NAMESPACE
@@ -276,6 +279,7 @@ namespace QQmlPrivate
const QMetaObject *instanceMetaObject; // new in version 1
int typeId; // new in version 2
int revision; // new in version 2
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
// If this is extended ensure "version" is bumped!!!
};
@@ -319,6 +323,13 @@ namespace QQmlPrivate
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
+ struct Q_QML_EXPORT RegisterSingletonFunctor
+ {
+ QObject *operator()(QQmlEngine *, QJSEngine *);
+
+ QPointer<QObject> m_object;
+ bool alreadyCalled = false;
+ };
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index c8166695ba..5f57e0eca1 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1216,10 +1216,18 @@ bool QQmlPropertyPrivate::write(QObject *object,
if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
} else if (property.isQObject()) {
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, variantType);
+ QVariant val = value;
+ int varType = variantType;
+ if (variantType == QMetaType::Nullptr) {
+ // This reflects the fact that you can assign a nullptr to a QObject pointer
+ // Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
+ varType = QMetaType::QObjectStar;
+ val = QVariant(QMetaType::QObjectStar, nullptr);
+ }
+ QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType);
if (valMo.isNull())
return false;
- QObject *o = *static_cast<QObject *const *>(value.constData());
+ QObject *o = *static_cast<QObject *const *>(val.constData());
QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
if (o)
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 544eab4c7f..285c34d7fa 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -56,14 +56,17 @@
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlcontext_p.h>
#include <private/qqmlboundsignalexpressionpointer_p.h>
+#include <private/qqmlpropertydata_p.h>
QT_BEGIN_NAMESPACE
class QQmlContext;
class QQmlEnginePrivate;
class QQmlJavaScriptExpression;
+class QQmlMetaObject;
class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
{
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 73bfd7bbaa..69957ab282 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -42,10 +42,10 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlvmemetaobject_p.h>
-#include <private/qv8engine_p.h>
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlpropertycachemethodarguments_p.h>
#include <private/qv4value_p.h>
@@ -65,21 +65,6 @@ QT_BEGIN_NAMESPACE
#define Q_INT16_MAX 32767
-class QQmlPropertyCacheMethodArguments
-{
-public:
- QQmlPropertyCacheMethodArguments *next;
-
- //for signal handler rewrites
- QString *signalParameterStringForJS;
- int parameterError:1;
- int argumentsValid:1;
-
- QList<QByteArray> *names;
-
- int arguments[1];
-};
-
// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
// to load
static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
@@ -113,8 +98,6 @@ static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags)
flags.type = QQmlPropertyData::Flags::QmlBindingType;
} else if (propType == qMetaTypeId<QJSValue>()) {
flags.type = QQmlPropertyData::Flags::QJSValueType;
- } else if (propType == qMetaTypeId<QQmlV4Handle>()) {
- flags.type = QQmlPropertyData::Flags::V4HandleType;
} else {
QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType);
@@ -141,24 +124,27 @@ QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
return flags;
}
-void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
+static void populate(QQmlPropertyData *data, const QMetaProperty &p)
{
- setCoreIndex(p.propertyIndex());
- setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
Q_ASSERT(p.revision() <= Q_INT16_MAX);
- setRevision(p.revision());
-
- setFlags(fastFlagsForProperty(p));
+ data->setCoreIndex(p.propertyIndex());
+ data->setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
+ data->setFlags(fastFlagsForProperty(p));
+ data->setRevision(p.revision());
+}
+void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
+{
+ populate(this, p);
int type = static_cast<int>(p.type());
if (type == QMetaType::QObjectStar) {
setPropType(type);
- _flags.type = Flags::QObjectDerivedType;
+ m_flags.type = Flags::QObjectDerivedType;
} else if (type == QMetaType::QVariant) {
setPropType(type);
- _flags.type = Flags::QVariantType;
+ m_flags.type = Flags::QVariantType;
} else if (type == QVariant::UserType || type == -1) {
- _flags.notFullyResolved = true;
+ m_flags.notFullyResolved = true;
} else {
setPropType(type);
}
@@ -166,13 +152,9 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
void QQmlPropertyData::load(const QMetaProperty &p)
{
+ populate(this, p);
setPropType(p.userType());
- setCoreIndex(p.propertyIndex());
- setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
- setFlags(fastFlagsForProperty(p));
- flagsForPropertyType(propType(), _flags);
- Q_ASSERT(p.revision() <= Q_INT16_MAX);
- setRevision(p.revision());
+ flagsForPropertyType(propType(), m_flags);
}
void QQmlPropertyData::load(const QMetaMethod &m)
@@ -182,23 +164,23 @@ void QQmlPropertyData::load(const QMetaMethod &m)
setPropType(m.returnType());
- _flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal)
- _flags.isSignal = true;
- else if (m.methodType() == QMetaMethod::Constructor) {
- _flags.isConstructor = true;
+ m_flags.type = Flags::FunctionType;
+ if (m.methodType() == QMetaMethod::Signal) {
+ m_flags.isSignal = true;
+ } else if (m.methodType() == QMetaMethod::Constructor) {
+ m_flags.isConstructor = true;
setPropType(QMetaType::QObjectStar);
}
- if (m.parameterCount()) {
- _flags.hasArguments = true;
- if ((m.parameterCount() == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*")) {
- _flags.isV4Function = true;
- }
+ const int paramCount = m.parameterCount();
+ if (paramCount) {
+ m_flags.hasArguments = true;
+ if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
+ m_flags.isV4Function = true;
}
if (m.attributes() & QMetaMethod::Cloned)
- _flags.isCloned = true;
+ m_flags.isCloned = true;
Q_ASSERT(m.revision() <= Q_INT16_MAX);
setRevision(m.revision());
@@ -206,37 +188,14 @@ void QQmlPropertyData::load(const QMetaMethod &m)
void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
{
- setCoreIndex(m.methodIndex());
- setPropType(QMetaType::Void);
- setArguments(nullptr);
- _flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal)
- _flags.isSignal = true;
- else if (m.methodType() == QMetaMethod::Constructor) {
- _flags.isConstructor = true;
- setPropType(QMetaType::QObjectStar);
- }
+ load(m);
const char *returnType = m.typeName();
if (!returnType)
returnType = "\0";
if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
- _flags.notFullyResolved = true;
- }
-
- const int paramCount = m.parameterCount();
- if (paramCount) {
- _flags.hasArguments = true;
- if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*")) {
- _flags.isV4Function = true;
- }
+ m_flags.notFullyResolved = true;
}
-
- if (m.attributes() & QMetaMethod::Cloned)
- _flags.isCloned = true;
-
- Q_ASSERT(m.revision() <= Q_INT16_MAX);
- setRevision(m.revision());
}
/*!
@@ -361,7 +320,7 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
data.setArguments(nullptr);
QQmlPropertyData handler = data;
- handler._flags.isSignalHandler = true;
+ handler.m_flags.isSignalHandler = true;
if (types) {
int argumentCount = *types;
@@ -389,17 +348,18 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
}
void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, const QList<QByteArray> &names)
+ int coreIndex, int returnType, const QList<QByteArray> &names,
+ const QVector<int> &parameterTypes)
{
int argumentCount = names.count();
QQmlPropertyData data;
- data.setPropType(QMetaType::QVariant);
+ data.setPropType(returnType);
data.setCoreIndex(coreIndex);
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
for (int ii = 0; ii < argumentCount; ++ii)
- args->arguments[ii + 1] = QMetaType::QVariant;
+ args->arguments[ii + 1] = parameterTypes.at(ii);
args->argumentsValid = true;
data.setArguments(args);
@@ -559,7 +519,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->setFlags(methodFlags);
data->lazyLoad(m);
- data->_flags.isDirect = !dynamicMetaObject;
+ data->m_flags.isDirect = !dynamicMetaObject;
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
@@ -567,7 +527,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
if (data->isSignal()) {
sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
*sigdata = *data;
- sigdata->_flags.isSignalHandler = true;
+ sigdata->m_flags.isSignalHandler = true;
}
QQmlPropertyData *old = nullptr;
@@ -609,7 +569,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
if (old) {
// We only overload methods in the same class, exactly like C++
if (old->isFunction() && old->coreIndex() >= methodOffset)
- data->_flags.isOverload = true;
+ data->m_flags.isOverload = true;
data->markAsOverrideOf(old);
}
@@ -640,7 +600,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->lazyLoad(p);
data->setTypeMinorVersion(typeMinorVersion);
- data->_flags.isDirect = !dynamicMetaObject;
+ data->m_flags.isDirect = !dynamicMetaObject;
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
@@ -666,7 +626,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
}
if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
- data->_flags.isDirect = false;
+ data->m_flags.isDirect = false;
else
data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
if (old)
@@ -677,7 +637,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
{
Q_ASSERT(data->notFullyResolved());
- data->_flags.notFullyResolved = false;
+ data->m_flags.notFullyResolved = false;
const QMetaObject *mo = firstCppMetaObject();
if (data->isFunction()) {
@@ -712,7 +672,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult);
}
}
- flagsForPropertyType(data->propType(), data->_flags);
+ flagsForPropertyType(data->propType(), data->m_flags);
}
}
@@ -889,52 +849,7 @@ void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
setOverrideIndexIsProperty(!predecessor->isFunction());
setOverrideIndex(predecessor->coreIndex());
- predecessor->_flags.isOverridden = true;
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-static bool isNamedEnumeratorInScope(const QMetaObject *resolvedMetaObject, const QByteArray &scope,
- const QByteArray &name)
-{
- for (int i = resolvedMetaObject->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = resolvedMetaObject->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return true;
- }
- return false;
-}
-
-static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scopedName)
-{
- QByteArray scope;
- QByteArray name;
- int scopeIdx = scopedName.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = scopedName.left(scopeIdx);
- name = scopedName.mid(scopeIdx + 2);
- } else {
- name = scopedName;
- }
-
- if (scope == "Qt")
- return isNamedEnumeratorInScope(StaticQtMetaObject::get(), scope, name);
-
- if (isNamedEnumeratorInScope(metaObj, scope, name))
- return true;
-
- if (metaObj->d.relatedMetaObjects && !scope.isEmpty()) {
- for (auto related = metaObj->d.relatedMetaObjects; *related; ++related) {
- if (isNamedEnumeratorInScope(*related, scope, name))
- return true;
- }
- }
-
- return false;
+ predecessor->m_flags.isOverridden = true;
}
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
@@ -954,7 +869,7 @@ QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int a
QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString)
{
bool unnamedParameter = false;
- const QSet<QString> &illegalNames = engine->v8Engine->illegalNames();
+ const QSet<QString> &illegalNames = engine->illegalNames();
QString parameters;
for (int i = 0; i < parameterNameList.count(); ++i) {
@@ -1517,262 +1432,4 @@ QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
return QList<QByteArray>();
}
-// Returns true if \a from is assignable to a property of type \a to
-bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
-{
- Q_ASSERT(!from.isNull() && !to.isNull());
-
- struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
- return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
- } };
-
- const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
- if (tom == &QObject::staticMetaObject) return true;
-
- if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
- QQmlPropertyCache *fromp = from._m.asT1();
- QQmlPropertyCache *top = to._m.asT1();
-
- while (fromp) {
- if (fromp == top) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
- QQmlPropertyCache *fromp = from._m.asT1();
-
- while (fromp) {
- const QMetaObject *fromm = fromp->metaObject();
- if (fromm && I::equal(fromm, tom)) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
- const QMetaObject *fromm = from._m.asT2();
-
- if (!tom) return false;
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- } else { // QMetaObject -> QMetaObject
- const QMetaObject *fromm = from._m.asT2();
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- }
-
- return false;
-}
-
-void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
-{
- int offset;
-
- switch (type) {
- case QMetaObject::ReadProperty:
- case QMetaObject::WriteProperty:
- case QMetaObject::ResetProperty:
- case QMetaObject::QueryPropertyDesignable:
- case QMetaObject::QueryPropertyEditable:
- case QMetaObject::QueryPropertyScriptable:
- case QMetaObject::QueryPropertyStored:
- case QMetaObject::QueryPropertyUser:
- offset = (*metaObject)->propertyOffset();
- while (*index < offset) {
- *metaObject = (*metaObject)->superClass();
- offset = (*metaObject)->propertyOffset();
- }
- break;
- case QMetaObject::InvokeMetaMethod:
- offset = (*metaObject)->methodOffset();
- while (*index < offset) {
- *metaObject = (*metaObject)->superClass();
- offset = (*metaObject)->methodOffset();
- }
- break;
- default:
- offset = 0;
- Q_UNIMPLEMENTED();
- offset = INT_MAX;
- }
-
- *index -= offset;
-}
-
-QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
-{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1();
- else return e->cache(_m.asT2());
-}
-
-int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0);
-
- int type = data.propType();
-
- const char *propTypeName = nullptr;
-
- if (type == QMetaType::UnknownType) {
- // Find the return type name from the method info
- QMetaMethod m;
-
- if (_m.isT1()) {
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (data.coreIndex() < c->methodIndexCacheStart)
- c = c->_parent;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- m = metaObject->method(data.coreIndex());
- } else {
- m = _m.asT2()->method(data.coreIndex());
- }
-
- type = m.returnType();
- propTypeName = m.typeName();
- }
-
- if (QMetaType::sizeOf(type) <= int(sizeof(int))) {
- if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration)
- return QMetaType::Int;
-
- if (isNamedEnumerator(metaObject(), propTypeName))
- return QMetaType::Int;
-
- if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = propTypeName;
- }
- } // else we know that it's a known type, as sizeOf(UnknownType) == 0
-
- return type;
-}
-
-int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && index >= 0);
-
- if (_m.isT1()) {
- typedef QQmlPropertyCacheMethodArguments A;
-
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (index < c->methodIndexCacheStart)
- c = c->_parent;
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
-
- if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid)
- return static_cast<A *>(rv->arguments())->arguments;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- QMetaMethod m = metaObject->method(index);
-
- int argc = m.parameterCount();
- if (!rv->arguments()) {
- A *args = c->createArgumentsObject(argc, m.parameterNames());
- rv->setArguments(args);
- }
- A *args = static_cast<A *>(rv->arguments());
-
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
-
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(metaObject, argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType){
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
-
- }
- args->arguments[ii + 1] = type;
- }
- args->argumentsValid = true;
- return static_cast<A *>(rv->arguments())->arguments;
-
- } else {
- QMetaMethod m = _m.asT2()->method(index);
- return methodParameterTypes(m, argStorage, unknownTypeError);
-
- }
-}
-
-int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(argStorage);
-
- int argc = m.parameterCount();
- argStorage->resize(argc + 1);
- argStorage->operator[](0) = argc;
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(_m.asT2(), argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
- }
- argStorage->operator[](ii + 1) = type;
- }
-
- return argStorage->data();
-}
-
-void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
-{
- if (ptr.isNull()) {
- const QMetaObject *metaObject = _m.asT2();
- metaObject->d.static_metacall(nullptr, type, index, argv);
- }
- else if (ptr.isT1()) {
- QMetaObject::metacall(ptr.asT1(), type, index, argv);
- }
- else {
- const QMetaObject *metaObject = _m.asT1()->metaObject();
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
- }
-}
-
-int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
- QByteArray *unknownTypeError) const
-{
- QMetaMethod m = _m.asT2()->constructor(index);
- return methodParameterTypes(m, dummy, unknownTypeError);
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index c3c818eb77..bfd78eef88 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -57,339 +57,25 @@
#include "qqmlnotifier_p.h"
#include <private/qqmlpropertyindex_p.h>
-#include <private/qhashedstring_p.h>
+#include <private/qlinkedstringhash_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <private/qv4value_p.h>
+#include <private/qqmlpropertydata_p.h>
+#include <private/qqmlenumdata_p.h>
+#include <private/qqmlenumvalue_p.h>
#include <limits>
QT_BEGIN_NAMESPACE
class QCryptographicHash;
-class QMetaProperty;
-class QQmlEngine;
class QJSEngine;
-class QQmlPropertyData;
class QMetaObjectBuilder;
-class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
-template <typename T> class QQmlPropertyCacheCreator;
-template <typename T> class QQmlPropertyCacheAliasCreator;
-
-// We have this somewhat awful split between RawData and Data so that RawData can be
-// used in unions. In normal code, you should always use Data which initializes RawData
-// to an invalid state on construction.
-// ### We should be able to remove this split nowadays
-class QQmlPropertyRawData
-{
-public:
- typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
-
- struct Flags {
- enum Types {
- OtherType = 0,
- FunctionType = 1, // Is an invokable
- QObjectDerivedType = 2, // Property type is a QObject* derived type
- EnumType = 3, // Property type is an enum
- QListType = 4, // Property type is a QML list
- QmlBindingType = 5, // Property type is a QQmlBinding*
- QJSValueType = 6, // Property type is a QScriptValue
- V4HandleType = 7, // Property type is a QQmlV4Handle
- VarPropertyType = 8, // Property type is a "var" property of VMEMO
- QVariantType = 9 // Property is a QVariant
- };
-
- // The _otherBits (which "pad" the Flags struct to align it nicely) are used
- // to store the relative property index. It will only get used when said index fits. See
- // trySetStaticMetaCallFunction for details.
- // (Note: this padding is done here, because certain compilers have surprising behavior
- // when an enum is declared in-between two bit fields.)
- enum { BitsLeftInFlags = 10 };
- unsigned _otherBits : BitsLeftInFlags; // align to 32 bits
-
- // Can apply to all properties, except IsFunction
- unsigned isConstant : 1; // Has CONST flag
- unsigned isWritable : 1; // Has WRITE function
- unsigned isResettable : 1; // Has RESET function
- unsigned isAlias : 1; // Is a QML alias to another property
- unsigned isFinal : 1; // Has FINAL flag
- unsigned isOverridden : 1; // Is overridden by a extension property
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
-
- unsigned type : 4; // stores an entry of Types
-
- // Apply only to IsFunctions
- unsigned isVMEFunction : 1; // Function was added by QML
- unsigned hasArguments : 1; // Function takes arguments
- unsigned isSignal : 1; // Function is a signal
- unsigned isVMESignal : 1; // Signal was added by QML
- unsigned isV4Function : 1; // Function takes QQmlV4Function* args
- unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
- unsigned isConstructor : 1; // The function was marked is a constructor
-
- // Internal QQmlPropertyCache flags
- unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
- unsigned overrideIndexIsProperty: 1;
-
- inline Flags();
- inline bool operator==(const Flags &other) const;
- inline void copyPropertyTypeFlags(Flags from);
- };
-
- Flags flags() const { return _flags; }
- void setFlags(Flags f)
- {
- unsigned otherBits = _flags._otherBits;
- _flags = f;
- _flags._otherBits = otherBits;
- }
-
- bool isValid() const { return coreIndex() != -1; }
-
- bool isConstant() const { return _flags.isConstant; }
- bool isWritable() const { return _flags.isWritable; }
- void setWritable(bool onoff) { _flags.isWritable = onoff; }
- bool isResettable() const { return _flags.isResettable; }
- bool isAlias() const { return _flags.isAlias; }
- bool isFinal() const { return _flags.isFinal; }
- bool isOverridden() const { return _flags.isOverridden; }
- bool isDirect() const { return _flags.isDirect; }
- bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
- bool isFunction() const { return _flags.type == Flags::FunctionType; }
- bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; }
- bool isEnum() const { return _flags.type == Flags::EnumType; }
- bool isQList() const { return _flags.type == Flags::QListType; }
- bool isQmlBinding() const { return _flags.type == Flags::QmlBindingType; }
- bool isQJSValue() const { return _flags.type == Flags::QJSValueType; }
- bool isV4Handle() const { return _flags.type == Flags::V4HandleType; }
- bool isVarProperty() const { return _flags.type == Flags::VarPropertyType; }
- bool isQVariant() const { return _flags.type == Flags::QVariantType; }
- bool isVMEFunction() const { return _flags.isVMEFunction; }
- bool hasArguments() const { return _flags.hasArguments; }
- bool isSignal() const { return _flags.isSignal; }
- bool isVMESignal() const { return _flags.isVMESignal; }
- bool isV4Function() const { return _flags.isV4Function; }
- bool isSignalHandler() const { return _flags.isSignalHandler; }
- bool isOverload() const { return _flags.isOverload; }
- void setOverload(bool onoff) { _flags.isOverload = onoff; }
- bool isCloned() const { return _flags.isCloned; }
- bool isConstructor() const { return _flags.isConstructor; }
-
- bool hasOverride() const { return overrideIndex() >= 0; }
- bool hasRevision() const { return revision() != 0; }
-
- bool isFullyResolved() const { return !_flags.notFullyResolved; }
-
- int propType() const { Q_ASSERT(isFullyResolved()); return _propType; }
- void setPropType(int pt)
- {
- Q_ASSERT(pt >= 0);
- Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
- _propType = quint16(pt);
- }
-
- int notifyIndex() const { return _notifyIndex; }
- void setNotifyIndex(int idx)
- {
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _notifyIndex = qint16(idx);
- }
-
- bool overrideIndexIsProperty() const { return _flags.overrideIndexIsProperty; }
- void setOverrideIndexIsProperty(bool onoff) { _flags.overrideIndexIsProperty = onoff; }
-
- int overrideIndex() const { return _overrideIndex; }
- void setOverrideIndex(int idx)
- {
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _overrideIndex = qint16(idx);
- }
-
- int coreIndex() const { return _coreIndex; }
- void setCoreIndex(int idx)
- {
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _coreIndex = qint16(idx);
- }
-
- quint8 revision() const { return _revision; }
- void setRevision(quint8 rev)
- {
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- _revision = quint8(rev);
- }
-
- /* If a property is a C++ type, then we store the minor
- * version of this type.
- * This is required to resolve property or signal revisions
- * if this property is used as a grouped property.
- *
- * Test.qml
- * property TextEdit someTextEdit: TextEdit {}
- *
- * Test {
- * someTextEdit.preeditText: "test" //revision 7
- * someTextEdit.onEditingFinished: console.log("test") //revision 6
- * }
- *
- * To determine if these properties with revisions are available we need
- * the minor version of TextEdit as imported in Test.qml.
- *
- */
-
- quint8 typeMinorVersion() const { return _typeMinorVersion; }
- void setTypeMinorVersion(quint8 rev)
- {
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- _typeMinorVersion = quint8(rev);
- }
-
- QQmlPropertyCacheMethodArguments *arguments() const { return _arguments; }
- void setArguments(QQmlPropertyCacheMethodArguments *args) { _arguments = args; }
-
- int metaObjectOffset() const { return _metaObjectOffset; }
- void setMetaObjectOffset(int off)
- {
- Q_ASSERT(off >= std::numeric_limits<qint16>::min());
- Q_ASSERT(off <= std::numeric_limits<qint16>::max());
- _metaObjectOffset = qint16(off);
- }
-
- StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; }
- void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
- {
- if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
- _flags._otherBits = relativePropertyIndex;
- _staticMetaCallFunction = f;
- }
- }
- quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; }
-
-private:
- Flags _flags;
- qint16 _coreIndex = 0;
- quint16 _propType = 0;
-
- // The notify index is in the range returned by QObjectPrivate::signalIndex().
- // This is different from QMetaMethod::methodIndex().
- qint16 _notifyIndex = 0;
- qint16 _overrideIndex = 0;
-
- quint8 _revision = 0;
- quint8 _typeMinorVersion = 0;
- qint16 _metaObjectOffset = 0;
-
- QQmlPropertyCacheMethodArguments *_arguments = nullptr;
- StaticMetaCallFunction _staticMetaCallFunction = nullptr;
-
- friend class QQmlPropertyData;
- friend class QQmlPropertyCache;
-};
-
-#if QT_POINTER_SIZE == 4
-Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 24);
-#else // QT_POINTER_SIZE == 8
-Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 32);
-#endif
-
-class QQmlPropertyData : public QQmlPropertyRawData
-{
-public:
- enum WriteFlag {
- BypassInterceptor = 0x01,
- DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
- };
- Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
-
- inline QQmlPropertyData();
- inline QQmlPropertyData(const QQmlPropertyRawData &);
-
- inline bool operator==(const QQmlPropertyRawData &);
-
- static Flags flagsForProperty(const QMetaProperty &);
- void load(const QMetaProperty &);
- void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
-
- void markAsOverrideOf(QQmlPropertyData *predecessor);
-
- inline void readProperty(QObject *target, void *property) const
- {
- void *args[] = { property, nullptr };
- readPropertyWithArgs(target, args);
- }
-
- inline void readPropertyWithArgs(QObject *target, void *args[]) const
- {
- if (hasStaticMetaCallFunction())
- staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
- else if (isDirect())
- target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
- else
- QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
- }
-
- bool writeProperty(QObject *target, void *value, WriteFlags flags) const
- {
- int status = -1;
- void *argv[] = { value, nullptr, &status, &flags };
- if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
- staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
- else if (flags.testFlag(BypassInterceptor) && isDirect())
- target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
- else
- QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
- return true;
- }
-
- static Flags defaultSignalFlags()
- {
- Flags f;
- f.isSignal = true;
- f.type = Flags::FunctionType;
- f.isVMESignal = true;
- return f;
- }
-
- static Flags defaultSlotFlags()
- {
- Flags f;
- f.type = Flags::FunctionType;
- f.isVMEFunction = true;
- return f;
- }
-
-private:
- friend class QQmlPropertyCache;
- void lazyLoad(const QMetaProperty &);
- void lazyLoad(const QMetaMethod &);
- bool notFullyResolved() const { return _flags.notFullyResolved; }
-};
-
-struct QQmlEnumValue
-{
- QQmlEnumValue() {}
- QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {}
- QString namedValue;
- int value = -1;
-};
-
-struct QQmlEnumData
-{
- QString name;
- QVector<QQmlEnumValue> values;
-};
-
class QQmlPropertyCacheMethodArguments;
+
class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
{
public:
@@ -399,28 +85,26 @@ public:
void update(const QMetaObject *);
void invalidate(const QMetaObject *);
- // Used by qmlpuppet. Remove as soon Creator requires Qt 5.5.
- void invalidate(void *, const QMetaObject *mo) { invalidate(mo); }
QQmlPropertyCache *copy();
QQmlPropertyCache *copyAndAppend(const QMetaObject *,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
+ QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
+ QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCache *copyAndReserve(int propertyCount,
int methodCount, int signalCount, int enumCount);
- void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex,
+ void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
int propType, int revision, int notifyIndex);
- void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex,
+ void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex,
const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>());
- void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
- const QList<QByteArray> &names = QList<QByteArray>());
+ void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, int returnType,
+ const QList<QByteArray> &names, const QVector<int> &parameterTypes);
void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
@@ -488,6 +172,10 @@ public:
static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
QByteArray checksum(bool *ok);
+
+ int allowedRevision(int index) const { return allowedRevisionCache[index]; }
+ void setAllowedRevision(int index, int allowed) { allowedRevisionCache[index] = allowed; }
+
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
@@ -495,19 +183,18 @@ private:
template <typename T> friend class QQmlPropertyCacheAliasCreator;
friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
- friend struct QQmlMetaTypeData;
inline QQmlPropertyCache *copy(int reserve);
void append(const QMetaObject *, int typeMinorVersion,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
+ QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names);
typedef QVector<QQmlPropertyData> IndexCache;
- typedef QStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
+ typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
typedef QVector<int> AllowedRevisionCache;
QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
@@ -556,172 +243,6 @@ private:
QByteArray _checksum;
};
-typedef QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCachePtr;
-
-// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
-// This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
-// we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
-// QObject type used in assignment or when we don't have a QQmlEngine etc.
-//
-// This class does NOT reference the propertycache.
-class QQmlEnginePrivate;
-class Q_QML_EXPORT QQmlMetaObject
-{
-public:
- typedef QVarLengthArray<int, 9> ArgTypeStorage;
-
- inline QQmlMetaObject();
- inline QQmlMetaObject(QObject *);
- inline QQmlMetaObject(const QMetaObject *);
- inline QQmlMetaObject(QQmlPropertyCache *);
- inline QQmlMetaObject(const QQmlMetaObject &);
-
- inline QQmlMetaObject &operator=(const QQmlMetaObject &);
-
- inline bool isNull() const;
-
- inline const char *className() const;
- inline int propertyCount() const;
-
- inline bool hasMetaObject() const;
- inline const QMetaObject *metaObject() const;
-
- QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
-
- int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
-
- static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
-
- // static_metacall (on Gadgets) doesn't call the base implementation and therefore
- // we need a helper to find the correct meta object and property/method index.
- static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
-
-protected:
- QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
- int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
-
-};
-
-class QQmlObjectOrGadget: public QQmlMetaObject
-{
-public:
- QQmlObjectOrGadget(QObject *obj)
- : QQmlMetaObject(obj),
- ptr(obj)
- {}
- QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
- : QQmlMetaObject(propertyCache)
- , ptr(gadget)
- {}
-
- void metacall(QMetaObject::Call type, int index, void **argv) const;
-
-private:
- QBiPointer<QObject, void> ptr;
-
-protected:
- QQmlObjectOrGadget(const QMetaObject* metaObject)
- : QQmlMetaObject(metaObject)
- {}
-
-};
-
-class QQmlStaticMetaObject : public QQmlObjectOrGadget {
-public:
- QQmlStaticMetaObject(const QMetaObject* metaObject)
- : QQmlObjectOrGadget(metaObject)
- {}
- int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
-};
-
-QQmlPropertyRawData::Flags::Flags()
- : _otherBits(0)
- , isConstant(false)
- , isWritable(false)
- , isResettable(false)
- , isAlias(false)
- , isFinal(false)
- , isOverridden(false)
- , isDirect(false)
- , type(OtherType)
- , isVMEFunction(false)
- , hasArguments(false)
- , isSignal(false)
- , isVMESignal(false)
- , isV4Function(false)
- , isSignalHandler(false)
- , isOverload(false)
- , isCloned(false)
- , isConstructor(false)
- , notFullyResolved(false)
- , overrideIndexIsProperty(false)
-{}
-
-bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const
-{
- return isConstant == other.isConstant &&
- isWritable == other.isWritable &&
- isResettable == other.isResettable &&
- isAlias == other.isAlias &&
- isFinal == other.isFinal &&
- isOverridden == other.isOverridden &&
- type == other.type &&
- isVMEFunction == other.isVMEFunction &&
- hasArguments == other.hasArguments &&
- isSignal == other.isSignal &&
- isVMESignal == other.isVMESignal &&
- isV4Function == other.isV4Function &&
- isSignalHandler == other.isSignalHandler &&
- isOverload == other.isOverload &&
- isCloned == other.isCloned &&
- isConstructor == other.isConstructor &&
- notFullyResolved == other.notFullyResolved &&
- overrideIndexIsProperty == other.overrideIndexIsProperty;
-}
-
-void QQmlPropertyRawData::Flags::copyPropertyTypeFlags(QQmlPropertyRawData::Flags from)
-{
- switch (from.type) {
- case QObjectDerivedType:
- case EnumType:
- case QListType:
- case QmlBindingType:
- case QJSValueType:
- case V4HandleType:
- case QVariantType:
- type = from.type;
- }
-}
-
-QQmlPropertyData::QQmlPropertyData()
-{
- setCoreIndex(-1);
- setPropType(0);
- setNotifyIndex(-1);
- setOverrideIndex(-1);
- setRevision(0);
- setMetaObjectOffset(-1);
- setArguments(nullptr);
- trySetStaticMetaCallFunction(nullptr, 0);
-}
-
-QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
-{
- *(static_cast<QQmlPropertyRawData *>(this)) = d;
-}
-
-bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
-{
- return flags() == other.flags() &&
- propType() == other.propType() &&
- coreIndex() == other.coreIndex() &&
- notifyIndex() == other.notifyIndex() &&
- revision() == other.revision();
-}
-
inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
{
if (p && Q_UNLIKELY(p->notFullyResolved()))
@@ -880,124 +401,6 @@ bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
return false;
}
-QQmlMetaObject::QQmlMetaObject()
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(QObject *o)
-{
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
- else _m = o->metaObject();
- }
-}
-
-QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
-: _m(m)
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
-: _m(m)
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
-: _m(o._m)
-{
-}
-
-QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
-{
- _m = o._m;
- return *this;
-}
-
-bool QQmlMetaObject::isNull() const
-{
- return _m.isNull();
-}
-
-const char *QQmlMetaObject::className() const
-{
- if (_m.isNull()) {
- return nullptr;
- } else if (_m.isT1()) {
- return _m.asT1()->className();
- } else {
- return _m.asT2()->className();
- }
-}
-
-int QQmlMetaObject::propertyCount() const
-{
- if (_m.isNull()) {
- return 0;
- } else if (_m.isT1()) {
- return _m.asT1()->propertyCount();
- } else {
- return _m.asT2()->propertyCount();
- }
-}
-
-bool QQmlMetaObject::hasMetaObject() const
-{
- return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
-}
-
-const QMetaObject *QQmlMetaObject::metaObject() const
-{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1()->createMetaObject();
- else return _m.asT2();
-}
-
-class QQmlPropertyCacheVector
-{
-public:
- QQmlPropertyCacheVector() {}
- QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
- : data(std::move(other.data)) {}
- QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
- QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
- data.swap(moved);
- return *this;
- }
-
- ~QQmlPropertyCacheVector() { clear(); }
- void resize(int size) { return data.resize(size); }
- int count() const { return data.count(); }
- void clear()
- {
- for (int i = 0; i < data.count(); ++i) {
- if (QQmlPropertyCache *cache = data.at(i).data())
- cache->release();
- }
- data.clear();
- }
-
- void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
- QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
- void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
- if (QQmlPropertyCache *oldCache = data.at(index).data()) {
- if (replacement.data() == oldCache)
- return;
- oldCache->release();
- }
- data[index] = replacement.data();
- replacement->addref();
- }
-
- void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
- bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
-private:
- Q_DISABLE_COPY(QQmlPropertyCacheVector)
- QVector<QFlagPointer<QQmlPropertyCache>> data;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
-
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHE_P_H
diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index fb54da5b73..034ebfc743 100644
--- a/src/qml/compiler/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -45,6 +45,35 @@ QT_BEGIN_NAMESPACE
QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
+
+int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type)
+{
+ switch (type) {
+ case QV4::CompiledData::BuiltinType::Var: return QMetaType::QVariant;
+ case QV4::CompiledData::BuiltinType::Variant: return QMetaType::QVariant;
+ case QV4::CompiledData::BuiltinType::Int: return QMetaType::Int;
+ case QV4::CompiledData::BuiltinType::Bool: return QMetaType::Bool;
+ case QV4::CompiledData::BuiltinType::Real: return QMetaType::Double;
+ case QV4::CompiledData::BuiltinType::String: return QMetaType::QString;
+ case QV4::CompiledData::BuiltinType::Url: return QMetaType::QUrl;
+ case QV4::CompiledData::BuiltinType::Color: return QMetaType::QColor;
+ case QV4::CompiledData::BuiltinType::Font: return QMetaType::QFont;
+ case QV4::CompiledData::BuiltinType::Time: return QMetaType::QTime;
+ case QV4::CompiledData::BuiltinType::Date: return QMetaType::QDate;
+ case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::QDateTime;
+ case QV4::CompiledData::BuiltinType::Rect: return QMetaType::QRectF;
+ case QV4::CompiledData::BuiltinType::Point: return QMetaType::QPointF;
+ case QV4::CompiledData::BuiltinType::Size: return QMetaType::QSizeF;
+ case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType::QVector2D;
+ case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType::QVector3D;
+ case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType::QVector4D;
+ case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType::QMatrix4x4;
+ case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType::QQuaternion;
+ case QV4::CompiledData::BuiltinType::InvalidBuiltin: break;
+ };
+ return QMetaType::UnknownType;
+}
+
QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
: referencingObjectIndex(referencingObjectIndex)
@@ -64,7 +93,9 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
- instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, &notInRevision, QmlIR::PropertyResolver::IgnoreRevision);
+ instantiatingProperty = QQmlPropertyResolver(referencingObjectPropertyCache)
+ .property(instantiatingPropertyName, &notInRevision,
+ QQmlPropertyResolver::IgnoreRevision);
return instantiatingProperty != nullptr;
}
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 901602d17b..39778aa328 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -52,9 +52,22 @@
#include <private/qqmlvaluetype_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmlmetaobject_p.h>
+#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmltypedata_p.h>
QT_BEGIN_NAMESPACE
+inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
+ const QString &description)
+{
+ QQmlJS::DiagnosticMessage error;
+ error.line = location.line;
+ error.column = location.column;
+ error.message = description;
+ return error;
+}
+
struct QQmlBindingInstantiationContext {
QQmlBindingInstantiationContext() {}
QQmlBindingInstantiationContext(int referencingObjectIndex,
@@ -82,6 +95,8 @@ struct QQmlPropertyCacheCreatorBase
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
public:
static QAtomicInt classIndexCounter;
+
+ static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
};
template <typename ObjectContainer>
@@ -95,12 +110,14 @@ public:
QQmlEnginePrivate *enginePrivate,
const ObjectContainer *objectContainer, const QQmlImports *imports);
- QQmlCompileError buildMetaObjects();
+ QQmlJS::DiagnosticMessage buildMetaObjects();
protected:
- QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
- QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
+ QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
+ QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const;
+ QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
+
+ int metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
QString stringAt(int index) const { return objectContainer->stringAt(index); }
@@ -126,18 +143,27 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
{
QQmlBindingInstantiationContext context;
return buildMetaObjectRecursively(/*root object*/0, context);
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
{
+ auto isAddressable = [](const QUrl &url) {
+ const QString fileName = url.fileName();
+ return !fileName.isEmpty() && fileName.front().isUpper();
+ };
+
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0
+ || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
+ || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || (objectIndex == 0 && isAddressable(objectContainer->url())))
+ && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0;
if (!needVMEMetaObject) {
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
@@ -153,8 +179,8 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
- if (error.isSet())
+ QQmlJS::DiagnosticMessage error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ if (error.isValid())
return error;
}
} else {
@@ -168,16 +194,16 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
{
- QQmlCompileError error;
+ QQmlJS::DiagnosticMessage error;
baseTypeCache = propertyCacheForObject(obj, context, &error);
- if (error.isSet())
+ if (error.isValid())
return error;
}
if (baseTypeCache) {
if (needVMEMetaObject) {
- QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache);
- if (error.isSet())
+ QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache);
+ if (error.isValid())
return error;
} else {
propertyCaches->set(objectIndex, baseTypeCache);
@@ -198,18 +224,18 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
if (!context.resolveInstantiatingProperty())
pendingGroupPropertyBindings->append(context);
- QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context);
- if (error.isSet())
+ QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context);
+ if (error.isValid())
return error;
}
}
- QQmlCompileError noError;
+ QQmlJS::DiagnosticMessage noError;
return noError;
}
template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const
+inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const
{
if (context.instantiatingProperty) {
return context.instantiatingPropertyCache(enginePrivate);
@@ -219,15 +245,15 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
if (typeRef->isFullyDynamicType) {
if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
+ *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
return nullptr;
}
if (obj->signalCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
+ *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
return nullptr;
}
if (obj->functionCount() > 0) {
- *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
+ *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
return nullptr;
}
}
@@ -239,22 +265,13 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
Q_ASSERT(typeRef);
QQmlType qmltype = typeRef->type;
if (!qmltype.isValid()) {
- QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
- if (imports->resolveType(propertyName, &qmltype, nullptr, nullptr, nullptr)) {
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
+ imports->resolveType(stringAt(context.instantiatingBinding->propertyNameIndex),
+ &qmltype, nullptr, nullptr, nullptr);
}
const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
if (!attachedMo) {
- *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
+ *error = qQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
return nullptr;
}
return enginePrivate->cache(attachedMo);
@@ -263,7 +280,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
{
QQmlRefPointer<QQmlPropertyCache> cache;
cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
@@ -273,33 +290,6 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
propertyCaches->set(objectIndex, cache);
propertyCaches->setNeedsVMEMetaObject(objectIndex);
- struct TypeData {
- QV4::CompiledData::Property::Type dtype;
- int metaType;
- } builtinTypes[] = {
- { QV4::CompiledData::Property::Var, QMetaType::QVariant },
- { QV4::CompiledData::Property::Variant, QMetaType::QVariant },
- { QV4::CompiledData::Property::Int, QMetaType::Int },
- { QV4::CompiledData::Property::Bool, QMetaType::Bool },
- { QV4::CompiledData::Property::Real, QMetaType::Double },
- { QV4::CompiledData::Property::String, QMetaType::QString },
- { QV4::CompiledData::Property::Url, QMetaType::QUrl },
- { QV4::CompiledData::Property::Color, QMetaType::QColor },
- { QV4::CompiledData::Property::Font, QMetaType::QFont },
- { QV4::CompiledData::Property::Time, QMetaType::QTime },
- { QV4::CompiledData::Property::Date, QMetaType::QDate },
- { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime },
- { QV4::CompiledData::Property::Rect, QMetaType::QRectF },
- { QV4::CompiledData::Property::Point, QMetaType::QPointF },
- { QV4::CompiledData::Property::Size, QMetaType::QSizeF },
- { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D },
- { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D },
- { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D },
- { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 },
- { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion }
-};
- static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData);
-
QByteArray newClassName;
if (objectIndex == /*root object*/0) {
@@ -322,18 +312,18 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
int varPropCount = 0;
- QmlIR::PropertyResolver resolver(baseTypeCache);
+ QQmlPropertyResolver resolver(baseTypeCache);
auto p = obj->propertiesBegin();
auto pend = obj->propertiesEnd();
for ( ; p != pend; ++p) {
- if (p->type == QV4::CompiledData::Property::Var)
+ if (p->builtinType() == QV4::CompiledData::BuiltinType::Var)
varPropCount++;
bool notInRevision = false;
QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
if (d && d->isFinal())
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
auto a = obj->aliasesBegin();
@@ -342,7 +332,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
bool notInRevision = false;
QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
if (d && d->isFinal())
- return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
+ return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
int effectivePropertyIndex = cache->propertyIndexCacheStart;
@@ -427,29 +417,13 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
auto end = s->parametersEnd();
for ( ; param != end; ++param, ++i) {
names.append(stringAt(param->nameIndex).toUtf8());
- if (param->type < builtinTypeCount) {
- // built-in type
- paramTypes[i + 1] = builtinTypes[param->type].metaType;
- } else {
- // lazily resolved type
- Q_ASSERT(param->type == QV4::CompiledData::Property::Custom);
- const QString customTypeName = stringAt(param->customTypeNameIndex);
- QQmlType qmltype;
- if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
-
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
-
- paramTypes[i + 1] = compilationUnit->metaTypeId;
- } else {
- paramTypes[i + 1] = qmltype.typeId();
- }
- }
+
+ QString customTypeName;
+ auto type = metaTypeForParameter(param->type, &customTypeName);
+ if (type == QMetaType::UnknownType)
+ return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
+
+ paramTypes[i + 1] = type;
}
}
@@ -459,7 +433,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
QString signalName = stringAt(s->nameIndex);
if (seenSignals.contains(signalName))
- return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
+ return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
seenSignals.insert(signalName);
cache->appendSignal(signalName, flags, effectiveMethodIndex++,
@@ -475,19 +449,28 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
const QString slotName = stringAt(function->nameIndex);
if (seenSignals.contains(slotName))
- return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
// Note: we don't append slotName to the seenSignals list, since we don't
// protect against overriding change signals or methods with properties.
QList<QByteArray> parameterNames;
+ QVector<int> parameterTypes;
auto formal = function->formalsBegin();
auto end = function->formalsEnd();
for ( ; formal != end; ++formal) {
flags.hasArguments = true;
- parameterNames << stringAt(*formal).toUtf8();
+ parameterNames << stringAt(formal->nameIndex).toUtf8();
+ int type = metaTypeForParameter(formal->type);
+ if (type == QMetaType::UnknownType)
+ type = QMetaType::QVariant;
+ parameterTypes << type;
}
- cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames);
+ int returnType = metaTypeForParameter(function->returnType);
+ if (returnType == QMetaType::UnknownType)
+ returnType = QMetaType::QVariant;
+
+ cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes);
}
@@ -501,21 +484,23 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
int propertTypeMinorVersion = 0;
QQmlPropertyData::Flags propertyFlags;
- if (p->type == QV4::CompiledData::Property::Var) {
- propertyType = QMetaType::QVariant;
+ const QV4::CompiledData::BuiltinType type = p->builtinType();
+
+ if (type == QV4::CompiledData::BuiltinType::Var)
propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
- } else if (p->type < builtinTypeCount) {
- propertyType = builtinTypes[p->type].metaType;
- if (p->type == QV4::CompiledData::Property::Variant)
+
+ if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
+ propertyType = metaTypeForPropertyType(type);
+
+ if (type == QV4::CompiledData::BuiltinType::Variant)
propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
} else {
- Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList ||
- p->type == QV4::CompiledData::Property::Custom);
+ Q_ASSERT(!p->isBuiltinType);
QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
- return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
+ if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
+ return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
Q_ASSERT(qmltype.isValid());
@@ -526,27 +511,27 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
auto compilationUnit = tdata->compilationUnit();
- if (p->type == QV4::CompiledData::Property::Custom) {
- propertyType = compilationUnit->metaTypeId;
- } else {
+ if (p->isList) {
propertyType = compilationUnit->listMetaTypeId;
+ } else {
+ propertyType = compilationUnit->metaTypeId;
}
} else {
- if (p->type == QV4::CompiledData::Property::Custom) {
+ if (p->isList) {
+ propertyType = qmltype.qListTypeId();
+ } else {
propertyType = qmltype.typeId();
propertTypeMinorVersion = qmltype.minorVersion();
- } else {
- propertyType = qmltype.qListTypeId();
}
}
- if (p->type == QV4::CompiledData::Property::Custom)
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else
+ if (p->isList)
propertyFlags.type = QQmlPropertyData::Flags::QListType;
+ else
+ propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
}
- if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList)
+ if (!p->isReadOnly && !p->isList)
propertyFlags.isWritable = true;
@@ -559,11 +544,40 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
effectiveSignalIndex++;
}
- QQmlCompileError noError;
+ QQmlJS::DiagnosticMessage noError;
return noError;
}
template <typename ObjectContainer>
+inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
+ QString *customTypeName)
+{
+ if (param.indexIsBuiltinType) {
+ // built-in type
+ return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ }
+
+ // lazily resolved type
+ const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ if (customTypeName)
+ *customTypeName = typeName;
+ QQmlType qmltype;
+ if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr))
+ return QMetaType::UnknownType;
+
+ if (!qmltype.isComposite())
+ return qmltype.typeId();
+
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+
+ auto compilationUnit = tdata->compilationUnit();
+
+ return compilationUnit->metaTypeId;
+}
+
+template <typename ObjectContainer>
class QQmlPropertyCacheAliasCreator
{
public:
@@ -571,13 +585,13 @@ public:
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
- void appendAliasPropertiesToMetaObjects();
+ void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
- QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex);
+ QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex);
- QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyRawData::Flags *propertyFlags);
+ void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv);
+ QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv);
void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
@@ -596,7 +610,7 @@ inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCre
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv)
{
// skip the root object (index 0) as that one does not have a first object index originating
// from a binding.
@@ -606,15 +620,15 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
continue;
const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
+ appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv);
}
const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
+ appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv);
}
template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex)
+inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv)
{
QVector<int> objectsWithAliases;
collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
@@ -654,7 +668,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex);
+ appendAliasesToPropertyCache(component, objectIndex, enginePriv);
} else {
pendingObjects.append(objectIndex);
}
@@ -688,9 +702,8 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
- const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
+ QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv)
{
*type = 0;
bool writable = false;
@@ -714,7 +727,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
if (seenAliases.contains(targetAlias)) {
- return QQmlCompileError(targetAlias->location,
+ return qQmlCompileError(targetAlias->location,
QQmlPropertyCacheCreatorBase::tr("Cyclic alias"));
}
@@ -722,7 +735,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
lastAlias = targetAlias;
} while (lastAlias->aliasToLocalAlias);
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags);
+ return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv);
}
const int targetObjectIndex = objectForId(component, alias.targetObjectId);
@@ -736,7 +749,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
// Can be caused by the alias target not being a valid id or property. E.g.:
// property alias dataValue: dataVal
// invalidAliasComponent { id: dataVal }
- return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ return qQmlCompileError(targetObject.location,
+ QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
}
if (typeRef->type.isValid())
@@ -753,45 +767,62 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
+
QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
- *type = targetProperty->propType();
+ // for deep aliases, valueTypeIndex is always set
+ if (!QQmlValueTypeFactory::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ // deep alias property
+ *type = targetProperty->propType();
+ targetCache = enginePriv->propertyCacheForType(*type);
+ Q_ASSERT(targetCache);
+ targetProperty = targetCache->property(valueTypeIndex);
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
+ *type = targetProperty->propType();
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
} else {
- if (targetProperty->isEnum()) {
- *type = QVariant::Int;
+ // value type or primitive type or enum
+ *type = targetProperty->propType();
+
+ writable = targetProperty->isWritable();
+ resettable = targetProperty->isResettable();
+
+ if (valueTypeIndex != -1) {
+ const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
+ if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
+ *type = QVariant::Int;
+ else
+ *type = valueTypeMetaObject->property(valueTypeIndex).userType();
} else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
+ if (targetProperty->isEnum()) {
+ *type = QVariant::Int;
+ } else {
+ // Copy type flags
+ propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
+ if (targetProperty->isVarProperty())
+ propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
+ }
}
}
}
- propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable;
+ propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable;
propertyFlags->isResettable = resettable;
- return QQmlCompileError();
+ return QQmlJS::DiagnosticMessage();
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
- const CompiledObject &component, int objectIndex)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
+ const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
- return QQmlCompileError();
+ return QQmlJS::DiagnosticMessage();
QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
Q_ASSERT(propertyCache);
@@ -808,8 +839,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl
int type = 0;
int minorVersion = 0;
QQmlPropertyData::Flags propertyFlags;
- QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags);
- if (error.isSet())
+ QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags, enginePriv);
+ if (error.isValid())
return error;
const QString propertyName = objectContainer->stringAt(alias->nameIndex);
@@ -821,7 +852,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl
type, minorVersion, effectiveSignalIndex++);
}
- return QQmlCompileError();
+ return QQmlJS::DiagnosticMessage();
}
template <typename ObjectContainer>
diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
index c8700c3ca5..62f09bdfff 100644
--- a/src/qml/jsruntime/qv4serialize_p.h
+++ b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QV4SERIALIZE_P_H
-#define QV4SERIALIZE_P_H
+#ifndef QQMLPROPERTYCACHEMETODARGUMENTS_P_H
+#define QQMLPROPERTYCACHEMETODARGUMENTS_P_H
//
// W A R N I N G
@@ -51,26 +51,27 @@
// We mean it.
//
+#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
-#include <private/qv4value_p.h>
QT_BEGIN_NAMESPACE
-namespace QV4 {
-
-class Serialize {
+class QString;
+class QQmlPropertyCacheMethodArguments
+{
public:
+ QQmlPropertyCacheMethodArguments *next;
- static QByteArray serialize(const Value &, ExecutionEngine *);
- static ReturnedValue deserialize(const QByteArray &, ExecutionEngine *);
+ //for signal handler rewrites
+ QString *signalParameterStringForJS;
+ int parameterError:1;
+ int argumentsValid:1;
-private:
- static void serialize(QByteArray &, const Value &, ExecutionEngine *);
- static ReturnedValue deserialize(const char *&, ExecutionEngine *);
-};
+ QList<QByteArray> *names;
-}
+ int arguments[1];
+};
QT_END_NAMESPACE
-#endif // QV8WORKER_P_H
+#endif // QQMLPROPERTYCACHEMETODARGUMENTS_P_H
diff --git a/src/qml/debugger/qqmlmemoryprofiler_p.h b/src/qml/qml/qqmlpropertycachevector_p.h
index 12a31a851f..1dff7c61a6 100644
--- a/src/qml/debugger/qqmlmemoryprofiler_p.h
+++ b/src/qml/qml/qqmlpropertycachevector_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLMEMORYPROFILER_H
-#define QQMLMEMORYPROFILER_H
+#ifndef QQMLPROPERTYCACHEVECTOR_P_H
+#define QQMLPROPERTYCACHEVECTOR_P_H
//
// W A R N I N G
@@ -51,84 +51,54 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <QUrl>
+#include <private/qflagpointer_p.h>
+#include <private/qqmlpropertycache_p.h>
QT_BEGIN_NAMESPACE
-#if !QT_CONFIG(qml_debug)
-
-#define QML_MEMORY_SCOPE_URL(url)
-#define QML_MEMORY_SCOPE_STRING(s)
-
-#else
-
-class Q_QML_PRIVATE_EXPORT QQmlMemoryScope
+class QQmlPropertyCacheVector
{
public:
- explicit QQmlMemoryScope(const QUrl &url)
- : pushed(false)
- {
- if (Q_UNLIKELY(openLibrary()))
- init(url.path().toUtf8().constData());
+ QQmlPropertyCacheVector() {}
+ QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
+ : data(std::move(other.data)) {}
+ QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
+ QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
+ data.swap(moved);
+ return *this;
}
- explicit QQmlMemoryScope(const char *string)
- : pushed(false)
+ ~QQmlPropertyCacheVector() { clear(); }
+ void resize(int size) { return data.resize(size); }
+ int count() const { return data.count(); }
+ void clear()
{
- if (Q_UNLIKELY(openLibrary()))
- init(string);
+ for (int i = 0; i < data.count(); ++i) {
+ if (QQmlPropertyCache *cache = data.at(i).data())
+ cache->release();
+ }
+ data.clear();
}
- ~QQmlMemoryScope()
- {
- if (Q_UNLIKELY(pushed))
- done();
- }
-
- enum LibraryState
- {
- Unloaded,
- Failed,
- Loaded
- };
-
- static bool openLibrary()
- {
- if (Q_LIKELY(state == Loaded))
- return true;
- if (state == Failed)
- return false;
-
- return doOpenLibrary();
+ void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
+ QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
+ void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
+ if (QQmlPropertyCache *oldCache = data.at(index).data()) {
+ if (replacement.data() == oldCache)
+ return;
+ oldCache->release();
+ }
+ data[index] = replacement.data();
+ replacement->addref();
}
+ void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
+ bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
private:
- Q_NEVER_INLINE void init(const char *string);
- Q_NEVER_INLINE void done();
- Q_NEVER_INLINE static bool doOpenLibrary();
-
- static LibraryState state;
-
- bool pushed;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlMemoryProfiler
-{
-public:
- static void enable();
- static void disable();
- static bool isEnabled();
-
- static void clear();
- static void stats(int *allocCount, int *bytesAllocated);
- static void save(const char *filename);
+ Q_DISABLE_COPY(QQmlPropertyCacheVector)
+ QVector<QFlagPointer<QQmlPropertyCache>> data;
};
-#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url)
-#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s)
-
-#endif
-
QT_END_NAMESPACE
-#endif // QQMLMEMORYPROFILER_H
+
+#endif // QQMLPROPERTYCACHEVECTOR_P_H
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
new file mode 100644
index 0000000000..dec696226e
--- /dev/null
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYDATA_P_H
+#define QQMLPROPERTYDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyCacheMethodArguments;
+class QQmlPropertyData
+{
+public:
+ enum WriteFlag {
+ BypassInterceptor = 0x01,
+ DontRemoveBinding = 0x02,
+ RemoveBindingOnAliasWrite = 0x04
+ };
+ Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
+
+ typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
+
+ struct Flags {
+ enum Types {
+ OtherType = 0,
+ FunctionType = 1, // Is an invokable
+ QObjectDerivedType = 2, // Property type is a QObject* derived type
+ EnumType = 3, // Property type is an enum
+ QListType = 4, // Property type is a QML list
+ QmlBindingType = 5, // Property type is a QQmlBinding*
+ QJSValueType = 6, // Property type is a QScriptValue
+ // Gap, used to be V4HandleType
+ VarPropertyType = 8, // Property type is a "var" property of VMEMO
+ QVariantType = 9 // Property is a QVariant
+ };
+
+ // The _otherBits (which "pad" the Flags struct to align it nicely) are used
+ // to store the relative property index. It will only get used when said index fits. See
+ // trySetStaticMetaCallFunction for details.
+ // (Note: this padding is done here, because certain compilers have surprising behavior
+ // when an enum is declared in-between two bit fields.)
+ enum { BitsLeftInFlags = 10 };
+ unsigned otherBits : BitsLeftInFlags; // align to 32 bits
+
+ // Can apply to all properties, except IsFunction
+ unsigned isConstant : 1; // Has CONST flag
+ unsigned isWritable : 1; // Has WRITE function
+ unsigned isResettable : 1; // Has RESET function
+ unsigned isAlias : 1; // Is a QML alias to another property
+ unsigned isFinal : 1; // Has FINAL flag
+ unsigned isOverridden : 1; // Is overridden by a extension property
+ unsigned isDirect : 1; // Exists on a C++ QMetaObject
+
+ unsigned type : 4; // stores an entry of Types
+
+ // Apply only to IsFunctions
+ unsigned isVMEFunction : 1; // Function was added by QML
+ unsigned hasArguments : 1; // Function takes arguments
+ unsigned isSignal : 1; // Function is a signal
+ unsigned isVMESignal : 1; // Signal was added by QML
+ unsigned isV4Function : 1; // Function takes QQmlV4Function* args
+ unsigned isSignalHandler : 1; // Function is a signal handler
+ unsigned isOverload : 1; // Function is an overload of another function
+ unsigned isCloned : 1; // The function was marked as cloned
+ unsigned isConstructor : 1; // The function was marked is a constructor
+
+ // Internal QQmlPropertyCache flags
+ unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
+ unsigned overrideIndexIsProperty: 1;
+
+ inline Flags();
+ inline bool operator==(const Flags &other) const;
+ inline void copyPropertyTypeFlags(Flags from);
+ };
+
+ inline bool operator==(const QQmlPropertyData &) const;
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f)
+ {
+ unsigned otherBits = m_flags.otherBits;
+ m_flags = f;
+ m_flags.otherBits = otherBits;
+ }
+
+ bool isValid() const { return coreIndex() != -1; }
+
+ bool isConstant() const { return m_flags.isConstant; }
+ bool isWritable() const { return m_flags.isWritable; }
+ void setWritable(bool onoff) { m_flags.isWritable = onoff; }
+ bool isResettable() const { return m_flags.isResettable; }
+ bool isAlias() const { return m_flags.isAlias; }
+ bool isFinal() const { return m_flags.isFinal; }
+ bool isOverridden() const { return m_flags.isOverridden; }
+ bool isDirect() const { return m_flags.isDirect; }
+ bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
+ bool isFunction() const { return m_flags.type == Flags::FunctionType; }
+ bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
+ bool isEnum() const { return m_flags.type == Flags::EnumType; }
+ bool isQList() const { return m_flags.type == Flags::QListType; }
+ bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
+ bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
+ bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
+ bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
+ bool isVMEFunction() const { return m_flags.isVMEFunction; }
+ bool hasArguments() const { return m_flags.hasArguments; }
+ bool isSignal() const { return m_flags.isSignal; }
+ bool isVMESignal() const { return m_flags.isVMESignal; }
+ bool isV4Function() const { return m_flags.isV4Function; }
+ bool isSignalHandler() const { return m_flags.isSignalHandler; }
+ bool isOverload() const { return m_flags.isOverload; }
+ void setOverload(bool onoff) { m_flags.isOverload = onoff; }
+ bool isCloned() const { return m_flags.isCloned; }
+ bool isConstructor() const { return m_flags.isConstructor; }
+
+ bool hasOverride() const { return overrideIndex() >= 0; }
+ bool hasRevision() const { return revision() != 0; }
+
+ bool isFullyResolved() const { return !m_flags.notFullyResolved; }
+
+ int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
+ void setPropType(int pt)
+ {
+ Q_ASSERT(pt >= 0);
+ Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
+ m_propType = quint16(pt);
+ }
+
+ int notifyIndex() const { return m_notifyIndex; }
+ void setNotifyIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ m_notifyIndex = qint16(idx);
+ }
+
+ bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
+ void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
+
+ int overrideIndex() const { return m_overrideIndex; }
+ void setOverrideIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ m_overrideIndex = qint16(idx);
+ }
+
+ int coreIndex() const { return m_coreIndex; }
+ void setCoreIndex(int idx)
+ {
+ Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
+ m_coreIndex = qint16(idx);
+ }
+
+ quint8 revision() const { return m_revision; }
+ void setRevision(quint8 rev)
+ {
+ Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
+ m_revision = quint8(rev);
+ }
+
+ /* If a property is a C++ type, then we store the minor
+ * version of this type.
+ * This is required to resolve property or signal revisions
+ * if this property is used as a grouped property.
+ *
+ * Test.qml
+ * property TextEdit someTextEdit: TextEdit {}
+ *
+ * Test {
+ * someTextEdit.preeditText: "test" //revision 7
+ * someTextEdit.onEditingFinished: console.log("test") //revision 6
+ * }
+ *
+ * To determine if these properties with revisions are available we need
+ * the minor version of TextEdit as imported in Test.qml.
+ *
+ */
+
+ quint8 typeMinorVersion() const { return m_typeMinorVersion; }
+ void setTypeMinorVersion(quint8 rev)
+ {
+ Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
+ m_typeMinorVersion = quint8(rev);
+ }
+
+ QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
+ void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
+
+ int metaObjectOffset() const { return m_metaObjectOffset; }
+ void setMetaObjectOffset(int off)
+ {
+ Q_ASSERT(off >= std::numeric_limits<qint16>::min());
+ Q_ASSERT(off <= std::numeric_limits<qint16>::max());
+ m_metaObjectOffset = qint16(off);
+ }
+
+ StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
+ void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
+ {
+ if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
+ m_flags.otherBits = relativePropertyIndex;
+ m_staticMetaCallFunction = f;
+ }
+ }
+ quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
+
+ static Flags flagsForProperty(const QMetaProperty &);
+ void load(const QMetaProperty &);
+ void load(const QMetaMethod &);
+ QString name(QObject *) const;
+ QString name(const QMetaObject *) const;
+
+ void markAsOverrideOf(QQmlPropertyData *predecessor);
+
+ inline void readProperty(QObject *target, void *property) const
+ {
+ void *args[] = { property, nullptr };
+ readPropertyWithArgs(target, args);
+ }
+
+ inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ {
+ if (hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
+ else if (isDirect())
+ target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
+ else
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
+ }
+
+ bool writeProperty(QObject *target, void *value, WriteFlags flags) const
+ {
+ int status = -1;
+ void *argv[] = { value, nullptr, &status, &flags };
+ if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
+ else if (flags.testFlag(BypassInterceptor) && isDirect())
+ target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
+ else
+ QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
+ return true;
+ }
+
+ static Flags defaultSignalFlags()
+ {
+ Flags f;
+ f.isSignal = true;
+ f.type = Flags::FunctionType;
+ f.isVMESignal = true;
+ return f;
+ }
+
+ static Flags defaultSlotFlags()
+ {
+ Flags f;
+ f.type = Flags::FunctionType;
+ f.isVMEFunction = true;
+ return f;
+ }
+
+private:
+ friend class QQmlPropertyCache;
+ void lazyLoad(const QMetaProperty &);
+ void lazyLoad(const QMetaMethod &);
+ bool notFullyResolved() const { return m_flags.notFullyResolved; }
+
+ Flags m_flags;
+ qint16 m_coreIndex = -1;
+ quint16 m_propType = 0;
+
+ // The notify index is in the range returned by QObjectPrivate::signalIndex().
+ // This is different from QMetaMethod::methodIndex().
+ qint16 m_notifyIndex = -1;
+ qint16 m_overrideIndex = -1;
+
+ quint8 m_revision = 0;
+ quint8 m_typeMinorVersion = 0;
+ qint16 m_metaObjectOffset = -1;
+
+ QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
+ StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
+};
+
+#if QT_POINTER_SIZE == 4
+ Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
+#else // QT_POINTER_SIZE == 8
+ Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
+#endif
+
+bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
+{
+ return flags() == other.flags() &&
+ propType() == other.propType() &&
+ coreIndex() == other.coreIndex() &&
+ notifyIndex() == other.notifyIndex() &&
+ revision() == other.revision();
+}
+
+QQmlPropertyData::Flags::Flags()
+ : otherBits(0)
+ , isConstant(false)
+ , isWritable(false)
+ , isResettable(false)
+ , isAlias(false)
+ , isFinal(false)
+ , isOverridden(false)
+ , isDirect(false)
+ , type(OtherType)
+ , isVMEFunction(false)
+ , hasArguments(false)
+ , isSignal(false)
+ , isVMESignal(false)
+ , isV4Function(false)
+ , isSignalHandler(false)
+ , isOverload(false)
+ , isCloned(false)
+ , isConstructor(false)
+ , notFullyResolved(false)
+ , overrideIndexIsProperty(false)
+{}
+
+bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
+{
+ return isConstant == other.isConstant &&
+ isWritable == other.isWritable &&
+ isResettable == other.isResettable &&
+ isAlias == other.isAlias &&
+ isFinal == other.isFinal &&
+ isOverridden == other.isOverridden &&
+ type == other.type &&
+ isVMEFunction == other.isVMEFunction &&
+ hasArguments == other.hasArguments &&
+ isSignal == other.isSignal &&
+ isVMESignal == other.isVMESignal &&
+ isV4Function == other.isV4Function &&
+ isSignalHandler == other.isSignalHandler &&
+ isOverload == other.isOverload &&
+ isCloned == other.isCloned &&
+ isConstructor == other.isConstructor &&
+ notFullyResolved == other.notFullyResolved &&
+ overrideIndexIsProperty == other.overrideIndexIsProperty;
+}
+
+void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
+{
+ switch (from.type) {
+ case QObjectDerivedType:
+ case EnumType:
+ case QListType:
+ case QmlBindingType:
+ case QJSValueType:
+ case QVariantType:
+ type = from.type;
+ }
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYDATA_P_H
diff --git a/src/qml/qml/qqmlpropertyresolver.cpp b/src/qml/qml/qqmlpropertyresolver.cpp
new file mode 100644
index 0000000000..90eaca0b90
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyresolver.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlpropertyresolver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
+ RevisionCheck check) const
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+
+ // Find the first property
+ while (d && d->isFunction())
+ d = cache->overrideData(d);
+
+ if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return nullptr;
+ } else {
+ return d;
+ }
+}
+
+
+QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
+{
+ if (notInRevision) *notInRevision = false;
+
+ QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+ if (notInRevision) *notInRevision = false;
+
+ while (d && !(d->isFunction()))
+ d = cache->overrideData(d);
+
+ if (d && !cache->isAllowedInRevision(d)) {
+ if (notInRevision) *notInRevision = true;
+ return nullptr;
+ } else if (d && d->isSignal()) {
+ return d;
+ }
+
+ if (name.endsWith(QLatin1String("Changed"))) {
+ QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
+
+ d = property(propName, notInRevision);
+ if (d)
+ return cache->signal(d->notifyIndex());
+ }
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertyresolver_p.h b/src/qml/qml/qqmlpropertyresolver_p.h
new file mode 100644
index 0000000000..df857f242e
--- /dev/null
+++ b/src/qml/qml/qqmlpropertyresolver_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLPROPERTYRESOLVER_P_H
+#define QQMLPROPERTYRESOLVER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlrefcount_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct Q_QML_EXPORT QQmlPropertyResolver
+{
+ QQmlPropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
+ : cache(cache)
+ {}
+
+ QQmlPropertyData *property(int index) const
+ {
+ return cache->property(index);
+ }
+
+ enum RevisionCheck {
+ CheckRevision,
+ IgnoreRevision
+ };
+
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
+ RevisionCheck check = CheckRevision) const;
+
+ // This code must match the semantics of QQmlPropertyPrivate::findSignalByName
+ QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
+
+ QQmlRefPointer<QQmlPropertyCache> cache;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYRESOLVER_P_H
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index d20efe616b..6959b05105 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -40,12 +40,29 @@
#include "qqmlpropertyvalidator_p.h"
#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlirbuilder_p.h>
#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertyresolver_p.h>
+
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+static bool isPrimitiveType(int typeId)
+{
+ switch (typeId) {
+#define HANDLE_PRIMITIVE(Type, id, T) \
+ case QMetaType::Type:
+QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
+#undef HANDLE_PRIMITIVE
+ return true;
+ default:
+ return false;
+ }
+}
+
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
, imports(imports)
@@ -56,7 +73,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c
bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
}
-QVector<QQmlCompileError> QQmlPropertyValidator::validate()
+QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate()
{
return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
}
@@ -79,7 +96,8 @@ struct BindingFinder
}
};
-QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
+QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
+ int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
@@ -92,7 +110,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
if (!propertyCache)
- return QVector<QQmlCompileError>();
+ return QVector<QQmlJS::DiagnosticMessage>();
QQmlCustomParser *customParser = nullptr;
if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
@@ -121,7 +139,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
groupProperties.insert(pos, binding);
}
- QmlIR::PropertyResolver propertyResolver(propertyCache);
+ QQmlPropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
QQmlPropertyData *defaultProperty = nullptr;
@@ -134,7 +152,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
defaultProperty = propertyCache->defaultProperty();
}
- QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
@@ -164,7 +182,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
- QmlIR::PropertyResolver::CheckRevision);
+ QQmlPropertyResolver::CheckRevision);
}
if (notInRevision) {
@@ -202,7 +220,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
= pd
&& QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
&& !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
- const QVector<QQmlCompileError> subObjectValidatorErrors
+ const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
if (!subObjectValidatorErrors.isEmpty())
@@ -259,12 +277,12 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
}
if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding);
- if (bindingError.isSet())
+ QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding);
+ if (bindingError.isValid())
return recordError(bindingError);
} else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- QQmlCompileError bindingError = validateObjectBinding(pd, name, binding);
- if (bindingError.isSet())
+ QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding);
+ if (bindingError.isValid())
return recordError(bindingError);
} else if (binding->isGroupProperty()) {
if (QQmlValueTypeFactory::isValueType(pd->propType())) {
@@ -276,11 +294,21 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- if (!enginePrivate->propertyCacheForType(pd->propType())) {
+ const int typeId = pd->propType();
+ if (isPrimitiveType(typeId)) {
+ return recordError(
+ binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
+ .arg(name)
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
+ );
+ }
+
+ if (!enginePrivate->propertyCacheForType(typeId)) {
return recordError(binding->location,
tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
.arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(pd->propType())))
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
);
}
}
@@ -315,30 +343,30 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
customParser->validator = nullptr;
customParser->engine = nullptr;
customParser->imports = (QQmlImports*)nullptr;
- QVector<QQmlCompileError> parserErrors = customParser->errors();
+ QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors();
if (!parserErrors.isEmpty())
return parserErrors;
}
(*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
- QVector<QQmlCompileError> noError;
+ QVector<QQmlJS::DiagnosticMessage> noError;
return noError;
}
-QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
{
if (property->isQList()) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
}
- QQmlCompileError noError;
+ QQmlJS::DiagnosticMessage noError;
if (property->isEnum()) {
if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
return noError;
- QString value = binding->valueAsString(compilationUnit.data());
+ QString value = compilationUnit->bindingValueAsString(binding);
QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
bool ok;
if (p.isFlagType()) {
@@ -347,7 +375,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
if (!ok) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
+ return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
}
return noError;
}
@@ -364,7 +392,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
enginePrivate->warning(warning);
return noError;
}
- return QQmlCompileError(binding->valueLocation, error);
+ return qQmlCompileError(binding->valueLocation, error);
};
switch (property->propType()) {
@@ -396,7 +424,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::UInt: {
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber(compilationUnit->constants);
+ double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
}
@@ -405,7 +433,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::Int: {
if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double d = binding->valueAsNumber(compilationUnit->constants);
+ double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
}
@@ -426,7 +454,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::Color: {
bool ok = false;
- QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: color expected"));
}
@@ -435,7 +463,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
#if QT_CONFIG(datestring)
case QVariant::Date: {
bool ok = false;
- QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: date expected"));
}
@@ -443,7 +471,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::Time: {
bool ok = false;
- QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: time expected"));
}
@@ -451,7 +479,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::DateTime: {
bool ok = false;
- QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: datetime expected"));
}
@@ -460,7 +488,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
#endif // datestring
case QVariant::Point: {
bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
@@ -468,7 +496,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::PointF: {
bool ok = false;
- QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
@@ -476,7 +504,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::Size: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
@@ -484,7 +512,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::SizeF: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
@@ -492,7 +520,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::Rect: {
bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: rect expected"));
}
@@ -500,7 +528,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
break;
case QVariant::RectF: {
bool ok = false;
- QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok);
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
@@ -517,7 +545,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float xp;
float yp;
} vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
return warnOrError(tr("Invalid property assignment: 2D vector expected"));
}
}
@@ -528,7 +556,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float yp;
float zy;
} vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
return warnOrError(tr("Invalid property assignment: 3D vector expected"));
}
}
@@ -540,7 +568,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float zy;
float wp;
} vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
+ if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
return warnOrError(tr("Invalid property assignment: 4D vector expected"));
}
}
@@ -552,12 +580,13 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
float yp;
float zp;
} vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) {
+ if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
return warnOrError(tr("Invalid property assignment: quaternion expected"));
}
}
break;
case QVariant::RegExp:
+ case QVariant::RegularExpression:
return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
default: {
// generate single literal value assignment to a list property if required
@@ -569,7 +598,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
} else if (property->propType() == qMetaTypeId<QList<int> >()) {
bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
if (ok) {
- double n = binding->valueAsNumber(compilationUnit->constants);
+ double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
ok = false;
}
@@ -627,23 +656,23 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
return false;
}
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
+QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
{
- QVector<QQmlCompileError> errors;
- errors.append(QQmlCompileError(location, description));
+ QVector<QQmlJS::DiagnosticMessage> errors;
+ errors.append(qQmlCompileError(location, description));
return errors;
}
-QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const
+QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const
{
- QVector<QQmlCompileError> errors;
+ QVector<QQmlJS::DiagnosticMessage> errors;
errors.append(error);
return errors;
}
-QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
{
- QQmlCompileError noError;
+ QQmlJS::DiagnosticMessage noError;
if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
@@ -667,59 +696,73 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
}
if (!isValueSource && !isPropertyInterceptor) {
- return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
+ return qQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
}
return noError;
}
- if (QQmlMetaType::isInterface(property->propType())) {
+ const int propType = property->propType();
+ const auto rhsType = [&]() {
+ return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex);
+ };
+
+ if (QQmlMetaType::isInterface(propType)) {
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType());
+ const int listType = enginePrivate->listType(propType);
if (!QQmlMetaType::isInterface(listType)) {
QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
}
}
return noError;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
- } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- auto typeName = QMetaType::typeName(property->propType());
- return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
- .arg(propertyName));
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
- return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
+ } else if (isPrimitiveType(propType)) {
+ auto typeName = QMetaType::typeName(propType);
+ return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
+ .arg(rhsType())
+ .arg(propertyName)
+ .arg(typeName));
+ } else if (QQmlValueTypeFactory::isValueType(propType)) {
+ return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
+ .arg(rhsType()).arg(propertyName));
+ } else if (propType == qMetaTypeId<QQmlScriptString>()) {
+ return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else {
// We want to use the raw metaObject here as the raw metaobject is the
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
// Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1);
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
if (propertyMetaObject) {
+ // Will be true if the assigned type inherits propertyMetaObject
+ // Determine isAssignable value
+ bool isAssignable = false;
QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
}
- }
- if (!isAssignable) {
- return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ if (!isAssignable) {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
+ .arg(rhsType()).arg(QLatin1String(QMetaType::typeName(propType))));
+ }
+ } else {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
+ .arg(QLatin1String(QMetaType::typeName(propType))));
}
+
}
return noError;
}
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h
index e9ae844ccb..74a1281927 100644
--- a/src/qml/compiler/qqmlpropertyvalidator_p.h
+++ b/src/qml/qml/qqmlpropertyvalidator_p.h
@@ -50,7 +50,13 @@
// We mean it.
//
-#include <private/qqmltypecompiler_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qv4compileddata_p.h>
+
+#include <QtCore/qcoreapplication.h>
QT_BEGIN_NAMESPACE
@@ -58,32 +64,40 @@ class QQmlPropertyValidator
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
- QVector<QQmlCompileError> validate();
+ QVector<QQmlJS::DiagnosticMessage> validate();
private:
- QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const;
- QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
- QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
+ QVector<QQmlJS::DiagnosticMessage> validateObject(
+ int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
+ bool populatingValueTypeGroupProperty = false) const;
+ QQmlJS::DiagnosticMessage validateLiteralBinding(
+ QQmlPropertyCache *propertyCache, QQmlPropertyData *property,
+ const QV4::CompiledData::Binding *binding) const;
+ QQmlJS::DiagnosticMessage validateObjectBinding(
+ QQmlPropertyData *property, const QString &propertyName,
+ const QV4::CompiledData::Binding *binding) const;
bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const;
- Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const;
+ Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError(
+ const QV4::CompiledData::Location &location, const QString &description) const;
+ Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError(
+ const QQmlJS::DiagnosticMessage &error) const;
QString stringAt(int index) const { return compilationUnit->stringAt(index); }
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
+ QV4::ResolvedTypeReference *resolvedType(int id) const
{
return compilationUnit->resolvedType(id);
}
QQmlEnginePrivate *enginePrivate;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
const QQmlImports &imports;
const QV4::CompiledData::Unit *qmlUnit;
const QQmlPropertyCacheVector &propertyCaches;
- QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
+ QVector<QV4::BindingPropertyData> * const bindingPropertyDataPerObject;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
new file mode 100644
index 0000000000..6ac30d3ab5
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qv4runtimecodegen_p.h>
+#include <private/qv4script_p.h>
+
+#include <QtCore/qloggingcategory.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
+ : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
+ , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
+{
+}
+
+QQmlScriptBlob::~QQmlScriptBlob()
+{
+}
+
+QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
+{
+ return m_scriptData;
+}
+
+void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
+{
+ if (!diskCacheDisabled() || diskCacheForced()) {
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
+ = QV4::ExecutableCompilationUnit::create();
+ QString error;
+ if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ initializeFromCompilationUnit(unit);
+ return;
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
+ }
+ }
+
+ if (!data.exists()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ return;
+ }
+
+ QString error;
+ QString source = data.readAll(&error);
+ if (!error.isEmpty()) {
+ setError(error);
+ return;
+ }
+
+ QV4::CompiledData::CompilationUnit unit;
+
+ if (m_isModule) {
+ QList<QQmlJS::DiagnosticMessage> diagnostics;
+ unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source,
+ data.sourceTimeStamp(), &diagnostics);
+ QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ } else {
+ QmlIR::Document irUnit(isDebugging());
+
+ irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
+
+ QmlIR::ScriptDirectivesCollector collector(&irUnit);
+ irUnit.jsParserEngine.setDirectives(&collector);
+
+ QList<QQmlError> errors;
+ irUnit.javaScriptCompilationUnit = QV4::Script::precompile(
+ &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
+
+ source.clear();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+
+ QmlIR::QmlUnitGenerator qmlGenerator;
+ qmlGenerator.generate(irUnit);
+ unit = std::move(irUnit.javaScriptCompilationUnit);
+ }
+
+ auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
+
+ if ((!diskCacheDisabled() || diskCacheForced()) && !isDebugging()) {
+ QString errorString;
+ if (executableUnit->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ // ignore error, keep using the in-memory compilation unit.
+ }
+ } else {
+ qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
+ << executableUnit->fileName() << "to disk:" << errorString;
+ }
+ }
+
+ initializeFromCompilationUnit(executableUnit);
+}
+
+void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
+ QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
+}
+
+void QQmlScriptBlob::done()
+{
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ if (!m_isModule) {
+ m_scriptData->typeNameCache.adopt(new QQmlTypeNameCache(m_importCache));
+
+ QSet<QString> ns;
+
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const ScriptReference &script = m_scripts.at(scriptIndex);
+
+ m_scriptData->scripts.append(script.script);
+
+ if (!script.nameSpace.isNull()) {
+ if (!ns.contains(script.nameSpace)) {
+ ns.insert(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
+ }
+ }
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ }
+
+ m_importCache.populateCache(m_scriptData->typeNameCache.data());
+ }
+ m_scripts.clear();
+}
+
+QString QQmlScriptBlob::stringAt(int index) const
+{
+ return m_scriptData->m_precompiledScript->stringAt(index);
+}
+
+void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+ ref.nameSpace = nameSpace;
+
+ m_scripts << ref;
+}
+
+void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData.adopt(new QQmlScriptData());
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_precompiledScript = unit;
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> script = m_scriptData->m_precompiledScript;
+
+ if (!m_isModule) {
+ QList<QQmlError> errors;
+ for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = script->importAt(i);
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return;
+ }
+ }
+ }
+
+ auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
+
+ v4->injectModule(unit);
+
+ for (const QString &request: unit->moduleRequests()) {
+ if (v4->moduleForUrl(QUrl(request), unit.data()))
+ continue;
+
+ const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
+ addDependency(blob.data());
+ scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
new file mode 100644
index 0000000000..10c0437e7b
--- /dev/null
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSCRIPTBLOB_P_H
+#define QQMLSCRIPTBLOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlScriptData;
+class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
+{
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlScriptBlob() override;
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QString nameSpace;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+ QQmlRefPointer<QQmlScriptData> scriptData() const;
+
+protected:
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void done() override;
+
+ QString stringAt(int index) const override;
+
+private:
+ void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ void initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit);
+
+ QList<ScriptReference> m_scripts;
+ QQmlRefPointer<QQmlScriptData> m_scriptData;
+ const bool m_isModule;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSCRIPTBLOB_P_H
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
new file mode 100644
index 0000000000..ae268ca904
--- /dev/null
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4module_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlScriptData::QQmlScriptData()
+ : typeNameCache(nullptr)
+ , m_loaded(false)
+{
+}
+
+QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
+{
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+
+ if (m_precompiledScript->isESModule())
+ return nullptr;
+
+ auto qmlContextData = new QQmlContextData();
+
+ qmlContextData->isInternal = true;
+ qmlContextData->isJSContext = true;
+ if (m_precompiledScript->isSharedLibrary())
+ qmlContextData->isPragmaLibraryContext = true;
+ else
+ qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
+ qmlContextData->baseUrl = url;
+ qmlContextData->baseUrlString = urlString;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!typeNameCache->isEmpty()) {
+ qmlContextData->imports = typeNameCache;
+ } else if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->imports = parentQmlContextData->imports;
+ qmlContextData->importedScripts = parentQmlContextData->importedScripts;
+ }
+
+ if (!m_precompiledScript->isSharedLibrary()) {
+ qmlContextData->setParent(parentQmlContextData);
+ } else {
+ qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
+ }
+
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::Scope scope(v4);
+ QV4::ScopedObject scriptsArray(scope);
+ if (qmlContextData->importedScripts.isNullOrUndefined()) {
+ scriptsArray = v4->newArrayObject(scripts.count());
+ qmlContextData->importedScripts.set(v4, scriptsArray);
+ } else {
+ scriptsArray = qmlContextData->importedScripts.valueRef();
+ }
+ QV4::ScopedValue v(scope);
+ for (int ii = 0; ii < scripts.count(); ++ii)
+ scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
+
+ return qmlContextData;
+}
+
+QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
+{
+ if (m_loaded)
+ return m_value.value();
+
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::Scope scope(v4);
+
+ if (!hasEngine()) {
+ addToEngine(parentQmlContextData->engine);
+ addref();
+ }
+
+ QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
+ QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
+ if (qmlContextData)
+ qmlExecutionContext =
+ QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
+
+ QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
+ if (module) {
+ if (qmlContextData) {
+ module->d()->scope->outer.set(v4, qmlExecutionContext->d());
+ qmlExecutionContext->d()->qml()->module.set(v4, module->d());
+ }
+
+ module->evaluate();
+ }
+
+ if (v4->hasException) {
+ QQmlError error = v4->catchExceptionAsQmlError();
+ if (error.isValid())
+ QQmlEnginePrivate::get(v4)->warning(error);
+ }
+
+ QV4::ScopedValue value(scope);
+ if (qmlContextData)
+ value = qmlExecutionContext->d()->qml();
+ else if (module)
+ value = module->d();
+
+ if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
+ m_loaded = true;
+ m_value.set(v4, value);
+ }
+
+ return value->asReturnedValue();
+}
+
+void QQmlScriptData::clear()
+{
+ typeNameCache = nullptr;
+ scripts.clear();
+
+ // An addref() was made when the QQmlCleanup was added to the engine.
+ release();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/types/qquickworkerscript_p.h b/src/qml/qml/qqmlscriptdata_p.h
index 1a8d2ab076..80b65b699c 100644
--- a/src/qml/types/qquickworkerscript_p.h
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQUICKWORKERSCRIPT_P_H
-#define QQUICKWORKERSCRIPT_P_H
+#ifndef QQMLSCRIPTDATA_P_H
+#define QQMLSCRIPTDATA_P_H
//
// W A R N I N G
@@ -51,74 +51,58 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlcleanup_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4persistent_p.h>
+#include <private/qv4executablecompilationunit_p.h>
-#include <QtQml/qqmlparserstatus.h>
-#include <QtCore/qthread.h>
-#include <QtQml/qjsvalue.h>
#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
-
-class QQuickWorkerScript;
-class QQuickWorkerScriptEnginePrivate;
-class QQuickWorkerScriptEngine : public QThread
+class QQmlTypeNameCache;
+class QQmlContextData;
+
+// QQmlScriptData instances are created, uninitialized, by the loader in the
+// load thread. The first time they are used by the VME, they are initialized which
+// creates their v8 objects and they are referenced and added to the engine's cleanup
+// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
+// reference that was created is released but final deletion only occurs once all the
+// references as released. This is all intended to ensure that the v8 resources are
+// only created and destroyed in the main thread :)
+class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
{
-Q_OBJECT
-public:
- QQuickWorkerScriptEngine(QQmlEngine *parent = nullptr);
- ~QQuickWorkerScriptEngine();
-
- int registerWorkerScript(QQuickWorkerScript *);
- void removeWorkerScript(int);
- void executeUrl(int, const QUrl &);
- void sendMessage(int, const QByteArray &);
-
-protected:
- void run() override;
-
private:
- QQuickWorkerScriptEnginePrivate *d;
-};
+ friend class QQmlTypeLoader;
-class QQmlV4Function;
-class QQmlV4Handle;
-class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ QQmlScriptData();
- Q_INTERFACES(QQmlParserStatus)
public:
- QQuickWorkerScript(QObject *parent = nullptr);
- ~QQuickWorkerScript();
-
- QUrl source() const;
- void setSource(const QUrl &);
+ QUrl url;
+ QString urlString;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+ QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
-public Q_SLOTS:
- void sendMessage(QQmlV4Function*);
+ QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
-Q_SIGNALS:
- void sourceChanged();
- void message(const QQmlV4Handle &messageObject);
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
protected:
- void classBegin() override;
- void componentComplete() override;
- bool event(QEvent *) override;
+ void clear() override; // From QQmlCleanup
private:
- QQuickWorkerScriptEngine *engine();
- QQuickWorkerScriptEngine *m_engine;
- int m_scriptId;
- QUrl m_source;
- bool m_componentComplete;
+ friend class QQmlScriptBlob;
+
+ void initialize(QQmlEngine *);
+ QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
+
+ bool m_loaded;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
+ QV4::PersistentValue m_value;
};
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickWorkerScript)
-
-#endif // QQUICKWORKERSCRIPT_P_H
+#endif // QQMLSCRIPTDATA_P_H
diff --git a/src/qml/qml/qqmlsourcecoordinate_p.h b/src/qml/qml/qqmlsourcecoordinate_p.h
new file mode 100644
index 0000000000..55e11fd147
--- /dev/null
+++ b/src/qml/qml/qqmlsourcecoordinate_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSOURCECOORDINATE_P_H
+#define QQMLSOURCECOORDINATE_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/qglobal.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+// These methods are needed because in some public methods we historically interpret -1 as the
+// invalid line or column, even though all the lines and columns are 1-based. Also, the different
+// integer ranges may turn certain large values into invalid ones on conversion.
+
+template<typename From, typename To>
+To qmlConvertSourceCoordinate(From n);
+
+template<>
+inline quint16 qmlConvertSourceCoordinate<int, quint16>(int n)
+{
+ return (n > 0 && n <= int(std::numeric_limits<quint16>::max())) ? quint16(n) : 0;
+}
+
+template<>
+inline quint32 qmlConvertSourceCoordinate<int, quint32>(int n)
+{
+ return n > 0 ? quint32(n) : 0u;
+}
+
+// TODO: In Qt6, change behavior and make the invalid coordinate 0 for the following two methods.
+
+template<>
+inline int qmlConvertSourceCoordinate<quint16, int>(quint16 n)
+{
+ return (n == 0u) ? -1 : int(n);
+}
+
+template<>
+inline int qmlConvertSourceCoordinate<quint32, int>(quint32 n)
+{
+ return (n == 0u || n > quint32(std::numeric_limits<int>::max())) ? -1 : int(n);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLSOURCECOORDINATE_P_H
diff --git a/src/qml/qml/qqmlstaticmetaobject.cpp b/src/qml/qml/qqmlstaticmetaobject.cpp
new file mode 100644
index 0000000000..218d0134fd
--- /dev/null
+++ b/src/qml/qml/qqmlstaticmetaobject.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlstaticmetaobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
+ QByteArray *unknownTypeError) const
+{
+ QMetaMethod m = _m.asT2()->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstaticmetaobject_p.h b/src/qml/qml/qqmlstaticmetaobject_p.h
new file mode 100644
index 0000000000..e1ca496080
--- /dev/null
+++ b/src/qml/qml/qqmlstaticmetaobject_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLSTATICMETAOBJECT_P_H
+#define QQMLSTATICMETAOBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlobjectorgadget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlStaticMetaObject : public QQmlObjectOrGadget {
+public:
+ QQmlStaticMetaObject(const QMetaObject* metaObject)
+ : QQmlObjectOrGadget(metaObject)
+ {}
+ int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSTATICMETAOBJECT_P_H
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
new file mode 100644
index 0000000000..874bcd4bca
--- /dev/null
+++ b/src/qml/qml/qqmltype.cpp
@@ -0,0 +1,885 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltype_p_p.h"
+
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlmetatypedata_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmltypedata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
+ : regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
+ containsRevisionedAttributes(false), baseMetaObject(nullptr),
+ index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false),
+ haveSuperType(false)
+{
+ switch (type) {
+ case QQmlType::CppType:
+ extraData.cd = new QQmlCppTypeData;
+ extraData.cd->allocationSize = 0;
+ extraData.cd->newFunc = nullptr;
+ extraData.cd->parserStatusCast = -1;
+ extraData.cd->extFunc = nullptr;
+ extraData.cd->extMetaObject = nullptr;
+ extraData.cd->customParser = nullptr;
+ extraData.cd->attachedPropertiesFunc = nullptr;
+ extraData.cd->attachedPropertiesType = nullptr;
+ extraData.cd->propertyValueSourceCast = -1;
+ extraData.cd->propertyValueInterceptorCast = -1;
+ extraData.cd->registerEnumClassesUnscoped = true;
+ break;
+ case QQmlType::SingletonType:
+ case QQmlType::CompositeSingletonType:
+ extraData.sd = new QQmlSingletonTypeData;
+ extraData.sd->singletonInstanceInfo = nullptr;
+ break;
+ case QQmlType::InterfaceType:
+ extraData.cd = nullptr;
+ break;
+ case QQmlType::CompositeType:
+ extraData.fd = new QQmlCompositeTypeData;
+ break;
+ default: qFatal("QQmlTypePrivate Internal Error.");
+ }
+}
+
+QQmlTypePrivate::~QQmlTypePrivate()
+{
+ qDeleteAll(scopedEnums);
+ for (const auto &metaObject : metaObjects)
+ free(metaObject.metaObject);
+ switch (regType) {
+ case QQmlType::CppType:
+ delete extraData.cd->customParser;
+ delete extraData.cd;
+ break;
+ case QQmlType::SingletonType:
+ case QQmlType::CompositeSingletonType:
+ delete extraData.sd->singletonInstanceInfo;
+ delete extraData.sd;
+ break;
+ case QQmlType::CompositeType:
+ delete extraData.fd;
+ break;
+ default: //Also InterfaceType, because it has no extra data
+ break;
+ }
+}
+
+QQmlType::QQmlType() = default;
+QQmlType::QQmlType(const QQmlType &) = default;
+QQmlType::QQmlType(QQmlType &&) = default;
+QQmlType &QQmlType::operator =(const QQmlType &other) = default;
+QQmlType &QQmlType::operator =(QQmlType &&other) = default;
+QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {}
+QQmlType::~QQmlType() = default;
+
+QHashedString QQmlType::module() const
+{
+ if (!d)
+ return QHashedString();
+ return d->module;
+}
+
+int QQmlType::majorVersion() const
+{
+ if (!d)
+ return -1;
+ return d->version_maj;
+}
+
+int QQmlType::minorVersion() const
+{
+ if (!d)
+ return -1;
+ return d->version_min;
+}
+
+bool QQmlType::availableInVersion(int vmajor, int vminor) const
+{
+ Q_ASSERT(vmajor >= 0 && vminor >= 0);
+ if (!d)
+ return false;
+ return vmajor == d->version_maj && vminor >= d->version_min;
+}
+
+bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
+{
+ Q_ASSERT(vmajor >= 0 && vminor >= 0);
+ if (!d)
+ return false;
+ return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
+}
+
+QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
+{
+ Q_ASSERT(isComposite());
+ if (!engine)
+ return QQmlType();
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
+ if (td.isNull() || !td->isComplete())
+ return QQmlType();
+ QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
+ const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ return QQmlMetaType::qmlType(mo);
+}
+
+QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *engine) const
+{
+ // similar logic to resolveCompositeBaseType
+ Q_ASSERT(isComposite());
+ if (!engine)
+ return nullptr;
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
+ if (td.isNull() || !td->isComplete())
+ return nullptr;
+ QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
+ return compilationUnit->rootPropertyCache().data();
+}
+
+static bool isPropertyRevisioned(const QMetaObject *mo, int index)
+{
+ int i = index;
+ i -= mo->propertyOffset();
+ if (i < 0 && mo->d.superdata)
+ return isPropertyRevisioned(mo->d.superdata, index);
+
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
+ if (i >= 0 && i < mop->propertyCount) {
+ int handle = mop->propertyData + 3*i;
+ int flags = mo->d.data[handle + 2];
+
+ return (flags & Revisioned);
+ }
+
+ return false;
+}
+
+void QQmlTypePrivate::init() const
+{
+ if (isSetup)
+ return;
+
+ QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
+ if (isSetup)
+ return;
+
+ const QMetaObject *mo = baseMetaObject;
+ if (!mo) {
+ // version 0 singleton type without metaobject information
+ return;
+ }
+
+ if (regType == QQmlType::CppType) {
+ // Setup extended meta object
+ // XXX - very inefficient
+ if (extraData.cd->extFunc) {
+ QMetaObjectBuilder builder;
+ QQmlMetaType::clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject,
+ extraData.cd->extMetaObject);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = mo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
+ metaObjects << data;
+ }
+ }
+
+ metaObjects.append(QQmlMetaType::proxyData(
+ mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
+ : metaObjects.constLast().metaObject));
+
+ for (int ii = 0; ii < metaObjects.count(); ++ii) {
+ metaObjects[ii].propertyOffset =
+ metaObjects.at(ii).metaObject->propertyOffset();
+ metaObjects[ii].methodOffset =
+ metaObjects.at(ii).metaObject->methodOffset();
+ }
+
+ // Check for revisioned details
+ {
+ const QMetaObject *mo = nullptr;
+ if (metaObjects.isEmpty())
+ mo = baseMetaObject;
+ else
+ mo = metaObjects.constFirst().metaObject;
+
+ for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
+ if (isPropertyRevisioned(mo, ii))
+ containsRevisionedAttributes = true;
+ }
+
+ for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
+ if (mo->method(ii).revision() != 0)
+ containsRevisionedAttributes = true;
+ }
+ }
+
+ isSetup = true;
+ lock.unlock();
+}
+
+void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
+{
+ const QQmlPropertyCache *cache = (!isEnumFromCacheSetup && isComposite())
+ ? compositePropertyCache(engine)
+ : nullptr;
+
+ const QMetaObject *metaObject = !isEnumFromCacheSetup
+ ? baseMetaObject // beware: It could be a singleton type without metaobject
+ : nullptr;
+
+ if (!cache && !metaObject)
+ return;
+
+ init();
+
+ QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
+
+ if (cache) {
+ insertEnumsFromPropertyCache(cache);
+ isEnumFromCacheSetup = true;
+ }
+
+ if (metaObject) {
+ insertEnums(metaObject);
+ isEnumFromBaseSetup = true;
+ }
+}
+
+void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
+{
+ // Add any enum values defined by 'related' classes
+ if (metaObject->d.relatedMetaObjects) {
+ const auto *related = metaObject->d.relatedMetaObjects;
+ if (related) {
+ while (*related)
+ insertEnums(*related++);
+ }
+ }
+
+ QSet<QString> localEnums;
+ const QMetaObject *localMetaObject = nullptr;
+
+ // Add any enum values defined by this class, overwriting any inherited values
+ for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ const bool isScoped = e.isScoped();
+ QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr;
+
+ // We allow enums in sub-classes to overwrite enums from base-classes, such as
+ // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin).
+ // This is acceptable because the _use_ of the enum from the QML side requires qualification
+ // anyway, i.e. ListView.Center vs. Item.Center.
+ // However if a class defines two enums with the same value, then that must produce a warning
+ // because it represents a valid conflict.
+ if (e.enclosingMetaObject() != localMetaObject) {
+ localEnums.clear();
+ localMetaObject = e.enclosingMetaObject();
+ }
+
+ for (int jj = 0; jj < e.keyCount(); ++jj) {
+ const QString key = QString::fromUtf8(e.key(jj));
+ const int value = e.value(jj);
+ if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
+ if (localEnums.contains(key)) {
+ auto existingEntry = enums.find(key);
+ if (existingEntry != enums.end() && existingEntry.value() != value) {
+ qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
+ createEnumConflictReport(metaObject, key);
+ }
+ } else {
+ localEnums.insert(key);
+ }
+ enums.insert(key, value);
+ }
+ if (isScoped)
+ scoped->insert(key, value);
+ }
+
+ if (isScoped) {
+ scopedEnums << scoped;
+ scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
+ }
+ }
+}
+
+void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const
+{
+ path.append(QString::fromUtf8(metaObject->className()));
+
+ if (metaObject->d.relatedMetaObjects) {
+ const auto *related = metaObject->d.relatedMetaObjects;
+ if (related) {
+ while (*related)
+ createListOfPossibleConflictingItems(*related++, enumInfoList, path);
+ }
+ }
+
+ for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+ const auto e = metaObject->enumerator(ii);
+
+ for (int jj = 0; jj < e.keyCount(); ++jj) {
+ const QString key = QString::fromUtf8(e.key(jj));
+
+ EnumInfo enumInfo;
+ enumInfo.metaObjectName = QString::fromUtf8(metaObject->className());
+ enumInfo.enumName = QString::fromUtf8(e.name());
+ enumInfo.enumKey = key;
+ enumInfo.scoped = e.isScoped();
+ enumInfo.path = path;
+ enumInfo.metaEnumScope = QString::fromUtf8(e.scope());
+ enumInfoList.append(enumInfo);
+ }
+ }
+}
+
+void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const
+{
+ QList<EnumInfo> enumInfoList;
+
+ if (baseMetaObject) // prefer baseMetaObject if available
+ metaObject = baseMetaObject;
+
+ if (!metaObject) { // If there is no metaObject at all return early
+ qWarning() << "No meta object information available. Skipping conflict analysis.";
+ return;
+ }
+
+ createListOfPossibleConflictingItems(metaObject, enumInfoList, QStringList());
+
+ qWarning().noquote() << QLatin1String("Possible conflicting items:");
+ // find items with conflicting key
+ for (const auto &i : qAsConst(enumInfoList)) {
+ if (i.enumKey == conflictingKey)
+ qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
+ << i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
+ }
+}
+
+void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
+{
+ const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
+
+ while (cache && cache->metaObject() != cppMetaObject) {
+
+ int count = cache->qmlEnumCount();
+ for (int ii = 0; ii < count; ++ii) {
+ QStringHash<int> *scoped = new QStringHash<int>();
+ QQmlEnumData *enumData = cache->qmlEnum(ii);
+
+ for (int jj = 0; jj < enumData->values.count(); ++jj) {
+ const QQmlEnumValue &value = enumData->values.at(jj);
+ enums.insert(value.namedValue, value.value);
+ scoped->insert(value.namedValue, value.value);
+ }
+ scopedEnums << scoped;
+ scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
+ }
+ cache = cache->parent();
+ }
+ insertEnums(cppMetaObject);
+}
+
+void QQmlTypePrivate::setName(const QString &uri, const QString &element)
+{
+ module = uri;
+ elementName = element;
+ name = uri.isEmpty() ? element : (uri + QLatin1Char('/') + element);
+}
+
+QByteArray QQmlType::typeName() const
+{
+ if (d) {
+ if (d->regType == SingletonType || d->regType == CompositeSingletonType)
+ return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
+ else if (d->baseMetaObject)
+ return d->baseMetaObject->className();
+ }
+ return QByteArray();
+}
+
+QString QQmlType::elementName() const
+{
+ if (!d)
+ return QString();
+ return d->elementName;
+}
+
+QString QQmlType::qmlTypeName() const
+{
+ if (!d)
+ return QString();
+ return d->name;
+}
+
+QObject *QQmlType::create() const
+{
+ if (!d || !isCreatable())
+ return nullptr;
+
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
+ d->extraData.cd->newFunc(rv);
+
+ if (rv && !d->metaObjects.isEmpty())
+ (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+
+ return rv;
+}
+
+void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
+{
+ if (!d || !isCreatable())
+ return;
+
+ d->init();
+
+ QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
+ d->extraData.cd->newFunc(rv);
+
+ if (rv && !d->metaObjects.isEmpty())
+ (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+
+ *out = rv;
+ *memory = ((char *)rv) + d->extraData.cd->allocationSize;
+}
+
+QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+{
+ if (!d)
+ return nullptr;
+ if (d->regType != SingletonType && d->regType != CompositeSingletonType)
+ return nullptr;
+ return d->extraData.sd->singletonInstanceInfo;
+}
+
+QQmlCustomParser *QQmlType::customParser() const
+{
+ if (!d)
+ return nullptr;
+ if (d->regType != CppType)
+ return nullptr;
+ return d->extraData.cd->customParser;
+}
+
+QQmlType::CreateFunc QQmlType::createFunction() const
+{
+ if (!d || d->regType != CppType)
+ return nullptr;
+ return d->extraData.cd->newFunc;
+}
+
+QString QQmlType::noCreationReason() const
+{
+ if (!d || d->regType != CppType)
+ return QString();
+ return d->extraData.cd->noCreationReason;
+}
+
+bool QQmlType::isCreatable() const
+{
+ return d && d->regType == CppType && d->extraData.cd->newFunc;
+}
+
+QQmlType::ExtensionFunc QQmlType::extensionFunction() const
+{
+ if (!d || d->regType != CppType)
+ return nullptr;
+ return d->extraData.cd->extFunc;
+}
+
+bool QQmlType::isExtendedType() const
+{
+ if (!d)
+ return false;
+ d->init();
+
+ return !d->metaObjects.isEmpty();
+}
+
+bool QQmlType::isSingleton() const
+{
+ return d && (d->regType == SingletonType || d->regType == CompositeSingletonType);
+}
+
+bool QQmlType::isInterface() const
+{
+ return d && d->regType == InterfaceType;
+}
+
+bool QQmlType::isComposite() const
+{
+ return d && d->isComposite();
+}
+
+bool QQmlType::isCompositeSingleton() const
+{
+ return d && d->regType == CompositeSingletonType;
+}
+
+bool QQmlType::isQObjectSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
+}
+
+bool QQmlType::isQJSValueSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
+}
+
+int QQmlType::typeId() const
+{
+ return d ? d->typeId : -1;
+}
+
+int QQmlType::qListTypeId() const
+{
+ return d ? d->listId : -1;
+}
+
+const QMetaObject *QQmlType::metaObject() const
+{
+ if (!d)
+ return nullptr;
+ d->init();
+
+ if (d->metaObjects.isEmpty())
+ return d->baseMetaObject;
+ else
+ return d->metaObjects.constFirst().metaObject;
+
+}
+
+const QMetaObject *QQmlType::baseMetaObject() const
+{
+ return d ? d->baseMetaObject : nullptr;
+}
+
+bool QQmlType::containsRevisionedAttributes() const
+{
+ if (!d)
+ return false;
+ d->init();
+
+ return d->containsRevisionedAttributes;
+}
+
+int QQmlType::metaObjectRevision() const
+{
+ return d ? d->revision : -1;
+}
+
+QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
+{
+ if (!d)
+ return nullptr;
+ if (d->regType == CppType)
+ return d->extraData.cd->attachedPropertiesFunc;
+
+ QQmlType base;
+ if (d->regType == CompositeType)
+ base = d->resolveCompositeBaseType(engine);
+ return base.attachedPropertiesFunction(engine);
+}
+
+const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
+{
+ if (!d)
+ return nullptr;
+ if (d->regType == CppType)
+ return d->extraData.cd->attachedPropertiesType;
+
+ QQmlType base;
+ if (d->regType == CompositeType)
+ base = d->resolveCompositeBaseType(engine);
+ return base.attachedPropertiesType(engine);
+}
+
+#if QT_DEPRECATED_SINCE(5, 14)
+/*
+This is the id passed to qmlAttachedPropertiesById(). This is different from the index
+for the case that a single class is registered under two or more names (eg. Item in
+Qt 4.7 and QtQuick 1.0).
+*/
+int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
+{
+ if (!d)
+ return -1;
+ if (d->regType == CppType)
+ return d->extraData.cd->attachedPropertiesType ? d->index : -1;
+
+ QQmlType base;
+ if (d->regType == CompositeType)
+ base = d->resolveCompositeBaseType(engine);
+ return base.attachedPropertiesId(engine);
+}
+#endif
+
+int QQmlType::parserStatusCast() const
+{
+ if (!d || d->regType != CppType)
+ return -1;
+ return d->extraData.cd->parserStatusCast;
+}
+
+int QQmlType::propertyValueSourceCast() const
+{
+ if (!d || d->regType != CppType)
+ return -1;
+ return d->extraData.cd->propertyValueSourceCast;
+}
+
+int QQmlType::propertyValueInterceptorCast() const
+{
+ if (!d || d->regType != CppType)
+ return -1;
+ return d->extraData.cd->propertyValueInterceptorCast;
+}
+
+const char *QQmlType::interfaceIId() const
+{
+ if (!d || d->regType != InterfaceType)
+ return nullptr;
+ return d->iid;
+}
+
+int QQmlType::index() const
+{
+ return d ? d->index : -1;
+}
+
+QUrl QQmlType::sourceUrl() const
+{
+ return d ? d->sourceUrl() : QUrl();
+}
+
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->enums.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->enums.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->enums.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
+{
+ Q_UNUSED(engine)
+ Q_ASSERT(ok);
+ *ok = true;
+
+ if (d) {
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
+{
+ Q_UNUSED(engine)
+ Q_ASSERT(ok);
+ *ok = true;
+
+ if (d) {
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
+ if (rv)
+ return *rv;
+ }
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ *ok = true;
+
+ d->initEnums(engine);
+
+ int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
+ if (rv)
+ return *rv;
+ }
+ }
+
+ *ok = false;
+ return -1;
+}
+
+void QQmlType::refHandle(const QQmlTypePrivate *priv)
+{
+ if (priv)
+ priv->addref();
+}
+
+void QQmlType::derefHandle(const QQmlTypePrivate *priv)
+{
+ if (priv)
+ priv->release();
+}
+
+int QQmlType::refCount(const QQmlTypePrivate *priv)
+{
+ if (priv)
+ return priv->count();
+ return -1;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
new file mode 100644
index 0000000000..ec27b38a73
--- /dev/null
+++ b/src/qml/qml/qqmltype_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPE_P_H
+#define QQMLTYPE_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 <functional>
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmlrefcount_p.h>
+
+#include <QtQml/qqmlprivate.h>
+#include <QtQml/qjsvalue.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHashedCStringRef;
+class QQmlTypePrivate;
+class QHashedString;
+class QHashedStringRef;
+class QQmlCustomParser;
+class QQmlEnginePrivate;
+class QQmlPropertyCache;
+
+namespace QV4 {
+struct String;
+}
+
+class Q_QML_PRIVATE_EXPORT QQmlType
+{
+public:
+ QQmlType();
+ QQmlType(const QQmlType &other);
+ QQmlType(QQmlType &&other);
+ QQmlType &operator =(const QQmlType &other);
+ QQmlType &operator =(QQmlType &&other);
+ explicit QQmlType(const QQmlTypePrivate *priv);
+ ~QQmlType();
+
+ bool operator ==(const QQmlType &other) const {
+ return d.data() == other.d.data();
+ }
+
+ bool isValid() const { return !d.isNull(); }
+
+ QByteArray typeName() const;
+ QString qmlTypeName() const;
+ QString elementName() const;
+
+ QHashedString module() const;
+ int majorVersion() const;
+ int minorVersion() const;
+
+ bool availableInVersion(int vmajor, int vminor) const;
+ bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const;
+
+ QObject *create() const;
+ void create(QObject **, void **, size_t) const;
+
+ typedef void (*CreateFunc)(void *);
+ CreateFunc createFunction() const;
+ QQmlCustomParser *customParser() const;
+
+ bool isCreatable() const;
+ typedef QObject *(*ExtensionFunc)(QObject *);
+ ExtensionFunc extensionFunction() const;
+ bool isExtendedType() const;
+ QString noCreationReason() const;
+
+ bool isSingleton() const;
+ bool isInterface() const;
+ bool isComposite() const;
+ bool isCompositeSingleton() const;
+ bool isQObjectSingleton() const;
+ bool isQJSValueSingleton() const;
+
+ int typeId() const;
+ int qListTypeId() const;
+
+ const QMetaObject *metaObject() const;
+ const QMetaObject *baseMetaObject() const;
+ int metaObjectRevision() const;
+ bool containsRevisionedAttributes() const;
+
+ QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
+ const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
+#if QT_DEPRECATED_SINCE(5, 14)
+ QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const;
+#endif
+
+ int parserStatusCast() const;
+ const char *interfaceIId() const;
+ int propertyValueSourceCast() const;
+ int propertyValueInterceptorCast() const;
+
+ int index() const;
+
+ struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ {
+ QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {};
+ const QMetaObject *instanceMetaObject = nullptr;
+ QString typeName;
+ QUrl url; // used by composite singletons
+ };
+ SingletonInstanceInfo *singletonInstanceInfo() const;
+
+ QUrl sourceUrl() const;
+
+ int enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, bool *ok) const;
+ int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const;
+ int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
+
+ const QQmlTypePrivate *priv() const { return d.data(); }
+ static void refHandle(const QQmlTypePrivate *priv);
+ static void derefHandle(const QQmlTypePrivate *priv);
+ static int refCount(const QQmlTypePrivate *priv);
+
+ enum RegistrationType {
+ CppType = 0,
+ SingletonType = 1,
+ InterfaceType = 2,
+ CompositeType = 3,
+ CompositeSingletonType = 4,
+ AnyRegistrationType = 255
+ };
+
+private:
+ friend uint qHash(const QQmlType &t, uint seed);
+ QQmlRefPointer<const QQmlTypePrivate> d;
+};
+
+inline uint qHash(const QQmlType &t, uint seed = 0)
+{
+ return qHash(reinterpret_cast<quintptr>(t.d.data()), seed);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPE_P_H
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
new file mode 100644
index 0000000000..6a2d961de8
--- /dev/null
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPE_P_P_H
+#define QQMLTYPE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltype_p.h>
+#include <private/qstringhash_p.h>
+#include <private/qqmlproxymetaobject_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlpropertycache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypePrivate : public QQmlRefCount
+{
+ Q_DISABLE_COPY_MOVE(QQmlTypePrivate)
+public:
+ QQmlTypePrivate(QQmlType::RegistrationType type);
+
+ void init() const;
+ void initEnums(QQmlEnginePrivate *engine) const;
+ void insertEnums(const QMetaObject *metaObject) const;
+ void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
+
+ QUrl sourceUrl() const
+ {
+ switch (regType) {
+ case QQmlType::CompositeType:
+ return extraData.fd->url;
+ case QQmlType::CompositeSingletonType:
+ return extraData.sd->singletonInstanceInfo->url;
+ default:
+ return QUrl();
+ }
+ }
+
+ bool isComposite() const
+ {
+ return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType;
+ }
+
+ QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
+ QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
+
+ QQmlType::RegistrationType regType;
+
+ struct QQmlCppTypeData
+ {
+ int allocationSize;
+ void (*newFunc)(void *);
+ QString noCreationReason;
+ int parserStatusCast;
+ QObject *(*extFunc)(QObject *);
+ const QMetaObject *extMetaObject;
+ QQmlCustomParser *customParser;
+ QQmlAttachedPropertiesFunc attachedPropertiesFunc;
+ const QMetaObject *attachedPropertiesType;
+ int propertyValueSourceCast;
+ int propertyValueInterceptorCast;
+ bool registerEnumClassesUnscoped;
+ };
+
+ struct QQmlSingletonTypeData
+ {
+ QQmlType::SingletonInstanceInfo *singletonInstanceInfo;
+ };
+
+ struct QQmlCompositeTypeData
+ {
+ QUrl url;
+ };
+
+ union extraData {
+ QQmlCppTypeData* cd;
+ QQmlSingletonTypeData* sd;
+ QQmlCompositeTypeData* fd;
+ } extraData;
+
+ const char *iid;
+ QHashedString module;
+ QString name;
+ QString elementName;
+ int version_maj;
+ int version_min;
+ int typeId;
+ int listId;
+ int revision;
+ mutable bool containsRevisionedAttributes;
+ mutable QQmlType superType;
+ const QMetaObject *baseMetaObject;
+
+ int index;
+ mutable volatile bool isSetup:1;
+ mutable volatile bool isEnumFromCacheSetup:1;
+ mutable volatile bool isEnumFromBaseSetup:1;
+ mutable bool haveSuperType:1;
+ mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
+ mutable QStringHash<int> enums;
+ mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
+ mutable QList<QStringHash<int>*> scopedEnums;
+
+ void setName(const QString &uri, const QString &element);
+
+private:
+ ~QQmlTypePrivate() override;
+
+ struct EnumInfo {
+ QStringList path;
+ QString metaObjectName;
+ QString enumName;
+ QString enumKey;
+ QString metaEnumScope;
+ bool scoped;
+ };
+
+ void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const;
+ void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPE_P_P_H
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 66d3afc7a0..9ff0e3fb9e 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -39,12 +39,11 @@
#include "qqmltypecompiler_p.h"
-#include <private/qqmlirbuilder_p.h>
#include <private/qqmlobjectcreator_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmldelegatecomponent_p.h>
+#include <private/qqmlpropertyresolver_p.h>
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -56,7 +55,7 @@ QT_BEGIN_NAMESPACE
QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, typeData(typeData)
@@ -66,7 +65,7 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *type
{
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
+QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
{
// Build property caches and VME meta object data
@@ -83,8 +82,8 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
{
QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
engine, this, imports());
- QQmlCompileError error = propertyCacheBuilder.buildMetaObjects();
- if (error.isSet()) {
+ QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects();
+ if (error.isValid()) {
recordError(error);
return nullptr;
}
@@ -134,7 +133,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
return nullptr;
}
- if (!document->javaScriptCompilationUnit) {
+ if (!document->javaScriptCompilationUnit.unitData()) {
// Compile JS binding expressions and signal handlers if necessary
{
// We can compile script strings ahead of time, but they must be compiled
@@ -145,11 +144,11 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
- QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
- QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
- if (!jsCodeGen.generateCodeForComponents())
+ QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
+ if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
+ recordError(v4CodeGenerator.error());
return nullptr;
+ }
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
@@ -159,22 +158,17 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
QmlIR::QmlUnitGenerator qmlGenerator;
qmlGenerator.generate(*document, dependencyHasher);
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = document->javaScriptCompilationUnit;
+ if (!errors.isEmpty())
+ return nullptr;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
+ = QV4::ExecutableCompilationUnit::create(std::move(
+ document->javaScriptCompilationUnit));
compilationUnit->typeNameCache = typeNameCache;
compilationUnit->resolvedTypes = *resolvedTypes;
compilationUnit->propertyCaches = std::move(m_propertyCaches);
Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
-
- if (errors.isEmpty())
- return compilationUnit;
- else
- return nullptr;
-}
-
-void QQmlTypeCompiler::recordError(QQmlError error)
-{
- error.setUrl(url());
- errors << error;
+ return compilationUnit;
}
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
@@ -187,9 +181,14 @@ void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location,
errors << error;
}
-void QQmlTypeCompiler::recordError(const QQmlCompileError &error)
+void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message)
{
- recordError(error.location, error.description);
+ QQmlError error;
+ error.setDescription(message.message);
+ error.setLine(message.line);
+ error.setColumn(message.column);
+ error.setUrl(url());
+ errors << error;
}
QString QQmlTypeCompiler::stringAt(int idx) const
@@ -209,7 +208,7 @@ int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
- return document->javaScriptCompilationUnit->unitData();
+ return document->javaScriptCompilationUnit.unitData();
}
const QQmlImports *QQmlTypeCompiler::imports() const
@@ -253,11 +252,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
return &document->jsGenerator.stringTable;
}
-void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
-{
- document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData;
-}
-
QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
{
return object->bindingAsString(document, scriptIndex);
@@ -298,7 +292,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
, imports(typeCompiler->imports())
, customParsers(typeCompiler->customParserCache())
- , illegalNames(typeCompiler->enginePrivate()->v8engine()->illegalNames())
+ , illegalNames(typeCompiler->enginePrivate()->v4engine()->illegalNames())
, propertyCaches(typeCompiler->propertyCaches())
{
}
@@ -333,18 +327,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid()) {
- if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
- if (type.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
- }
- }
- }
+ if (!type.isValid())
+ imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr);
const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
if (!attachedType)
@@ -358,7 +342,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
continue;
- QmlIR::PropertyResolver resolver(propertyCache);
+ QQmlPropertyResolver resolver(propertyCache);
Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
propertyName.remove(0, 2);
@@ -514,7 +498,7 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
- QmlIR::PropertyResolver resolver(propertyCache);
+ QQmlPropertyResolver resolver(propertyCache);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
@@ -723,7 +707,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
const QmlIR::Object *obj = qmlObjects.at(i);
- QmlIR::PropertyResolver resolver(propertyCache);
+ QQmlPropertyResolver resolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
@@ -755,7 +739,7 @@ void QQmlScriptStringScanner::scan()
const QmlIR::Object *obj = qmlObjects.at(i);
- QmlIR::PropertyResolver resolver(propertyCache);
+ QQmlPropertyResolver resolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
@@ -781,9 +765,26 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
{
}
+static bool isUsableComponent(const QMetaObject *metaObject)
+{
+ // The metaObject is a component we're interested in if it either is a QQmlComponent itself
+ // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
+ // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
+
+ if (metaObject == &QQmlComponent::staticMetaObject)
+ return true;
+
+ for (; metaObject; metaObject = metaObject->superClass()) {
+ if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
+ return true;
+ }
+
+ return false;
+}
+
void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
{
- QmlIR::PropertyResolver propertyResolver(propertyCache);
+ QQmlPropertyResolver propertyResolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
@@ -802,15 +803,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
firstMetaObject = tr->type.metaObject();
else if (tr->compilationUnit)
firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- // 1: test for QQmlComponent
- if (firstMetaObject && firstMetaObject == &QQmlComponent::staticMetaObject)
+ if (isUsableComponent(firstMetaObject))
continue;
- // 2: test for QQmlAbstractDelegateComponent
- while (firstMetaObject && firstMetaObject != &QQmlAbstractDelegateComponent::staticMetaObject)
- firstMetaObject = firstMetaObject->superClass();
- if (firstMetaObject)
- continue;
- // if here, not a QQmlComponent or a QQmlAbstractDelegateComponent, so needs wrapping
+ // if here, not a QQmlComponent, so needs wrapping
QQmlPropertyData *pd = nullptr;
if (binding->propertyNameIndex != quint32(0)) {
@@ -846,7 +841,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::CompiledData::ResolvedTypeReference;
+ auto typeRef = new QV4::ResolvedTypeReference;
typeRef->type = componentType;
typeRef->majorVersion = componentType.majorVersion();
typeRef->minorVersion = componentType.minorVersion();
@@ -1012,17 +1007,17 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
for (int objectIndex: qAsConst(_objectsWithAliases)) {
- QQmlCompileError error;
+ QQmlJS::DiagnosticMessage error;
const auto result = resolveAliasesInObject(objectIndex, &error);
- if (error.isSet()) {
+ if (error.isValid()) {
recordError(error);
return false;
}
if (result == AllAliasesResolved) {
- QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex);
- if (error.isSet()) {
+ QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate);
+ if (error.isValid()) {
recordError(error);
return false;
}
@@ -1050,7 +1045,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
return true;
}
-QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error)
+QQmlComponentAndAliasResolver::AliasResolutionResult
+QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
+ QQmlJS::DiagnosticMessage *error)
{
const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
if (!obj->aliasCount())
@@ -1068,7 +1065,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
const int idIndex = alias->idIndex;
const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
break;
}
@@ -1096,11 +1095,13 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
if (!targetCache) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
- QmlIR::PropertyResolver resolver(targetCache);
+ QQmlPropertyResolver resolver(targetCache);
QQmlPropertyData *targetProperty = resolver.property(property.toString());
@@ -1131,7 +1132,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
}
if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
@@ -1140,19 +1143,42 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv
if (!subProperty.isEmpty()) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
if (!valueTypeMetaObject) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
+ // could be a deep alias
+ bool isDeepAlias = subProperty.at(0).isLower();
+ if (isDeepAlias) {
+ isDeepAlias = false;
+ for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
+ auto binding = *it;
+ if (compiler->stringAt(binding.propertyNameIndex) == property) {
+ resolver = QQmlPropertyResolver(propertyCaches.at(binding.value.objectIndex));
+ QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
+ if (actualProperty) {
+ propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
+ isDeepAlias = true;
+ }
+ }
+ }
+ }
+ if (!isDeepAlias) {
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ } else {
- int valueTypeIndex =
- valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
- if (valueTypeIndex == -1) {
- *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
- break;
- }
- Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
+ int valueTypeIndex =
+ valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1) {
+ *error = qQmlCompileError(
+ alias->referenceLocation,
+ tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ break;
+ }
+ Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
- propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
+ propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
+ }
} else {
if (targetProperty->isQObject())
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
@@ -1214,7 +1240,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
- QmlIR::PropertyResolver propertyResolver(propertyCache);
+ QQmlPropertyResolver propertyResolver(propertyCache);
QStringList deferredPropertyNames;
{
@@ -1253,7 +1279,8 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
continue;
bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision, QmlIR::PropertyResolver::CheckRevision);
+ pd = propertyResolver.property(name, &notInRevision,
+ QQmlPropertyResolver::CheckRevision);
}
bool seenSubObjectWithId = false;
@@ -1289,78 +1316,6 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
return true;
}
-QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
- : QQmlCompilePass(typeCompiler)
- , customParsers(typeCompiler->customParserCache())
- , qmlObjects(*typeCompiler->qmlObjects())
- , propertyCaches(typeCompiler->propertyCaches())
- , v4CodeGen(v4CodeGen)
-{
-}
-
-bool QQmlJSCodeGenerator::generateCodeForComponents()
-{
- const QVector<quint32> &componentRoots = compiler->componentRoots();
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool QQmlJSCodeGenerator::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = qmlObjects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
- return false;
-
- return true;
-}
-
-bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = qmlObjects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
- return true;
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
- const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
- if (!jsErrors.isEmpty()) {
- for (const QQmlError &e : jsErrors)
- compiler->recordError(e);
- return false;
- }
-
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
- }
-
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
-
- return true;
-}
-
QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, qmlObjects(*typeCompiler->qmlObjects())
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index a49b97453f..40b0337848 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -81,7 +81,7 @@ struct QQmlTypeCompiler
public:
QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
// --- interface used by QQmlPropertyCacheCreator
@@ -91,15 +91,14 @@ public:
QString stringAt(int idx) const;
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
// ---
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile();
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compile();
QList<QQmlError> compilationErrors() const { return errors; }
- void recordError(QQmlError error);
void recordError(const QV4::CompiledData::Location &location, const QString &description);
- void recordError(const QQmlCompileError &error);
+ void recordError(const QQmlJS::DiagnosticMessage &error);
int registerString(const QString &str);
int registerConstant(QV4::ReturnedValue v);
@@ -118,7 +117,6 @@ public:
QQmlJS::MemoryPool *memoryPool();
QStringRef newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
- void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
@@ -126,7 +124,7 @@ public:
void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
+ QV4::ResolvedTypeReference *resolvedType(int id) const
{
return resolvedTypes->value(id);
}
@@ -154,15 +152,15 @@ struct QQmlCompilePass
protected:
void recordError(const QV4::CompiledData::Location &location, const QString &description) const
{ compiler->recordError(location, description); }
- void recordError(const QQmlCompileError &error)
+ void recordError(const QQmlJS::DiagnosticMessage &error)
{ compiler->recordError(error); }
- QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const
+ QV4::ResolvedTypeReference *resolvedType(int id) const
{ return compiler->resolvedType(id); }
bool containsResolvedType(int id) const
{ return compiler->resolvedTypes->contains(id); }
- QV4::CompiledData::ResolvedTypeReferenceMap::iterator insertResolvedType(
- int id, QV4::CompiledData::ResolvedTypeReference *value)
+ QV4::ResolvedTypeReferenceMap::iterator insertResolvedType(
+ int id, QV4::ResolvedTypeReference *value)
{ return compiler->resolvedTypes->insert(id, value); }
QQmlTypeCompiler *compiler;
@@ -277,7 +275,7 @@ protected:
AllAliasesResolved
};
- AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error);
+ AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlJS::DiagnosticMessage *error);
QQmlEnginePrivate *enginePrivate;
QQmlJS::MemoryPool *pool;
@@ -311,24 +309,6 @@ private:
bool _seenObjectWithId;
};
-// ### merge with QtQml::JSCodeGen and operate directly on object->functionsAndExpressions once old compiler is gone.
-class QQmlJSCodeGenerator : public QQmlCompilePass
-{
-public:
- QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen);
-
- bool generateCodeForComponents();
-
-private:
- bool compileComponent(int componentRoot);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
-
- const QHash<int, QQmlCustomParser*> &customParsers;
- const QVector<QmlIR::Object*> &qmlObjects;
- const QQmlPropertyCacheVector * const propertyCaches;
- QmlIR::JSCodeGen * const v4CodeGen;
-};
-
class QQmlDefaultPropertyMerger : public QQmlCompilePass
{
public:
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
new file mode 100644
index 0000000000..cfdcf6aad5
--- /dev/null
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -0,0 +1,846 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmlirloader_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmltypecompiler_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcryptographichash.h>
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeData::TypeDataCallback::~TypeDataCallback()
+{
+}
+
+QString QQmlTypeData::TypeReference::qualifiedName() const
+{
+ QString result;
+ if (!prefix.isEmpty()) {
+ result = prefix + QLatin1Char('.');
+ }
+ result.append(type.qmlTypeName());
+ return result;
+}
+
+QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
+ : QQmlTypeLoader::Blob(url, QmlFile, manager),
+ m_typesResolved(false), m_implicitImportLoaded(false)
+{
+
+}
+
+QQmlTypeData::~QQmlTypeData()
+{
+ m_scripts.clear();
+ m_compositeSingletons.clear();
+ m_resolvedTypes.clear();
+}
+
+const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
+{
+ return m_scripts;
+}
+
+QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
+{
+ return m_compiledData.data();
+}
+
+void QQmlTypeData::registerCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(!m_callbacks.contains(callback));
+ m_callbacks.append(callback);
+}
+
+void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
+{
+ Q_ASSERT(m_callbacks.contains(callback));
+ m_callbacks.removeOne(callback);
+ Q_ASSERT(!m_callbacks.contains(callback));
+}
+
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (diskCacheDisabled() && !diskCacheForced())
+ return false;
+
+ if (isDebugging())
+ return false;
+
+ QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
+ if (!v4)
+ return false;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ {
+ QString error;
+ if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
+ return false;
+ }
+ }
+
+ if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(std::move(*unit));
+ return true;
+ }
+
+ m_compiledData = unit;
+
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
+ m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return false;
+
+ // find the implicit import
+ for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
+ if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
+ && import->qualifierIndex == 0
+ && import->majorVersion == -1
+ && import->minorVersion == -1) {
+ QList<QQmlError> errors;
+ auto pendingImport = std::make_shared<PendingImport>(this, import);
+ if (!fetchQmldir(qmldirUrl, pendingImport, 1, &errors)) {
+ setError(errors);
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
+ QList<QQmlError> errors;
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void QQmlTypeData::createTypeAndPropertyCaches(
+ const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
+{
+ Q_ASSERT(m_compiledData);
+ m_compiledData->typeNameCache = typeNameCache;
+ m_compiledData->resolvedTypes = resolvedTypeCache;
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
+
+ {
+ QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
+ &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
+ m_compiledData.data(), &m_importCache);
+ QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
+ if (error.isValid()) {
+ setError(error);
+ return;
+ }
+ }
+
+ QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
+ &m_compiledData->propertyCaches, m_compiledData.data());
+ aliasCreator.appendAliasPropertiesToMetaObjects(engine);
+
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+}
+
+static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+{
+ for (const auto &typeRef: typeRefs) {
+ if (typeRef.typeData) {
+ const auto unit = typeRef.typeData->compilationUnit()->unitData();
+ hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
+ } else if (typeRef.type.isValid()) {
+ const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
+ bool ok = false;
+ hash->addData(propertyCache->checksum(&ok));
+ if (!ok)
+ return false;
+ }
+ }
+ return true;
+}
+
+void QQmlTypeData::done()
+{
+ auto cleanup = qScopeGuard([this]{
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError())
+ m_compiledData = nullptr;
+ });
+
+ if (isError())
+ return;
+
+ // Check all script dependencies for errors
+ for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ const ScriptReference &script = m_scripts.at(ii);
+ Q_ASSERT(script.script->isCompleteOrError());
+ if (script.script->isError()) {
+ QList<QQmlError> errors = script.script->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(script.location.line);
+ error.setColumn(script.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ // Check all type dependencies for errors
+ for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ ++it) {
+ const TypeReference &type = *it;
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ const QString typeName = stringAt(it.key());
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ // Check all composite singleton type dependencies for errors
+ for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
+ const TypeReference &type = m_compositeSingletons.at(ii);
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ if (type.typeData && type.typeData->isError()) {
+ QString typeName = type.type.qmlTypeName();
+
+ QList<QQmlError> errors = type.typeData->errors();
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ }
+ }
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+ QV4::ResolvedTypeReferenceMap resolvedTypeCache;
+ {
+ QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ if (error.isValid()) {
+ setError(error);
+ qDeleteAll(resolvedTypeCache);
+ return;
+ }
+ }
+
+ QQmlEngine *const engine = typeLoader()->engine();
+
+ const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ return (resolvedTypeCache.addToHash(&hash, engine)
+ && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
+ ? hash.result()
+ : QByteArray();
+ };
+
+ // verify if any dependencies changed if we're using a cache
+ if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
+ qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
+ if (!loadFromSource())
+ return;
+ m_backupSourceCode = SourceCodeData();
+ m_compiledData = nullptr;
+ }
+
+ if (!m_document.isNull()) {
+ // Compile component
+ compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
+ } else {
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ }
+
+ if (isError())
+ return;
+
+ {
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ {
+ // Sanity check property bindings
+ QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
+ QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
+ if (!errors.isEmpty()) {
+ setError(errors);
+ return;
+ }
+ }
+
+ m_compiledData->finalizeCompositeType(enginePrivate);
+ }
+
+ {
+ QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
+ if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
+ if (!type.isValid()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
+ setError(error);
+ return;
+ } else if (!type.isCompositeSingleton()) {
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
+ setError(error);
+ return;
+ }
+ } else {
+ // If the type is CompositeSingleton but there was no pragma Singleton in the
+ // QML file, lets report an error.
+ if (type.isValid() && type.isCompositeSingleton()) {
+ QString typeName = type.qmlTypeName();
+ setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
+ return;
+ }
+ }
+ }
+
+ {
+ // Collect imported scripts
+ m_compiledData->dependentScripts.reserve(m_scripts.count());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
+
+ QStringRef qualifier(&script.qualifier);
+ QString enclosingNamespace;
+
+ const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
+ if (lastDotIndex != -1) {
+ enclosingNamespace = qualifier.left(lastDotIndex).toString();
+ qualifier = qualifier.mid(lastDotIndex+1);
+ }
+
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
+ m_compiledData->dependentScripts << scriptData;
+ }
+ }
+}
+
+void QQmlTypeData::completed()
+{
+ // Notify callbacks
+ while (!m_callbacks.isEmpty()) {
+ TypeDataCallback *callback = m_callbacks.takeFirst();
+ callback->typeDataReady(this);
+ }
+}
+
+bool QQmlTypeData::loadImplicitImport()
+{
+ m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
+
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
+ // For local urls, add an implicit import "." as most overridden lookup.
+ // This will also trigger the loading of the qmldir and the import of any native
+ // types from available plugins.
+ QList<QQmlError> implicitImportErrors;
+ m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
+
+ if (!implicitImportErrors.isEmpty()) {
+ setError(implicitImportErrors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::dataReceived(const SourceCodeData &data)
+{
+ m_backupSourceCode = data;
+
+ if (tryLoadFromDiskCache())
+ return;
+
+ if (isError())
+ return;
+
+ if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else if (!m_backupSourceCode.exists())
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ else
+ setError(QQmlTypeLoader::tr("File is empty"));
+ return;
+ }
+
+ if (!loadFromSource())
+ return;
+
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QQmlIRLoader loader(unit, m_document.data());
+ loader.load();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
+ m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
+ continueLoadFromIR();
+}
+
+bool QQmlTypeData::loadFromSource()
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
+ QQmlEngine *qmlEngine = typeLoader()->engine();
+ QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames());
+
+ QString sourceError;
+ const QString source = m_backupSourceCode.readAll(&sourceError);
+ if (!sourceError.isEmpty()) {
+ setError(sourceError);
+ return false;
+ }
+
+ if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
+ QList<QQmlError> errors;
+ errors.reserve(compiler.errors.count());
+ for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
+ QQmlError e;
+ e.setUrl(url());
+ e.setLine(msg.line);
+ e.setColumn(msg.column);
+ e.setDescription(msg.message);
+ errors << e;
+ }
+ setError(errors);
+ return false;
+ }
+ return true;
+}
+
+void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QQmlIRLoader loader(unit.unitData(), m_document.data());
+ loader.load();
+ m_document->jsModule.fileName = urlString();
+ m_document->jsModule.finalUrl = finalUrlString();
+ m_document->javaScriptCompilationUnit = std::move(unit);
+ continueLoadFromIR();
+}
+
+void QQmlTypeData::continueLoadFromIR()
+{
+ m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
+ m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+
+ // For remote URLs, we don't delay the loading of the implicit import
+ // because the loading probably requires an asynchronous fetch of the
+ // qmldir (so we can't load it just in time).
+ if (!finalUrl().scheme().isEmpty()) {
+ QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ if (!loadImplicitImport())
+ return;
+ // This qmldir is for the implicit import
+ auto implicitImport = std::make_shared<PendingImport>();
+ implicitImport->uri = QLatin1String(".");
+ implicitImport->majorVersion = -1;
+ implicitImport->minorVersion = -1;
+ QList<QQmlError> errors;
+
+ if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
+ setError(errors);
+ return;
+ }
+ }
+ }
+
+ QList<QQmlError> errors;
+
+ for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
+ if (!addImport(import, &errors)) {
+ Q_ASSERT(errors.size());
+ QQmlError error(errors.takeFirst());
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error); // put it back on the list after filling out information.
+ setError(errors);
+ return;
+ }
+ }
+}
+
+void QQmlTypeData::allDependenciesDone()
+{
+ QQmlTypeLoader::Blob::allDependenciesDone();
+
+ if (!m_typesResolved) {
+ // Check that all imports were resolved
+ QList<QQmlError> errors;
+ auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ for ( ; it != end; ++it) {
+ if ((*it)->priority == 0) {
+ // This import was not resolved
+ for (auto keyIt = m_unresolvedImports.constBegin(),
+ keyEnd = m_unresolvedImports.constEnd();
+ keyIt != keyEnd; ++keyIt) {
+ PendingImportPtr import = *keyIt;
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
+ error.setUrl(m_importCache.baseUrl());
+ error.setLine(import->location.line);
+ error.setColumn(import->location.column);
+ errors.prepend(error);
+ }
+ }
+ }
+ if (errors.size()) {
+ setError(errors);
+ return;
+ }
+
+ resolveTypes();
+ m_typesResolved = true;
+ }
+}
+
+void QQmlTypeData::downloadProgressChanged(qreal p)
+{
+ for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ TypeDataCallback *callback = m_callbacks.at(ii);
+ callback->typeDataProgress(this, p);
+ }
+}
+
+QString QQmlTypeData::stringAt(int index) const
+{
+ if (m_compiledData)
+ return m_compiledData->stringAt(index);
+ return m_document->jsGenerator.stringTable.stringForIndex(index);
+}
+
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
+{
+ Q_ASSERT(m_compiledData.isNull());
+
+ const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData()
+ && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+
+ QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
+ m_compiledData = compiler.compile();
+ if (!m_compiledData) {
+ qDeleteAll(*resolvedTypeCache);
+ resolvedTypeCache->clear();
+ setError(compiler.compilationErrors());
+ return;
+ }
+
+ const bool trySaveToDisk = (!diskCacheDisabled() || diskCacheForced())
+ && !m_document->jsModule.debugMode && !typeRecompilation;
+ if (trySaveToDisk) {
+ QString errorString;
+ if (m_compiledData->saveToDisk(url(), &errorString)) {
+ QString error;
+ if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ // ignore error, keep using the in-memory compilation unit.
+ }
+ } else {
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
+ }
+ }
+}
+
+void QQmlTypeData::resolveTypes()
+{
+ // Add any imported scripts to our resolved set
+ const auto resolvedScripts = m_importCache.resolvedScripts();
+ for (const QQmlImports::ScriptReference &script : resolvedScripts) {
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
+ addDependency(blob.data());
+
+ ScriptReference ref;
+ //ref.location = ...
+ if (!script.qualifier.isEmpty())
+ {
+ ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(script.qualifier);
+ } else {
+ ref.qualifier = script.nameSpace;
+ }
+
+ ref.script = blob;
+ m_scripts << ref;
+ }
+
+ // Lets handle resolved composite singleton types
+ const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
+ TypeReference ref;
+ QString typeName;
+ if (!csRef.prefix.isEmpty()) {
+ typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
+ // Add a reference to the enclosing namespace
+ m_namespaces.insert(csRef.prefix);
+ } else {
+ typeName = csRef.typeName;
+ }
+
+ int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
+ int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
+
+ if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
+ QQmlType::CompositeSingletonType))
+ return;
+
+ if (ref.type.isCompositeSingleton()) {
+ ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
+ if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) {
+ // TODO: give an error message? If so, we should record and show the path of the cycle.
+ continue;
+ }
+ addDependency(ref.typeData.data());
+ ref.prefix = csRef.prefix;
+
+ m_compositeSingletons << ref;
+ }
+ }
+
+ for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
+ unresolvedRef != end; ++unresolvedRef) {
+
+ TypeReference ref; // resolved reference
+
+ const bool reportErrors = unresolvedRef->errorWhenNotFound;
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ const QString name = stringAt(unresolvedRef.key());
+
+ if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
+ unresolvedRef->location.column, reportErrors,
+ QQmlType::AnyRegistrationType) && reportErrors)
+ return;
+
+ if (ref.type.isComposite()) {
+ ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
+ addDependency(ref.typeData.data());
+ }
+ ref.majorVersion = majorVersion;
+ ref.minorVersion = minorVersion;
+
+ ref.location.line = unresolvedRef->location.line;
+ ref.location.column = unresolvedRef->location.column;
+
+ ref.needsCreation = unresolvedRef->needsCreation;
+
+ m_resolvedTypes.insert(unresolvedRef.key(), ref);
+ }
+
+ // ### this allows enums to work without explicit import or instantiation of the type
+ if (!m_implicitImportLoaded)
+ loadImplicitImport();
+}
+
+QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const
+{
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
+
+ for (const QString &ns: m_namespaces)
+ (*typeNameCache)->add(ns);
+
+ // Add any Composite Singletons that were used to the import cache
+ for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
+ (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
+
+ m_importCache.populateCache(typeNameCache->data());
+
+ QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+
+ for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
+ QScopedPointer<QV4::ResolvedTypeReference> ref(new QV4::ResolvedTypeReference);
+ QQmlType qmlType = resolvedType->type;
+ if (resolvedType->typeData) {
+ if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
+ return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
+ }
+ ref->compilationUnit = resolvedType->typeData->compilationUnit();
+ } else if (qmlType.isValid()) {
+ ref->type = qmlType;
+ Q_ASSERT(ref->type.isValid());
+
+ if (resolvedType->needsCreation && !ref->type.isCreatable()) {
+ QString reason = ref->type.noCreationReason();
+ if (reason.isEmpty())
+ reason = tr("Element is not creatable.");
+ return qQmlCompileError(resolvedType->location, reason);
+ }
+
+ if (ref->type.containsRevisionedAttributes()) {
+ ref->typePropertyCache = engine->cache(ref->type,
+ resolvedType->minorVersion);
+ }
+ }
+ ref->majorVersion = resolvedType->majorVersion;
+ ref->minorVersion = resolvedType->minorVersion;
+ ref->doDynamicTypeCheck();
+ resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ }
+ QQmlJS::DiagnosticMessage noError;
+ return noError;
+}
+
+bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ TypeReference &ref, int lineNumber, int columnNumber,
+ bool reportErrors, QQmlType::RegistrationType registrationType)
+{
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+
+ bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
+ &typeNamespace, &errors, registrationType);
+ if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
+ // Lazy loading of implicit import
+ if (loadImplicitImport()) {
+ // Try again to find the type
+ errors.clear();
+ typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
+ &typeNamespace, &errors, registrationType);
+ } else {
+ return false; //loadImplicitImport() hit an error, and called setError already
+ }
+ }
+
+ if ((!typeFound || typeNamespace) && reportErrors) {
+ // Known to not be a type:
+ // - known to be a namespace (Namespace {})
+ // - type with unknown namespace (UnknownNamespace.SomeType {})
+ QQmlError error;
+ if (typeNamespace) {
+ error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
+ } else {
+ if (errors.size()) {
+ error = errors.takeFirst();
+ } else {
+ // this should not be possible!
+ // Description should come from error provided by addImport() function.
+ error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
+ }
+ error.setUrl(m_importCache.baseUrl());
+ error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
+ }
+
+ if (lineNumber != -1)
+ error.setLine(lineNumber);
+ if (columnNumber != -1)
+ error.setColumn(columnNumber);
+
+ errors.prepend(error);
+ setError(errors);
+ return false;
+ }
+
+ return true;
+}
+
+void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+{
+ ScriptReference ref;
+ ref.script = blob;
+ ref.location = location;
+ ref.qualifier = qualifier;
+
+ m_scripts << ref;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
new file mode 100644
index 0000000000..e1d0c900ea
--- /dev/null
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPEDATA_P_H
+#define QQMLTYPEDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypeloader_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
+public:
+ struct TypeReference
+ {
+ TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
+
+ QV4::CompiledData::Location location;
+ QQmlType type;
+ int majorVersion;
+ int minorVersion;
+ QQmlRefPointer<QQmlTypeData> typeData;
+ QString prefix; // used by CompositeSingleton types
+ QString qualifiedName() const;
+ bool needsCreation;
+ };
+
+ struct ScriptReference
+ {
+ QV4::CompiledData::Location location;
+ QString qualifier;
+ QQmlRefPointer<QQmlScriptBlob> script;
+ };
+
+private:
+ friend class QQmlTypeLoader;
+
+ QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+
+public:
+ ~QQmlTypeData() override;
+
+ const QList<ScriptReference> &resolvedScripts() const;
+
+ QV4::ExecutableCompilationUnit *compilationUnit() const;
+
+ // Used by QQmlComponent to get notifications
+ struct TypeDataCallback {
+ virtual ~TypeDataCallback();
+ virtual void typeDataProgress(QQmlTypeData *, qreal) {}
+ virtual void typeDataReady(QQmlTypeData *) {}
+ };
+ void registerCallback(TypeDataCallback *);
+ void unregisterCallback(TypeDataCallback *);
+
+protected:
+ void done() override;
+ void completed() override;
+ void dataReceived(const SourceCodeData &) override;
+ void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void allDependenciesDone() override;
+ void downloadProgressChanged(qreal) override;
+
+ QString stringAt(int index) const override;
+
+private:
+ bool tryLoadFromDiskCache();
+ bool loadFromSource();
+ void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
+ void continueLoadFromIR();
+ void resolveTypes();
+ QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ ) const;
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::ResolvedTypeReferenceMap &resolvedTypeCache);
+ bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
+ bool reportErrors = true,
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
+
+ void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+
+
+ SourceCodeData m_backupSourceCode; // used when cache verification fails.
+ QScopedPointer<QmlIR::Document> m_document;
+ QV4::CompiledData::TypeReferenceMap m_typeReferences;
+
+ QList<ScriptReference> m_scripts;
+
+ QSet<QString> m_namespaces;
+ QList<TypeReference> m_compositeSingletons;
+
+ // map from name index to resolved type
+ // While this could be a hash, a map is chosen here to provide a stable
+ // order, which is used to calculating a check-sum on dependent meta-objects.
+ QMap<int, TypeReference> m_resolvedTypes;
+ bool m_typesResolved:1;
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+
+ QList<TypeDataCallback *> m_callbacks;
+
+ bool m_implicitImportLoaded;
+ bool loadImplicitImport();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEDATA_P_H
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5d3b1cedc5..62007effdd 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -37,77 +37,37 @@
**
****************************************************************************/
-#include "qqmltypeloader_p.h"
-#include "qqmlabstracturlinterceptor.h"
-#include "qqmlexpression_p.h"
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlthread_p.h>
-#include <private/qv4codegen_p.h>
-#include <private/qqmlcomponent_p.h>
+#include <private/qqmltypeloader_p.h>
+
+#include <private/qqmldirdata_p.h>
#include <private/qqmlprofiler_p.h>
-#include <private/qqmlmemoryprofiler_p.h>
-#include <private/qqmltypecompiler_p.h>
-#include <private/qqmlpropertyvalidator_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-#include <private/qv4module_p.h>
+#include <private/qqmlscriptblob_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#include <QtQml/qqmlabstracturlinterceptor.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlextensioninterface.h>
+#include <QtQml/qqmlfile.h>
#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
-#include <QtQml/qqmlfile.h>
-#include <QtCore/qdiriterator.h>
-#include <QtQml/qqmlcomponent.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtQml/qqmlextensioninterface.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qscopeguard.h>
#include <functional>
-#if defined (Q_OS_UNIX)
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
-#if defined (QT_LINUXBASE)
-// LSB doesn't declare NAME_MAX. Use SYMLINK_MAX instead, which seems to
-// always be identical to NAME_MAX
-#ifndef NAME_MAX
-# define NAME_MAX _POSIX_SYMLINK_MAX
-#endif
-
-#endif
-
// #define DATABLOB_DEBUG
-
#ifdef DATABLOB_DEBUG
-
-#define ASSERT_MAINTHREAD() do { if (m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in main thread"); } while (false)
#define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false)
-#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
-
#else
-
-#define ASSERT_MAINTHREAD()
#define ASSERT_LOADTHREAD()
-#define ASSERT_CALLBACK()
-
#endif
-DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
-
QT_BEGIN_NAMESPACE
namespace {
@@ -121,830 +81,6 @@ namespace {
};
}
-#if QT_CONFIG(qml_network)
-// This is a lame object that we need to ensure that slots connected to
-// QNetworkReply get called in the correct thread (the loader thread).
-// As QQmlTypeLoader lives in the main thread, and we can't use
-// Qt::DirectConnection connections from a QNetworkReply (because then
-// sender() wont work), we need to insert this object in the middle.
-class QQmlTypeLoaderNetworkReplyProxy : public QObject
-{
- Q_OBJECT
-public:
- QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
-
-public slots:
- void finished();
- void downloadProgress(qint64, qint64);
- void manualFinished(QNetworkReply*);
-
-private:
- QQmlTypeLoader *l;
-};
-#endif // qml_network
-
-class QQmlTypeLoaderThread : public QQmlThread
-{
- typedef QQmlTypeLoaderThread This;
-
-public:
- QQmlTypeLoaderThread(QQmlTypeLoader *loader);
-#if QT_CONFIG(qml_network)
- QNetworkAccessManager *networkAccessManager() const;
- QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
-#endif // qml_network
- void load(QQmlDataBlob *b);
- void loadAsync(QQmlDataBlob *b);
- void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
- void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompleted(QQmlDataBlob *b);
- void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
- void initializeEngine(QQmlExtensionInterface *, const char *);
-
-protected:
- void shutdownThread() override;
-
-private:
- void loadThread(QQmlDataBlob *b);
- void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompletedMain(QQmlDataBlob *b);
- void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
- void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
-
- QQmlTypeLoader *m_loader;
-#if QT_CONFIG(qml_network)
- mutable QNetworkAccessManager *m_networkAccessManager;
- mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
-#endif // qml_network
-};
-
-#if QT_CONFIG(qml_network)
-QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
-: l(l)
-{
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::finished()
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyFinished(reply);
-}
-
-void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
-{
- Q_ASSERT(sender());
- Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
- QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
- l->networkReplyProgress(reply, bytesReceived, bytesTotal);
-}
-
-// This function is for when you want to shortcut the signals and call directly
-void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
-{
- qint64 replySize = reply->size();
- l->networkReplyProgress(reply, replySize, replySize);
- l->networkReplyFinished(reply);
-}
-#endif // qml_network
-
-/*!
-\class QQmlDataBlob
-\brief The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
-\internal
-
-QQmlDataBlob's are loaded by a QQmlTypeLoader. The user creates the QQmlDataBlob
-and then calls QQmlTypeLoader::load() or QQmlTypeLoader::loadWithStaticData() to load it.
-The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes available.
-*/
-
-/*!
-\enum QQmlDataBlob::Status
-
-This enum describes the status of the data blob.
-
-\list
-\li Null The blob has not yet been loaded by a QQmlTypeLoader
-\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
-invoked or has not yet returned.
-\li WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status
-only occurs after the QQmlDataBlob::setData() callback has been made, and when the blob has outstanding
-dependencies.
-\li Complete The blob's data has been loaded and all dependencies are done.
-\li Error An error has been set on this blob.
-\endlist
-*/
-
-/*!
-\enum QQmlDataBlob::Type
-
-This enum describes the type of the data blob.
-
-\list
-\li QmlFile This is a QQmlTypeData
-\li JavaScriptFile This is a QQmlScriptData
-\li QmldirFile This is a QQmlQmldirData
-\endlist
-*/
-
-/*!
-Create a new QQmlDataBlob for \a url and of the provided \a type.
-*/
-QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
-: m_typeLoader(manager), m_type(type), m_url(url), m_finalUrl(url), m_redirectCount(0),
- m_inCallback(false), m_isDone(false)
-{
- //Set here because we need to get the engine from the manager
- if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
- m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
- (QQmlAbstractUrlInterceptor::DataType)m_type);
-}
-
-/*! \internal */
-QQmlDataBlob::~QQmlDataBlob()
-{
- Q_ASSERT(m_waitingOnMe.isEmpty());
-
- cancelAllWaitingFor();
-}
-
-/*!
- Must be called before loading can occur.
-*/
-void QQmlDataBlob::startLoading()
-{
- Q_ASSERT(status() == QQmlDataBlob::Null);
- m_data.setStatus(QQmlDataBlob::Loading);
-}
-
-/*!
-Returns the type provided to the constructor.
-*/
-QQmlDataBlob::Type QQmlDataBlob::type() const
-{
- return m_type;
-}
-
-/*!
-Returns the blob's status.
-*/
-QQmlDataBlob::Status QQmlDataBlob::status() const
-{
- return m_data.status();
-}
-
-/*!
-Returns true if the status is Null.
-*/
-bool QQmlDataBlob::isNull() const
-{
- return status() == Null;
-}
-
-/*!
-Returns true if the status is Loading.
-*/
-bool QQmlDataBlob::isLoading() const
-{
- return status() == Loading;
-}
-
-/*!
-Returns true if the status is WaitingForDependencies.
-*/
-bool QQmlDataBlob::isWaiting() const
-{
- return status() == WaitingForDependencies ||
- status() == ResolvingDependencies;
-}
-
-/*!
-Returns true if the status is Complete.
-*/
-bool QQmlDataBlob::isComplete() const
-{
- return status() == Complete;
-}
-
-/*!
-Returns true if the status is Error.
-*/
-bool QQmlDataBlob::isError() const
-{
- return status() == Error;
-}
-
-/*!
-Returns true if the status is Complete or Error.
-*/
-bool QQmlDataBlob::isCompleteOrError() const
-{
- Status s = status();
- return s == Error || s == Complete;
-}
-
-/*!
-Returns the data download progress from 0 to 1.
-*/
-qreal QQmlDataBlob::progress() const
-{
- quint8 p = m_data.progress();
- if (p == 0xFF) return 1.;
- else return qreal(p) / qreal(0xFF);
-}
-
-/*!
-Returns the physical url of the data. Initially this is the same as
-finalUrl(), but if a URL interceptor is set, it will work on this URL
-and leave finalUrl() alone.
-
-\sa finalUrl()
-*/
-QUrl QQmlDataBlob::url() const
-{
- return m_url;
-}
-
-QString QQmlDataBlob::urlString() const
-{
- if (m_urlString.isEmpty())
- m_urlString = m_url.toString();
-
- return m_urlString;
-}
-
-/*!
-Returns the logical URL to be used for resolving further URLs referred to in
-the code.
-
-This is the blob url passed to the constructor. If a URL interceptor rewrites
-the URL, this one stays the same. If a network redirect happens while fetching
-the data, this url is updated to reflect the new location. Therefore, if both
-an interception and a redirection happen, the final url will indirectly
-incorporate the result of the interception, potentially breaking further
-lookups.
-
-\sa url()
-*/
-QUrl QQmlDataBlob::finalUrl() const
-{
- return m_finalUrl;
-}
-
-/*!
-Returns the finalUrl() as a string.
-*/
-QString QQmlDataBlob::finalUrlString() const
-{
- if (m_finalUrlString.isEmpty())
- m_finalUrlString = m_finalUrl.toString();
-
- return m_finalUrlString;
-}
-
-/*!
-Return the errors on this blob.
-
-May only be called from the load thread, or after the blob isCompleteOrError().
-*/
-QList<QQmlError> QQmlDataBlob::errors() const
-{
- Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread()));
- return m_errors;
-}
-
-/*!
-Mark this blob as having \a errors.
-
-All outstanding dependencies will be cancelled. Requests to add new dependencies
-will be ignored. Entry into the Error state is irreversable.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::setError(const QQmlError &errors)
-{
- ASSERT_CALLBACK();
-
- QList<QQmlError> l;
- l << errors;
- setError(l);
-}
-
-/*!
-\overload
-*/
-void QQmlDataBlob::setError(const QList<QQmlError> &errors)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Error);
- Q_ASSERT(m_errors.isEmpty());
-
- m_errors = errors; // Must be set before the m_data fence
- m_data.setStatus(Error);
-
- if (dumpErrors()) {
- qWarning().nospace() << "Errors for " << urlString();
- for (int ii = 0; ii < errors.count(); ++ii)
- qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
- }
- cancelAllWaitingFor();
-
- if (!m_inCallback)
- tryDone();
-}
-
-void QQmlDataBlob::setError(const QQmlCompileError &error)
-{
- QQmlError e;
- e.setColumn(error.location.column);
- e.setLine(error.location.line);
- e.setDescription(error.description);
- e.setUrl(url());
- setError(e);
-}
-
-void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors)
-{
- QList<QQmlError> finalErrors;
- finalErrors.reserve(errors.count());
- for (const QQmlCompileError &error: errors) {
- QQmlError e;
- e.setColumn(error.location.column);
- e.setLine(error.location.line);
- e.setDescription(error.description);
- e.setUrl(url());
- finalErrors << e;
- }
- setError(finalErrors);
-}
-
-void QQmlDataBlob::setError(const QString &description)
-{
- QQmlError e;
- e.setDescription(description);
- e.setUrl(url());
- setError(e);
-}
-
-/*!
-Wait for \a blob to become complete or to error. If \a blob is already
-complete or in error, or this blob is already complete, this has no effect.
-
-The setError() method may only be called from within a QQmlDataBlob callback.
-*/
-void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
-{
- ASSERT_CALLBACK();
-
- Q_ASSERT(status() != Null);
-
- if (!blob ||
- blob->status() == Error || blob->status() == Complete ||
- status() == Error || status() == Complete || m_isDone)
- return;
-
- for (auto existingDep: qAsConst(m_waitingFor))
- if (existingDep.data() == blob)
- return;
-
- m_data.setStatus(WaitingForDependencies);
-
- m_waitingFor.append(blob);
- blob->m_waitingOnMe.append(this);
-}
-
-/*!
-\fn void QQmlDataBlob::dataReceived(const Data &data)
-
-Invoked when data for the blob is received. Implementors should use this callback
-to determine a blob's dependencies. Within this callback you may call setError()
-or addDependency().
-*/
-
-/*!
-Invoked once data has either been received or a network error occurred, and all
-dependencies are complete.
-
-You can set an error in this method, but you cannot add new dependencies. Implementors
-should use this callback to finalize processing of data.
-
-The default implementation does nothing.
-
-XXX Rename processData() or some such to avoid confusion between done() (processing thread)
-and completed() (main thread)
-*/
-void QQmlDataBlob::done()
-{
-}
-
-#if QT_CONFIG(qml_network)
-/*!
-Invoked if there is a network error while fetching this blob.
-
-The default implementation sets an appropriate QQmlError.
-*/
-void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
-{
- Q_UNUSED(networkError);
-
- QQmlError error;
- error.setUrl(m_url);
-
- const char *errorString = nullptr;
- switch (networkError) {
- default:
- errorString = "Network error";
- break;
- case QNetworkReply::ConnectionRefusedError:
- errorString = "Connection refused";
- break;
- case QNetworkReply::RemoteHostClosedError:
- errorString = "Remote host closed the connection";
- break;
- case QNetworkReply::HostNotFoundError:
- errorString = "Host not found";
- break;
- case QNetworkReply::TimeoutError:
- errorString = "Timeout";
- break;
- case QNetworkReply::ProxyConnectionRefusedError:
- case QNetworkReply::ProxyConnectionClosedError:
- case QNetworkReply::ProxyNotFoundError:
- case QNetworkReply::ProxyTimeoutError:
- case QNetworkReply::ProxyAuthenticationRequiredError:
- case QNetworkReply::UnknownProxyError:
- errorString = "Proxy error";
- break;
- case QNetworkReply::ContentAccessDenied:
- errorString = "Access denied";
- break;
- case QNetworkReply::ContentNotFoundError:
- errorString = "File not found";
- break;
- case QNetworkReply::AuthenticationRequiredError:
- errorString = "Authentication required";
- break;
- };
-
- error.setDescription(QLatin1String(errorString));
-
- setError(error);
-}
-#endif // qml_network
-
-/*!
-Called if \a blob, which was previously waited for, has an error.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyError(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called if \a blob, which was previously waited for, has completed.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::dependencyComplete(QQmlDataBlob *blob)
-{
- Q_UNUSED(blob);
-}
-
-/*!
-Called when all blobs waited for have completed. This occurs regardless of
-whether they are in error, or complete state.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::allDependenciesDone()
-{
- m_data.setStatus(QQmlDataBlob::ResolvingDependencies);
-}
-
-/*!
-Called when the download progress of this blob changes. \a progress goes
-from 0 to 1.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::downloadProgressChanged(qreal progress)
-{
- Q_UNUSED(progress);
-}
-
-/*!
-Invoked on the main thread sometime after done() was called on the load thread.
-
-You cannot modify the blobs state at all in this callback and cannot depend on the
-order or timeliness of these callbacks. Implementors should use this callback to notify
-dependencies on the main thread that the blob is done and not a lot else.
-
-This callback is only invoked if an asynchronous load for this blob is
-made. An asynchronous load is one in which the Asynchronous mode is
-specified explicitly, or one that is implicitly delayed due to a network
-operation.
-
-The default implementation does nothing.
-*/
-void QQmlDataBlob::completed()
-{
-}
-
-
-void QQmlDataBlob::tryDone()
-{
- if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
- m_isDone = true;
- addref();
-
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob::done() %s", qPrintable(urlString()));
-#endif
- done();
-
- if (status() != Error)
- m_data.setStatus(Complete);
-
- notifyAllWaitingOnMe();
-
- // Locking is not required here, as anyone expecting callbacks must
- // already be protected against the blob being completed (as set above);
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlDataBlob: Dispatching completed");
-#endif
- m_typeLoader->m_thread->callCompleted(this);
-
- release();
- }
-}
-
-void QQmlDataBlob::cancelAllWaitingFor()
-{
- while (m_waitingFor.count()) {
- QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
-
- Q_ASSERT(blob->m_waitingOnMe.contains(this));
-
- blob->m_waitingOnMe.removeOne(this);
- }
-}
-
-void QQmlDataBlob::notifyAllWaitingOnMe()
-{
- while (m_waitingOnMe.count()) {
- QQmlDataBlob *blob = m_waitingOnMe.takeLast();
-
- Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
- [this](const QQmlRefPointer<QQmlDataBlob> &waiting) { return waiting.data() == this; }));
-
- blob->notifyComplete(this);
- }
-}
-
-void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
-{
- Q_ASSERT(blob->status() == Error || blob->status() == Complete);
- QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
-
- m_inCallback = true;
-
- QQmlRefPointer<QQmlDataBlob> blobRef;
- for (int i = 0; i < m_waitingFor.count(); ++i) {
- if (m_waitingFor.at(i).data() == blob) {
- blobRef = m_waitingFor.takeAt(i);
- break;
- }
- }
- Q_ASSERT(blobRef);
-
- if (blob->status() == Error) {
- dependencyError(blob);
- } else if (blob->status() == Complete) {
- dependencyComplete(blob);
- }
-
- if (!isError() && m_waitingFor.isEmpty())
- allDependenciesDone();
-
- m_inCallback = false;
-
- tryDone();
-}
-
-#define TD_STATUS_MASK 0x0000FFFF
-#define TD_STATUS_SHIFT 0
-#define TD_PROGRESS_MASK 0x00FF0000
-#define TD_PROGRESS_SHIFT 16
-#define TD_ASYNC_MASK 0x80000000
-
-QQmlDataBlob::ThreadData::ThreadData()
-: _p(0)
-{
-}
-
-QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const
-{
- return QQmlDataBlob::Status((_p.load() & TD_STATUS_MASK) >> TD_STATUS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status)
-{
- while (true) {
- int d = _p.load();
- int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-bool QQmlDataBlob::ThreadData::isAsync() const
-{
- return _p.load() & TD_ASYNC_MASK;
-}
-
-void QQmlDataBlob::ThreadData::setIsAsync(bool v)
-{
- while (true) {
- int d = _p.load();
- int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-quint8 QQmlDataBlob::ThreadData::progress() const
-{
- return quint8((_p.load() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT);
-}
-
-void QQmlDataBlob::ThreadData::setProgress(quint8 v)
-{
- while (true) {
- int d = _p.load();
- int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK);
- if (d == nd || _p.testAndSetOrdered(d, nd)) return;
- }
-}
-
-QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
-: m_loader(loader)
-#if QT_CONFIG(qml_network)
-, m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
-#endif // qml_network
-{
- // Do that after initializing all the members.
- startup();
-}
-
-#if QT_CONFIG(qml_network)
-QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
-{
- Q_ASSERT(isThisThread());
- if (!m_networkAccessManager) {
- m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
- m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
- }
-
- return m_networkAccessManager;
-}
-
-QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
-{
- Q_ASSERT(isThisThread());
- Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
- return m_networkReplyProxy;
-}
-#endif // qml_network
-
-void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
-{
- b->addref();
- callMethodInThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
-{
- b->addref();
- postMethodToThread(&This::loadThread, b);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- callMethodInThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
-{
- b->addref();
- postMethodToThread(&This::loadWithStaticDataThread, b, d);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- b->addref();
- postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
-}
-
-void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
-{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callCompletedMain, b);
-#else
- postMethodToMain(&This::callCompletedMain, b);
-#endif
-}
-
-void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
-{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
-#else
- postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
-#endif
-}
-
-void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
- const char *uri)
-{
- callMethodInMain(&This::initializeEngineMain, iface, uri);
-}
-
-void QQmlTypeLoaderThread::shutdownThread()
-{
-#if QT_CONFIG(qml_network)
- delete m_networkAccessManager;
- m_networkAccessManager = nullptr;
- delete m_networkReplyProxy;
- m_networkReplyProxy = nullptr;
-#endif // qml_network
-}
-
-void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
-{
- m_loader->loadThread(b);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
-{
- m_loader->loadWithStaticDataThread(b, d);
- b->release();
-}
-
-void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
-{
- m_loader->loadWithCachedUnitThread(b, unit);
- b->release();
-}
-
-void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
-{
- QML_MEMORY_SCOPE_URL(b->url());
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
-#endif
- b->completed();
- b->release();
-}
-
-void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
-{
-#ifdef DATABLOB_DEBUG
- qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
- qPrintable(b->urlString()), p);
-#endif
- b->downloadProgressChanged(p);
- b->release();
-}
-
-void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
- const char *uri)
-{
- Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
- iface->initializeEngine(m_loader->engine(), uri);
-}
-
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -1146,8 +282,6 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
return;
}
- QML_MEMORY_SCOPE_URL(blob->m_url);
-
if (QQmlFile::isSynchronous(blob->m_url)) {
const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
if (!QQml_isFileCaseCorrect(fileName)) {
@@ -1277,7 +411,6 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
{
- QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
d.inlineSourceCode = QString::fromUtf8(data);
d.hasInlineSourceCode = true;
@@ -1286,7 +419,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
{
- QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
d.fileInfo = QFileInfo(fileName);
setData(blob, d);
@@ -1294,7 +426,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
{
- QML_MEMORY_SCOPE_URL(blob->url());
QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -1314,7 +445,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit)
{
- QML_MEMORY_SCOPE_URL(blob->url());
QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -1338,6 +468,16 @@ void QQmlTypeLoader::shutdownThread()
m_thread->shutdown();
}
+QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+{
+ type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type));
+ uri = blob->stringAt(import->uriIndex);
+ qualifier = blob->stringAt(import->qualifierIndex);
+ majorVersion = import->majorVersion;
+ minorVersion = import->minorVersion;
+ location = import->location;
+}
+
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
: QQmlDataBlob(url, type, loader), m_importCache(loader)
{
@@ -1347,11 +487,11 @@ QQmlTypeLoader::Blob::~Blob()
{
}
-bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors)
{
QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
- data->setImport(this, import);
+ data->setImport(this, std::move(import));
data->setPriority(this, priority);
if (data->status() == Error) {
@@ -1367,26 +507,25 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData:
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
- if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), stringAt(import->uriIndex), stringAt(import->qualifierIndex), qmldirIdentifier, qmldirUrl, errors))
+ if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors))
return false;
- QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
- if (it != m_unresolvedImports.end()) {
- *it = data->priority(this);
- }
+ if (!loadImportDependencies(import, qmldirIdentifier, errors))
+ return false;
+
+ import->priority = data->priority(this);
// Release this reference at destruction
m_qmldirs << data;
- const QString &importQualifier = stringAt(import->qualifierIndex);
- if (!importQualifier.isEmpty()) {
+ if (!import->qualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
@@ -1396,7 +535,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, script.nameSpace, importQualifier);
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
}
}
@@ -1405,36 +544,42 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
+ return addImport(std::make_shared<PendingImport>(this, import), errors);
+}
+
+bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
+{
Q_ASSERT(errors);
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- const QString &importUri = stringAt(import->uriIndex);
- const QString &importQualifier = stringAt(import->qualifierIndex);
if (import->type == QV4::CompiledData::Import::ImportScript) {
- QUrl scriptUrl = finalUrl().resolved(QUrl(importUri));
+ QUrl scriptUrl = finalUrl().resolved(QUrl(import->uri));
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, importQualifier, QString());
+ scriptImported(blob, import->location, import->qualifier, QString());
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
QString qmldirFilePath;
QString qmldirUrl;
- if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) {
+ if (QQmlMetaType::isLockedModule(import->uri, import->majorVersion)) {
//Locked modules are checked first, to save on filesystem checks
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), false, errors))
return false;
- } else if (m_importCache.locateQmldir(importDatabase, importUri, import->majorVersion, import->minorVersion,
+ } else if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
&qmldirFilePath, &qmldirUrl)) {
// This is a local library import
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
return false;
- if (!importQualifier.isEmpty()) {
+ if (!loadImportDependencies(import, qmldirFilePath, errors))
+ return false;
+
+ if (!import->qualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
@@ -1444,18 +589,18 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
addDependency(blob.data());
- scriptImported(blob, import->location, script.nameSpace, importQualifier);
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
}
}
} else {
// Is this a module?
- if (QQmlMetaType::isAnyModule(importUri)) {
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (QQmlMetaType::isAnyModule(import->uri)) {
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), false, errors))
return false;
} else {
// We haven't yet resolved this import
- m_unresolvedImports.insert(import, 0);
+ m_unresolvedImports << import;
QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
@@ -1466,13 +611,13 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
: QQmlImportDatabase::Remote);
if (!remotePathList.isEmpty()) {
// Add this library and request the possible locations for it
- if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, QString(), QString(), true, errors))
return false;
// Probe for all possible locations
int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion);
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
for (const QString &qmldirPath : qmlDirPaths) {
if (interceptor) {
QUrl url = interceptor->intercept(
@@ -1495,7 +640,7 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
bool incomplete = false;
- QUrl importUrl(importUri);
+ QUrl importUrl(import->uri);
QString path = importUrl.path();
path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
importUrl.setPath(path);
@@ -1505,7 +650,7 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
incomplete = true;
}
- if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion,
+ if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
import->minorVersion, incomplete, errors))
return false;
@@ -1523,7 +668,7 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
- const QV4::CompiledData::Import *import = data->import(this);
+ PendingImportPtr import = data->import(this);
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
@@ -1538,16 +683,39 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
}
}
+bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors)
+{
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
+ for (const QString &implicitImports: qmldir.imports()) {
+ auto dependencyImport = std::make_shared<PendingImport>();
+ dependencyImport->uri = implicitImports;
+ dependencyImport->qualifier = currentImport->qualifier;
+ dependencyImport->majorVersion = currentImport->majorVersion;
+ dependencyImport->minorVersion = currentImport->minorVersion;
+ if (!addImport(dependencyImport, errors))
+ return false;
+ }
+ return true;
+}
+
bool QQmlTypeLoader::Blob::isDebugging() const
{
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::diskCacheDisabled()
+{
+ return disableDiskCache();
+}
+
+bool QQmlTypeLoader::Blob::diskCacheForced()
{
- bool resolve = true;
+ return forceDiskCache();
+}
- const QV4::CompiledData::Import *import = data->import(this);
+bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+{
+ PendingImportPtr import = data->import(this);
data->setImport(this, nullptr);
int priority = data->priority(this);
@@ -1555,10 +723,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
if (import) {
// Do we need to resolve this import?
- QHash<const QV4::CompiledData::Import *, int>::iterator it = m_unresolvedImports.find(import);
- if (it != m_unresolvedImports.end()) {
- resolve = (*it == 0) || (*it > priority);
- }
+ const bool resolve = (import->priority == 0) || (import->priority > priority);
if (resolve) {
// This is the (current) best resolution for this import
@@ -1566,8 +731,7 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
return false;
}
- if (it != m_unresolvedImports.end())
- *it = priority;
+ import->priority = priority;
return true;
}
}
@@ -1575,63 +739,6 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirDa
return true;
}
-
-QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
-{
-}
-
-bool QQmlTypeLoaderQmldirContent::hasError() const
-{
- return m_parser.hasError();
-}
-
-QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
-{
- return m_parser.errors(uri);
-}
-
-QString QQmlTypeLoaderQmldirContent::typeNamespace() const
-{
- return m_parser.typeNamespace();
-}
-
-void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
-{
- m_hasContent = true;
- m_location = location;
- m_parser.parse(content);
-}
-
-void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
-{
- m_parser.setError(error);
-}
-
-QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
-{
- return m_parser.components();
-}
-
-QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
-{
- return m_parser.scripts();
-}
-
-QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
-{
- return m_parser.plugins();
-}
-
-QString QQmlTypeLoaderQmldirContent::pluginLocation() const
-{
- return m_location;
-}
-
-bool QQmlTypeLoaderQmldirContent::designerSupported() const
-{
- return m_parser.designerSupported();
-}
-
/*!
Constructs a new type loader that uses the given \a engine.
*/
@@ -1785,17 +892,6 @@ QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url)
return qmldirData;
}
-// #### Qt 6: Remove this function, it exists only for binary compatibility.
-/*!
- * \internal
- */
-bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
-{
- Q_UNUSED(name)
- Q_UNUSED(fileName)
- return false;
-}
-
/*!
Returns the absolute filename of path via a directory cache.
Returns a empty string if the path does not exist.
@@ -1868,8 +964,10 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
{
- if (path.isEmpty())
+ const QChar nullChar(QChar::Null);
+ if (path.isEmpty() || path.contains(nullChar) || file.isEmpty() || file.contains(nullChar))
return false;
+
Q_ASSERT(path.endsWith(QLatin1Char('/')));
if (path.at(0) == QLatin1Char(':')) {
// qrc resource
@@ -2106,1215 +1204,4 @@ bool QQmlTypeLoader::isScriptLoaded(const QUrl &url) const
return m_scriptCache.contains(url);
}
-QQmlTypeData::TypeDataCallback::~TypeDataCallback()
-{
-}
-
-QString QQmlTypeData::TypeReference::qualifiedName() const
-{
- QString result;
- if (!prefix.isEmpty()) {
- result = prefix + QLatin1Char('.');
- }
- result.append(type.qmlTypeName());
- return result;
-}
-
-QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
-: QQmlTypeLoader::Blob(url, QmlFile, manager),
- m_typesResolved(false), m_implicitImportLoaded(false)
-{
-
-}
-
-QQmlTypeData::~QQmlTypeData()
-{
- m_scripts.clear();
- m_compositeSingletons.clear();
- m_resolvedTypes.clear();
-}
-
-const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
-{
- return m_scripts;
-}
-
-QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
-{
- return m_compiledData.data();
-}
-
-void QQmlTypeData::registerCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(!m_callbacks.contains(callback));
- m_callbacks.append(callback);
-}
-
-void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
-{
- Q_ASSERT(m_callbacks.contains(callback));
- m_callbacks.removeOne(callback);
- Q_ASSERT(!m_callbacks.contains(callback));
-}
-
-bool QQmlTypeData::tryLoadFromDiskCache()
-{
- if (disableDiskCache() && !forceDiskCache())
- return false;
-
- if (isDebugging())
- return false;
-
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
- return false;
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
- {
- QString error;
- if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
- return false;
- }
- }
-
- if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
- restoreIR(unit);
- return true;
- }
-
- m_compiledData = unit;
-
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- // For remote URLs, we don't delay the loading of the implicit import
- // because the loading probably requires an asynchronous fetch of the
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return false;
-
- // find the implicit import
- for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
- if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
- && import->qualifierIndex == 0
- && import->majorVersion == -1
- && import->minorVersion == -1) {
- QList<QQmlError> errors;
- if (!fetchQmldir(qmldirUrl, import, 1, &errors)) {
- setError(errors);
- return false;
- }
- break;
- }
- }
- }
- }
-
- for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
- QList<QQmlError> errors;
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return false;
- }
- }
-
- return true;
-}
-
-void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
-{
- Q_ASSERT(m_compiledData);
- m_compiledData->typeNameCache = typeNameCache;
- m_compiledData->resolvedTypes = resolvedTypeCache;
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
-
- QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
-
- {
- QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches,
- &pendingGroupPropertyBindings,
- engine, m_compiledData.data(), &m_importCache);
- QQmlCompileError error = propertyCacheCreator.buildMetaObjects();
- if (error.isSet()) {
- setError(error);
- return;
- }
- }
-
- QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects();
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
-}
-
-static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
-{
- for (const auto &typeRef: typeRefs) {
- if (typeRef.typeData) {
- const auto unit = typeRef.typeData->compilationUnit()->unitData();
- hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
- } else if (typeRef.type.isValid()) {
- const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
- bool ok = false;
- hash->addData(propertyCache->checksum(&ok));
- if (!ok)
- return false;
- }
- }
- return true;
-}
-
-void QQmlTypeData::done()
-{
- auto cleanup = qScopeGuard([this]{
- m_document.reset();
- m_typeReferences.clear();
- if (isError())
- m_compiledData = nullptr;
- });
-
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
- const ScriptReference &script = m_scripts.at(ii);
- Q_ASSERT(script.script->isCompleteOrError());
- if (script.script->isError()) {
- QList<QQmlError> errors = script.script->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- // Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
- ++it) {
- const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
- if (type.typeData && type.typeData->isError()) {
- const QString typeName = stringAt(it.key());
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- // Check all composite singleton type dependencies for errors
- for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
- const TypeReference &type = m_compositeSingletons.at(ii);
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
- if (type.typeData && type.typeData->isError()) {
- QString typeName = type.type.qmlTypeName();
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
- {
- QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
- if (error.isSet()) {
- setError(error);
- return;
- }
- }
-
- QQmlEngine *const engine = typeLoader()->engine();
-
- const auto dependencyHasher = [engine, &resolvedTypeCache, this](QCryptographicHash *hash) {
- if (!resolvedTypeCache.addToHash(hash, engine))
- return false;
- return ::addTypeReferenceChecksumsToHash(m_compositeSingletons, hash, engine);
- };
-
- // verify if any dependencies changed if we're using a cache
- if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
- qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
- if (!loadFromSource())
- return;
- m_backupSourceCode = SourceCodeData();
- m_compiledData = nullptr;
- }
-
- if (!m_document.isNull()) {
- // Compile component
- compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
- }
-
- if (isError())
- return;
-
- {
- QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
- {
- // Sanity check property bindings
- QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
- QVector<QQmlCompileError> errors = validator.validate();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- }
-
- m_compiledData->finalizeCompositeType(enginePrivate);
- }
-
- {
- QQmlType type = QQmlMetaType::qmlType(finalUrl(), true);
- if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
- if (!type.isValid()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
- setError(error);
- return;
- } else if (!type.isCompositeSingleton()) {
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
- setError(error);
- return;
- }
- } else {
- // If the type is CompositeSingleton but there was no pragma Singleton in the
- // QML file, lets report an error.
- if (type.isValid() && type.isCompositeSingleton()) {
- QString typeName = type.qmlTypeName();
- setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
- return;
- }
- }
- }
-
- {
- // Collect imported scripts
- m_compiledData->dependentScripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
-
- QStringRef qualifier(&script.qualifier);
- QString enclosingNamespace;
-
- const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
- if (lastDotIndex != -1) {
- enclosingNamespace = qualifier.left(lastDotIndex).toString();
- qualifier = qualifier.mid(lastDotIndex+1);
- }
-
- m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
- m_compiledData->dependentScripts << scriptData;
- }
- }
-}
-
-void QQmlTypeData::completed()
-{
- // Notify callbacks
- while (!m_callbacks.isEmpty()) {
- TypeDataCallback *callback = m_callbacks.takeFirst();
- callback->typeDataReady(this);
- }
-}
-
-bool QQmlTypeData::loadImplicitImport()
-{
- m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- // For local urls, add an implicit import "." as most overridden lookup.
- // This will also trigger the loading of the qmldir and the import of any native
- // types from available plugins.
- QList<QQmlError> implicitImportErrors;
- m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
-
- if (!implicitImportErrors.isEmpty()) {
- setError(implicitImportErrors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::dataReceived(const SourceCodeData &data)
-{
- m_backupSourceCode = data;
-
- if (tryLoadFromDiskCache())
- return;
-
- if (isError())
- return;
-
- if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else if (!m_backupSourceCode.exists())
- setError(QQmlTypeLoader::tr("No such file or directory"));
- else
- setError(QQmlTypeLoader::tr("File is empty"));
- return;
- }
-
- if (!loadFromSource())
- return;
-
- continueLoadFromIR();
-}
-
-void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- QmlIR::IRLoader loader(unit, m_document.data());
- loader.load();
- m_document->jsModule.fileName = urlString();
- m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit));
- continueLoadFromIR();
-}
-
-bool QQmlTypeData::loadFromSource()
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
- QQmlEngine *qmlEngine = typeLoader()->engine();
- QmlIR::IRBuilder compiler(qmlEngine->handle()->v8Engine->illegalNames());
-
- QString sourceError;
- const QString source = m_backupSourceCode.readAll(&sourceError);
- if (!sourceError.isEmpty()) {
- setError(sourceError);
- return false;
- }
-
- if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
- QList<QQmlError> errors;
- errors.reserve(compiler.errors.count());
- for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
- QQmlError e;
- e.setUrl(url());
- e.setLine(msg.loc.startLine);
- e.setColumn(msg.loc.startColumn);
- e.setDescription(msg.message);
- errors << e;
- }
- setError(errors);
- return false;
- }
- return true;
-}
-
-void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit)
-{
- m_document.reset(new QmlIR::Document(isDebugging()));
- QmlIR::IRLoader loader(unit->unitData(), m_document.data());
- loader.load();
- m_document->jsModule.fileName = urlString();
- m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = unit;
- continueLoadFromIR();
-}
-
-void QQmlTypeData::continueLoadFromIR()
-{
- m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- // For remote URLs, we don't delay the loading of the implicit import
- // because the loading probably requires an asynchronous fetch of the
- // qmldir (so we can't load it just in time).
- if (!finalUrl().scheme().isEmpty()) {
- QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
- if (!QQmlImports::isLocal(qmldirUrl)) {
- if (!loadImplicitImport())
- return;
- // This qmldir is for the implicit import
- QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool();
- auto implicitImport = pool->New<QV4::CompiledData::Import>();
- implicitImport->uriIndex = m_document->registerString(QLatin1String("."));
- implicitImport->qualifierIndex = 0; // empty string
- implicitImport->majorVersion = -1;
- implicitImport->minorVersion = -1;
- QList<QQmlError> errors;
-
- if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
- setError(errors);
- return;
- }
- }
- }
-
- QList<QQmlError> errors;
-
- for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
- }
- }
-}
-
-void QQmlTypeData::allDependenciesDone()
-{
- QQmlTypeLoader::Blob::allDependenciesDone();
-
- if (!m_typesResolved) {
- // Check that all imports were resolved
- QList<QQmlError> errors;
- QHash<const QV4::CompiledData::Import *, int>::const_iterator it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
- for ( ; it != end; ++it) {
- if (*it == 0) {
- // This import was not resolved
- for (auto keyIt = m_unresolvedImports.keyBegin(),
- keyEnd = m_unresolvedImports.keyEnd();
- keyIt != keyEnd; ++keyIt) {
- const QV4::CompiledData::Import *import = *keyIt;
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(stringAt(import->uriIndex)));
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error);
- }
- }
- }
- if (errors.size()) {
- setError(errors);
- return;
- }
-
- resolveTypes();
- m_typesResolved = true;
- }
-}
-
-void QQmlTypeData::downloadProgressChanged(qreal p)
-{
- for (int ii = 0; ii < m_callbacks.count(); ++ii) {
- TypeDataCallback *callback = m_callbacks.at(ii);
- callback->typeDataProgress(this, p);
- }
-}
-
-QString QQmlTypeData::stringAt(int index) const
-{
- if (m_compiledData)
- return m_compiledData->stringAt(index);
- return m_document->jsGenerator.stringTable.stringForIndex(index);
-}
-
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
-{
- Q_ASSERT(m_compiledData.isNull());
-
- const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit && m_document->javaScriptCompilationUnit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation;
-
- QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
- m_compiledData = compiler.compile();
- if (!m_compiledData) {
- setError(compiler.compilationErrors());
- return;
- }
-
- const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation;
- if (trySaveToDisk) {
- QString errorString;
- if (m_compiledData->saveToDisk(url(), &errorString)) {
- QString error;
- if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
- // ignore error, keep using the in-memory compilation unit.
- }
- } else {
- qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
- }
- }
-}
-
-void QQmlTypeData::resolveTypes()
-{
- // Add any imported scripts to our resolved set
- const auto resolvedScripts = m_importCache.resolvedScripts();
- for (const QQmlImports::ScriptReference &script : resolvedScripts) {
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
- addDependency(blob.data());
-
- ScriptReference ref;
- //ref.location = ...
- if (!script.qualifier.isEmpty())
- {
- ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(script.qualifier);
- } else {
- ref.qualifier = script.nameSpace;
- }
-
- ref.script = blob;
- m_scripts << ref;
- }
-
- // Lets handle resolved composite singleton types
- const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
- for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
- TypeReference ref;
- QString typeName;
- if (!csRef.prefix.isEmpty()) {
- typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
- // Add a reference to the enclosing namespace
- m_namespaces.insert(csRef.prefix);
- } else {
- typeName = csRef.typeName;
- }
-
- int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
- int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
-
- if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
- QQmlType::CompositeSingletonType))
- return;
-
- if (ref.type.isCompositeSingleton()) {
- ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) {
- // TODO: give an error message? If so, we should record and show the path of the cycle.
- continue;
- }
- addDependency(ref.typeData.data());
- ref.prefix = csRef.prefix;
-
- m_compositeSingletons << ref;
- }
- }
-
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
- unresolvedRef != end; ++unresolvedRef) {
-
- TypeReference ref; // resolved reference
-
- const bool reportErrors = unresolvedRef->errorWhenNotFound;
-
- int majorVersion = -1;
- int minorVersion = -1;
-
- const QString name = stringAt(unresolvedRef.key());
-
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
- return;
-
- if (ref.type.isComposite()) {
- ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- addDependency(ref.typeData.data());
- }
- ref.majorVersion = majorVersion;
- ref.minorVersion = minorVersion;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
-
- ref.needsCreation = unresolvedRef->needsCreation;
-
- m_resolvedTypes.insert(unresolvedRef.key(), ref);
- }
-
- // ### this allows enums to work without explicit import or instantiation of the type
- if (!m_implicitImportLoaded)
- loadImplicitImport();
-}
-
-QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
-{
- typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
-
- for (const QString &ns: m_namespaces)
- (*typeNameCache)->add(ns);
-
- // Add any Composite Singletons that were used to the import cache
- for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
- (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
-
- m_importCache.populateCache(typeNameCache->data());
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
-
- for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
- QScopedPointer<QV4::CompiledData::ResolvedTypeReference> ref(new QV4::CompiledData::ResolvedTypeReference);
- QQmlType qmlType = resolvedType->type;
- if (resolvedType->typeData) {
- if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
- return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
- }
- ref->compilationUnit = resolvedType->typeData->compilationUnit();
- } else if (qmlType.isValid()) {
- ref->type = qmlType;
- Q_ASSERT(ref->type.isValid());
-
- if (resolvedType->needsCreation && !ref->type.isCreatable()) {
- QString reason = ref->type.noCreationReason();
- if (reason.isEmpty())
- reason = tr("Element is not creatable.");
- return QQmlCompileError(resolvedType->location, reason);
- }
-
- if (ref->type.containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
- }
- }
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
- ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
- }
- QQmlCompileError noError;
- return noError;
-}
-
-bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
- TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
-{
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
-
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
- if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
- // Lazy loading of implicit import
- if (loadImplicitImport()) {
- // Try again to find the type
- errors.clear();
- typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
- } else {
- return false; //loadImplicitImport() hit an error, and called setError already
- }
- }
-
- if ((!typeFound || typeNamespace) && reportErrors) {
- // Known to not be a type:
- // - known to be a namespace (Namespace {})
- // - type with unknown namespace (UnknownNamespace.SomeType {})
- QQmlError error;
- if (typeNamespace) {
- error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
- } else {
- if (errors.size()) {
- error = errors.takeFirst();
- } else {
- // this should not be possible!
- // Description should come from error provided by addImport() function.
- error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
- }
- error.setUrl(m_importCache.baseUrl());
- error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
- }
-
- if (lineNumber != -1)
- error.setLine(lineNumber);
- if (columnNumber != -1)
- error.setColumn(columnNumber);
-
- errors.prepend(error);
- setError(errors);
- return false;
- }
-
- return true;
-}
-
-void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
-
- m_scripts << ref;
-}
-
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
-{
-}
-
-QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
-{
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
-
- if (m_precompiledScript->isESModule())
- return nullptr;
-
- auto qmlContextData = new QQmlContextData();
-
- qmlContextData->isInternal = true;
- qmlContextData->isJSContext = true;
- if (m_precompiledScript->isSharedLibrary())
- qmlContextData->isPragmaLibraryContext = true;
- else
- qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
- qmlContextData->baseUrl = url;
- qmlContextData->baseUrlString = urlString;
-
- // For backward compatibility, if there are no imports, we need to use the
- // imports from the parent context. See QTBUG-17518.
- if (!typeNameCache->isEmpty()) {
- qmlContextData->imports = typeNameCache;
- } else if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->imports = parentQmlContextData->imports;
- qmlContextData->importedScripts = parentQmlContextData->importedScripts;
- }
-
- if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->setParent(parentQmlContextData);
- } else {
- qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
- }
-
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
- QV4::Scope scope(v4);
- QV4::ScopedObject scriptsArray(scope);
- if (qmlContextData->importedScripts.isNullOrUndefined()) {
- scriptsArray = v4->newArrayObject(scripts.count());
- qmlContextData->importedScripts.set(v4, scriptsArray);
- } else {
- scriptsArray = qmlContextData->importedScripts.valueRef();
- }
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < scripts.count(); ++ii)
- scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
-
- return qmlContextData;
-}
-
-QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
-{
- if (m_loaded)
- return m_value.value();
-
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
- QV4::Scope scope(v4);
-
- if (!hasEngine()) {
- addToEngine(parentQmlContextData->engine);
- addref();
- }
-
- QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
- QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
- if (qmlContextData)
- qmlExecutionContext =
- QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
-
- QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
- if (module) {
- if (qmlContextData) {
- module->d()->scope->outer.set(v4, qmlExecutionContext->d());
- qmlExecutionContext->d()->qml()->module.set(v4, module->d());
- }
-
- module->evaluate();
- }
-
- if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- if (error.isValid())
- QQmlEnginePrivate::get(v4)->warning(error);
- }
-
- QV4::ScopedValue value(scope);
- if (qmlContextData)
- value = qmlExecutionContext->d()->qml();
- else if (module)
- value = module->d();
-
- if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) {
- m_loaded = true;
- m_value.set(v4, value);
- }
-
- return value->asReturnedValue();
-}
-
-void QQmlScriptData::clear()
-{
- if (typeNameCache) {
- typeNameCache->release();
- typeNameCache = nullptr;
- }
-
- scripts.clear();
-
- // An addref() was made when the QQmlCleanup was added to the engine.
- release();
-}
-
-QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
- : QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
- , m_isModule(url.path().endsWith(QLatin1String(".mjs")))
-{
-}
-
-QQmlScriptBlob::~QQmlScriptBlob()
-{
-}
-
-QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
-{
- return m_scriptData;
-}
-
-void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
-{
- if (!disableDiskCache() || forceDiskCache()) {
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading();
- QString error;
- if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- initializeFromCompilationUnit(unit);
- return;
- } else {
- qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
- }
- }
-
- if (!data.exists()) {
- if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
- setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
- else
- setError(QQmlTypeLoader::tr("No such file or directory"));
- return;
- }
-
- QString error;
- QString source = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
-
- if (m_isModule) {
- QList<QQmlJS::DiagnosticMessage> diagnostics;
- unit = QV4::ExecutionEngine::compileModule(isDebugging(), urlString(), source, data.sourceTimeStamp(), &diagnostics);
- QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics);
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- } else {
- QmlIR::Document irUnit(isDebugging());
-
- irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp();
-
- QmlIR::ScriptDirectivesCollector collector(&irUnit);
- irUnit.jsParserEngine.setDirectives(&collector);
-
- QList<QQmlError> errors;
- unit = QV4::Script::precompile(
- &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
- source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML);
- // No need to addref on unit, it's initial refcount is 1
- source.clear();
- if (!errors.isEmpty()) {
- setError(errors);
- return;
- }
- if (!unit) {
- unit.adopt(new QV4::CompiledData::CompilationUnit);
- }
- irUnit.javaScriptCompilationUnit = unit;
-
- QmlIR::QmlUnitGenerator qmlGenerator;
- qmlGenerator.generate(irUnit);
- }
-
- if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) {
- QString errorString;
- if (unit->saveToDisk(url(), &errorString)) {
- QString error;
- if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- // ignore error, keep using the in-memory compilation unit.
- }
- } else {
- qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString;
- }
- }
-
- initializeFromCompilationUnit(unit);
-}
-
-void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
-{
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
- compilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString()));
- initializeFromCompilationUnit(compilationUnit);
-}
-
-void QQmlScriptBlob::done()
-{
- if (isError())
- return;
-
- // Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
- const ScriptReference &script = m_scripts.at(ii);
- Q_ASSERT(script.script->isCompleteOrError());
- if (script.script->isError()) {
- QList<QQmlError> errors = script.script->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
- }
- }
-
- if (!m_isModule) {
- m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
-
- QSet<QString> ns;
-
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
- const ScriptReference &script = m_scripts.at(scriptIndex);
-
- m_scriptData->scripts.append(script.script);
-
- if (!script.nameSpace.isNull()) {
- if (!ns.contains(script.nameSpace)) {
- ns.insert(script.nameSpace);
- m_scriptData->typeNameCache->add(script.nameSpace);
- }
- }
- m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
- }
-
- m_importCache.populateCache(m_scriptData->typeNameCache);
- }
- m_scripts.clear();
-}
-
-QString QQmlScriptBlob::stringAt(int index) const
-{
- return m_scriptData->m_precompiledScript->stringAt(index);
-}
-
-void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
-{
- ScriptReference ref;
- ref.script = blob;
- ref.location = location;
- ref.qualifier = qualifier;
- ref.nameSpace = nameSpace;
-
- m_scripts << ref;
-}
-
-void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
-{
- Q_ASSERT(!m_scriptData);
- m_scriptData.adopt(new QQmlScriptData());
- m_scriptData->url = finalUrl();
- m_scriptData->urlString = finalUrlString();
- m_scriptData->m_precompiledScript = unit;
-
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> script = m_scriptData->m_precompiledScript;
-
- if (!m_isModule) {
- QList<QQmlError> errors;
- for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = script->importAt(i);
- if (!addImport(import, &errors)) {
- Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
- return;
- }
- }
- }
-
- auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
-
- v4->injectModule(unit);
-
- for (const QString &request: unit->moduleRequests()) {
- if (v4->moduleForUrl(QUrl(request), unit.data()))
- continue;
-
- const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
- addDependency(blob.data());
- scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
- }
-}
-
-QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, QmldirFile, loader)
-{
-}
-
-const QString &QQmlQmldirData::content() const
-{
- return m_content;
-}
-
-const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *>::const_iterator it =
- m_imports.find(blob);
- if (it == m_imports.end())
- return nullptr;
- return *it;
-}
-
-void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
-{
- m_imports[blob] = import;
-}
-
-int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
- if (it == m_priorities.end())
- return 0;
- return *it;
-}
-
-void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
-{
- m_priorities[blob] = priority;
-}
-
-void QQmlQmldirData::dataReceived(const SourceCodeData &data)
-{
- QString error;
- m_content = data.readAll(&error);
- if (!error.isEmpty()) {
- setError(error);
- return;
- }
-}
-
-void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
-{
- Q_UNIMPLEMENTED();
-}
-
-QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
-{
- error->clear();
- if (hasInlineSourceCode)
- return inlineSourceCode;
-
- QFile f(fileInfo.absoluteFilePath());
- if (!f.open(QIODevice::ReadOnly)) {
- *error = f.errorString();
- return QString();
- }
-
- const qint64 fileSize = fileInfo.size();
-
- if (uchar *mappedData = f.map(0, fileSize)) {
- QString source = QString::fromUtf8(reinterpret_cast<const char *>(mappedData), fileSize);
- f.unmap(mappedData);
- return source;
- }
-
- QByteArray data(fileSize, Qt::Uninitialized);
- if (f.read(data.data(), data.length()) != data.length()) {
- *error = f.errorString();
- return QString();
- }
- return QString::fromUtf8(data);
-}
-
-QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
-{
- if (hasInlineSourceCode)
- return QDateTime();
-
- return fileInfo.lastModified();
-}
-
-bool QQmlDataBlob::SourceCodeData::exists() const
-{
- if (hasInlineSourceCode)
- return true;
- return fileInfo.exists();
-}
-
-bool QQmlDataBlob::SourceCodeData::isEmpty() const
-{
- if (hasInlineSourceCode)
- return inlineSourceCode.isEmpty();
- return fileInfo.size() == 0;
-}
-
QT_END_NAMESPACE
-
-#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 987e47222d..612d6777ed 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -51,213 +51,27 @@
// We mean it.
//
+#include <private/qqmldatablob_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <QtQml/qtqmlglobal.h>
-#include <QtCore/qobject.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qcache.h>
-#if QT_CONFIG(qml_network)
-#include <QtNetwork/qnetworkreply.h>
-#endif
#include <QtQml/qqmlerror.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlfile.h>
-#include <QtQml/qqmlabstracturlinterceptor.h>
-#include <private/qhashedstring_p.h>
-#include <private/qqmlimport_p.h>
-#include <private/qqmlcleanup_p.h>
-#include <private/qqmldirparser_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlirbuilder_p.h>
+#include <QtCore/qcache.h>
+#include <QtCore/qmutex.h>
-#include <private/qv4value_p.h>
-#include <private/qv4script_p.h>
+#include <memory>
QT_BEGIN_NAMESPACE
-class QQmlScriptData;
class QQmlScriptBlob;
class QQmlQmldirData;
-class QQmlTypeLoader;
-class QQmlComponentPrivate;
class QQmlTypeData;
-class QQmlTypeLoader;
class QQmlExtensionInterface;
class QQmlProfiler;
-struct QQmlCompileError;
-
-namespace QmlIR {
-struct Document;
-}
-
-class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
-{
-public:
- enum Status {
- Null, // Prior to QQmlTypeLoader::load()
- Loading, // Prior to data being received and dataReceived() being called
- WaitingForDependencies, // While there are outstanding addDependency()s
- ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
- Complete, // Finished
- Error // Error
- };
-
- enum Type { //Matched in QQmlAbstractUrlInterceptor
- QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
- JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
- QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
- };
-
- QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
-
- void startLoading();
-
- QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
-
- Type type() const;
-
- Status status() const;
- bool isNull() const;
- bool isLoading() const;
- bool isWaiting() const;
- bool isComplete() const;
- bool isError() const;
- bool isCompleteOrError() const;
-
- qreal progress() const;
-
- QUrl url() const;
- QString urlString() const;
- QUrl finalUrl() const;
- QString finalUrlString() const;
-
- QList<QQmlError> errors() const;
-
- class SourceCodeData {
- public:
- QString readAll(QString *error) const;
- QDateTime sourceTimeStamp() const;
- bool exists() const;
- bool isEmpty() const;
- private:
- friend class QQmlDataBlob;
- friend class QQmlTypeLoader;
- QString inlineSourceCode;
- QFileInfo fileInfo;
- bool hasInlineSourceCode = false;
- };
-
-protected:
- // Can be called from within callbacks
- void setError(const QQmlError &);
- void setError(const QList<QQmlError> &errors);
- void setError(const QQmlCompileError &error);
- void setError(const QVector<QQmlCompileError> &errors);
- void setError(const QString &description);
- void addDependency(QQmlDataBlob *);
-
- // Callbacks made in load thread
- virtual void dataReceived(const SourceCodeData &) = 0;
- virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
- virtual void done();
-#if QT_CONFIG(qml_network)
- virtual void networkError(QNetworkReply::NetworkError);
-#endif
- virtual void dependencyError(QQmlDataBlob *);
- virtual void dependencyComplete(QQmlDataBlob *);
- virtual void allDependenciesDone();
-
- // Callbacks made in main thread
- virtual void downloadProgressChanged(qreal);
- virtual void completed();
-
-protected:
- // Manager that is currently fetching data for me
- QQmlTypeLoader *m_typeLoader;
-
-private:
- friend class QQmlTypeLoader;
- friend class QQmlTypeLoaderThread;
-
- void tryDone();
- void cancelAllWaitingFor();
- void notifyAllWaitingOnMe();
- void notifyComplete(QQmlDataBlob *);
-
- struct ThreadData {
- inline ThreadData();
- inline QQmlDataBlob::Status status() const;
- inline void setStatus(QQmlDataBlob::Status);
- inline bool isAsync() const;
- inline void setIsAsync(bool);
- inline quint8 progress() const;
- inline void setProgress(quint8);
-
- private:
- QAtomicInt _p;
- };
- ThreadData m_data;
-
- // m_errors should *always* be written before the status is set to Error.
- // We use the status change as a memory fence around m_errors so that locking
- // isn't required. Once the status is set to Error (or Complete), m_errors
- // cannot be changed.
- QList<QQmlError> m_errors;
-
- Type m_type;
-
- QUrl m_url;
- QUrl m_finalUrl;
- mutable QString m_urlString;
- mutable QString m_finalUrlString;
-
- // List of QQmlDataBlob's that are waiting for me to complete.
- QList<QQmlDataBlob *> m_waitingOnMe;
-
- // List of QQmlDataBlob's that I am waiting for to complete.
- QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
-
- int m_redirectCount:30;
- bool m_inCallback:1;
- bool m_isDone:1;
-};
-
class QQmlTypeLoaderThread;
-
-class QQmlTypeLoaderQmldirContent
-{
-private:
- friend class QQmlTypeLoader;
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
-public:
- QQmlTypeLoaderQmldirContent();
- QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
- QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
-
- bool hasContent() const { return m_hasContent; }
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
-private:
- QQmlDirParser m_parser;
- QString m_location;
- bool m_hasContent = false;
-};
+class QQmlEngine;
class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
{
@@ -275,11 +89,31 @@ public:
void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
+ struct PendingImport
+ {
+ QV4::CompiledData::Import::ImportType type = QV4::CompiledData::Import::ImportType::ImportLibrary;
+
+ QString uri;
+ QString qualifier;
+
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ QV4::CompiledData::Location location;
+
+ int priority = 0;
+
+ PendingImport() = default;
+ PendingImport(Blob *blob, const QV4::CompiledData::Import *import);
+ };
+ using PendingImportPtr = std::shared_ptr<PendingImport>;
+
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool addImport(PendingImportPtr import, QList<QQmlError> *errors);
- bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors);
+ bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors);
private:
virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
@@ -288,13 +122,18 @@ public:
void dependencyComplete(QQmlDataBlob *) override;
+ bool loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors);
+
protected:
virtual QString stringAt(int) const { return QString(); }
bool isDebugging() const;
+ static bool diskCacheDisabled();
+ static bool diskCacheForced();
+
QQmlImports m_importCache;
- QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
+ QVector<PendingImportPtr> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
};
@@ -418,209 +257,6 @@ private:
friend struct StaticLoader;
};
-class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
-public:
- struct TypeReference
- {
- TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
-
- QV4::CompiledData::Location location;
- QQmlType type;
- int majorVersion;
- int minorVersion;
- QQmlRefPointer<QQmlTypeData> typeData;
- QString prefix; // used by CompositeSingleton types
- QString qualifiedName() const;
- bool needsCreation;
- };
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
-private:
- friend class QQmlTypeLoader;
-
- QQmlTypeData(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlTypeData() override;
-
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::CompiledData::CompilationUnit *compilationUnit() const;
-
- // Used by QQmlComponent to get notifications
- struct TypeDataCallback {
- virtual ~TypeDataCallback();
- virtual void typeDataProgress(QQmlTypeData *, qreal) {}
- virtual void typeDataReady(QQmlTypeData *) {}
- };
- void registerCallback(TypeDataCallback *);
- void unregisterCallback(TypeDataCallback *);
-
-protected:
- void done() override;
- void completed() override;
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
- void allDependenciesDone() override;
- void downloadProgressChanged(qreal) override;
-
- QString stringAt(int index) const override;
-
-private:
- bool tryLoadFromDiskCache();
- bool loadFromSource();
- void restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit);
- void continueLoadFromIR();
- void resolveTypes();
- QQmlCompileError buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
- const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
- bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
- TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
- bool reportErrors = true,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
-
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
-
-
- SourceCodeData m_backupSourceCode; // used when cache verification fails.
- QScopedPointer<QmlIR::Document> m_document;
- QV4::CompiledData::TypeReferenceMap m_typeReferences;
-
- QList<ScriptReference> m_scripts;
-
- QSet<QString> m_namespaces;
- QList<TypeReference> m_compositeSingletons;
-
- // map from name index to resolved type
- // While this could be a hash, a map is chosen here to provide a stable
- // order, which is used to calculating a check-sum on dependent meta-objects.
- QMap<int, TypeReference> m_resolvedTypes;
- bool m_typesResolved:1;
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compiledData;
-
- QList<TypeDataCallback *> m_callbacks;
-
- bool m_implicitImportLoaded;
- bool loadImplicitImport();
-};
-
-// QQmlScriptData instances are created, uninitialized, by the loader in the
-// load thread. The first time they are used by the VME, they are initialized which
-// creates their v8 objects and they are referenced and added to the engine's cleanup
-// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
-// reference that was created is released but final deletion only occurs once all the
-// references as released. This is all intended to ensure that the v8 resources are
-// only created and destroyed in the main thread :)
-class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptData();
-
-public:
- QUrl url;
- QString urlString;
- QQmlTypeNameCache *typeNameCache;
- QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
-
- QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
-
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit() const { return m_precompiledScript; }
-
-protected:
- void clear() override; // From QQmlCleanup
-
-private:
- friend class QQmlScriptBlob;
-
- void initialize(QQmlEngine *);
- QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
-
- bool m_loaded;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_precompiledScript;
- QV4::PersistentValue m_value;
-};
-
-class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
-
-public:
- ~QQmlScriptBlob() override;
-
- struct ScriptReference
- {
- QV4::CompiledData::Location location;
- QString qualifier;
- QString nameSpace;
- QQmlRefPointer<QQmlScriptBlob> script;
- };
-
- QQmlRefPointer<QQmlScriptData> scriptData() const;
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
- void done() override;
-
- QString stringAt(int index) const override;
-
-private:
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- void initializeFromCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit);
-
- QList<ScriptReference> m_scripts;
- QQmlRefPointer<QQmlScriptData> m_scriptData;
- const bool m_isModule;
-};
-
-class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
-{
-private:
- friend class QQmlTypeLoader;
-
- QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
-
-public:
- const QString &content() const;
-
- const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const;
- void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *);
-
- int priority(QQmlTypeLoader::Blob *) const;
- void setPriority(QQmlTypeLoader::Blob *, int);
-
-protected:
- void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
-
-private:
- QString m_content;
- QHash<QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *> m_imports;
- QHash<QQmlTypeLoader::Blob *, int> m_priorities;
-};
-
-
QT_END_NAMESPACE
#endif // QQMLTYPELOADER_P_H
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
new file mode 100644
index 0000000000..af97643163
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <private/qqmltypeloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l)
+ : l(l)
+{
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::finished()
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyFinished(reply);
+}
+
+void QQmlTypeLoaderNetworkReplyProxy::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_ASSERT(sender());
+ Q_ASSERT(qobject_cast<QNetworkReply *>(sender()));
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ l->networkReplyProgress(reply, bytesReceived, bytesTotal);
+}
+
+// This function is for when you want to shortcut the signals and call directly
+void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
+{
+ qint64 replySize = reply->size();
+ l->networkReplyProgress(reply, replySize, replySize);
+ l->networkReplyFinished(reply);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
new file mode 100644
index 0000000000..ed87a2b508
--- /dev/null
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADERNETWORKREPLYPROXY_P_H
+#define QQMLTYPELOADERNETWORKREPLYPROXY_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 <QtQml/qtqmlglobal.h>
+#include <QtCore/qobject.h>
+
+QT_REQUIRE_CONFIG(qml_network);
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+class QQmlTypeLoader;
+
+// This is a lame object that we need to ensure that slots connected to
+// QNetworkReply get called in the correct thread (the loader thread).
+// As QQmlTypeLoader lives in the main thread, and we can't use
+// Qt::DirectConnection connections from a QNetworkReply (because then
+// sender() wont work), we need to insert this object in the middle.
+class QQmlTypeLoaderNetworkReplyProxy : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
+
+public slots:
+ void finished();
+ void downloadProgress(qint64, qint64);
+ void manualFinished(QNetworkReply*);
+
+private:
+ QQmlTypeLoader *l;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERNETWORKREPLYPROXY_P_H
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
new file mode 100644
index 0000000000..8e983db756
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <QtQml/qqmlerror.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
+{
+}
+
+bool QQmlTypeLoaderQmldirContent::hasError() const
+{
+ return m_parser.hasError();
+}
+
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
+{
+ QList<QQmlError> errors;
+ const QUrl url(uri);
+ const auto parseErrors = m_parser.errors(uri);
+ for (const auto &parseError : parseErrors) {
+ QQmlError error;
+ error.setUrl(url);
+ error.setLine(parseError.line);
+ error.setColumn(parseError.column);
+ error.setDescription(parseError.message);
+ errors.append(error);
+ }
+ return errors;
+}
+
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
+{
+ return m_parser.typeNamespace();
+}
+
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
+{
+ m_hasContent = true;
+ m_location = location;
+ m_parser.parse(content);
+}
+
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
+{
+ QQmlJS::DiagnosticMessage parseError;
+ parseError.line = error.line();
+ parseError.column = error.column();
+ parseError.message = error.description();
+ m_parser.setError(parseError);
+}
+
+QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
+{
+ return m_parser.components();
+}
+
+QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
+{
+ return m_parser.scripts();
+}
+
+QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
+{
+ return m_parser.plugins();
+}
+
+QStringList QQmlTypeLoaderQmldirContent::imports() const
+{
+ return m_parser.imports();
+}
+
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
+{
+ return m_location;
+}
+
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
+{
+ return m_parser.designerSupported();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/types/qquickpackage_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
index 122c7fcb30..698643c7ec 100644
--- a/src/qml/types/qquickpackage_p.h
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQUICKPACKAGE_H
-#define QQUICKPACKAGE_H
+#ifndef QQMLTYPELOADERQMLDIRCONTENT_P_H
+#define QQMLTYPELOADERQMLDIRCONTENT_P_H
//
// W A R N I N G
@@ -51,51 +51,45 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qqmldirparser_p.h>
QT_BEGIN_NAMESPACE
-class QQuickPackagePrivate;
-class QQuickPackageAttached;
-class Q_AUTOTEST_EXPORT QQuickPackage : public QObject
+class QQmlError;
+class QQmlTypeLoaderQmldirContent
{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQuickPackage)
+private:
+ friend class QQmlTypeLoader;
- Q_CLASSINFO("DefaultProperty", "data")
- Q_PROPERTY(QQmlListProperty<QObject> data READ data)
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
public:
- QQuickPackage(QObject *parent=nullptr);
- virtual ~QQuickPackage();
+ QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
+ QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
- QQmlListProperty<QObject> data();
+ bool hasContent() const { return m_hasContent; }
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
- QObject *part(const QString & = QString());
- bool hasPart(const QString &);
+ QString typeNamespace() const;
- static QQuickPackageAttached *qmlAttachedProperties(QObject *);
-};
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+ QStringList imports() const;
-class QQuickPackageAttached : public QObject
-{
-Q_OBJECT
-Q_PROPERTY(QString name READ name WRITE setName)
-public:
- QQuickPackageAttached(QObject *parent);
- virtual ~QQuickPackageAttached();
+ QString pluginLocation() const;
- QString name() const;
- void setName(const QString &n);
+ bool designerSupported() const;
- static QHash<QObject *, QQuickPackageAttached *> attached;
private:
- QString _name;
+ QQmlDirParser m_parser;
+ QString m_location;
+ bool m_hasContent = false;
};
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickPackage)
-QML_DECLARE_TYPEINFO(QQuickPackage, QML_HAS_ATTACHED_PROPERTIES)
-
-#endif // QQUICKPACKAGE_H
+#endif // QQMLTYPELOADERQMLDIRCONTENT_P_H
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
new file mode 100644
index 0000000000..0e1cecd1e5
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypeloaderthread_p.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
+ : m_loader(loader)
+#if QT_CONFIG(qml_network)
+ , m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
+#endif // qml_network
+{
+ // Do that after initializing all the members.
+ startup();
+}
+
+#if QT_CONFIG(qml_network)
+QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
+{
+ Q_ASSERT(isThisThread());
+ if (!m_networkAccessManager) {
+ m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
+ m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
+ }
+
+ return m_networkAccessManager;
+}
+
+QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
+{
+ Q_ASSERT(isThisThread());
+ Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first
+ return m_networkReplyProxy;
+}
+#endif // qml_network
+
+void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
+{
+ b->addref();
+ callMethodInThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
+{
+ b->addref();
+ postMethodToThread(&This::loadThread, b);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithStaticDataThread, b, d);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ b->addref();
+ postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
+}
+
+void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
+{
+ b->addref();
+#if !QT_CONFIG(thread)
+ if (!isThisThread())
+ postMethodToThread(&This::callCompletedMain, b);
+#else
+ postMethodToMain(&This::callCompletedMain, b);
+#endif
+}
+
+void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
+{
+ b->addref();
+#if !QT_CONFIG(thread)
+ if (!isThisThread())
+ postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
+#else
+ postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
+#endif
+}
+
+void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ callMethodInMain(&This::initializeEngineMain, iface, uri);
+}
+
+void QQmlTypeLoaderThread::shutdownThread()
+{
+#if QT_CONFIG(qml_network)
+ delete m_networkAccessManager;
+ m_networkAccessManager = nullptr;
+ delete m_networkReplyProxy;
+ m_networkReplyProxy = nullptr;
+#endif // qml_network
+}
+
+void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
+{
+ m_loader->loadThread(b);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+{
+ m_loader->loadWithStaticDataThread(b, d);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+{
+ m_loader->loadWithCachedUnitThread(b, unit);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
+#endif
+ b->completed();
+ b->release();
+}
+
+void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+{
+#ifdef DATABLOB_DEBUG
+ qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
+ qPrintable(b->urlString()), p);
+#endif
+ b->downloadProgressChanged(p);
+ b->release();
+}
+
+void QQmlTypeLoaderThread::initializeEngineMain(QQmlExtensionInterface *iface,
+ const char *uri)
+{
+ Q_ASSERT(m_loader->engine()->thread() == QThread::currentThread());
+ iface->initializeEngine(m_loader->engine(), uri);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
new file mode 100644
index 0000000000..67e47e86de
--- /dev/null
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPELOADERTHREAD_P_H
+#define QQMLTYPELOADERTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlthread_p.h>
+#include <private/qv4compileddata_p.h>
+
+#include <QtQml/qtqmlglobal.h>
+
+#if QT_CONFIG(qml_network)
+#include <private/qqmltypeloadernetworkreplyproxy_p.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQmlDataBlob;
+class QQmlTypeLoader;
+class QQmlExtensionInterface;
+
+class QQmlTypeLoaderThread : public QQmlThread
+{
+ typedef QQmlTypeLoaderThread This;
+
+public:
+ QQmlTypeLoaderThread(QQmlTypeLoader *loader);
+#if QT_CONFIG(qml_network)
+ QNetworkAccessManager *networkAccessManager() const;
+ QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
+#endif // qml_network
+ void load(QQmlDataBlob *b);
+ void loadAsync(QQmlDataBlob *b);
+ void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
+ void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void callCompleted(QQmlDataBlob *b);
+ void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
+ void initializeEngine(QQmlExtensionInterface *, const char *);
+
+protected:
+ void shutdownThread() override;
+
+private:
+ void loadThread(QQmlDataBlob *b);
+ void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
+ void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
+ void callCompletedMain(QQmlDataBlob *b);
+ void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
+ void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri);
+
+ QQmlTypeLoader *m_loader;
+#if QT_CONFIG(qml_network)
+ mutable QNetworkAccessManager *m_networkAccessManager;
+ mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+#endif // qml_network
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPELOADERTHREAD_P_H
diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp
new file mode 100644
index 0000000000..9c9bf3e48f
--- /dev/null
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypemodule_p_p.h"
+
+#include <private/qqmltype_p_p.h>
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeModule::QQmlTypeModule(const QString &module, int majorVersion)
+ : d(new QQmlTypeModulePrivate(module, majorVersion))
+{
+}
+
+QQmlTypeModule::~QQmlTypeModule()
+{
+ delete d;
+}
+
+QString QQmlTypeModule::module() const
+{
+ // No need to lock. d->module is const
+ return d->module;
+}
+
+int QQmlTypeModule::majorVersion() const
+{
+ // No need to lock. d->majorVersion is const
+ return d->majorVersion;
+}
+
+int QQmlTypeModule::minimumMinorVersion() const
+{
+ return d->minMinorVersion.loadRelaxed();
+}
+
+int QQmlTypeModule::maximumMinorVersion() const
+{
+ return d->maxMinorVersion.loadRelaxed();
+}
+
+void QQmlTypeModule::addMinorVersion(int version)
+{
+ for (int oldVersion = d->minMinorVersion.loadRelaxed();
+ oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = d->minMinorVersion.loadRelaxed()) {
+ }
+
+ for (int oldVersion = d->maxMinorVersion.loadRelaxed();
+ oldVersion < version && !d->maxMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = d->maxMinorVersion.loadRelaxed()) {
+ }
+}
+
+void QQmlTypeModule::add(QQmlTypePrivate *type)
+{
+ QMutexLocker lock(&d->mutex);
+ addMinorVersion(type->version_min);
+
+ QList<QQmlTypePrivate *> &list = d->typeHash[type->elementName];
+ for (int ii = 0; ii < list.count(); ++ii) {
+ Q_ASSERT(list.at(ii));
+ if (list.at(ii)->version_min < type->version_min) {
+ list.insert(ii, type);
+ return;
+ }
+ }
+ list.append(type);
+}
+
+void QQmlTypeModule::remove(const QQmlTypePrivate *type)
+{
+ QMutexLocker lock(&d->mutex);
+ for (auto elementIt = d->typeHash.begin(); elementIt != d->typeHash.end();) {
+ QQmlMetaType::removeQQmlTypePrivate(elementIt.value(), type);
+
+#if 0
+ if (list.isEmpty())
+ elementIt = typeHash.erase(elementIt);
+ else
+ ++elementIt;
+#else
+ ++elementIt;
+#endif
+ }
+}
+
+bool QQmlTypeModule::isLocked() const
+{
+ return d->locked.loadRelaxed() != 0;
+}
+
+void QQmlTypeModule::lock()
+{
+ d->locked.storeRelaxed(1);
+}
+
+QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const
+{
+ QMutexLocker lock(&d->mutex);
+ QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
+ if (types) {
+ for (int ii = 0; ii < types->count(); ++ii)
+ if (types->at(ii)->version_min <= minor)
+ return QQmlType(types->at(ii));
+ }
+
+ return QQmlType();
+}
+
+QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
+{
+ QMutexLocker lock(&d->mutex);
+ QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
+ if (types) {
+ for (int ii = 0; ii < types->count(); ++ii)
+ if (types->at(ii)->version_min <= minor)
+ return QQmlType(types->at(ii));
+ }
+
+ return QQmlType();
+}
+
+void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
+{
+ QMutexLocker lock(&d->mutex);
+ for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
+ typeCandidates != end; ++typeCandidates) {
+ for (auto type: typeCandidates.value()) {
+ if (type->regType == QQmlType::CompositeSingletonType)
+ callback(QQmlType(type));
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h
new file mode 100644
index 0000000000..b84a91b5db
--- /dev/null
+++ b/src/qml/qml/qqmltypemodule_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPEMODULE_P_H
+#define QQMLTYPEMODULE_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 <QtQml/qtqmlglobal.h>
+#include <QtCore/qstring.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlType;
+class QQmlTypePrivate;
+struct QQmlMetaTypeData;
+class QHashedString;
+class QHashedStringRef;
+
+namespace QV4 {
+struct String;
+}
+
+class QQmlTypeModulePrivate;
+class QQmlTypeModule
+{
+public:
+ QQmlTypeModule(const QString &uri = QString(), int majorVersion = 0);
+ ~QQmlTypeModule();
+
+ void add(QQmlTypePrivate *);
+ void remove(const QQmlTypePrivate *type);
+
+ bool isLocked() const;
+ void lock();
+
+ QString module() const;
+ int majorVersion() const;
+
+ void addMinorVersion(int minorVersion);
+ int minimumMinorVersion() const;
+ int maximumMinorVersion() const;
+
+ QQmlType type(const QHashedStringRef &, int) const;
+ QQmlType type(const QV4::String *, int) const;
+
+ void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
+
+private:
+ QQmlTypeModulePrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEMODULE_P_H
diff --git a/src/qml/qml/qqmltypemodule_p_p.h b/src/qml/qml/qqmltypemodule_p_p.h
new file mode 100644
index 0000000000..b1dab1c4a0
--- /dev/null
+++ b/src/qml/qml/qqmltypemodule_p_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPEMODULE_P_P_H
+#define QQMLTYPEMODULE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmltypemodule_p.h>
+#include <private/qstringhash_p.h>
+#include <private/qqmlmetatypedata_p.h>
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeModulePrivate
+{
+public:
+ QQmlTypeModulePrivate(QString module, int majorVersion) :
+ module(std::move(module)), majorVersion(majorVersion)
+ {}
+
+ const QString module;
+ const int majorVersion = 0;
+
+ // Can only ever decrease
+ QAtomicInt minMinorVersion = std::numeric_limits<int>::max();
+
+ // Can only ever increase
+ QAtomicInt maxMinorVersion = 0;
+
+ // Bool. Can only be set to 1 once.
+ QAtomicInt locked = 0;
+
+ typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash;
+ TypeHash typeHash;
+
+ QMutex mutex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEMODULE_P_P_H
diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp
new file mode 100644
index 0000000000..bbbfa1a7b6
--- /dev/null
+++ b/src/qml/qml/qqmltypemoduleversion.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypemoduleversion_p.h"
+
+#include <private/qqmltype_p.h>
+#include <private/qqmltypemodule_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion()
+ : m_module(nullptr), m_minor(0)
+{
+}
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
+ : m_module(module), m_minor(minor)
+{
+ Q_ASSERT(m_module);
+ Q_ASSERT(m_minor >= 0);
+}
+
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
+ : m_module(o.m_module), m_minor(o.m_minor)
+{
+}
+
+QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVersion &o)
+{
+ m_module = o.m_module;
+ m_minor = o.m_minor;
+ return *this;
+}
+
+QQmlTypeModule *QQmlTypeModuleVersion::module() const
+{
+ return m_module;
+}
+
+int QQmlTypeModuleVersion::minorVersion() const
+{
+ return m_minor;
+}
+
+QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
+{
+ if (!m_module)
+ return QQmlType();
+ return m_module->type(name, m_minor);
+}
+
+QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const
+{
+ if (!m_module)
+ return QQmlType();
+ return m_module->type(name, m_minor);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h
new file mode 100644
index 0000000000..20f4709ecb
--- /dev/null
+++ b/src/qml/qml/qqmltypemoduleversion_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTYPEMODULEVERSION_P_H
+#define QQMLTYPEMODULEVERSION_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 <QtQml/qtqmlglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlTypeModule;
+class QQmlType;
+class QHashedStringRef;
+
+namespace QV4 {
+struct String;
+}
+
+class QQmlTypeModuleVersion
+{
+public:
+ QQmlTypeModuleVersion();
+ QQmlTypeModuleVersion(QQmlTypeModule *, int);
+ QQmlTypeModuleVersion(const QQmlTypeModuleVersion &);
+ QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &);
+
+ QQmlTypeModule *module() const;
+ int minorVersion() const;
+
+ QQmlType type(const QHashedStringRef &) const;
+ QQmlType type(const QV4::String *) const;
+
+private:
+ QQmlTypeModule *m_module;
+ int m_minor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTYPEMODULEVERSION_P_H
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 28b5e7f0ad..b98fe77ed5 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -55,8 +55,9 @@
#include "qqmlcleanup_p.h"
#include "qqmlmetatype_p.h"
-#include <private/qhashedstring_p.h>
+#include <private/qstringhash_p.h>
#include <private/qqmlimport_p.h>
+#include <private/qqmltypemoduleversion_p.h>
#include <QtCore/qvector.h>
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index c5fa4a04ec..ef4a628a04 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -38,10 +38,11 @@
****************************************************************************/
#include "qqmltypewrapper_p.h"
-#include <private/qv8engine_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltypedata_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4functionobject_p.h>
@@ -89,10 +90,8 @@ QObject* QQmlTypeWrapper::singletonObject() const
if (!isSingleton())
return nullptr;
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- return siinfo->qobjectApi(e);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ return e->singletonInstance<QObject*>(d()->type());
}
QVariant QQmlTypeWrapper::toVariant() const
@@ -100,13 +99,12 @@ QVariant QQmlTypeWrapper::toVariant() const
if (!isSingleton())
return QVariant::fromValue<QObject *>(d()->object);
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
- return QVariant::fromValue<QObject*>(qobjectSingleton);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ const QQmlType type = d()->type();
+ if (type.isQJSValueSingleton())
+ return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
- return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e));
+ return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
@@ -194,50 +192,51 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// singleton types are handled differently to other types.
if (type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- // check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (includeEnums && name->startsWithUpper()) {
- bool ok = false;
- int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return QV4::Value::fromInt32(value).asReturnedValue();
-
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
- if (ok) {
- Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
- enumWrapper->d()->typePrivate = type.priv();
- QQmlType::refHandle(enumWrapper->d()->typePrivate);
- enumWrapper->d()->scopeEnumIndex = value;
- return enumWrapper.asReturnedValue();
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ QJSValue scriptSingleton;
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ // check for enum value
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (includeEnums && name->startsWithUpper()) {
+ bool ok = false;
+ int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return QV4::Value::fromInt32(value).asReturnedValue();
+
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+ return enumWrapper.asReturnedValue();
+ }
}
- }
- // check for property.
- bool ok;
- const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
- if (hasProperty)
- *hasProperty = ok;
-
- // Warn when attempting to access a lowercased enum value, singleton case
- if (!ok && includeEnums && !name->startsWithUpper()) {
- enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return throwLowercaseEnumError(v4, name, type);
- }
+ // check for property.
+ bool ok;
+ const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
+ if (hasProperty)
+ *hasProperty = ok;
+
+ // Warn when attempting to access a lowercased enum value, singleton case
+ if (!ok && includeEnums && !name->startsWithUpper()) {
+ enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return throwLowercaseEnumError(v4, name, type);
+ }
- return result;
- } 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::convertedToValue(v4, siinfo->scriptApi(e)));
- if (!!o)
- return o->get(name);
+ return result;
+ }
+ } else if (type.isQJSValueSingleton()) {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
+ if (!!o)
+ return o->get(name);
+ }
}
// Fall through to base implementation
@@ -342,21 +341,22 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
return false;
} else if (type.isSingleton()) {
- QQmlEngine *e = scope.engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, siinfo->scriptApi(e)));
- if (!apiprivate) {
- QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
- scope.engine->throwError(error);
- return false;
- } else {
- return apiprivate->put(name, value);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
+ return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+
+ } else {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ if (!apiprivate) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
+ scope.engine->throwError(error);
+ return false;
+ } else {
+ return apiprivate->put(name, value);
+ }
}
}
}
@@ -419,7 +419,7 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return Encode(false);
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- CompiledData::CompilationUnit *cu = td->compilationUnit();
+ ExecutableCompilationUnit *cu = td->compilationUnit();
myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
@@ -448,27 +448,25 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (type.isValid()) {
if (type.isSingleton()) {
- QQmlEngine *e = engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (!includeEnums || !name->startsWithUpper()) {
- QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
- if (ddata && ddata->propertyCache) {
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
- if (property) {
- ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- lookup->qobjectLookup.qmlTypeIc = This->internalClass();
- lookup->qobjectLookup.ic = val->objectValue()->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
- return lookup->getter(lookup, engine, *object);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (!includeEnums || !name->startsWithUpper()) {
+ QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
+ if (ddata && ddata->propertyCache) {
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ if (property) {
+ ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
+ lookup->qobjectLookup.qmlTypeIc = This->internalClass();
+ lookup->qobjectLookup.ic = val->objectValue()->internalClass();
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
+ return lookup->getter(lookup, engine, *object);
+ }
+ // Fall through to base implementation
}
// Fall through to base implementation
}
@@ -478,6 +476,34 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
}
// Fall through to base implementation
}
+
+ if (name->startsWithUpper()) {
+ bool ok = false;
+ int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
+ if (ok) {
+ lookup->qmlEnumValueLookup.ic = This->internalClass();
+ lookup->qmlEnumValueLookup.encodedEnumValue
+ = QV4::Value::fromInt32(value).asReturnedValue();
+ lookup->getter = QQmlTypeWrapper::lookupEnumValue;
+ return lookup->getter(lookup, engine, *object);
+ }
+
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(
+ scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+
+ lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
+ lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
+ = static_cast<Heap::Object*>(enumWrapper->heapObject());
+ lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
+ return enumWrapper.asReturnedValue();
+ }
+ // Fall through to base implementation
+ }
// Fall through to base implementation
}
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
@@ -509,22 +535,46 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
if (!type.isValid())
return revertLookup();
- if (!type.isSingleton())
+ if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
return revertLookup();
- QQmlEngine *e = engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (!qobjectSingleton)
- return revertLookup();
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
+ Q_ASSERT(qobjectSingleton);
Scope scope(engine);
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
}
+ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
+{
+ auto *o = static_cast<Heap::Object *>(base.heapObject());
+ if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, base);
+ }
+
+ return l->qmlEnumValueLookup.encodedEnumValue;
+}
+
+ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
+{
+ Scope scope(engine);
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
+
+ auto *o = static_cast<Heap::Object *>(base.heapObject());
+ if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
+ QQmlType::derefHandle(enumWrapper->d()->typePrivate);
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, base);
+ }
+
+ return enumWrapper.asReturnedValue();
+}
+
void Heap::QQmlScopedEnumWrapper::destroy()
{
QQmlType::derefHandle(typePrivate);
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 5f3cb2523f..7dc3f55310 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -81,7 +81,7 @@ struct QQmlTypeWrapper : Object {
QQmlType type() const;
- QQmlTypePrivate *typePrivate;
+ const QQmlTypePrivate *typePrivate;
QQmlTypeNameCache *typeNamespace;
const QQmlImportRef *importNamespace;
};
@@ -90,7 +90,7 @@ struct QQmlScopedEnumWrapper : Object {
void init() { Object::init(); }
void destroy();
int scopeEnumIndex;
- QQmlTypePrivate *typePrivate;
+ const QQmlTypePrivate *typePrivate;
QQmlType type() const;
};
@@ -115,6 +115,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base);
protected:
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 6fd0f0d37c..a4737b3da9 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -38,12 +38,14 @@
****************************************************************************/
#include "qqmlvaluetype_p.h"
-#include "qqmlmetatype_p.h"
+#include <QtCore/qmutex.h>
#include <private/qqmlglobal_p.h>
#include <QtCore/qdebug.h>
#include <private/qmetaobjectbuilder_p.h>
+#if QT_CONFIG(qml_itemmodel)
#include <private/qqmlmodelindexvaluetype_p.h>
+#endif
#include <private/qmetatype_p.h>
QT_BEGIN_NAMESPACE
@@ -63,32 +65,34 @@ struct QQmlValueTypeFactoryImpl
QQmlValueType *valueTypes[QVariant::UserType];
QHash<int, QQmlValueType *> userTypes;
QMutex mutex;
+
+ QQmlValueType invalidValueType;
};
QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
{
- std::fill_n(valueTypes, int(QVariant::UserType), nullptr);
+ std::fill_n(valueTypes, int(QVariant::UserType), &invalidValueType);
+#if QT_CONFIG(qml_itemmodel)
// See types wrapped in qqmlmodelindexvaluetype_p.h
qRegisterMetaType<QItemSelectionRange>();
+#endif
}
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
{
- qDeleteAll(valueTypes, valueTypes + QVariant::UserType);
+ for (QQmlValueType *type : valueTypes) {
+ if (type != &invalidValueType)
+ delete type;
+ }
qDeleteAll(userTypes);
}
-bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+bool isInternalType(int idx)
{
- if (idx >= QMetaType::User)
- return valueType(idx) != nullptr;
-
- if (idx < 0)
- return false;
-
// Qt internal types
switch (idx) {
+ case QMetaType::UnknownType:
case QMetaType::QStringList:
case QMetaType::QObjectStar:
case QMetaType::VoidStar:
@@ -97,12 +101,20 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx)
case QMetaType::QLocale:
case QMetaType::QImage: // scarce type, keep as QVariant
case QMetaType::QPixmap: // scarce type, keep as QVariant
- return false;
- default:
return true;
+ default:
+ return false;
}
}
+bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+{
+ if (idx < 0 || isInternalType(idx))
+ return false;
+
+ return valueType(idx) != nullptr;
+}
+
const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
{
switch (t) {
@@ -120,13 +132,17 @@ const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
return &QQmlRectFValueType::staticMetaObject;
case QVariant::EasingCurve:
return &QQmlEasingValueType::staticMetaObject;
+#if QT_CONFIG(qml_itemmodel)
case QVariant::ModelIndex:
return &QQmlModelIndexValueType::staticMetaObject;
case QVariant::PersistentModelIndex:
return &QQmlPersistentModelIndexValueType::staticMetaObject;
+#endif
default:
+#if QT_CONFIG(qml_itemmodel)
if (t == qMetaTypeId<QItemSelectionRange>())
return &QQmlItemSelectionRangeValueType::staticMetaObject;
+#endif
if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
return mo;
@@ -158,15 +174,17 @@ QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
}
QQmlValueType *rv = valueTypes[idx];
- if (!rv) {
+ if (rv == &invalidValueType) {
// No need for mutex protection - the most we can lose is a valueType instance
// TODO: Investigate the performance/memory characteristics of
// removing the preallocated array
- if (const QMetaObject *mo = metaObjectForMetaType(idx)) {
- rv = new QQmlValueType(idx, mo);
- valueTypes[idx] = rv;
- }
+ if (isInternalType(idx))
+ rv = valueTypes[idx] = nullptr;
+ else if (const QMetaObject *mo = metaObjectForMetaType(idx))
+ rv = valueTypes[idx] = new QQmlValueType(idx, mo);
+ else
+ rv = valueTypes[idx] = nullptr;
}
return rv;
@@ -196,6 +214,13 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor,
qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
}
+QQmlValueType::QQmlValueType() :
+ _metaObject(nullptr),
+ gadgetPtr(nullptr),
+ metaType(QMetaType::UnknownType)
+{
+}
+
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
: gadgetPtr(QMetaType::create(typeId))
, metaType(typeId)
@@ -213,7 +238,7 @@ QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
QQmlValueType::~QQmlValueType()
{
QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(op->metaObject == this);
+ Q_ASSERT(op->metaObject == nullptr || op->metaObject == this);
op->metaObject = nullptr;
::free(const_cast<QMetaObject *>(_metaObject));
metaType.destroy(gadgetPtr);
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 89f1b71d61..cf53b8cb4a 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -66,6 +66,7 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject
{
public:
+ QQmlValueType();
QQmlValueType(int userType, const QMetaObject *metaObject);
~QQmlValueType() override;
void read(QObject *, int);
@@ -90,7 +91,7 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
{
public:
- static bool isValueType(int);
+ static bool isValueType(int idx);
static QQmlValueType *valueType(int idx);
static const QMetaObject *metaObjectForMetaType(int type);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 7df5757b95..cf6553d129 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qqmlvaluetypewrapper_p.h"
-#include <private/qv8engine_p.h>
+
#include <private/qqmlvaluetype_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlglobal_p.h>
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 6bc469c836..abdc686ec2 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -57,6 +57,8 @@
#include <private/qv4scopedvalue_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertycachemethodarguments_p.h>
QT_BEGIN_NAMESPACE
@@ -162,8 +164,19 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
if (!targetDData)
return;
- int coreIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex).coreIndex();
+ QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
+ int coreIndex = encodedIndex.coreIndex();
+ int valueTypeIndex = encodedIndex.valueTypeIndex();
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) {
+ // deep alias
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
+ auto const *newPropertyCache = enginePriv->propertyCacheForType(pd->propType());
+ void *argv[1] = { &target };
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ Q_ASSERT(newPropertyCache);
+ pd = newPropertyCache->property(valueTypeIndex);
+ }
if (!pd)
return;
@@ -316,7 +329,7 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje
QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
QObject *obj,
- const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlCompilationUnit, int qmlObjectId)
+ const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
engine(engine),
ctxt(QQmlData::get(obj, true)->outerContext),
@@ -594,7 +607,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
QV4::Scope scope(engine);
QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id));
if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
- QVariant variant(qVariantFromValue(QList<QObject*>()));
+ QVariant variant(QVariant::fromValue(QList<QObject*>()));
v = engine->newVariantObject(variant);
md->set(engine, id, v);
}
@@ -638,205 +651,170 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= propOffset();
if (id < propertyCount) {
- const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type));
- bool needActivate = false;
-
- if (t == QV4::CompiledData::Property::Var) {
- // the context can be null if accessing var properties from cpp after re-parenting an item.
- QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine);
- if (ep) {
- if (c == QMetaObject::ReadProperty) {
- *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
- } else if (c == QMetaObject::WriteProperty) {
- writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- }
- } else if (c == QMetaObject::ReadProperty) {
- // if the context was disposed, we just return an invalid variant from read.
- *reinterpret_cast<QVariant *>(a[0]) = QVariant();
- }
+ const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id];
+ const QV4::CompiledData::BuiltinType t = property.builtinType();
- } else {
- int fallbackMetaType = QMetaType::UnknownType;
+ // the context can be null if accessing var properties from cpp after re-parenting an item.
+ QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine);
+
+ const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t);
+
+ if (c == QMetaObject::ReadProperty) {
switch (t) {
- case QV4::CompiledData::Property::Font:
- fallbackMetaType = QMetaType::QFont;
+ case QV4::CompiledData::BuiltinType::Int:
+ *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
break;
- case QV4::CompiledData::Property::Time:
- fallbackMetaType = QMetaType::QTime;
+ case QV4::CompiledData::BuiltinType::Bool:
+ *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
break;
- case QV4::CompiledData::Property::Color:
- fallbackMetaType = QMetaType::QColor;
+ case QV4::CompiledData::BuiltinType::Real:
+ *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
break;
- case QV4::CompiledData::Property::Vector2D:
- fallbackMetaType = QMetaType::QVector2D;
+ case QV4::CompiledData::BuiltinType::String:
+ *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
break;
- case QV4::CompiledData::Property::Vector3D:
- fallbackMetaType = QMetaType::QVector3D;
+ case QV4::CompiledData::BuiltinType::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
break;
- case QV4::CompiledData::Property::Vector4D:
- fallbackMetaType = QMetaType::QVector4D;
+ case QV4::CompiledData::BuiltinType::Date:
+ *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
break;
- case QV4::CompiledData::Property::Matrix4x4:
- fallbackMetaType = QMetaType::QMatrix4x4;
+ case QV4::CompiledData::BuiltinType::DateTime:
+ *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
break;
- case QV4::CompiledData::Property::Quaternion:
- fallbackMetaType = QMetaType::QQuaternion;
+ case QV4::CompiledData::BuiltinType::Rect:
+ *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
break;
- default: break;
- }
-
-
- if (c == QMetaObject::ReadProperty) {
- switch (t) {
- case QV4::CompiledData::Property::Int:
- *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
- break;
- case QV4::CompiledData::Property::Bool:
- *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
- break;
- case QV4::CompiledData::Property::Real:
- *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
- break;
- case QV4::CompiledData::Property::String:
- *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
- break;
- case QV4::CompiledData::Property::Url:
- *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
- break;
- case QV4::CompiledData::Property::Date:
- *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
- break;
- case QV4::CompiledData::Property::DateTime:
- *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
- break;
- case QV4::CompiledData::Property::Rect:
- *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
- break;
- case QV4::CompiledData::Property::Size:
- *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
- break;
- case QV4::CompiledData::Property::Point:
- *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
- break;
- case QV4::CompiledData::Property::Custom:
- *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
- break;
- case QV4::CompiledData::Property::Variant:
+ case QV4::CompiledData::BuiltinType::Size:
+ *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
+ break;
+ case QV4::CompiledData::BuiltinType::Point:
+ *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
+ break;
+ case QV4::CompiledData::BuiltinType::Variant:
+ *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ break;
+ case QV4::CompiledData::BuiltinType::Font:
+ case QV4::CompiledData::BuiltinType::Time:
+ case QV4::CompiledData::BuiltinType::Color:
+ case QV4::CompiledData::BuiltinType::Vector2D:
+ case QV4::CompiledData::BuiltinType::Vector3D:
+ case QV4::CompiledData::BuiltinType::Vector4D:
+ case QV4::CompiledData::BuiltinType::Matrix4x4:
+ case QV4::CompiledData::BuiltinType::Quaternion:
+ Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QVariant propertyAsVariant;
+ if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
+ propertyAsVariant = v->d()->data();
+ QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
+ }
+ break;
+ case QV4::CompiledData::BuiltinType::Var:
+ if (ep) {
*reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
- break;
- case QV4::CompiledData::Property::CustomList: {
+ } else {
+ // if the context was disposed, we just return an invalid variant from read.
+ *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ }
+ break;
+ case QV4::CompiledData::BuiltinType::InvalidBuiltin:
+ if (property.isList) {
QList<QObject *> *list = readPropertyAsList(id);
QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
*p = QQmlListProperty<QObject>(object, list,
- list_append, list_count, list_at,
- list_clear);
+ list_append, list_count, list_at,
+ list_clear);
p->dummy1 = this;
p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
- break;
+ } else {
+ *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
}
- case QV4::CompiledData::Property::Font:
- case QV4::CompiledData::Property::Time:
- case QV4::CompiledData::Property::Color:
- case QV4::CompiledData::Property::Vector2D:
- case QV4::CompiledData::Property::Vector3D:
- case QV4::CompiledData::Property::Vector4D:
- case QV4::CompiledData::Property::Matrix4x4:
- case QV4::CompiledData::Property::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- QVariant propertyAsVariant;
- if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
- propertyAsVariant = v->d()->data();
- QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
+ }
+
+ } else if (c == QMetaObject::WriteProperty) {
+ bool needActivate = false;
+ switch (t) {
+ case QV4::CompiledData::BuiltinType::Int:
+ needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
+ writeProperty(id, *reinterpret_cast<int *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Bool:
+ needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
+ writeProperty(id, *reinterpret_cast<bool *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Real:
+ needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
+ writeProperty(id, *reinterpret_cast<double *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::String:
+ needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
+ writeProperty(id, *reinterpret_cast<QString *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Url:
+ needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
+ writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Date:
+ needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
+ writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::DateTime:
+ needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
+ writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Rect:
+ needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
+ writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Size:
+ needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
+ writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Point:
+ needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
+ writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Variant:
+ writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ break;
+ case QV4::CompiledData::BuiltinType::Font:
+ case QV4::CompiledData::BuiltinType::Time:
+ case QV4::CompiledData::BuiltinType::Color:
+ case QV4::CompiledData::BuiltinType::Vector2D:
+ case QV4::CompiledData::BuiltinType::Vector3D:
+ case QV4::CompiledData::BuiltinType::Vector4D:
+ case QV4::CompiledData::BuiltinType::Matrix4x4:
+ case QV4::CompiledData::BuiltinType::Quaternion:
+ Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
+ if (!v) {
+ md->set(engine, id, engine->newVariantObject(QVariant()));
+ v = (md->data() + id)->as<QV4::VariantObject>();
+ QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
}
- break;
- case QV4::CompiledData::Property::Var:
- Q_UNREACHABLE();
+ needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data());
+ QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data());
}
-
- } else if (c == QMetaObject::WriteProperty) {
-
- switch(t) {
- case QV4::CompiledData::Property::Int:
- needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
- writeProperty(id, *reinterpret_cast<int *>(a[0]));
- break;
- case QV4::CompiledData::Property::Bool:
- needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
- writeProperty(id, *reinterpret_cast<bool *>(a[0]));
- break;
- case QV4::CompiledData::Property::Real:
- needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
- writeProperty(id, *reinterpret_cast<double *>(a[0]));
- break;
- case QV4::CompiledData::Property::String:
- needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
- writeProperty(id, *reinterpret_cast<QString *>(a[0]));
- break;
- case QV4::CompiledData::Property::Url:
- needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
- writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
- break;
- case QV4::CompiledData::Property::Date:
- needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
- writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
- break;
- case QV4::CompiledData::Property::DateTime:
- needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
- writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
- break;
- case QV4::CompiledData::Property::Rect:
- needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
- writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
- break;
- case QV4::CompiledData::Property::Size:
- needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
- writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
- break;
- case QV4::CompiledData::Property::Point:
- needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
- writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
- break;
- case QV4::CompiledData::Property::Custom:
- needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
- writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
- break;
- case QV4::CompiledData::Property::Variant:
+ break;
+ case QV4::CompiledData::BuiltinType::Var:
+ if (ep)
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- break;
- case QV4::CompiledData::Property::CustomList:
+ break;
+ case QV4::CompiledData::BuiltinType::InvalidBuiltin:
+ if (property.isList) {
// Writing such a property is not supported. Content is added through the list property
// methods.
- break;
- case QV4::CompiledData::Property::Font:
- case QV4::CompiledData::Property::Time:
- case QV4::CompiledData::Property::Color:
- case QV4::CompiledData::Property::Vector2D:
- case QV4::CompiledData::Property::Vector3D:
- case QV4::CompiledData::Property::Vector4D:
- case QV4::CompiledData::Property::Matrix4x4:
- case QV4::CompiledData::Property::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
- if (!v) {
- md->set(engine, id, engine->newVariantObject(QVariant()));
- v = (md->data() + id)->as<QV4::VariantObject>();
- QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
- }
- needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data());
- QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data());
- }
- break;
- case QV4::CompiledData::Property::Var:
- Q_UNREACHABLE();
+ } else {
+ needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
+ writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
}
- }
- }
+ }
- if (c == QMetaObject::WriteProperty && needActivate) {
- activate(object, methodOffset() + id, nullptr);
+ if (needActivate)
+ activate(object, methodOffset() + id, nullptr);
}
return -1;
@@ -891,17 +869,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (!targetDData->propertyCache)
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
- // Value type property
+ // Value type property or deep alias
QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
- Q_ASSERT(valueType);
+ if (valueType) {
- valueType->read(target, coreIndex);
- int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
+ valueType->read(target, coreIndex);
+ int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
- if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, nullptr);
+ if (c == QMetaObject::WriteProperty)
+ valueType->write(target, coreIndex, nullptr);
- return rv;
+ return rv;
+ } else {
+ // deep alias
+ void *argv[1] = { &target };
+ QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ return QMetaObject::metacall(target, c, valueTypePropertyIndex, a);
+ }
} else {
return QMetaObject::metacall(target, c, coreIndex, a);
@@ -951,21 +935,38 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1; // The dynamic method with that id is not available.
}
- const unsigned int parameterCount = function->formalParameterCount();
+ auto methodData = cache->method(_id);
+ auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr;
+
+ const unsigned int parameterCount = (arguments && arguments->names) ? arguments->names->count() : 0;
+ Q_ASSERT(parameterCount == function->formalParameterCount());
+
QV4::JSCallData jsCallData(scope, parameterCount);
*jsCallData->thisObject = v4->global();
- for (uint ii = 0; ii < parameterCount; ++ii)
- jsCallData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]);
+ for (uint ii = 0; ii < parameterCount; ++ii) {
+ jsCallData->args[ii] = scope.engine->metaTypeToJS(arguments->arguments[ii + 1], a[ii + 1]);
+ }
+ const int returnType = methodData->propType();
QV4::ScopedValue result(scope, function->call(jsCallData));
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
ep->warning(error);
- if (a[0]) *(QVariant *)a[0] = QVariant();
+ if (a[0]) {
+ QMetaType::destruct(returnType, a[0]);
+ QMetaType::construct(returnType, a[0], nullptr);
+ }
} else {
- if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
+ if (a[0]) {
+ // When the return type is QVariant, JS objects are to be returned as QJSValue wrapped in
+ // QVariant.
+ if (returnType == QMetaType::QVariant)
+ *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
+ else
+ scope.engine->metaTypeFromJS(result, returnType, a[0]);
+ }
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -1000,7 +1001,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
@@ -1025,7 +1026,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const
void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -1065,7 +1066,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
- if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) {
+ if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index dbcc9d2884..5025987586 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -65,9 +65,7 @@
#include "qqmlguard_p.h"
#include "qqmlcontext_p.h"
-#include "qqmlpropertycache_p.h"
-#include <private/qv8engine_p.h>
#include <private/qflagpointer_p.h>
#include <private/qv4object_p.h>
@@ -146,7 +144,7 @@ class QQmlVMEMetaObjectEndpoint;
class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
- QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlCompilationUnit, int qmlObjectId);
+ QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId);
~QQmlVMEMetaObject() override;
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
@@ -228,7 +226,7 @@ public:
// keep a reference to the compilation unit in order to still
// do property access when the context has been invalidated.
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
const QV4::CompiledData::Object *compiledObject;
};
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 9877cc027f..4db0562c0e 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -39,8 +39,6 @@
#include "qqmlxmlhttprequest_p.h"
-#include <private/qv8engine_p.h>
-
#include "qqmlengine.h"
#include "qqmlengine_p.h"
#include <private/qqmlrefcount_p.h>
@@ -70,8 +68,6 @@
using namespace QV4;
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
-
#define V4THROW_REFERENCE(string) \
do { \
ScopedObject error(scope, scope.engine->newReferenceErrorObject(QStringLiteral(string))); \
@@ -99,7 +95,7 @@ struct QQmlXMLHttpRequestData {
static inline QQmlXMLHttpRequestData *xhrdata(ExecutionEngine *v4)
{
- return (QQmlXMLHttpRequestData *)v4->v8Engine->xmlHttpRequestData();
+ return (QQmlXMLHttpRequestData *)v4->xmlHttpRequestData();
}
QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
@@ -595,7 +591,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
if (d->nodePrototype.isUndefined()) {
ScopedObject p(scope, v4->memoryManager->allocate<NodePrototype>());
d->nodePrototype.set(v4, p);
- v4->v8Engine->freezeObject(p);
+ v4->freezeObject(p);
}
return d->nodePrototype.value();
}
@@ -644,7 +640,7 @@ ReturnedValue Element::prototype(ExecutionEngine *engine)
p->setPrototypeUnchecked((pp = NodePrototype::getProto(engine)));
p->defineAccessorProperty(QStringLiteral("tagName"), NodePrototype::method_get_nodeName, nullptr);
d->elementPrototype.set(engine, p);
- engine->v8Engine->freezeObject(p);
+ engine->freezeObject(p);
}
return d->elementPrototype.value();
}
@@ -661,7 +657,7 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine)
p->defineAccessorProperty(QStringLiteral("value"), method_value, nullptr);
p->defineAccessorProperty(QStringLiteral("ownerElement"), method_ownerElement, nullptr);
d->attrPrototype.set(engine, p);
- engine->v8Engine->freezeObject(p);
+ engine->freezeObject(p);
}
return d->attrPrototype.value();
}
@@ -717,7 +713,7 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
p->defineAccessorProperty(QStringLiteral("data"), NodePrototype::method_get_nodeValue, nullptr);
p->defineAccessorProperty(QStringLiteral("length"), method_length, nullptr);
d->characterDataPrototype.set(v4, p);
- v4->v8Engine->freezeObject(p);
+ v4->freezeObject(p);
}
return d->characterDataPrototype.value();
}
@@ -753,7 +749,7 @@ ReturnedValue Text::prototype(ExecutionEngine *v4)
p->defineAccessorProperty(QStringLiteral("isElementContentWhitespace"), method_isElementContentWhitespace, nullptr);
p->defineAccessorProperty(QStringLiteral("wholeText"), method_wholeText, nullptr);
d->textPrototype.set(v4, p);
- v4->v8Engine->freezeObject(p);
+ v4->freezeObject(p);
}
return d->textPrototype.value();
}
@@ -768,7 +764,7 @@ ReturnedValue CDATA::prototype(ExecutionEngine *v4)
ScopedObject pp(scope);
p->setPrototypeUnchecked((pp = Text::prototype(v4)));
d->cdataPrototype.set(v4, p);
- v4->v8Engine->freezeObject(p);
+ v4->freezeObject(p);
}
return d->cdataPrototype.value();
}
@@ -786,7 +782,7 @@ ReturnedValue Document::prototype(ExecutionEngine *v4)
p->defineAccessorProperty(QStringLiteral("xmlStandalone"), method_xmlStandalone, nullptr);
p->defineAccessorProperty(QStringLiteral("documentElement"), method_documentElement, nullptr);
d->documentPrototype.set(v4, p);
- v4->v8Engine->freezeObject(p);
+ v4->freezeObject(p);
}
return d->documentPrototype.value();
}
@@ -1651,7 +1647,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(f->engine());
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine);
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototypeUnchecked(proto);
@@ -2073,6 +2069,4 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4)
QT_END_NAMESPACE
-#endif // xmlstreamreader && qml_network
-
#include <qqmlxmlhttprequest.moc>
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 4422195e3d..d634a48443 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -40,6 +40,7 @@
#include "qqmlbuiltinfunctions_p.h"
#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlfile.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlloggingcategory_p.h>
@@ -47,7 +48,6 @@
#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
#endif
-#include <private/qv8engine_p.h>
#include <private/qqmldelayedcallqueue_p.h>
#include <QFileInfo>
@@ -439,7 +439,7 @@ ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, cons
QV4::ExecutionEngine *v4 = scope.engine;
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(argv[0]), v4, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, argv[0], v4, &ok);
if (!ok)
THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
return scope.engine->fromVariant(v);
@@ -559,7 +559,7 @@ ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *,
if (argc == 1 && argv[0].isObject()) {
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(argv[0]), scope.engine, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, argv[0], scope.engine, &ok);
if (!ok)
THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
return scope.engine->fromVariant(v);
@@ -1710,10 +1710,8 @@ ReturnedValue ConsoleObject::method_time(const FunctionObject *b, const Value *,
if (argc != 1)
THROW_GENERIC_ERROR("console.time(): Invalid arguments");
- QV8Engine *v8engine = scope.engine->v8Engine;
-
QString name = argv[0].toQStringNoThrow();
- v8engine->startTimer(name);
+ scope.engine->startTimer(name);
return QV4::Encode::undefined();
}
@@ -1723,11 +1721,9 @@ ReturnedValue ConsoleObject::method_timeEnd(const FunctionObject *b, const Value
if (argc != 1)
THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments");
- QV8Engine *v8engine = scope.engine->v8Engine;
-
QString name = argv[0].toQStringNoThrow();
bool wasRunning;
- qint64 elapsed = v8engine->stopTimer(name, &wasRunning);
+ qint64 elapsed = scope.engine->stopTimer(name, &wasRunning);
if (wasRunning) {
qDebug("%s: %llims", qPrintable(name), elapsed);
}
@@ -1743,13 +1739,12 @@ ReturnedValue ConsoleObject::method_count(const FunctionObject *b, const Value *
Scope scope(b);
QV4::ExecutionEngine *v4 = scope.engine;
- QV8Engine *v8engine = scope.engine->v8Engine;
QV4::CppStackFrame *frame = v4->currentStackFrame;
QString scriptName = frame->source();
- int value = v8engine->consoleCountHelper(scriptName, frame->lineNumber(), 0);
+ int value = v4->consoleCountHelper(scriptName, frame->lineNumber(), 0);
QString message = name + QLatin1String(": ") + QString::number(value);
QMessageLogger(qPrintable(scriptName), frame->lineNumber(),
@@ -1972,29 +1967,32 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
QString context;
- if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
- QString path = ctxt->urlString();
- 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 {
- CppStackFrame *frame = scope.engine->currentStackFrame;
- // The first non-empty source URL in the call stack determines the translation context.
- while (frame && context.isEmpty()) {
- if (CompiledData::CompilationUnit *unit = frame->v4Function->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();
+ CppStackFrame *frame = scope.engine->currentStackFrame;
+ // The first non-empty source URL in the call stack determines the translation context.
+ while (frame && context.isEmpty()) {
+ if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) {
+ const auto *unit = static_cast<const CompiledData::CompilationUnit *>(baseUnit);
+ 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;
}
- frame = frame->parent;
+ context = QFileInfo(context).baseName();
+ }
+ frame = frame->parent;
+ }
+
+ if (context.isEmpty()) {
+ if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
+ QString path = ctxt->urlString();
+ 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();
}
}
@@ -2173,8 +2171,7 @@ function.
*/
ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
- QV8Engine *v8engine = b->engine()->v8Engine;
- return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc);
+ return b->engine()->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
deleted file mode 100644
index d76344b613..0000000000
--- a/src/qml/qml/v8/qv8engine.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8engine_p.h"
-
-#if QT_CONFIG(qml_sequence_object)
-#include "qv4sequenceobject_p.h"
-#endif
-
-#include "private/qjsengine_p.h"
-
-#include <private/qqmlbuiltinfunctions_p.h>
-#include <private/qqmllist_p.h>
-#include <private/qqmlengine_p.h>
-#if QT_CONFIG(qml_xml_http_request)
-#include <private/qqmlxmlhttprequest_p.h>
-#endif
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlmemoryprofiler_p.h>
-#include <private/qqmlplatform_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qqmltypewrapper_p.h>
-#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qqmllistwrapper_p.h>
-#include <private/qv4scopedvalue_p.h>
-
-#include "qv4domerrors_p.h"
-#include "qv4sqlerrors_p.h"
-
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonvalue.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdatastream.h>
-#include <private/qsimd_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4mm_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4globalobject_p.h>
-#include <private/qv4regexpobject_p.h>
-#include <private/qv4variantobject_p.h>
-#include <private/qv4script_p.h>
-#include <private/qv4include_p.h>
-#include <private/qv4jsonobject_p.h>
-#include <private/qv4identifiertable_p.h>
-
-Q_DECLARE_METATYPE(QList<int>)
-
-
-// XXX TODO: Need to check all the global functions will also work in a worker script where the
-// QQmlEngine is not available
-QT_BEGIN_NAMESPACE
-
-template <typename ReturnType>
-ReturnType convertJSValueToVariantType(const QJSValue &value)
-{
- return value.toVariant().value<ReturnType>();
-}
-
-static void saveJSValue(QDataStream &stream, const void *data)
-{
- const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
- quint32 isNullOrUndefined = 0;
- if (jsv->isNull())
- isNullOrUndefined |= 0x1;
- if (jsv->isUndefined())
- isNullOrUndefined |= 0x2;
- stream << isNullOrUndefined;
- if (!isNullOrUndefined)
- reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
-}
-
-static void restoreJSValue(QDataStream &stream, void *data)
-{
- QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
-
- quint32 isNullOrUndefined;
- stream >> isNullOrUndefined;
-
- if (isNullOrUndefined & 0x1) {
- *jsv = QJSValue(QJSValue::NullValue);
- } else if (isNullOrUndefined & 0x2) {
- *jsv = QJSValue();
- } else {
- QVariant v;
- v.load(stream);
- QJSValuePrivate::setVariant(jsv, v);
- }
-}
-
-QV8Engine::QV8Engine(QV4::ExecutionEngine *v4)
- : m_engine(nullptr)
- , m_v4Engine(v4)
-#if QT_CONFIG(qml_xml_http_request)
- , m_xmlHttpRequestData(nullptr)
-#endif
-{
-#ifndef Q_OS_WASM // wasm does not have working simd QTBUG-63924
-#ifdef Q_PROCESSOR_X86_32
- if (!qCpuHasFeature(SSE2)) {
- qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer");
- }
-#endif
-#endif
-
- QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine");
- qMetaTypeId<QJSValue>();
- qMetaTypeId<QList<int> >();
-
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
- QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
- QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
- QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
- QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue);
-
- m_delayedCallQueue.init(m_v4Engine);
-
- QV4::QObjectWrapper::initializeBindings(m_v4Engine);
-}
-
-QV8Engine::~QV8Engine()
-{
- qDeleteAll(m_extensionData);
- m_extensionData.clear();
-
-#if QT_CONFIG(qml_xml_http_request)
- qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData);
- m_xmlHttpRequestData = nullptr;
-#endif
-}
-
-#if QT_CONFIG(qml_network)
-QNetworkAccessManager *QV8Engine::networkAccessManager()
-{
- return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager();
-}
-#endif
-
-const QSet<QString> &QV8Engine::illegalNames() const
-{
- return m_illegalNames;
-}
-
-void QV8Engine::initializeGlobal()
-{
- QV4::Scope scope(m_v4Engine);
- QV4::GlobalExtensions::init(m_v4Engine->globalObject, QJSEngine::AllExtensions);
-
- QV4::ScopedObject qt(scope, m_v4Engine->memoryManager->allocate<QV4::QtObject>(m_engine));
- m_v4Engine->globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
-
-#if QT_CONFIG(qml_locale)
- QQmlLocale::registerStringLocaleCompare(m_v4Engine);
- QQmlDateExtension::registerExtension(m_v4Engine);
- QQmlNumberExtension::registerExtension(m_v4Engine);
-#endif
-
-#if QT_CONFIG(qml_xml_http_request)
- qt_add_domexceptions(m_v4Engine);
- m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine);
-#endif
-
- qt_add_sqlexceptions(m_v4Engine);
-
- {
- for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) {
- if (m_v4Engine->globalObject->internalClass()->nameMap.at(i).isString()) {
- QV4::PropertyKey id = m_v4Engine->globalObject->internalClass()->nameMap.at(i);
- m_illegalNames.insert(id.toQString());
- }
- }
- }
-}
-
-static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
-{
- if (object->as<QV4::QObjectWrapper>())
- return;
-
- QV4::Scope scope(v4);
-
- bool instanceOfObject = false;
- QV4::ScopedObject p(scope, object->getPrototypeOf());
- while (p) {
- if (p->d() == v4->objectPrototype()->d()) {
- instanceOfObject = true;
- break;
- }
- p = p->getPrototypeOf();
- }
- if (!instanceOfObject)
- return;
-
- QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen();
- if (object->internalClass() == frozen)
- return;
- object->setInternalClass(frozen);
-
- QV4::ScopedObject o(scope);
- for (uint i = 0; i < frozen->size; ++i) {
- if (!frozen->nameMap.at(i).isStringOrSymbol())
- continue;
- o = *object->propertyData(i);
- if (o)
- freeze_recursive(v4, o);
- }
-}
-
-void QV8Engine::freezeObject(const QV4::Value &value)
-{
- QV4::Scope scope(m_v4Engine);
- QV4::ScopedObject o(scope, value);
- freeze_recursive(m_v4Engine, o);
-}
-
-struct QV8EngineRegistrationData
-{
- QV8EngineRegistrationData() : extensionCount(0) {}
-
- QMutex mutex;
- int extensionCount;
-};
-Q_GLOBAL_STATIC(QV8EngineRegistrationData, registrationData);
-
-QMutex *QV8Engine::registrationMutex()
-{
- return &registrationData()->mutex;
-}
-
-int QV8Engine::registerExtension()
-{
- return registrationData()->extensionCount++;
-}
-
-void QV8Engine::setExtensionData(int index, Deletable *data)
-{
- if (m_extensionData.count() <= index)
- m_extensionData.resize(index + 1);
-
- if (m_extensionData.at(index))
- delete m_extensionData.at(index);
-
- m_extensionData[index] = data;
-}
-
-void QV8Engine::initQmlGlobalObject()
-{
- initializeGlobal();
- freezeObject(*m_v4Engine->globalObject);
-}
-
-void QV8Engine::setEngine(QQmlEngine *engine)
-{
- m_engine = engine;
- initQmlGlobalObject();
-}
-
-void QV8Engine::startTimer(const QString &timerName)
-{
- if (!m_time.isValid())
- m_time.start();
- m_startedTimers[timerName] = m_time.elapsed();
-}
-
-qint64 QV8Engine::stopTimer(const QString &timerName, bool *wasRunning)
-{
- if (!m_startedTimers.contains(timerName)) {
- *wasRunning = false;
- return 0;
- }
- *wasRunning = true;
- qint64 startedAt = m_startedTimers.take(timerName);
- return m_time.elapsed() - startedAt;
-}
-
-int QV8Engine::consoleCountHelper(const QString &file, quint16 line, quint16 column)
-{
- const QString key = file + QString::number(line) + QString::number(column);
- int number = m_consoleCount.value(key, 0);
- number++;
- m_consoleCount.insert(key, number);
- return number;
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
deleted file mode 100644
index 23559618ef..0000000000
--- a/src/qml/qml/v8/qv8engine_p.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLV8ENGINE_P_H
-#define QQMLV8ENGINE_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/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qset.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qstack.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/QElapsedTimer>
-#include <QtCore/QThreadStorage>
-
-#include <QtQml/qjsengine.h>
-#include "private/qintrusivelist_p.h"
-
-
-#include <private/qv4value_p.h>
-#include <private/qv4identifier_p.h>
-#include <private/qv4context_p.h>
-#include <private/qv4stackframe_p.h>
-#include <private/qqmldelayedcallqueue_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
- struct ArrayObject;
- struct ExecutionEngine;
- struct QObjectMethod;
-}
-
-#define V4_DEFINE_EXTENSION(dataclass, datafunction) \
- static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \
- { \
- static int extensionId = -1; \
- if (extensionId == -1) { \
- QV8Engine::registrationMutex()->lock(); \
- if (extensionId == -1) \
- extensionId = QV8Engine::registerExtension(); \
- QV8Engine::registrationMutex()->unlock(); \
- } \
- dataclass *rv = (dataclass *)engine->v8Engine->extensionData(extensionId); \
- if (!rv) { \
- rv = new dataclass(engine); \
- engine->v8Engine->setExtensionData(extensionId, rv); \
- } \
- return rv; \
- } \
-
-// Used to allow a QObject method take and return raw V4 handles without having to expose
-// 48 in the public API.
-// Use like this:
-// class MyClass : public QObject {
-// Q_OBJECT
-// ...
-// Q_INVOKABLE void myMethod(QQmlV4Function*);
-// };
-// The QQmlV8Function - and consequently the arguments and return value - only remains
-// valid during the call. If the return value isn't set within myMethod(), the will return
-// undefined.
-
-class QQmlV4Function
-{
-public:
- int length() const { return callData->argc(); }
- QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); }
- void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; }
- QV4::ExecutionEngine *v4engine() const { return e; }
-private:
- friend struct QV4::QObjectMethod;
- QQmlV4Function();
- QQmlV4Function(const QQmlV4Function &);
- QQmlV4Function &operator=(const QQmlV4Function &);
-
- QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e)
- : callData(callData), retVal(retVal), e(e)
- {
- callData->thisObject = QV4::Encode::undefined();
- }
-
- QV4::CallData *callData;
- QV4::Value *retVal;
- QV4::ExecutionEngine *e;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlV4Handle
-{
-public:
- QQmlV4Handle() : d(QV4::Encode::undefined()) {}
- explicit QQmlV4Handle(const QV4::Value &v) : d(v.asReturnedValue()) {}
- explicit QQmlV4Handle(QV4::ReturnedValue v) : d(v) {}
-
- operator QV4::ReturnedValue() const { return d; }
-
-private:
- quint64 d;
-};
-
-class QObject;
-class QQmlEngine;
-class QNetworkAccessManager;
-class QQmlContextData;
-
-class Q_QML_PRIVATE_EXPORT QV8Engine
-{
- friend class QJSEngine;
-public:
-// static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
- static QV4::ExecutionEngine *getV4(QV8Engine *d) { return d->m_v4Engine; }
-
- QV8Engine(QV4::ExecutionEngine *v4);
- virtual ~QV8Engine();
-
- // This enum should be in sync with QQmlEngine::ObjectOwnership
- enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
-
- struct Deletable {
- virtual ~Deletable() {}
- };
-
- void initQmlGlobalObject();
- void setEngine(QQmlEngine *engine);
- QQmlEngine *engine() { return m_engine; }
- QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
-
-#if QT_CONFIG(qml_xml_http_request)
- void *xmlHttpRequestData() const { return m_xmlHttpRequestData; }
-#endif
-
- void freezeObject(const QV4::Value &value);
-
-#if QT_CONFIG(qml_network)
- // Return the network access manager for this engine. By default this returns the network
- // access manager of the QQmlEngine. It is overridden in the case of a threaded v8
- // instance (like in WorkerScript).
- virtual QNetworkAccessManager *networkAccessManager();
-#endif
-
- // Return the list of illegal id names (the names of the properties on the global object)
- const QSet<QString> &illegalNames() const;
-
- static QMutex *registrationMutex();
- static int registerExtension();
-
- inline Deletable *extensionData(int) const;
- void setExtensionData(int, Deletable *);
-
-public:
- // used for console.time(), console.timeEnd()
- void startTimer(const QString &timerName);
- qint64 stopTimer(const QString &timerName, bool *wasRunning);
-
- // used for console.count()
- int consoleCountHelper(const QString &file, quint16 line, quint16 column);
-
-protected:
- QQmlEngine *m_engine;
- QQmlDelayedCallQueue m_delayedCallQueue;
-
- QV4::ExecutionEngine *m_v4Engine;
-
-#if QT_CONFIG(qml_xml_http_request)
- void *m_xmlHttpRequestData;
-#endif
-
- QVector<Deletable *> m_extensionData;
-
- QSet<QString> m_illegalNames;
-
- QElapsedTimer m_time;
- QHash<QString, qint64> m_startedTimers;
-
- QHash<QString, quint32> m_consoleCount;
-
- void initializeGlobal();
-
-private:
- Q_DISABLE_COPY(QV8Engine)
-};
-
-inline QV8Engine::Deletable *QV8Engine::extensionData(int index) const
-{
- if (index < m_extensionData.count())
- return m_extensionData[index];
- else
- return nullptr;
-}
-
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QQmlV4Handle)
-
-#endif // QQMLV8ENGINE_P_H
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
index 4592022939..fbcc47de0c 100644
--- a/src/qml/qml/v8/v8.pri
+++ b/src/qml/qml/v8/v8.pri
@@ -1,11 +1,9 @@
HEADERS += \
- $$PWD/qv8engine_p.h \
$$PWD/qv4domerrors_p.h \
$$PWD/qv4sqlerrors_p.h \
$$PWD/qqmlbuiltinfunctions_p.h
SOURCES += \
- $$PWD/qv8engine.cpp \
$$PWD/qv4domerrors.cpp \
$$PWD/qv4sqlerrors.cpp \
$$PWD/qqmlbuiltinfunctions.cpp
diff --git a/src/qml/qmldirparser/qmldirparser.pri b/src/qml/qmldirparser/qmldirparser.pri
index 660e7b395a..fefe2e75be 100644
--- a/src/qml/qmldirparser/qmldirparser.pri
+++ b/src/qml/qmldirparser/qmldirparser.pri
@@ -2,10 +2,7 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
HEADERS += \
- $$PWD/qqmldirparser_p.h \
- $$PWD/qqmlerror.h \
- $$PWD/qqmlsourcecoordinate_p.h
+ $$PWD/qqmldirparser_p.h
SOURCES += \
- $$PWD/qqmldirparser.cpp \
- $$PWD/qqmlerror.cpp
+ $$PWD/qqmldirparser.cpp
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index e944b52e47..5bf33d3602 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qqmldirparser_p.h"
-#include "qqmlerror.h"
#include <QtCore/QtDebug>
@@ -263,6 +262,13 @@ bool QQmlDirParser::parse(const QString &source)
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
+ } else if (sections[0] == QLatin1String("import")) {
+ if (sectionCount != 2) {
+ reportError(lineNumber, 0,
+ QStringLiteral("import requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ continue;
+ }
+ _imports << sections[1];
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
@@ -297,8 +303,8 @@ bool QQmlDirParser::parse(const QString &source)
void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description)
{
QQmlJS::DiagnosticMessage error;
- error.loc.startLine = line;
- error.loc.startColumn = column;
+ error.line = line;
+ error.column = column;
error.message = description;
_errors.append(error);
}
@@ -311,27 +317,20 @@ bool QQmlDirParser::hasError() const
return false;
}
-void QQmlDirParser::setError(const QQmlError &e)
+void QQmlDirParser::setError(const QQmlJS::DiagnosticMessage &e)
{
_errors.clear();
- reportError(e.line(), e.column(), e.description());
+ reportError(e.line, e.column, e.message);
}
-QList<QQmlError> QQmlDirParser::errors(const QString &uri) const
+QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const
{
- QUrl url(uri);
- QList<QQmlError> errors;
+ QList<QQmlJS::DiagnosticMessage> errors;
const int numErrors = _errors.size();
errors.reserve(numErrors);
for (int i = 0; i < numErrors; ++i) {
- const QQmlJS::DiagnosticMessage &msg = _errors.at(i);
- QQmlError e;
- QString description = msg.message;
- description.replace(QLatin1String("$$URI$$"), uri);
- e.setDescription(description);
- e.setUrl(url);
- e.setLine(msg.loc.startLine);
- e.setColumn(msg.loc.startColumn);
+ QQmlJS::DiagnosticMessage e = _errors.at(i);
+ e.message.replace(QLatin1String("$$URI$$"), uri);
errors << e;
}
return errors;
@@ -362,6 +361,11 @@ QHash<QString, QQmlDirParser::Component> QQmlDirParser::dependencies() const
return _dependencies;
}
+QStringList QQmlDirParser::imports() const
+{
+ return _imports;
+}
+
QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
{
return _scripts;
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index f7a91c8b81..37ca1ef2ce 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -54,14 +54,14 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qqmljsengine_p.h>
-#include <private/qv4global_p.h>
+#include <private/qqmljsdiagnosticmessage_p.h>
QT_BEGIN_NAMESPACE
-class QQmlError;
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlDirParser
+class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlDirParser
{
public:
QQmlDirParser();
@@ -70,8 +70,8 @@ public:
bool parse(const QString &source);
bool hasError() const;
- void setError(const QQmlError &);
- QList<QQmlError> errors(const QString &uri) const;
+ void setError(const QQmlJS::DiagnosticMessage &);
+ QList<QQmlJS::DiagnosticMessage> errors(const QString &uri) const;
QString typeNamespace() const;
void setTypeNamespace(const QString &s);
@@ -136,6 +136,7 @@ public:
QHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const;
+ QStringList imports() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;
bool designerSupported() const;
@@ -162,6 +163,7 @@ private:
QString _typeNamespace;
QHash<QString,Component> _components; // multi hash
QHash<QString,Component> _dependencies;
+ QStringList _imports;
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported;
diff --git a/src/qml/qtqmlcompilerglobal.h b/src/qml/qtqmlcompilerglobal.h
new file mode 100644
index 0000000000..850d413372
--- /dev/null
+++ b/src/qml/qtqmlcompilerglobal.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQMLCOMPILERGLOBAL_H
+#define QTQMLCOMPILERGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) || defined(QT_STATIC)
+# define Q_QMLCOMPILER_EXPORT
+#else
+# if defined(QT_BUILD_QML_LIB)
+# define Q_QMLCOMPILER_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QMLCOMPILER_EXPORT Q_DECL_IMPORT
+# endif
+#endif
+
+QT_END_NAMESPACE
+#endif // QTQMLCOMPILERGLOBAL_H
diff --git a/src/qml/qtqmlcompilerglobal_p.h b/src/qml/qtqmlcompilerglobal_p.h
new file mode 100644
index 0000000000..9c8bce23d3
--- /dev/null
+++ b/src/qml/qtqmlcompilerglobal_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQMLCOMPILERGLOBAL_P_H
+#define QTQMLCOMPILERGLOBAL_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/private/qglobal_p.h>
+#include <qtqmlcompilerglobal.h>
+
+#define Q_QMLCOMPILER_PRIVATE_EXPORT Q_QMLCOMPILER_EXPORT
+
+#endif // QTQMLCOMPILERGLOBAL_P_H
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 090b830b3c..3e275c6359 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -53,7 +53,9 @@
#else
# define QT_FEATURE_qml_debug -1
# define QT_FEATURE_qml_sequence_object 1
-# define QT_FEATURE_qml_tracing -1
+# define QT_FEATURE_qml_jit -1
+# define QT_FEATURE_qml_worker_script -1
+# define QT_FEATURE_qml_xml_http_request -1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 60988d12e6..9ca0cf2abe 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -56,8 +56,7 @@
#ifndef QT_QML_BOOTSTRAPPED
# include <QtQml/private/qtqml-config_p.h>
#endif
-
-#define Q_QML_PRIVATE_API_VERSION 3
+#include <private/qqmlapiversion_p.h>
#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 513f7f2997..921d60caa1 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -43,6 +43,8 @@
#include <private/qqmlproperty_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4persistent_p.h>
#include <qqmlengine.h>
#include <qqmlcontext.h>
@@ -52,28 +54,50 @@
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qloggingcategory.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+
class QQmlBindPrivate : public QObjectPrivate
{
public:
- QQmlBindPrivate() : obj(nullptr), componentComplete(true), delayed(false), pendingEval(false) {}
+ QQmlBindPrivate()
+ : obj(nullptr)
+ , prevBind(QQmlAbstractBinding::Ptr())
+ , prevIsVariant(false)
+ , componentComplete(true)
+ , delayed(false)
+ , pendingEval(false)
+ , restoreBinding(true)
+ , restoreValue(false)
+ , restoreModeExplicit(false)
+ , writingProperty(false)
+ {}
~QQmlBindPrivate() { }
QQmlNullableValue<bool> when;
QPointer<QObject> obj;
QString propName;
- QQmlNullableValue<QVariant> value;
+ QQmlNullableValue<QJSValue> value;
QQmlProperty prop;
QQmlAbstractBinding::Ptr prevBind;
+ QV4::PersistentValue v4Value;
+ QVariant prevValue;
+ bool prevIsVariant:1;
bool componentComplete:1;
bool delayed:1;
bool pendingEval:1;
+ bool restoreBinding:1;
+ bool restoreValue:1;
+ bool restoreModeExplicit:1;
+ bool writingProperty: 1;
void validate(QObject *binding) const;
+ void clearPrev();
};
void QQmlBindPrivate::validate(QObject *binding) const
@@ -174,6 +198,13 @@ QQmlBind::~QQmlBind()
When the binding becomes inactive again, any direct bindings that were previously
set on the property will be restored.
+
+ \note By default, a previously set literal value is not restored when the Binding becomes
+ inactive. Rather, the last value set by the now inactive Binding is retained. You can customize
+ the restoration behavior for literal values as well as bindings using the \l restoreMode
+ property. The default will change in Qt 6.0.
+
+ \sa restoreMode
*/
bool QQmlBind::when() const
{
@@ -216,7 +247,7 @@ void QQmlBind::setObject(QObject *obj)
}
d->obj = obj;
if (d->componentComplete) {
- d->prop = QQmlProperty(d->obj, d->propName);
+ setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
d->validate(this);
}
eval();
@@ -262,7 +293,7 @@ void QQmlBind::setProperty(const QString &p)
}
d->propName = p;
if (d->componentComplete) {
- d->prop = QQmlProperty(d->obj, d->propName);
+ setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
d->validate(this);
}
eval();
@@ -274,13 +305,13 @@ void QQmlBind::setProperty(const QString &p)
The value to be set on the target object and property. This can be a
constant (which isn't very useful), or a bound expression.
*/
-QVariant QQmlBind::value() const
+QJSValue QQmlBind::value() const
{
Q_D(const QQmlBind);
return d->value.value;
}
-void QQmlBind::setValue(const QVariant &v)
+void QQmlBind::setValue(const QJSValue &v)
{
Q_D(QQmlBind);
d->value = v;
@@ -323,9 +354,71 @@ void QQmlBind::setDelayed(bool delayed)
eval();
}
+/*!
+ \qmlproperty enumeration QtQml::Binding::restoreMode
+ \since 5.14
+
+ This property can be used to describe if and how the original value should
+ be restored when the binding is disabled.
+
+ The possible values are:
+ \list
+ \li Binding.RestoreNone The original value is not restored at all
+ \li Binding.RestoreBinding The original value is restored if it was another
+ binding. In that case the old binding is in effect again.
+ \li Binding.RestoreValue The original value is restored if it was a plain
+ value rather than a binding.
+ \li Binding.RestoreBindingOrValue The original value is always restored.
+ \endlist
+
+ \warning The default value is Binding.RestoreBinding. This will change in
+ Qt 6.0 to Binding.RestoreBindingOrValue.
+
+ If you rely on any specific behavior regarding the restoration of plain
+ values when bindings get disabled you should migrate to explicitly set the
+ restoreMode.
+
+ Reliance on a restoreMode that doesn't restore the previous binding or value
+ for a specific property results in a run-time warning.
+*/
+QQmlBind::RestorationMode QQmlBind::restoreMode() const
+{
+ Q_D(const QQmlBind);
+ unsigned result = RestoreNone;
+ if (d->restoreValue)
+ result |= RestoreValue;
+ if (d->restoreBinding)
+ result |= RestoreBinding;
+ return RestorationMode(result);
+}
+
+void QQmlBind::setRestoreMode(RestorationMode newMode)
+{
+ Q_D(QQmlBind);
+ d->restoreModeExplicit = true;
+ if (newMode != restoreMode()) {
+ d->restoreValue = (newMode & RestoreValue);
+ d->restoreBinding = (newMode & RestoreBinding);
+ emit restoreModeChanged();
+ }
+}
+
void QQmlBind::setTarget(const QQmlProperty &p)
{
Q_D(QQmlBind);
+
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (QObject *oldObject = d->prop.object()) {
+ QMetaProperty prop = oldObject->metaObject()->property(d->prop.index());
+ if (prop.hasNotifySignal()) {
+ QByteArray signal('2' + prop.notifySignal().methodSignature());
+ QObject::disconnect(oldObject, signal.constData(),
+ this, SLOT(targetValueChanged()));
+ }
+ }
+ p.connectNotifySignal(this, SLOT(targetValueChanged()));
+ }
+
d->prop = p;
}
@@ -340,7 +433,7 @@ void QQmlBind::componentComplete()
Q_D(QQmlBind);
d->componentComplete = true;
if (!d->prop.isValid()) {
- d->prop = QQmlProperty(d->obj, d->propName);
+ setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
d->validate(this);
}
eval();
@@ -358,6 +451,14 @@ void QQmlBind::prepareEval()
}
}
+void QQmlBindPrivate::clearPrev()
+{
+ prevBind = nullptr;
+ v4Value.clear();
+ prevValue.clear();
+ prevIsVariant = false;
+}
+
void QQmlBind::eval()
{
Q_D(QQmlBind);
@@ -369,20 +470,91 @@ void QQmlBind::eval()
if (!d->when) {
//restore any previous binding
if (d->prevBind) {
- QQmlAbstractBinding::Ptr p = d->prevBind;
- d->prevBind = nullptr;
- QQmlPropertyPrivate::setBinding(p.data());
+ if (d->restoreBinding) {
+ QQmlAbstractBinding::Ptr p = d->prevBind;
+ d->clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
+ QQmlPropertyPrivate::setBinding(p.data());
+ }
+ } else if (!d->v4Value.isEmpty()) {
+ if (d->restoreValue) {
+ auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
+ Q_ASSERT(vmemo);
+ vmemo->setVMEProperty(propPriv->core.coreIndex(), *d->v4Value.valueRef());
+ d->clearPrev();
+ } else if (!d->restoreModeExplicit) {
+ qmlWarning(this)
+ << "Not restoring previous value because restoreMode has not been set."
+ << "This behavior is deprecated."
+ << "In Qt < 6.0 the default is Binding.RestoreBinding."
+ << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.";
+ }
+ } else if (d->prevIsVariant) {
+ if (d->restoreValue) {
+ d->prop.write(d->prevValue);
+ d->clearPrev();
+ } else if (!d->restoreModeExplicit) {
+ qmlWarning(this)
+ << "Not restoring previous value because restoreMode has not been set."
+ << "This behavior is deprecated."
+ << "In Qt < 6.0 the default is Binding.RestoreBinding."
+ << "In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.";
+ }
}
return;
}
//save any set binding for restoration
- if (!d->prevBind)
+ if (!d->prevBind && d->v4Value.isEmpty() && !d->prevIsVariant) {
+ // try binding first
d->prevBind = QQmlPropertyPrivate::binding(d->prop);
+
+ if (!d->prevBind) { // nope, try a V4 value next
+ auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ auto propData = propPriv->core;
+ if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
+ Q_ASSERT(vmemo);
+ auto retVal = vmemo->vmeProperty(propData.coreIndex());
+ d->v4Value = QV4::PersistentValue(vmemo->engine, retVal);
+ } else { // nope, use the meta object to get a QVariant
+ d->prevValue = d->prop.read();
+ d->prevIsVariant = true;
+ }
+ }
+ }
+
QQmlPropertyPrivate::removeBinding(d->prop);
}
- d->prop.write(d->value.value);
+ d->writingProperty = true;
+ d->prop.write(d->value.value.toVariant());
+ d->writingProperty = false;
+}
+
+void QQmlBind::targetValueChanged()
+{
+ Q_D(QQmlBind);
+ if (d->writingProperty)
+ return;
+
+ if (d->when.isValid() && !d->when)
+ return;
+
+ QUrl url;
+ quint16 line = 0;
+
+ const QQmlData *ddata = QQmlData::get(this, false);
+ if (ddata && ddata->outerContext) {
+ url = ddata->outerContext->url();
+ line = ddata->lineNumber;
+ }
+
+ qCInfo(lcBindingRemoval,
+ "The target property of the Binding element created at %s:%d was changed from "
+ "elsewhere. This does not overwrite the binding. The target property will still be "
+ "updated when the value of the Binding element changes.",
+ qPrintable(url.toString()), line);
}
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index 5bf9ef85c6..7bf4fc4dfd 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -60,15 +60,27 @@ QT_BEGIN_NAMESPACE
class QQmlBindPrivate;
class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
{
+public:
+ enum RestorationMode {
+ RestoreNone = 0x0,
+ RestoreBinding = 0x1,
+ RestoreValue = 0x2,
+ RestoreBindingOrValue = RestoreBinding | RestoreValue
+ };
+
+private:
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlBind)
Q_INTERFACES(QQmlParserStatus)
Q_INTERFACES(QQmlPropertyValueSource)
Q_PROPERTY(QObject *target READ object WRITE setObject)
Q_PROPERTY(QString property READ property WRITE setProperty)
- Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QJSValue value READ value WRITE setValue)
Q_PROPERTY(bool when READ when WRITE setWhen)
Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION 8)
+ Q_PROPERTY(RestorationMode restoreMode READ restoreMode WRITE setRestoreMode
+ NOTIFY restoreModeChanged REVISION 14)
+ Q_ENUM(RestorationMode)
public:
QQmlBind(QObject *parent=nullptr);
@@ -83,12 +95,18 @@ public:
QString property() const;
void setProperty(const QString &);
- QVariant value() const;
- void setValue(const QVariant &);
+ QJSValue value() const;
+ void setValue(const QJSValue &);
bool delayed() const;
void setDelayed(bool);
+ RestorationMode restoreMode() const;
+ void setRestoreMode(RestorationMode);
+
+Q_SIGNALS:
+ void restoreModeChanged();
+
protected:
void setTarget(const QQmlProperty &) override;
void classBegin() override;
@@ -97,6 +115,9 @@ protected:
private:
void prepareEval();
void eval();
+
+private Q_SLOTS:
+ void targetValueChanged();
};
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index f601087690..1e801641e5 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -44,6 +44,7 @@
#include <private/qqmlboundsignal_p.h>
#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qqmlinfo.h>
#include <QtCore/qdebug.h>
@@ -66,7 +67,7 @@ public:
bool ignoreUnknownSignals;
bool componentcomplete;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
};
@@ -105,7 +106,7 @@ public:
\qml
MouseArea {
Connections {
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
}
\endqml
@@ -122,7 +123,7 @@ public:
\qml
Connections {
target: area
- onClicked: foo(parameters)
+ function onClicked(mouse) { foo(mouse) }
}
\endqml
@@ -231,7 +232,7 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore)
d->ignoreUnknownSignals = ignore;
}
-void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props)
+void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
for (int ii = 0; ii < props.count(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
@@ -256,7 +257,7 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::CompiledDat
}
}
-void QQmlConnectionsParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
+void QQmlConnectionsParser::applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
{
QQmlConnectionsPrivate *p =
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
@@ -270,8 +271,76 @@ void QQmlConnections::connectSignals()
if (!d->componentcomplete || (d->targetSet && !target()))
return;
- if (d->bindings.isEmpty())
+ if (d->bindings.isEmpty()) {
+ connectSignalsToMethods();
+ } else {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
+ "Use this syntax instead: function onFoo(<arguments>) { ... }");
+#endif
+ connectSignalsToBindings();
+ }
+}
+
+void QQmlConnections::connectSignalsToMethods()
+{
+ Q_D(QQmlConnections);
+
+ QObject *target = this->target();
+ QQmlData *ddata = QQmlData::get(this);
+ if (!ddata)
return;
+
+ QV4::ExecutionEngine *engine = ddata->context->engine->handle();
+
+ QQmlContextData *ctxtdata = ddata->outerContext;
+ for (int i = ddata->propertyCache->methodOffset(),
+ end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
+ i < end;
+ ++i) {
+
+ QQmlPropertyData *handler = ddata->propertyCache->method(i);
+ if (!handler || !handler->isVMEFunction())
+ continue;
+
+ const QString propName = handler->name(this);
+
+ QQmlProperty prop(target, propName);
+ if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
+ int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
+ auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
+
+ QV4::Scope scope(engine);
+ QV4::ScopedContext global(scope, engine->rootContext());
+
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+
+ QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
+
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(
+ target, signalIndex, ctxtdata, this,
+ method->as<QV4::FunctionObject>()->function())
+ : nullptr;
+
+ signal->takeExpression(expression);
+ d->boundsignals += signal;
+ } else if (!d->ignoreUnknownSignals
+ && propName.startsWith(QLatin1String("on")) && propName.length() > 2
+ && propName.at(2).isUpper()) {
+ qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
+ "This is probably intended to be a signal handler but no "
+ "signal of the target matches the name.").arg(propName);
+ }
+ }
+}
+
+// TODO: Drop this as soon as we can
+void QQmlConnections::connectSignalsToBindings()
+{
+ Q_D(QQmlConnections);
QObject *target = this->target();
QQmlData *ddata = QQmlData::get(this);
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index bd03d7e152..5d28e8e8be 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatu
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 1)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
public:
@@ -87,19 +87,23 @@ public:
Q_SIGNALS:
void targetChanged();
- Q_REVISION(1) void enabledChanged();
+ Q_REVISION(3) void enabledChanged();
private:
void connectSignals();
+ void connectSignalsToMethods();
+ void connectSignalsToBindings();
+
void classBegin() override;
void componentComplete() override;
};
+// TODO: Drop this class as soon as we can
class QQmlConnectionsParser : public QQmlCustomParser
{
public:
- void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override;
- void applyBindings(QObject *object, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
+ void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override;
+ void applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
};
diff --git a/src/qml/types/qqmldelegatecomponent.cpp b/src/qml/types/qqmldelegatecomponent.cpp
deleted file mode 100644
index 676a524872..0000000000
--- a/src/qml/types/qqmldelegatecomponent.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldelegatecomponent_p.h"
-#include <QtQml/private/qqmladaptormodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
- : QQmlComponent(parent)
-{
-}
-
-QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
-{
-}
-
-QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
-{
- if (!adaptorModel)
- return QVariant();
- return adaptorModel->value(adaptorModel->indexAt(row, column), role);
-}
-
-/*!
- \qmltype DelegateChoice
- \instantiates QQmlDelegateChoice
- \inqmlmodule Qt.labs.qmlmodels
- \brief Encapsulates a delegate and when to use it.
-
- The DelegateChoice type wraps a delegate and defines the circumstances
- in which it should be chosen.
-
- DelegateChoices can be nested inside a DelegateChooser.
-
- \sa DelegateChooser
-*/
-
-/*!
- \qmlproperty string QtQml.Models::DelegateChoice::roleValue
- This property holds the value used to match the role data for the role provided by \l DelegateChooser::role.
-*/
-QVariant QQmlDelegateChoice::roleValue() const
-{
- return m_value;
-}
-
-void QQmlDelegateChoice::setRoleValue(const QVariant &value)
-{
- if (m_value == value)
- return;
- m_value = value;
- emit roleValueChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::row
- This property holds the value used to match the row value of model elements.
- With models that have only the index property (and thus only one column), this property
- should be intended as an index, and set to the desired index value.
-
- \note Setting both row and index has undefined behavior. The two are equivalent and only
- one should be used.
-
- \sa index
-*/
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::index
- This property holds the value used to match the index value of model elements.
- This is effectively an alias for \l row.
-
- \sa row
-*/
-int QQmlDelegateChoice::row() const
-{
- return m_row;
-}
-
-void QQmlDelegateChoice::setRow(int r)
-{
- if (m_row == r)
- return;
- m_row = r;
- emit rowChanged();
- emit indexChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty index QtQml.Models::DelegateChoice::column
- This property holds the value used to match the column value of model elements.
-*/
-int QQmlDelegateChoice::column() const
-{
- return m_column;
-}
-
-void QQmlDelegateChoice::setColumn(int c)
-{
- if (m_column == c)
- return;
- m_column = c;
- emit columnChanged();
- emit changed();
-}
-
-QQmlComponent *QQmlDelegateChoice::delegate() const
-{
- return m_delegate;
-}
-
-/*!
- \qmlproperty Component QtQml.Models::DelegateChoice::delegate
- This property holds the delegate to use if this choice matches the model item.
-*/
-void QQmlDelegateChoice::setDelegate(QQmlComponent *delegate)
-{
- if (m_delegate == delegate)
- return;
- QQmlAbstractDelegateComponent *adc = static_cast<QQmlAbstractDelegateComponent *>(m_delegate);
- if (adc)
- disconnect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- m_delegate = delegate;
- adc = static_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc)
- connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- emit delegateChanged();
- emit changed();
-}
-
-bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
-{
- if (!m_value.isValid() && m_row < 0 && m_column < 0)
- return true;
-
- const bool roleMatched = (m_value.isValid()) ? value == m_value : true;
- const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
- const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
- return roleMatched && rowMatched && columnMatched;
-}
-
-/*!
- \qmltype DelegateChooser
- \instantiates QQmlDelegateChooser
- \inqmlmodule Qt.labs.qmlmodels
- \brief Allows a view to use different delegates for different types of items in the model.
-
- The DelegateChooser is a special \l Component type intended for those scenarios where a Component is required
- by a view and used as a delegate.
- DelegateChooser encapsulates a set of \l {DelegateChoice}s.
- These choices are used to determine the delegate that will be instantiated for each
- item in the model.
- The selection of the choice is performed based on the value that a model item has for \l role,
- and also based on index.
-
- DelegateChooser is commonly used when a view needs to display a set of delegates that are significantly
- different from each other. For example, a typical phone settings view might include toggle switches,
- sliders, radio buttons, and other visualizations based on the type of each setting. In this case, DelegateChooser
- could provide an easy way to associate a different type of delegate with each setting:
-
- \qml \QtMinorVersion
- import QtQuick 2.\1
- import QtQuick.Controls 2.\1
- import Qt.labs.qmlmodels 1.0
-
- ListView {
- width: 200; height: 400
-
- ListModel {
- id: listModel
- ListElement { type: "info"; ... }
- ListElement { type: "switch"; ... }
- ListElement { type: "swipe"; ... }
- ListElement { type: "switch"; ... }
- }
-
- DelegateChooser {
- id: chooser
- role: "type"
- DelegateChoice { roleValue: "info"; ItemDelegate { ... } }
- DelegateChoice { roleValue: "switch"; SwitchDelegate { ... } }
- DelegateChoice { roleValue: "swipe"; SwipeDelegate { ... } }
- }
-
- model: listModel
- delegate: chooser
- }
- \endqml
-
- \note This type is intended to transparently work only with TableView and any DelegateModel-based view.
- Views (including user-defined views) that aren't internally based on a DelegateModel need to explicitly support
- this type of component to make it function as described.
-
- \sa DelegateChoice
-*/
-
-/*!
- \qmlproperty string QtQml.Models::DelegateChooser::role
- This property holds the role used to determine the delegate for a given model item.
-
- \sa DelegateChoice
-*/
-void QQmlDelegateChooser::setRole(const QString &role)
-{
- if (m_role == role)
- return;
- m_role = role;
- emit roleChanged();
-}
-
-/*!
- \qmlproperty list<DelegateChoice> QtQml.Models::DelegateChooser::choices
- \default
-
- The list of DelegateChoices for the chooser.
-
- The list is treated as an ordered list, where the first DelegateChoice to match
- will be used be a view.
-
- It should not generally be necessary to refer to the \c choices property,
- as it is the default property for DelegateChooser and thus all child items are
- automatically assigned to this property.
-*/
-
-QQmlListProperty<QQmlDelegateChoice> QQmlDelegateChooser::choices()
-{
- return QQmlListProperty<QQmlDelegateChoice>(this, nullptr,
- QQmlDelegateChooser::choices_append,
- QQmlDelegateChooser::choices_count,
- QQmlDelegateChooser::choices_at,
- QQmlDelegateChooser::choices_clear);
-}
-
-void QQmlDelegateChooser::choices_append(QQmlListProperty<QQmlDelegateChoice> *prop, QQmlDelegateChoice *choice)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- q->m_choices.append(choice);
- connect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->delegateChanged();
-}
-
-int QQmlDelegateChooser::choices_count(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.count();
-}
-
-QQmlDelegateChoice *QQmlDelegateChooser::choices_at(QQmlListProperty<QQmlDelegateChoice> *prop, int index)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.at(index);
-}
-
-void QQmlDelegateChooser::choices_clear(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- for (QQmlDelegateChoice *choice : q->m_choices)
- disconnect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->m_choices.clear();
- q->delegateChanged();
-}
-
-QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const
-{
- QVariant v;
- if (!m_role.isNull())
- v = value(adaptorModel, row, column, m_role);
- if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
- v = value(adaptorModel, row, column, QStringLiteral("modelData"));
- if (v.isValid())
- v = v.toMap().value(m_role);
- }
- // loop through choices, finding first one that fits
- for (int i = 0; i < m_choices.count(); ++i) {
- const QQmlDelegateChoice *choice = m_choices.at(i);
- if (choice->match(row, column, v))
- return choice->delegate();
- }
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmldelegatecomponent_p.h b/src/qml/types/qqmldelegatecomponent_p.h
deleted file mode 100644
index c925ed9a60..0000000000
--- a/src/qml/types/qqmldelegatecomponent_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDELEGATECOMPONENT_P_H
-#define QQMLDELEGATECOMPONENT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <qqmlcomponent.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-// TODO: consider making QQmlAbstractDelegateComponent public API
-class QQmlAbstractDelegateComponentPrivate;
-class QQmlAdaptorModel;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
-{
- Q_OBJECT
-public:
- QQmlAbstractDelegateComponent(QObject *parent = nullptr);
- ~QQmlAbstractDelegateComponent() override;
-
- virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
-
-signals:
- void delegateChanged();
-
-protected:
- QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
-
-private:
- Q_DECLARE_PRIVATE(QQmlAbstractDelegateComponent)
- Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
- Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged)
- Q_PROPERTY(int index READ row WRITE setRow NOTIFY indexChanged)
- Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
- Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
-public:
- QVariant roleValue() const;
- void setRoleValue(const QVariant &roleValue);
-
- int row() const;
- void setRow(int r);
-
- int column() const;
- void setColumn(int c);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *delegate);
-
- virtual bool match(int row, int column, const QVariant &value) const;
-
-signals:
- void roleValueChanged();
- void rowChanged();
- void indexChanged();
- void columnChanged();
- void delegateChanged();
- void changed();
-
-private:
- QVariant m_value;
- int m_row = -1;
- int m_column = -1;
- QQmlComponent *m_delegate = nullptr;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
-{
- Q_OBJECT
- Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
- Q_PROPERTY(QQmlListProperty<QQmlDelegateChoice> choices READ choices CONSTANT)
- Q_CLASSINFO("DefaultProperty", "choices")
-
-public:
- QString role() const { return m_role; }
- void setRole(const QString &role);
-
- virtual QQmlListProperty<QQmlDelegateChoice> choices();
- static void choices_append(QQmlListProperty<QQmlDelegateChoice> *, QQmlDelegateChoice *);
- static int choices_count(QQmlListProperty<QQmlDelegateChoice> *);
- static QQmlDelegateChoice *choices_at(QQmlListProperty<QQmlDelegateChoice> *, int);
- static void choices_clear(QQmlListProperty<QQmlDelegateChoice> *);
-
- QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = -1) const override;
-
-signals:
- void roleChanged();
-
-private:
- QString m_role;
- QList<QQmlDelegateChoice *> m_choices;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlDelegateChoice)
-QML_DECLARE_TYPE(QQmlDelegateChooser)
-
-#endif // QQMLDELEGATECOMPONENT_P_H
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
deleted file mode 100644
index f58bab7c09..0000000000
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ /dev/null
@@ -1,3557 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldelegatemodel_p_p.h"
-#include "qqmldelegatecomponent_p.h"
-
-#include <QtQml/qqmlinfo.h>
-
-#include <private/qquickpackage_p.h>
-#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmladaptormodel_p.h>
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlcomponent_p.h>
-#include <private/qqmlincubator_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-#include <qv4objectiterator_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlDelegateModelItem;
-
-namespace QV4 {
-
-namespace Heap {
-
-struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
-
- QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
- uint flag;
-};
-
-struct QQmlDelegateModelGroupChange : Object {
- void init() { Object::init(); }
-
- QQmlChangeSet::ChangeData change;
-};
-
-struct QQmlDelegateModelGroupChangeArray : Object {
- void init(const QVector<QQmlChangeSet::Change> &changes);
- void destroy() {
- delete changes;
- Object::destroy();
- }
-
- QVector<QQmlChangeSet::Change> *changes;
-};
-
-
-}
-
-struct DelegateModelGroupFunction : QV4::FunctionObject
-{
- V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
-
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
- {
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
- }
-
- static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
- {
- QV4::Scope scope(that->engine());
- QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that));
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject);
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- QV4::ScopedValue v(scope, argc ? argv[0] : Value::undefinedValue());
- return f->d()->code(o->d()->item, f->d()->flag, v);
- }
-};
-
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
-{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
- this->flag = flag;
- this->code = code;
-}
-
-}
-
-DEFINE_OBJECT_VTABLE(QV4::DelegateModelGroupFunction);
-
-
-
-class QQmlDelegateModelEngineData : public QV8Engine::Deletable
-{
-public:
- QQmlDelegateModelEngineData(QV4::ExecutionEngine *v4);
- ~QQmlDelegateModelEngineData();
-
- QV4::ReturnedValue array(QV4::ExecutionEngine *engine,
- const QVector<QQmlChangeSet::Change> &changes);
-
- QV4::PersistentValue changeProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, engineData)
-
-
-void QQmlDelegateModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
-{
- prop.setWritable(false);
-}
-
-QVariant QQmlDelegateModelPartsMetaObject::initialValue(int id)
-{
- QQmlDelegateModelParts *parts = static_cast<QQmlDelegateModelParts *>(object());
- QQmlPartsModel *m = new QQmlPartsModel(
- parts->model, QString::fromUtf8(name(id)), parts);
- parts->models.append(m);
- return QVariant::fromValue(static_cast<QObject *>(m));
-}
-
-QQmlDelegateModelParts::QQmlDelegateModelParts(QQmlDelegateModel *parent)
-: QObject(parent), model(parent)
-{
- new QQmlDelegateModelPartsMetaObject(this);
-}
-
-//---------------------------------------------------------------------------
-
-/*!
- \qmltype DelegateModel
- \instantiates QQmlDelegateModel
- \inqmlmodule QtQml.Models
- \brief Encapsulates a model and delegate.
-
- The DelegateModel type encapsulates a model and the delegate that will
- be instantiated for items in the model.
-
- It is usually not necessary to create a DelegateModel.
- However, it can be useful for manipulating and accessing the \l modelIndex
- when a QAbstractItemModel subclass is used as the
- model. Also, DelegateModel is used together with \l Package to
- provide delegates to multiple views, and with DelegateModelGroup to sort and filter
- delegate items.
-
- The example below illustrates using a DelegateModel with a ListView.
-
- \snippet delegatemodel/delegatemodel.qml 0
-*/
-
-QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt)
- : m_delegateChooser(nullptr)
- , m_cacheMetaType(nullptr)
- , m_context(ctxt)
- , m_parts(nullptr)
- , m_filterGroup(QStringLiteral("items"))
- , m_count(0)
- , m_groupCount(Compositor::MinimumGroupCount)
- , m_compositorGroup(Compositor::Cache)
- , m_complete(false)
- , m_delegateValidated(false)
- , m_reset(false)
- , m_transaction(false)
- , m_incubatorCleanupScheduled(false)
- , m_waitingToFetchMore(false)
- , m_cacheItems(nullptr)
- , m_items(nullptr)
- , m_persistedItems(nullptr)
-{
-}
-
-QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate()
-{
- qDeleteAll(m_finishedIncubating);
-
- if (m_cacheMetaType)
- m_cacheMetaType->release();
-}
-
-int QQmlDelegateModelPrivate::adaptorModelCount() const
-{
- // QQmlDelegateModel currently only support list models.
- // So even if a model is a table model, only the first
- // column will be used.
- return m_adaptorModel.rowCount();
-}
-
-void QQmlDelegateModelPrivate::requestMoreIfNecessary()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_waitingToFetchMore && m_adaptorModel.canFetchMore()) {
- m_waitingToFetchMore = true;
- QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
- }
-}
-
-void QQmlDelegateModelPrivate::init()
-{
- Q_Q(QQmlDelegateModel);
- m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
-
- m_items = new QQmlDelegateModelGroup(QStringLiteral("items"), q, Compositor::Default, q);
- m_items->setDefaultInclude(true);
- m_persistedItems = new QQmlDelegateModelGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
- QQmlDelegateModelGroupPrivate::get(m_items)->emitters.insert(this);
-}
-
-QQmlDelegateModel::QQmlDelegateModel()
- : QQmlDelegateModel(nullptr, nullptr)
-{
-}
-
-QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent)
-: QQmlInstanceModel(*(new QQmlDelegateModelPrivate(ctxt)), parent)
-{
- Q_D(QQmlDelegateModel);
- d->init();
-}
-
-QQmlDelegateModel::~QQmlDelegateModel()
-{
- Q_D(QQmlDelegateModel);
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setObject(nullptr, this);
-
- for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) {
- if (cacheItem->object) {
- delete cacheItem->object;
-
- cacheItem->object = nullptr;
- cacheItem->contextData->invalidate();
- Q_ASSERT(cacheItem->contextData->refCount == 1);
- cacheItem->contextData = nullptr;
- cacheItem->scriptRef -= 1;
- }
- cacheItem->groups &= ~Compositor::UnresolvedFlag;
- cacheItem->objectRef = 0;
- if (!cacheItem->isReferenced())
- delete cacheItem;
- else if (cacheItem->incubationTask)
- cacheItem->incubationTask->vdm = nullptr;
- }
-}
-
-
-void QQmlDelegateModel::classBegin()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_context)
- d->m_context = qmlContext(this);
-}
-
-void QQmlDelegateModel::componentComplete()
-{
- Q_D(QQmlDelegateModel);
- d->m_complete = true;
-
- int defaultGroups = 0;
- QStringList groupNames;
- groupNames.append(QStringLiteral("items"));
- groupNames.append(QStringLiteral("persistedItems"));
- if (QQmlDelegateModelGroupPrivate::get(d->m_items)->defaultInclude)
- defaultGroups |= Compositor::DefaultFlag;
- if (QQmlDelegateModelGroupPrivate::get(d->m_persistedItems)->defaultInclude)
- defaultGroups |= Compositor::PersistedFlag;
- for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
- QString name = d->m_groups[i]->name();
- if (name.isEmpty()) {
- d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
- --d->m_groupCount;
- --i;
- } else if (name.at(0).isUpper()) {
- qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter");
- d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
- --d->m_groupCount;
- --i;
- } else {
- groupNames.append(name);
-
- QQmlDelegateModelGroupPrivate *group = QQmlDelegateModelGroupPrivate::get(d->m_groups[i]);
- group->setModel(this, Compositor::Group(i));
- if (group->defaultInclude)
- defaultGroups |= (1 << i);
- }
- }
-
- d->m_cacheMetaType = new QQmlDelegateModelItemMetaType(
- d->m_context->engine()->handle(), this, groupNames);
-
- d->m_compositor.setGroupCount(d->m_groupCount);
- d->m_compositor.setDefaultGroups(defaultGroups);
- d->updateFilterGroup();
-
- while (!d->m_pendingParts.isEmpty())
- static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
-
- QVector<Compositor::Insert> inserts;
- d->m_count = d->adaptorModelCount();
- d->m_compositor.append(
- &d->m_adaptorModel,
- 0,
- d->m_count,
- defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
- &inserts);
- d->itemsInserted(inserts);
- d->emitChanges();
- d->requestMoreIfNecessary();
-}
-
-/*!
- \qmlproperty model QtQml.Models::DelegateModel::model
- This property holds the model providing data for the DelegateModel.
-
- The model provides a set of data that is used to create the items
- for a view. For large or dynamic datasets the model is usually
- provided by a C++ model object. The C++ model object must be a \l
- {QAbstractItemModel} subclass or a simple list.
-
- Models can also be created directly in QML, using a \l{ListModel} or
- \l{QtQuick.XmlListModel::XmlListModel}{XmlListModel}.
-
- \sa {qml-data-models}{Data Models}
- \keyword dm-model-property
-*/
-QVariant QQmlDelegateModel::model() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.model();
-}
-
-void QQmlDelegateModelPrivate::connectToAbstractItemModel()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_adaptorModel.adaptsAim())
- return;
-
- auto aim = m_adaptorModel.aim();
-
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(modelReset()),
- q, QQmlDelegateModel, SLOT(_q_modelReset()));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-}
-
-void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_adaptorModel.adaptsAim())
- return;
-
- auto aim = m_adaptorModel.aim();
-
- QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(aim, SIGNAL(modelReset()),
- q, SLOT(_q_modelReset()));
- QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-}
-
-void QQmlDelegateModel::setModel(const QVariant &model)
-{
- Q_D(QQmlDelegateModel);
-
- if (d->m_complete)
- _q_itemsRemoved(0, d->m_count);
-
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setModel(model, this, d->m_context->engine());
- d->connectToAbstractItemModel();
-
- d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
- for (int i = 0; d->m_parts && i < d->m_parts->models.count(); ++i) {
- d->m_adaptorModel.replaceWatchedRoles(
- QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
- }
-
- if (d->m_complete) {
- _q_itemsInserted(0, d->adaptorModelCount());
- d->requestMoreIfNecessary();
- }
-}
-
-/*!
- \qmlproperty Component QtQml.Models::DelegateModel::delegate
-
- The delegate provides a template defining each item instantiated by a view.
- The index is exposed as an accessible \c index property. Properties of the
- model are also available depending upon the type of \l {qml-data-models}{Data Model}.
-*/
-QQmlComponent *QQmlDelegateModel::delegate() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_delegate;
-}
-
-void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
-{
- Q_D(QQmlDelegateModel);
- if (d->m_transaction) {
- qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated.");
- return;
- }
- if (d->m_delegate == delegate)
- return;
- bool wasValid = d->m_delegate != nullptr;
- d->m_delegate.setObject(delegate, this);
- d->m_delegateValidated = false;
- if (d->m_delegateChooser)
- QObject::disconnect(d->m_delegateChooserChanged);
-
- d->m_delegateChooser = nullptr;
- if (delegate) {
- QQmlAbstractDelegateComponent *adc =
- qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc) {
- d->m_delegateChooser = adc;
- d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
- [d](){ d->delegateChanged(); });
- }
- }
- d->delegateChanged(d->m_delegate, wasValid);
-}
-
-/*!
- \qmlproperty QModelIndex QtQml.Models::DelegateModel::rootIndex
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. \c rootIndex allows the children of
- any node in a QAbstractItemModel to be provided by this model.
-
- This property only affects models of type QAbstractItemModel that
- are hierarchical (e.g, a tree model).
-
- For example, here is a simple interactive file system browser.
- When a directory name is clicked, the view's \c rootIndex is set to the
- QModelIndex node of the clicked directory, thus updating the view to show
- the new directory's contents.
-
- \c main.cpp:
- \snippet delegatemodel/delegatemodel_rootindex/main.cpp 0
-
- \c view.qml:
- \snippet delegatemodel/delegatemodel_rootindex/view.qml 0
-
- If the \l {dm-model-property}{model} is a QAbstractItemModel subclass,
- the delegate can also reference a \c hasModelChildren property (optionally
- qualified by a \e model. prefix) that indicates whether the delegate's
- model item has any child nodes.
-
- \sa modelIndex(), parentModelIndex()
-*/
-QVariant QQmlDelegateModel::rootIndex() const
-{
- Q_D(const QQmlDelegateModel);
- return QVariant::fromValue(QModelIndex(d->m_adaptorModel.rootIndex));
-}
-
-void QQmlDelegateModel::setRootIndex(const QVariant &root)
-{
- Q_D(QQmlDelegateModel);
-
- QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
- const bool changed = d->m_adaptorModel.rootIndex != modelIndex;
- if (changed || !d->m_adaptorModel.isValid()) {
- const int oldCount = d->m_count;
- d->m_adaptorModel.rootIndex = modelIndex;
- if (!d->m_adaptorModel.isValid() && d->m_adaptorModel.aim()) {
- // The previous root index was invalidated, so we need to reconnect the model.
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setModel(d->m_adaptorModel.list.list(), this, d->m_context->engine());
- d->connectToAbstractItemModel();
- }
- if (d->m_adaptorModel.canFetchMore())
- d->m_adaptorModel.fetchMore();
- if (d->m_complete) {
- const int newCount = d->adaptorModelCount();
- if (oldCount)
- _q_itemsRemoved(0, oldCount);
- if (newCount)
- _q_itemsInserted(0, newCount);
- }
- if (changed)
- emit rootIndexChanged();
- }
-}
-
-/*!
- \qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index)
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. This function assists in using
- tree models in QML.
-
- Returns a QModelIndex for the specified \a index.
- This value can be assigned to rootIndex.
-
- \sa rootIndex
-*/
-QVariant QQmlDelegateModel::modelIndex(int idx) const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.modelIndex(idx);
-}
-
-/*!
- \qmlmethod QModelIndex QtQml.Models::DelegateModel::parentModelIndex()
-
- QAbstractItemModel provides a hierarchical tree of data, whereas
- QML only operates on list data. This function assists in using
- tree models in QML.
-
- Returns a QModelIndex for the parent of the current rootIndex.
- This value can be assigned to rootIndex.
-
- \sa rootIndex
-*/
-QVariant QQmlDelegateModel::parentModelIndex() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.parentModelIndex();
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateModel::count
-*/
-
-int QQmlDelegateModel::count() const
-{
- Q_D(const QQmlDelegateModel);
- if (!d->m_delegate)
- return 0;
- return d->m_compositor.count(d->m_compositorGroup);
-}
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object)
-{
- if (!object)
- return QQmlDelegateModel::ReleaseFlags(0);
-
- QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object);
- if (!cacheItem)
- return QQmlDelegateModel::ReleaseFlags(0);
-
- if (!cacheItem->releaseObject())
- return QQmlDelegateModel::Referenced;
-
- cacheItem->destroyObject();
- emitDestroyingItem(object);
- if (cacheItem->incubationTask) {
- releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
- }
- cacheItem->Dispose();
- return QQmlInstanceModel::Destroyed;
-}
-
-/*
- Returns ReleaseStatus flags.
-*/
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item)
-{
- Q_D(QQmlDelegateModel);
- QQmlInstanceModel::ReleaseFlags stat = d->release(item);
- return stat;
-}
-
-// Cancel a requested async item
-void QQmlDelegateModel::cancel(int index)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
- qWarning() << "DelegateModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
- return;
- }
-
- Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
- QQmlDelegateModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
- if (cacheItem) {
- if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
- d->releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
-
- if (cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- d->emitDestroyingPackage(package);
- else
- d->emitDestroyingItem(object);
- }
-
- cacheItem->scriptRef -= 1;
- }
- if (!cacheItem->isReferenced()) {
- d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
- d->m_cache.removeAt(it.cacheIndex);
- delete cacheItem;
- Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
- }
- }
-}
-
-void QQmlDelegateModelPrivate::group_append(
- QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- if (d->m_complete)
- return;
- if (d->m_groupCount == Compositor::MaximumGroupCount) {
- qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8");
- return;
- }
- d->m_groups[d->m_groupCount] = group;
- d->m_groupCount += 1;
-}
-
-int QQmlDelegateModelPrivate::group_count(
- QQmlListProperty<QQmlDelegateModelGroup> *property)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- return d->m_groupCount - 1;
-}
-
-QQmlDelegateModelGroup *QQmlDelegateModelPrivate::group_at(
- QQmlListProperty<QQmlDelegateModelGroup> *property, int index)
-{
- QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
- return index >= 0 && index < d->m_groupCount - 1
- ? d->m_groups[index + 1]
- : nullptr;
-}
-
-/*!
- \qmlproperty list<DelegateModelGroup> QtQml.Models::DelegateModel::groups
-
- This property holds a delegate model's group definitions.
-
- Groups define a sub-set of the items in a delegate model and can be used to filter
- a model.
-
- For every group defined in a DelegateModel two attached properties are added to each
- delegate item. The first of the form DelegateModel.in\e{GroupName} holds whether the
- item belongs to the group and the second DelegateModel.\e{groupName}Index holds the
- index of the item in that group.
-
- The following example illustrates using groups to select items in a model.
-
- \snippet delegatemodel/delegatemodelgroup.qml 0
- \keyword dm-groups-property
-*/
-
-QQmlListProperty<QQmlDelegateModelGroup> QQmlDelegateModel::groups()
-{
- Q_D(QQmlDelegateModel);
- return QQmlListProperty<QQmlDelegateModelGroup>(
- this,
- d,
- QQmlDelegateModelPrivate::group_append,
- QQmlDelegateModelPrivate::group_count,
- QQmlDelegateModelPrivate::group_at,
- nullptr);
-}
-
-/*!
- \qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::items
-
- This property holds default group to which all new items are added.
-*/
-
-QQmlDelegateModelGroup *QQmlDelegateModel::items()
-{
- Q_D(QQmlDelegateModel);
- return d->m_items;
-}
-
-/*!
- \qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::persistedItems
-
- This property holds delegate model's persisted items group.
-
- Items in this group are not destroyed when released by a view, instead they are persisted
- until removed from the group.
-
- An item can be removed from the persistedItems group by setting the
- DelegateModel.inPersistedItems property to false. If the item is not referenced by a view
- at that time it will be destroyed. Adding an item to this group will not create a new
- instance.
-
- Items returned by the \l QtQml.Models::DelegateModelGroup::create() function are automatically added
- to this group.
-*/
-
-QQmlDelegateModelGroup *QQmlDelegateModel::persistedItems()
-{
- Q_D(QQmlDelegateModel);
- return d->m_persistedItems;
-}
-
-/*!
- \qmlproperty string QtQml.Models::DelegateModel::filterOnGroup
-
- This property holds name of the group that is used to filter the delegate model.
-
- Only items that belong to this group are visible to a view.
-
- By default this is the \l items group.
-*/
-
-QString QQmlDelegateModel::filterGroup() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_filterGroup;
-}
-
-void QQmlDelegateModel::setFilterGroup(const QString &group)
-{
- Q_D(QQmlDelegateModel);
-
- if (d->m_transaction) {
- qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
- return;
- }
-
- if (d->m_filterGroup != group) {
- d->m_filterGroup = group;
- d->updateFilterGroup();
- emit filterGroupChanged();
- }
-}
-
-void QQmlDelegateModel::resetFilterGroup()
-{
- setFilterGroup(QStringLiteral("items"));
-}
-
-void QQmlDelegateModelPrivate::updateFilterGroup()
-{
- Q_Q(QQmlDelegateModel);
- if (!m_cacheMetaType)
- return;
-
- QQmlListCompositor::Group previousGroup = m_compositorGroup;
- m_compositorGroup = Compositor::Default;
- for (int i = 1; i < m_groupCount; ++i) {
- if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
- m_compositorGroup = Compositor::Group(i);
- break;
- }
- }
-
- QQmlDelegateModelGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
- if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Change> removes;
- QVector<QQmlChangeSet::Change> inserts;
- m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
-
- QQmlChangeSet changeSet;
- changeSet.move(removes, inserts);
- emit q->modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit q->countChanged();
-
- if (m_parts) {
- auto partsCopy = m_parts->models; // deliberate; this may alter m_parts
- for (QQmlPartsModel *model : qAsConst(partsCopy))
- model->updateFilterGroup(m_compositorGroup, changeSet);
- }
- }
-}
-
-/*!
- \qmlproperty object QtQml.Models::DelegateModel::parts
-
- The \a parts property selects a DelegateModel which creates
- delegates from the part named. This is used in conjunction with
- the \l Package type.
-
- For example, the code below selects a model which creates
- delegates named \e list from a \l Package:
-
- \code
- DelegateModel {
- id: visualModel
- delegate: Package {
- Item { Package.name: "list" }
- }
- model: myModel
- }
-
- ListView {
- width: 200; height:200
- model: visualModel.parts.list
- }
- \endcode
-
- \sa Package
-*/
-
-QObject *QQmlDelegateModel::parts()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_parts)
- d->m_parts = new QQmlDelegateModelParts(this);
- return d->m_parts;
-}
-
-const QAbstractItemModel *QQmlDelegateModel::abstractItemModel() const
-{
- Q_D(const QQmlDelegateModel);
- return d->m_adaptorModel.adaptsAim() ? d->m_adaptorModel.aim() : nullptr;
-}
-
-void QQmlDelegateModelPrivate::emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
-}
-
-void QQmlDelegateModelPrivate::emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
-}
-
-void QQmlDelegateModelPrivate::emitDestroyingPackage(QQuickPackage *package)
-{
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->destroyingPackage(package);
-}
-
-static bool isDoneIncubating(QQmlIncubator::Status status)
-{
- return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
-}
-
-void QQDMIncubationTask::statusChanged(Status status)
-{
- if (vdm) {
- vdm->incubatorStatusChanged(this, status);
- } else if (isDoneIncubating(status)) {
- Q_ASSERT(incubating);
- // The model was deleted from under our feet, cleanup ourselves
- delete incubating->object;
- incubating->object = nullptr;
- if (incubating->contextData) {
- incubating->contextData->invalidate();
- Q_ASSERT(incubating->contextData->refCount == 1);
- incubating->contextData = nullptr;
- }
- incubating->scriptRef = 0;
- incubating->deleteLater();
- }
-}
-
-void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTask)
-{
- Q_Q(QQmlDelegateModel);
- if (!incubationTask->isError())
- incubationTask->clear();
- m_finishedIncubating.append(incubationTask);
- if (!m_incubatorCleanupScheduled) {
- m_incubatorCleanupScheduled = true;
- QCoreApplication::postEvent(q, new QEvent(QEvent::User));
- }
-}
-
-void QQmlDelegateModelPrivate::addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it)
-{
- m_cache.insert(it.cacheIndex, item);
- m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
-}
-
-void QQmlDelegateModelPrivate::removeCacheItem(QQmlDelegateModelItem *cacheItem)
-{
- int cidx = m_cache.lastIndexOf(cacheItem);
- if (cidx >= 0) {
- m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
- m_cache.removeAt(cidx);
- }
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
-}
-
-void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status)
-{
- if (!isDoneIncubating(status))
- return;
-
- const QList<QQmlError> incubationTaskErrors = incubationTask->errors();
-
- QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
- cacheItem->incubationTask = nullptr;
- incubationTask->incubating = nullptr;
- releaseIncubator(incubationTask);
-
- if (status == QQmlIncubator::Ready) {
- cacheItem->referenceObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitCreatedPackage(incubationTask, package);
- else
- emitCreatedItem(incubationTask, cacheItem->object);
- cacheItem->releaseObject();
- } else if (status == QQmlIncubator::Error) {
- qmlInfo(m_delegate, incubationTaskErrors + m_delegate->errors()) << "Cannot create delegate";
- }
-
- if (!cacheItem->isObjectReferenced()) {
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(cacheItem->object);
- delete cacheItem->object;
- cacheItem->object = nullptr;
- cacheItem->scriptRef -= 1;
- if (cacheItem->contextData) {
- cacheItem->contextData->invalidate();
- Q_ASSERT(cacheItem->contextData->refCount == 1);
- }
- cacheItem->contextData = nullptr;
-
- if (!cacheItem->isReferenced()) {
- removeCacheItem(cacheItem);
- delete cacheItem;
- }
- }
-}
-
-void QQDMIncubationTask::setInitialState(QObject *o)
-{
- vdm->setInitialState(this, o);
-}
-
-void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
-{
- QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
- cacheItem->object = o;
-
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
- emitInitPackage(incubationTask, package);
- else
- emitInitItem(incubationTask, cacheItem->object);
-}
-
-QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode)
-{
- if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
- qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
- return nullptr;
- } else if (!m_context || !m_context->isValid()) {
- return nullptr;
- }
-
- Compositor::iterator it = m_compositor.find(group, index);
-
- QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
-
- if (!cacheItem) {
- cacheItem = m_adaptorModel.createItem(m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
- return nullptr;
-
- cacheItem->groups = it->flags;
- addCacheItem(cacheItem, it);
- }
-
- // Bump the reference counts temporarily so neither the content data or the delegate object
- // are deleted if incubatorStatusChanged() is called synchronously.
- cacheItem->scriptRef += 1;
- cacheItem->referenceObject();
-
- if (cacheItem->incubationTask) {
- bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
- if (sync && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
- // previously requested async - now needed immediately
- cacheItem->incubationTask->forceCompletion();
- }
- } else if (!cacheItem->object) {
- QQmlComponent *delegate = m_delegate;
- if (m_delegateChooser) {
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, index);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- if (!delegate)
- return nullptr;
- }
-
- QQmlContext *creationContext = delegate->creationContext();
-
- cacheItem->scriptRef += 1;
-
- cacheItem->incubationTask = new QQDMIncubationTask(this, incubationMode);
- cacheItem->incubationTask->incubating = cacheItem;
- cacheItem->incubationTask->clear();
-
- for (int i = 1; i < m_groupCount; ++i)
- cacheItem->incubationTask->index[i] = it.index[i];
-
- QQmlContextData *ctxt = new QQmlContextData;
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
- ctxt->contextObject = cacheItem;
- cacheItem->contextData = ctxt;
-
- if (m_adaptorModel.hasProxyObject()) {
- if (QQmlAdaptorModelProxyInterface *proxy
- = qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem)) {
- ctxt = new QQmlContextData;
- ctxt->setParent(cacheItem->contextData, /*stronglyReferencedByParent*/true);
- QObject *proxied = proxy->proxiedObject();
- ctxt->contextObject = proxied;
- // We don't own the proxied object. We need to clear it if it goes away.
- QObject::connect(proxied, &QObject::destroyed,
- cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);
- }
- }
-
- QQmlComponentPrivate *cp = QQmlComponentPrivate::get(delegate);
- cp->incubateObject(
- cacheItem->incubationTask,
- delegate,
- m_context->engine(),
- ctxt,
- QQmlContextData::get(m_context));
- }
-
- if (index == m_compositor.count(group) - 1)
- requestMoreIfNecessary();
-
- // Remove the temporary reference count.
- cacheItem->scriptRef -= 1;
- if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
- return cacheItem->object;
-
- cacheItem->releaseObject();
- if (!cacheItem->isReferenced()) {
- removeCacheItem(cacheItem);
- delete cacheItem;
- }
-
- return nullptr;
-}
-
-/*
- If asynchronous is true or the component is being loaded asynchronously due
- to an ancestor being loaded asynchronously, object() may return 0. In this
- case createdItem() will be emitted when the object is available. The object
- at this stage does not have any references, so object() must be called again
- to ensure a reference is held. Any call to object() which returns a valid object
- must be matched by a call to release() in order to destroy the object.
-*/
-QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
- qWarning() << "DelegateModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
- return nullptr;
- }
-
- return d->object(d->m_compositorGroup, index, incubationMode);
-}
-
-QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index)
-{
- Q_D(QQmlDelegateModel);
- Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
- if (!it->inCache())
- return QQmlIncubator::Null;
-
- if (auto incubationTask = d->m_cache.at(it.cacheIndex)->incubationTask)
- return incubationTask->status();
-
- return QQmlIncubator::Ready;
-}
-
-QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
-{
- Compositor::iterator it = m_compositor.find(group, index);
- if (QQmlAdaptorModel *model = it.list<QQmlAdaptorModel>()) {
- QString role = name;
- int dot = name.indexOf(QLatin1Char('.'));
- if (dot > 0)
- role = name.left(dot);
- QVariant value = model->value(it.modelIndex(), role);
- while (dot > 0) {
- QObject *obj = qvariant_cast<QObject*>(value);
- if (!obj)
- return QString();
- int from = dot+1;
- dot = name.indexOf(QLatin1Char('.'), from);
- value = obj->property(name.midRef(from, dot - from).toUtf8());
- }
- return value.toString();
- }
- return QString();
-}
-
-QString QQmlDelegateModel::stringValue(int index, const QString &name)
-{
- Q_D(QQmlDelegateModel);
- return d->stringValue(d->m_compositorGroup, index, name);
-}
-
-int QQmlDelegateModel::indexOf(QObject *item, QObject *) const
-{
- Q_D(const QQmlDelegateModel);
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(item))
- return cacheItem->groupIndex(d->m_compositorGroup);
- return -1;
-}
-
-void QQmlDelegateModel::setWatchedRoles(const QList<QByteArray> &roles)
-{
- Q_D(QQmlDelegateModel);
- d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
- d->m_watchedRoles = roles;
-}
-
-void QQmlDelegateModelPrivate::addGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Insert> inserts;
- m_compositor.setFlags(from, count, group, groupFlags, &inserts);
- itemsInserted(inserts);
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::removeGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Remove> removes;
- m_compositor.clearFlags(from, count, group, groupFlags, &removes);
- itemsRemoved(removes);
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::setGroups(
- Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
-{
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
-
- m_compositor.setFlags(from, count, group, groupFlags, &inserts);
- itemsInserted(inserts);
- const int removeFlags = ~groupFlags & Compositor::GroupMask;
-
- from = m_compositor.find(from.group, from.index[from.group]);
- m_compositor.clearFlags(from, count, group, removeFlags, &removes);
- itemsRemoved(removes);
- emitChanges();
-}
-
-bool QQmlDelegateModel::event(QEvent *e)
-{
- Q_D(QQmlDelegateModel);
- if (e->type() == QEvent::UpdateRequest) {
- d->m_waitingToFetchMore = false;
- d->m_adaptorModel.fetchMore();
- } else if (e->type() == QEvent::User) {
- d->m_incubatorCleanupScheduled = false;
- qDeleteAll(d->m_finishedIncubating);
- d->m_finishedIncubating.clear();
- }
- return QQmlInstanceModel::event(e);
-}
-
-void QQmlDelegateModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
-{
- if (!m_delegate)
- return;
-
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
-
- for (const Compositor::Change &change : changes) {
- for (int i = 1; i < m_groupCount; ++i) {
- if (change.inGroup(i)) {
- translatedChanges[i].append(QQmlChangeSet::Change(change.index[i], change.count));
- }
- }
- }
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.change(translatedChanges.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
- QVector<Compositor::Change> changes;
- d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
- d->itemsChanged(changes);
- d->emitChanges();
- }
-}
-
-static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
-{
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < count; ++i)
- incubationTask->index[i] += deltas[i];
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < qMin<int>(count, Compositor::MaximumGroupCount); ++i)
- attached->m_currentIndex[i] += deltas[i];
- }
-}
-
-void QQmlDelegateModelPrivate::itemsInserted(
- const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
-{
- int cacheIndex = 0;
-
- int inserted[Compositor::MaximumGroupCount];
- for (int i = 1; i < m_groupCount; ++i)
- inserted[i] = 0;
-
- for (const Compositor::Insert &insert : inserts) {
- for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
- incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
-
- for (int i = 1; i < m_groupCount; ++i) {
- if (insert.inGroup(i)) {
- (*translatedInserts)[i].append(
- QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId));
- inserted[i] += insert.count;
- }
- }
-
- if (!insert.inCache())
- continue;
-
- if (movedItems && insert.isMove()) {
- QList<QQmlDelegateModelItem *> items = movedItems->take(insert.moveId);
- Q_ASSERT(items.count() == insert.count);
- m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
- }
- if (insert.inGroup()) {
- for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
- QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
- cacheItem->groups |= insert.flags & Compositor::GroupMask;
-
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < m_groupCount; ++i)
- incubationTask->index[i] = cacheItem->groups & (1 << i)
- ? insert.index[i] + offset
- : insert.index[i];
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i)
- attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
- ? insert.index[i] + offset
- : insert.index[i];
- }
- }
- } else {
- cacheIndex = insert.cacheIndex + insert.count;
- }
- }
- for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.count(); ++cacheIndex)
- incrementIndexes(cache.at(cacheIndex), m_groupCount, inserted);
-}
-
-void QQmlDelegateModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
-{
- 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)
- return;
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(translatedInserts.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsInserted(int index, int count)
-{
-
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- d->m_count += count;
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- // layout change triggered by changing the modelIndex might have
- // already invalidated this item in d->m_cache and deleted it.
- if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
- continue;
-
- if (item->modelIndex() >= index) {
- const int newIndex = item->modelIndex() + count;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- }
- }
-
- QVector<Compositor::Insert> inserts;
- d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
- d->itemsInserted(inserts);
- d->emitChanges();
-}
-
-//### This method should be split in two. It will remove delegates, and it will re-render the list.
-// When e.g. QQmlListModel::remove is called, the removal of the delegates should be done on
-// QAbstractItemModel::rowsAboutToBeRemoved, and the re-rendering on
-// QAbstractItemModel::rowsRemoved. Currently both are done on the latter signal. The problem is
-// that the destruction of an item will emit a changed signal that ends up at the delegate, which
-// in turn will try to load the data from the model (which should have already freed it), resulting
-// in a use-after-free. See QTBUG-59256.
-void QQmlDelegateModelPrivate::itemsRemoved(
- const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
-{
- int cacheIndex = 0;
- int removedCache = 0;
-
- int removed[Compositor::MaximumGroupCount];
- for (int i = 1; i < m_groupCount; ++i)
- removed[i] = 0;
-
- for (const Compositor::Remove &remove : removes) {
- for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
- incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
-
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i)) {
- (*translatedRemoves)[i].append(
- QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId));
- removed[i] -= remove.count;
- }
- }
-
- if (!remove.inCache())
- continue;
-
- if (movedItems && remove.isMove()) {
- movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
- QList<QQmlDelegateModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
- QList<QQmlDelegateModelItem *>::iterator end = begin + remove.count;
- m_cache.erase(begin, end);
- } else {
- for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
- QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
- if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(object);
- cacheItem->scriptRef -= 1;
- }
- if (!cacheItem->isReferenced()) {
- m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
- m_cache.removeAt(cacheIndex);
- delete cacheItem;
- --cacheIndex;
- ++removedCache;
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
- } else if (remove.groups() == cacheItem->groups) {
- cacheItem->groups = 0;
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- for (int i = 1; i < m_groupCount; ++i)
- incubationTask->index[i] = -1;
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i)
- attached->m_currentIndex[i] = -1;
- }
- } else {
- if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
- if (!cacheItem->isObjectReferenced()) {
- releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
- if (cacheItem->object) {
- QObject *object = cacheItem->object;
- cacheItem->destroyObject();
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emitDestroyingPackage(package);
- else
- emitDestroyingItem(object);
- }
- cacheItem->scriptRef -= 1;
- } else {
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i))
- incubationTask->index[i] = remove.index[i];
- }
- }
- }
- if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
- for (int i = 1; i < m_groupCount; ++i) {
- if (remove.inGroup(i))
- attached->m_currentIndex[i] = remove.index[i];
- }
- }
- cacheItem->groups &= ~remove.flags;
- }
- }
- }
- }
-
- for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.count(); ++cacheIndex)
- incrementIndexes(cache.at(cacheIndex), m_groupCount, removed);
-}
-
-void QQmlDelegateModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
-{
- 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)
- return;
-
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(translatedRemoves.at(i));
-}
-
-void QQmlDelegateModel::_q_itemsRemoved(int index, int count)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0|| !d->m_complete)
- return;
-
- d->m_count -= count;
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- // layout change triggered by removal of a previous item might have
- // already invalidated this item in d->m_cache and deleted it
- if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
- continue;
-
- if (item->modelIndex() >= index + count) {
- const int newIndex = item->modelIndex() - count;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- } else if (item->modelIndex() >= index) {
- item->setModelIndex(-1, -1, -1);
- }
- }
-
- QVector<Compositor::Remove> removes;
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
- d->itemsRemoved(removes);
-
- d->emitChanges();
-}
-
-void QQmlDelegateModelPrivate::itemsMoved(
- const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
-{
- QHash<int, QList<QQmlDelegateModelItem *> > movedItems;
-
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
- itemsRemoved(removes, &translatedRemoves, &movedItems);
-
- 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());
- if (!m_delegate)
- return;
-
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.move(
- translatedRemoves.at(i),
- translatedInserts.at(i));
- }
-}
-
-void QQmlDelegateModel::_q_itemsMoved(int from, int to, int count)
-{
- Q_D(QQmlDelegateModel);
- if (count <= 0 || !d->m_complete)
- return;
-
- const int minimum = qMin(from, to);
- const int maximum = qMax(from, to) + count;
- const int difference = from > to ? count : -count;
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- // layout change triggered by changing the modelIndex might have
- // already invalidated this item in d->m_cache and deleted it.
- if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
- continue;
-
- if (item->modelIndex() >= from && item->modelIndex() < from + count) {
- const int newIndex = item->modelIndex() - from + to;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- } else if (item->modelIndex() >= minimum && item->modelIndex() < maximum) {
- const int newIndex = item->modelIndex() + difference;
- const int row = newIndex;
- const int column = 0;
- item->setModelIndex(newIndex, row, column);
- }
- }
-
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
- d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
- d->itemsMoved(removes, inserts);
- d->emitChanges();
-}
-
-void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- Q_Q(QQmlDelegateModel);
- emit q->modelUpdated(changeSet, reset);
- if (changeSet.difference() != 0)
- emit q->countChanged();
-}
-
-void QQmlDelegateModelPrivate::delegateChanged(bool add, bool remove)
-{
- Q_Q(QQmlDelegateModel);
- if (!m_complete)
- return;
-
- if (m_transaction) {
- qmlWarning(q) << QQmlDelegateModel::tr("The delegates of a DelegateModel cannot be changed within onUpdated.");
- return;
- }
-
- if (remove) {
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(
- 0, m_compositor.count(Compositor::Group(i)));
- }
- }
- if (add) {
- for (int i = 1; i < m_groupCount; ++i) {
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(
- 0, m_compositor.count(Compositor::Group(i)));
- }
- }
- emitChanges();
-}
-
-void QQmlDelegateModelPrivate::emitChanges()
-{
- if (m_transaction || !m_complete || !m_context || !m_context->isValid())
- return;
-
- m_transaction = true;
- QV4::ExecutionEngine *engine = m_context->engine()->handle();
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitChanges(engine);
- m_transaction = false;
-
- const bool reset = m_reset;
- m_reset = false;
- for (int i = 1; i < m_groupCount; ++i)
- QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
-
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
- for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) {
- if (cacheItem->attached)
- cacheItem->attached->emitChanges();
- }
-}
-
-void QQmlDelegateModel::_q_modelReset()
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_delegate)
- return;
-
- int oldCount = d->m_count;
- d->m_adaptorModel.rootIndex = QModelIndex();
-
- if (d->m_complete) {
- d->m_count = d->adaptorModelCount();
-
- const QList<QQmlDelegateModelItem *> cache = d->m_cache;
- for (int i = 0, c = cache.count(); i < c; ++i) {
- QQmlDelegateModelItem *item = cache.at(i);
- // layout change triggered by changing the modelIndex might have
- // already invalidated this item in d->m_cache and deleted it.
- if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
- continue;
-
- if (item->modelIndex() != -1)
- item->setModelIndex(-1, -1, -1);
- }
-
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
- if (oldCount)
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
- if (d->m_count)
- d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
- d->itemsMoved(removes, inserts);
- d->m_reset = true;
-
- if (d->m_adaptorModel.canFetchMore())
- d->m_adaptorModel.fetchMore();
-
- d->emitChanges();
- }
- emit rootIndexChanged();
-}
-
-void QQmlDelegateModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (parent == d->m_adaptorModel.rootIndex)
- _q_itemsInserted(begin, end - begin + 1);
-}
-
-void QQmlDelegateModel::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_adaptorModel.rootIndex.isValid())
- return;
- const QModelIndex index = d->m_adaptorModel.rootIndex;
- if (index.parent() == parent && index.row() >= begin && index.row() <= end) {
- const int oldCount = d->m_count;
- d->m_count = 0;
- d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.invalidateModel();
-
- if (d->m_complete && oldCount > 0) {
- QVector<Compositor::Remove> removes;
- d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
- d->itemsRemoved(removes);
- d->emitChanges();
- }
- }
-}
-
-void QQmlDelegateModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
-{
- Q_D(QQmlDelegateModel);
- if (parent == d->m_adaptorModel.rootIndex)
- _q_itemsRemoved(begin, end - begin + 1);
-}
-
-void QQmlDelegateModel::_q_rowsMoved(
- const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
- const QModelIndex &destinationParent, int destinationRow)
-{
- Q_D(QQmlDelegateModel);
- const int count = sourceEnd - sourceStart + 1;
- if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
- _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
- } else if (sourceParent == d->m_adaptorModel.rootIndex) {
- _q_itemsRemoved(sourceStart, count);
- } else if (destinationParent == d->m_adaptorModel.rootIndex) {
- _q_itemsInserted(destinationRow, count);
- }
-}
-
-void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
-{
- Q_D(QQmlDelegateModel);
- if (begin.parent() == d->m_adaptorModel.rootIndex)
- _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
-}
-
-bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
-{
- for (int i = 0, c = parents.count(); i < c; ++i) {
- for (QPersistentModelIndex parent = desc; parent.isValid(); parent = parent.parent()) {
- if (parent == parents[i])
- return true;
- }
- }
-
- return false;
-}
-
-void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
-{
- Q_D(QQmlDelegateModel);
- if (!d->m_complete)
- return;
-
- if (hint == QAbstractItemModel::VerticalSortHint) {
- if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
- return;
- }
-
- // mark all items as changed
- _q_itemsChanged(0, d->m_count, QVector<int>());
-
- } else if (hint == QAbstractItemModel::HorizontalSortHint) {
- // Ignored
- } else {
- // We don't know what's going on, so reset the model
- _q_modelReset();
- }
-}
-
-QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj)
-{
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(obj)) {
- if (cacheItem->object == obj) { // Don't create attached item for child objects.
- cacheItem->attached = new QQmlDelegateModelAttached(cacheItem, obj);
- return cacheItem->attached;
- }
- }
- return new QQmlDelegateModelAttached(obj);
-}
-
-bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
-{
- if (!m_context || !m_context->isValid())
- return false;
-
- QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, -1);
- if (!cacheItem)
- return false;
- if (!object.isObject())
- return false;
-
- QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, object);
- if (!o)
- return false;
-
- QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedValue propertyName(scope);
- QV4::ScopedValue v(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(v);
- if (propertyName->isNull())
- break;
- cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QVariant::Invalid));
- }
-
- cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
-
- // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
- itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
-
- before = m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
- m_cache.insert(before.cacheIndex, cacheItem);
-
- return true;
-}
-
-//============================================================================
-
-QQmlDelegateModelItemMetaType::QQmlDelegateModelItemMetaType(
- QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames)
- : model(model)
- , groupCount(groupNames.count() + 1)
- , v4Engine(engine)
- , metaObject(nullptr)
- , groupNames(groupNames)
-{
-}
-
-QQmlDelegateModelItemMetaType::~QQmlDelegateModelItemMetaType()
-{
- if (metaObject)
- metaObject->release();
-}
-
-void QQmlDelegateModelItemMetaType::initializeMetaObject()
-{
- QMetaObjectBuilder builder;
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- builder.setClassName(QQmlDelegateModelAttached::staticMetaObject.className());
- builder.setSuperClass(&QQmlDelegateModelAttached::staticMetaObject);
-
- int notifierId = 0;
- for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- QString propertyName = QLatin1String("in") + groupNames.at(i);
- propertyName.replace(2, 1, propertyName.at(2).toUpper());
- builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
- QMetaPropertyBuilder propertyBuilder = builder.addProperty(
- propertyName.toUtf8(), "bool", notifierId);
- propertyBuilder.setWritable(true);
- }
- for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
- const QString propertyName = groupNames.at(i) + QLatin1String("Index");
- builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
- QMetaPropertyBuilder propertyBuilder = builder.addProperty(
- propertyName.toUtf8(), "int", notifierId);
- propertyBuilder.setWritable(true);
- }
-
- metaObject = new QQmlDelegateModelAttachedMetaObject(this, builder.toMetaObject());
-}
-
-void QQmlDelegateModelItemMetaType::initializePrototype()
-{
- QV4::Scope scope(v4Engine);
-
- QV4::ScopedObject proto(scope, v4Engine->newObject());
- proto->defineAccessorProperty(QStringLiteral("model"), QQmlDelegateModelItem::get_model, nullptr);
- proto->defineAccessorProperty(QStringLiteral("groups"), QQmlDelegateModelItem::get_groups, QQmlDelegateModelItem::set_groups);
- QV4::ScopedString s(scope);
- QV4::ScopedProperty p(scope);
-
- s = v4Engine->newString(QStringLiteral("isUnresolved"));
- QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
-
- for (int i = 2; i < groupNames.count(); ++i) {
- QString propertyName = QLatin1String("in") + groupNames.at(i);
- propertyName.replace(2, 1, propertyName.at(2).toUpper());
- s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- }
- for (int i = 2; i < groupNames.count(); ++i) {
- const QString propertyName = groupNames.at(i) + QLatin1String("Index");
- s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
- p->setSetter(nullptr);
- proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
- }
- modelItemProto.set(v4Engine, proto);
-}
-
-int QQmlDelegateModelItemMetaType::parseGroups(const QStringList &groups) const
-{
- int groupFlags = 0;
- for (const QString &groupName : groups) {
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- }
- return groupFlags;
-}
-
-int QQmlDelegateModelItemMetaType::parseGroups(const QV4::Value &groups) const
-{
- int groupFlags = 0;
- QV4::Scope scope(v4Engine);
-
- QV4::ScopedString s(scope, groups);
- if (s) {
- const QString groupName = s->toQString();
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- return groupFlags;
- }
-
- QV4::ScopedArrayObject array(scope, groups);
- if (array) {
- QV4::ScopedValue v(scope);
- uint arrayLength = array->getLength();
- for (uint i = 0; i < arrayLength; ++i) {
- v = array->get(i);
- const QString groupName = v->toQString();
- int index = groupNames.indexOf(groupName);
- if (index != -1)
- groupFlags |= 2 << index;
- }
- }
- return groupFlags;
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_model(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return b->engine()->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!o->d()->item->metaType->model)
- RETURN_UNDEFINED();
-
- return o->d()->item->get();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_groups(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- QStringList groups;
- 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 scope.engine->fromVariant(groups);
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::set_groups(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- if (!argc)
- THROW_TYPE_ERROR();
-
- if (!o->d()->item->metaType->model)
- RETURN_UNDEFINED();
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
-
- const int groupFlags = model->m_cacheMetaType->parseGroups(argv[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();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
-{
- return QV4::Encode(bool(thisItem->groups & (1 << flag)));
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::set_member(QQmlDelegateModelItem *cacheItem, uint flag, const QV4::Value &arg)
-{
- if (!cacheItem->metaType->model)
- return QV4::Encode::undefined();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(cacheItem->metaType->model);
-
- bool member = arg.toBoolean();
- uint groupFlag = (1 << flag);
- if (member == ((cacheItem->groups & groupFlag) != 0))
- return QV4::Encode::undefined();
-
- const int cacheIndex = model->m_cache.indexOf(cacheItem);
- Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
- if (member)
- model->addGroups(it, 1, Compositor::Cache, groupFlag);
- else
- model->removeGroups(it, 1, Compositor::Cache, groupFlag);
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDelegateModelItem::get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
-{
- return QV4::Encode((int)thisItem->groupIndex(Compositor::Group(flag)));
-}
-
-void QQmlDelegateModelItem::childContextObjectDestroyed(QObject *childContextObject)
-{
- if (!contextData)
- return;
-
- for (QQmlContextData *ctxt = contextData->childContexts; ctxt; ctxt = ctxt->nextChild) {
- if (ctxt->contextObject == childContextObject)
- ctxt->contextObject = nullptr;
- }
-}
-
-
-//---------------------------------------------------------------------------
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelItemObject);
-
-void QV4::Heap::QQmlDelegateModelItemObject::destroy()
-{
- item->Dispose();
- Object::destroy();
-}
-
-
-QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int modelIndex, int row, int column)
- : v4(metaType->v4Engine)
- , metaType(metaType)
- , contextData(nullptr)
- , object(nullptr)
- , attached(nullptr)
- , incubationTask(nullptr)
- , delegate(nullptr)
- , poolTime(0)
- , objectRef(0)
- , scriptRef(0)
- , groups(0)
- , index(modelIndex)
- , row(row)
- , column(column)
-{
- metaType->addref();
-
- if (accessor->propertyCache) {
- // The property cache in the accessor is common for all the model
- // items in the model it wraps. It describes available model roles,
- // together with revisioned properties like row, column and index, all
- // which should be available in the delegate. We assign this cache to the
- // model item so that the QML engine can use the revision information
- // when resolving the properties (rather than falling back to just
- // inspecting the QObject in the model item directly).
- QQmlData *qmldata = QQmlData::get(this, true);
- if (qmldata->propertyCache)
- qmldata->propertyCache->release();
- qmldata->propertyCache = accessor->propertyCache.data();
- qmldata->propertyCache->addref();
- }
-}
-
-QQmlDelegateModelItem::~QQmlDelegateModelItem()
-{
- Q_ASSERT(scriptRef == 0);
- Q_ASSERT(objectRef == 0);
- Q_ASSERT(!object);
-
- if (incubationTask) {
- if (metaType->model)
- QQmlDelegateModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
- else
- delete incubationTask;
- }
-
- metaType->release();
-
-}
-
-void QQmlDelegateModelItem::Dispose()
-{
- --scriptRef;
- if (isReferenced())
- return;
-
- if (metaType->model) {
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
- model->removeCacheItem(this);
- }
- delete this;
-}
-
-void QQmlDelegateModelItem::setModelIndex(int idx, int newRow, int newColumn)
-{
- const int prevIndex = index;
- const int prevRow = row;
- const int prevColumn = column;
-
- index = idx;
- row = newRow;
- column = newColumn;
-
- if (idx != prevIndex)
- emit modelIndexChanged();
- if (row != prevRow)
- emit rowChanged();
- if (column != prevColumn)
- emit columnChanged();
-}
-
-void QQmlDelegateModelItem::destroyObject()
-{
- Q_ASSERT(object);
- Q_ASSERT(contextData);
-
- QQmlData *data = QQmlData::get(object);
- Q_ASSERT(data);
- if (data->ownContext) {
- data->ownContext->clearContext();
- if (data->ownContext->contextObject == object)
- data->ownContext->contextObject = nullptr;
- data->ownContext = nullptr;
- data->context = nullptr;
- }
- object->deleteLater();
-
- if (attached) {
- attached->m_cacheItem = nullptr;
- attached = nullptr;
- }
-
- contextData->invalidate();
- contextData = nullptr;
- object = nullptr;
-}
-
-QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
-{
- QQmlData *d = QQmlData::get(object);
- QQmlContextData *context = d ? d->context : nullptr;
- for (context = context ? context->parent : nullptr; context; context = context->parent) {
- if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
- context->contextObject)) {
- return cacheItem;
- }
- }
- return nullptr;
-}
-
-int QQmlDelegateModelItem::groupIndex(Compositor::Group group)
-{
- if (QQmlDelegateModelPrivate * const model = metaType->model
- ? QQmlDelegateModelPrivate::get(metaType->model)
- : nullptr) {
- return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
- }
- return -1;
-}
-
-//---------------------------------------------------------------------------
-
-QQmlDelegateModelAttachedMetaObject::QQmlDelegateModelAttachedMetaObject(
- QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject)
- : metaType(metaType)
- , metaObject(metaObject)
- , memberPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount())
- , indexPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
-{
- // Don't reference count the meta-type here as that would create a circular reference.
- // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
- // destroying all delegates with attached objects.
- *static_cast<QMetaObject *>(this) = *metaObject;
-}
-
-QQmlDelegateModelAttachedMetaObject::~QQmlDelegateModelAttachedMetaObject()
-{
- ::free(metaObject);
-}
-
-void QQmlDelegateModelAttachedMetaObject::objectDestroyed(QObject *)
-{
- release();
-}
-
-int QQmlDelegateModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
-{
- QQmlDelegateModelAttached *attached = static_cast<QQmlDelegateModelAttached *>(object);
- if (call == QMetaObject::ReadProperty) {
- if (_id >= indexPropertyOffset) {
- Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
- *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
- return -1;
- } else if (_id >= memberPropertyOffset) {
- Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
- *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
- return -1;
- }
- } else if (call == QMetaObject::WriteProperty) {
- if (_id >= memberPropertyOffset) {
- if (!metaType->model)
- return -1;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
- Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
- const int groupFlag = 1 << group;
- const bool member = attached->m_cacheItem->groups & groupFlag;
- if (member && !*static_cast<bool *>(arguments[0])) {
- Compositor::iterator it = model->m_compositor.find(
- group, attached->m_currentIndex[group]);
- model->removeGroups(it, 1, group, groupFlag);
- } else if (!member && *static_cast<bool *>(arguments[0])) {
- for (int i = 1; i < metaType->groupCount; ++i) {
- if (attached->m_cacheItem->groups & (1 << i)) {
- Compositor::iterator it = model->m_compositor.find(
- Compositor::Group(i), attached->m_currentIndex[i]);
- model->addGroups(it, 1, Compositor::Group(i), groupFlag);
- break;
- }
- }
- }
- return -1;
- }
- }
- return attached->qt_metacall(call, _id, arguments);
-}
-
-QQmlDelegateModelAttached::QQmlDelegateModelAttached(QObject *parent)
- : m_cacheItem(nullptr)
- , m_previousGroups(0)
-{
- QQml_setParent_noEvent(this, parent);
-}
-
-QQmlDelegateModelAttached::QQmlDelegateModelAttached(
- QQmlDelegateModelItem *cacheItem, QObject *parent)
- : m_cacheItem(cacheItem)
- , m_previousGroups(cacheItem->groups)
-{
- QQml_setParent_noEvent(this, parent);
- resetCurrentIndex();
- // Let m_previousIndex be equal to m_currentIndex
- std::copy(std::begin(m_currentIndex), std::end(m_currentIndex), std::begin(m_previousIndex));
-
- if (!cacheItem->metaType->metaObject)
- cacheItem->metaType->initializeMetaObject();
-
- QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
- cacheItem->metaType->metaObject->addref();
-}
-
-void QQmlDelegateModelAttached::resetCurrentIndex()
-{
- if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
- for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i)
- m_currentIndex[i] = incubationTask->index[i];
- } else {
- QQmlDelegateModelPrivate * const model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
- Compositor::iterator it = model->m_compositor.find(
- Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
- m_currentIndex[i] = it.index[i];
- }
-}
-
-/*!
- \qmlattachedproperty model QtQml.Models::DelegateModel::model
-
- This attached property holds the data model this delegate instance belongs to.
-
- It is attached to each instance of the delegate.
-*/
-
-QQmlDelegateModel *QQmlDelegateModelAttached::model() const
-{
- return m_cacheItem ? m_cacheItem->metaType->model : nullptr;
-}
-
-/*!
- \qmlattachedproperty stringlist QtQml.Models::DelegateModel::groups
-
- This attached property holds the name of DelegateModelGroups the item belongs to.
-
- It is attached to each instance of the delegate.
-*/
-
-QStringList QQmlDelegateModelAttached::groups() const
-{
- QStringList groups;
-
- if (!m_cacheItem)
- return groups;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
- if (m_cacheItem->groups & (1 << i))
- groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
- }
- return groups;
-}
-
-void QQmlDelegateModelAttached::setGroups(const QStringList &groups)
-{
- if (!m_cacheItem)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
-
- const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
- const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
- Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
- model->setGroups(it, 1, Compositor::Cache, groupFlags);
-}
-
-/*!
- \qmlattachedproperty bool QtQml.Models::DelegateModel::isUnresolved
-
- This attached property indicates whether the visual item is bound to a data model index.
- Returns true if the item is not bound to the model, and false if it is.
-
- An unresolved item can be bound to the data model using the DelegateModelGroup::resolve()
- function.
-
- It is attached to each instance of the delegate.
-*/
-
-bool QQmlDelegateModelAttached::isUnresolved() const
-{
- if (!m_cacheItem)
- return false;
-
- return m_cacheItem->groups & Compositor::UnresolvedFlag;
-}
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::inItems
-
- This attached property holds whether the item belongs to the default \l items DelegateModelGroup.
-
- Changing this property will add or remove the item from the items group.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::itemsIndex
-
- This attached property holds the index of the item in the default \l items DelegateModelGroup.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::inPersistedItems
-
- This attached property holds whether the item belongs to the \l persistedItems DelegateModelGroup.
-
- Changing this property will add or remove the item from the items group. Change with caution
- as removing an item from the persistedItems group will destroy the current instance if it is
- not referenced by a model.
-
- It is attached to each instance of the delegate.
-*/
-
-/*!
- \qmlattachedproperty int QtQml.Models::DelegateModel::persistedItemsIndex
-
- This attached property holds the index of the item in the \l persistedItems DelegateModelGroup.
-
- It is attached to each instance of the delegate.
-*/
-
-void QQmlDelegateModelAttached::emitChanges()
-{
- const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
- m_previousGroups = m_cacheItem->groups;
-
- int indexChanges = 0;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
- if (m_previousIndex[i] != m_currentIndex[i]) {
- m_previousIndex[i] = m_currentIndex[i];
- indexChanges |= (1 << i);
- }
- }
-
- int notifierId = 0;
- const QMetaObject *meta = metaObject();
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
- if (groupChanges & (1 << i))
- QMetaObject::activate(this, meta, notifierId, nullptr);
- }
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
- if (indexChanges & (1 << i))
- QMetaObject::activate(this, meta, notifierId, nullptr);
- }
-
- if (groupChanges)
- emit groupsChanged();
-}
-
-//============================================================================
-
-void QQmlDelegateModelGroupPrivate::setModel(QQmlDelegateModel *m, Compositor::Group g)
-{
- Q_ASSERT(!model);
- model = m;
- group = g;
-}
-
-bool QQmlDelegateModelGroupPrivate::isChangedConnected()
-{
- Q_Q(QQmlDelegateModelGroup);
- IS_SIGNAL_CONNECTED(q, QQmlDelegateModelGroup, changed, (const QQmlV4Handle &,const QQmlV4Handle &));
-}
-
-void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
-{
- Q_Q(QQmlDelegateModelGroup);
- if (isChangedConnected() && !changeSet.isEmpty()) {
- QV4::Scope scope(v4);
- QV4::ScopedValue removed(scope, engineData(scope.engine)->array(v4, changeSet.removes()));
- QV4::ScopedValue inserted(scope, engineData(scope.engine)->array(v4, changeSet.inserts()));
- emit q->changed(QQmlV4Handle(removed), QQmlV4Handle(inserted));
- }
- if (changeSet.difference() != 0)
- emit q->countChanged();
-}
-
-void QQmlDelegateModelGroupPrivate::emitModelUpdated(bool reset)
-{
- for (QQmlDelegateModelGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
- it->emitModelUpdated(changeSet, reset);
- changeSet.clear();
-}
-
-typedef QQmlDelegateModelGroupEmitterList::iterator GroupEmitterListIt;
-
-void QQmlDelegateModelGroupPrivate::createdPackage(int index, QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->createdPackage(index, package);
-}
-
-void QQmlDelegateModelGroupPrivate::initPackage(int index, QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->initPackage(index, package);
-}
-
-void QQmlDelegateModelGroupPrivate::destroyingPackage(QQuickPackage *package)
-{
- for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
- it->destroyingPackage(package);
-}
-
-/*!
- \qmltype DelegateModelGroup
- \instantiates QQmlDelegateModelGroup
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Encapsulates a filtered set of visual data items.
-
- The DelegateModelGroup type provides a means to address the model data of a
- DelegateModel's delegate items, as well as sort and filter these delegate
- items.
-
- The initial set of instantiable delegate items in a DelegateModel is represented
- by its \l {QtQml.Models::DelegateModel::items}{items} group, which normally directly reflects
- the contents of the model assigned to DelegateModel::model. This set can be changed to
- the contents of any other member of DelegateModel::groups by assigning the \l name of that
- DelegateModelGroup to the DelegateModel::filterOnGroup property.
-
- The data of an item in a DelegateModelGroup can be accessed using the get() function, which returns
- information about group membership and indexes as well as model data. In combination
- with the move() function this can be used to implement view sorting, with remove() to filter
- items out of a view, or with setGroups() and \l Package delegates to categorize items into
- different views. Different groups can only be sorted independently if they are disjunct. Moving
- an item in one group will also move it in all other groups it is a part of.
-
- Data from models can be supplemented by inserting data directly into a DelegateModelGroup
- with the insert() function. This can be used to introduce mock items into a view, or
- placeholder items that are later \l {resolve()}{resolved} to real model data when it becomes
- available.
-
- Delegate items can also be instantiated directly from a DelegateModelGroup using the
- create() function, making it possible to use DelegateModel without an accompanying view
- type or to cherry-pick specific items that should be instantiated irregardless of whether
- they're currently within a view's visible area.
-
- \sa {QML Dynamic View Ordering Tutorial}
-*/
-QQmlDelegateModelGroup::QQmlDelegateModelGroup(QObject *parent)
- : QObject(*new QQmlDelegateModelGroupPrivate, parent)
-{
-}
-
-QQmlDelegateModelGroup::QQmlDelegateModelGroup(
- const QString &name, QQmlDelegateModel *model, int index, QObject *parent)
- : QQmlDelegateModelGroup(parent)
-{
- Q_D(QQmlDelegateModelGroup);
- d->name = name;
- d->setModel(model, Compositor::Group(index));
-}
-
-QQmlDelegateModelGroup::~QQmlDelegateModelGroup()
-{
-}
-
-/*!
- \qmlproperty string QtQml.Models::DelegateModelGroup::name
-
- This property holds the name of the group.
-
- Each group in a model must have a unique name starting with a lower case letter.
-*/
-
-QString QQmlDelegateModelGroup::name() const
-{
- Q_D(const QQmlDelegateModelGroup);
- return d->name;
-}
-
-void QQmlDelegateModelGroup::setName(const QString &name)
-{
- Q_D(QQmlDelegateModelGroup);
- if (d->model)
- return;
- if (d->name != name) {
- d->name = name;
- emit nameChanged();
- }
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateModelGroup::count
-
- This property holds the number of items in the group.
-*/
-
-int QQmlDelegateModelGroup::count() const
-{
- Q_D(const QQmlDelegateModelGroup);
- if (!d->model)
- return 0;
- return QQmlDelegateModelPrivate::get(d->model)->m_compositor.count(d->group);
-}
-
-/*!
- \qmlproperty bool QtQml.Models::DelegateModelGroup::includeByDefault
-
- This property holds whether new items are assigned to this group by default.
-*/
-
-bool QQmlDelegateModelGroup::defaultInclude() const
-{
- Q_D(const QQmlDelegateModelGroup);
- return d->defaultInclude;
-}
-
-void QQmlDelegateModelGroup::setDefaultInclude(bool include)
-{
- Q_D(QQmlDelegateModelGroup);
- if (d->defaultInclude != include) {
- d->defaultInclude = include;
-
- if (d->model) {
- if (include)
- QQmlDelegateModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
- else
- QQmlDelegateModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
- }
- emit defaultIncludeChanged();
- }
-}
-
-/*!
- \qmlmethod object QtQml.Models::DelegateModelGroup::get(int index)
-
- Returns a javascript object describing the item at \a index in the group.
-
- The returned object contains the same information that is available to a delegate from the
- DelegateModel attached as well as the model for that item. It has the properties:
-
- \list
- \li \b model The model data of the item. This is the same as the model context property in
- a delegate
- \li \b groups A list the of names of groups the item is a member of. This property can be
- written to change the item's membership.
- \li \b inItems Whether the item belongs to the \l {QtQml.Models::DelegateModel::items}{items} group.
- Writing to this property will add or remove the item from the group.
- \li \b itemsIndex The index of the item within the \l {QtQml.Models::DelegateModel::items}{items} group.
- \li \b {in<GroupName>} Whether the item belongs to the dynamic group \e groupName. Writing to
- this property will add or remove the item from the group.
- \li \b {<groupName>Index} The index of the item within the dynamic group \e groupName.
- \li \b isUnresolved Whether the item is bound to an index in the model assigned to
- DelegateModel::model. Returns true if the item is not bound to the model, and false if it is.
- \endlist
-*/
-
-QQmlV4Handle QQmlDelegateModelGroup::get(int index)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return QQmlV4Handle(QV4::Encode::undefined());
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (!model->m_context || !model->m_context->isValid()) {
- return QQmlV4Handle(QV4::Encode::undefined());
- } else if (index < 0 || index >= model->m_compositor.count(d->group)) {
- qmlWarning(this) << tr("get: index out of range");
- return QQmlV4Handle(QV4::Encode::undefined());
- }
-
- Compositor::iterator it = model->m_compositor.find(d->group, index);
- QQmlDelegateModelItem *cacheItem = it->inCache()
- ? model->m_cache.at(it.cacheIndex)
- : 0;
-
- if (!cacheItem) {
- cacheItem = model->m_adaptorModel.createItem(
- model->m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
- return QQmlV4Handle(QV4::Encode::undefined());
- cacheItem->groups = it->flags;
-
- model->m_cache.insert(it.cacheIndex, cacheItem);
- model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- }
-
- if (model->m_cacheMetaType->modelItemProto.isUndefined())
- model->m_cacheMetaType->initializePrototype();
- QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine;
- QV4::Scope scope(v4);
- ++cacheItem->scriptRef;
- QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(cacheItem));
- QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
- o->setPrototypeOf(p);
-
- return QQmlV4Handle(o);
-}
-
-bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
-{
- if (value.isNumber()) {
- *index = value.toInt32();
- return true;
- }
-
- if (!value.isObject())
- return false;
-
- QV4::ExecutionEngine *v4 = value.as<QV4::Object>()->engine();
- QV4::Scope scope(v4);
- QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value);
-
- if (object) {
- QQmlDelegateModelItem * const cacheItem = object->d()->item;
- if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
- ? QQmlDelegateModelPrivate::get(cacheItem->metaType->model)
- : nullptr) {
- *index = model->m_cache.indexOf(cacheItem);
- *group = Compositor::Cache;
- return true;
- }
- }
- return false;
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::insert(int index, jsdict data, array groups = undefined)
- \qmlmethod QtQml.Models::DelegateModelGroup::insert(jsdict data, var groups = undefined)
-
- Creates a new entry at \a index in a DelegateModel with the values from \a data that
- correspond to roles in the model assigned to DelegateModel::model.
-
- If no index is supplied the data is appended to the model.
-
- The optional \a groups parameter identifies the groups the new entry should belong to,
- if unspecified this is equal to the group insert was called on.
-
- Data inserted into a DelegateModel can later be merged with an existing entry in
- DelegateModel::model using the \l resolve() function. This can be used to create placeholder
- items that are later replaced by actual data.
-*/
-
-void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- int index = model->m_compositor.count(d->group);
- Compositor::Group group = d->group;
-
- if (args->length() == 0)
- return;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (d->parseIndex(v, &index, &group)) {
- if (index < 0 || index > model->m_compositor.count(group)) {
- qmlWarning(this) << tr("insert: index out of range");
- return;
- }
- if (++i == args->length())
- return;
- v = (*args)[i];
- }
-
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
-
- int groups = 1 << d->group;
- if (++i < args->length()) {
- QV4::ScopedValue val(scope, (*args)[i]);
- groups |= model->m_cacheMetaType->parseGroups(val);
- }
-
- if (v->as<QV4::ArrayObject>()) {
- return;
- } else if (v->as<QV4::Object>()) {
- model->insert(before, v, groups);
- model->emitChanges();
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::create(int index)
- \qmlmethod QtQml.Models::DelegateModelGroup::create(int index, jsdict data, array groups = undefined)
- \qmlmethod QtQml.Models::DelegateModelGroup::create(jsdict data, array groups = undefined)
-
- Returns a reference to the instantiated item at \a index in the group.
-
- If a \a data object is provided it will be \l {insert}{inserted} at \a index and an item
- referencing this new entry will be returned. The optional \a groups parameter identifies
- the groups the new entry should belong to, if unspecified this is equal to the group create()
- was called on.
-
- All items returned by create are added to the
- \l {QtQml.Models::DelegateModel::persistedItems}{persistedItems} group. Items in this
- group remain instantiated when not referenced by any view.
-*/
-
-void QQmlDelegateModelGroup::create(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
-
- if (args->length() == 0)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- int index = model->m_compositor.count(d->group);
- Compositor::Group group = d->group;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (d->parseIndex(v, &index, &group))
- ++i;
-
- if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) {
- v = (*args)[i];
- if (v->as<QV4::Object>()) {
- int groups = 1 << d->group;
- if (++i < args->length()) {
- QV4::ScopedValue val(scope, (*args)[i]);
- groups |= model->m_cacheMetaType->parseGroups(val);
- }
-
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
-
- index = before.index[d->group];
- group = d->group;
-
- if (!model->insert(before, v, groups)) {
- return;
- }
- }
- }
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("create: index out of range");
- return;
- }
-
- QObject *object = model->object(group, index, QQmlIncubator::AsynchronousIfNested);
- if (object) {
- QVector<Compositor::Insert> inserts;
- Compositor::iterator it = model->m_compositor.find(group, index);
- model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
- model->itemsInserted(inserts);
- model->m_cache.at(it.cacheIndex)->releaseObject();
- }
-
- args->setReturnValue(QV4::QObjectWrapper::wrap(args->v4engine(), object));
- model->emitChanges();
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::resolve(int from, int to)
-
- Binds an unresolved item at \a from to an item in DelegateModel::model at index \a to.
-
- Unresolved items are entries whose data has been \l {insert()}{inserted} into a DelegateModelGroup
- instead of being derived from a DelegateModel::model index. Resolving an item will replace
- the item at the target index with the unresolved item. A resolved an item will reflect the data
- of the source model at its bound index and will move when that index moves like any other item.
-
- If a new item is replaced in the DelegateModelGroup onChanged() handler its insertion and
- replacement will be communicated to views as an atomic operation, creating the appearance
- that the model contents have not changed, or if the unresolved and model item are not adjacent
- that the previously unresolved item has simply moved.
-
-*/
-void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- if (args->length() < 2)
- return;
-
- int from = -1;
- int to = -1;
- Compositor::Group fromGroup = d->group;
- Compositor::Group toGroup = d->group;
-
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (d->parseIndex(v, &from, &fromGroup)) {
- if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
- qmlWarning(this) << tr("resolve: from index out of range");
- return;
- }
- } else {
- qmlWarning(this) << tr("resolve: from index invalid");
- return;
- }
-
- v = (*args)[1];
- if (d->parseIndex(v, &to, &toGroup)) {
- if (to < 0 || to >= model->m_compositor.count(toGroup)) {
- qmlWarning(this) << tr("resolve: to index out of range");
- return;
- }
- } else {
- qmlWarning(this) << tr("resolve: to index invalid");
- return;
- }
-
- Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
- Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
-
- if (!fromIt->isUnresolved()) {
- qmlWarning(this) << tr("resolve: from is not an unresolved item");
- return;
- }
- if (!toIt->list) {
- qmlWarning(this) << tr("resolve: to is not a model item");
- return;
- }
-
- const int unresolvedFlags = fromIt->flags;
- const int resolvedFlags = toIt->flags;
- const int resolvedIndex = toIt.modelIndex();
- void * const resolvedList = toIt->list;
-
- QQmlDelegateModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
- cacheItem->groups &= ~Compositor::UnresolvedFlag;
-
- if (toIt.cacheIndex > fromIt.cacheIndex)
- toIt.decrementIndexes(1, unresolvedFlags);
- if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
- from += 1;
-
- model->itemsMoved(
- QVector<Compositor::Remove>(1, Compositor::Remove(fromIt, 1, unresolvedFlags, 0)),
- QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, unresolvedFlags, 0)));
- model->itemsInserted(
- QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag)));
- toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
- model->itemsRemoved(QVector<Compositor::Remove>(1, Compositor::Remove(toIt, 1, resolvedFlags)));
-
- model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
- model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
-
- if (resolvedFlags & Compositor::CacheFlag)
- model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
-
- Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
-
- if (!cacheItem->isReferenced()) {
- Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
- model->m_cache.removeAt(toIt.cacheIndex);
- model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
- delete cacheItem;
- Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
- } else {
- cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
- if (cacheItem->attached)
- cacheItem->attached->emitUnresolvedChanged();
- }
-
- model->emitChanges();
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::remove(int index, int count)
-
- Removes \a count items starting at \a index from the group.
-*/
-
-void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- if (!d->model)
- return;
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
-
- if (args->length() == 0)
- return;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (!d->parseIndex(v, &index, &group)) {
- qmlWarning(this) << tr("remove: invalid index");
- return;
- }
-
- if (++i < args->length()) {
- v = (*args)[i];
- if (v->isNumber())
- count = v->toInt32();
- }
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("remove: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("remove: invalid count");
- } else {
- model->removeGroups(it, count, d->group, 1 << d->group);
- }
- }
-}
-
-bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
-{
- if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
- return false;
-
- if (args->length() < 2)
- return false;
-
- int i = 0;
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[i]);
- if (!parseIndex(v, index, group))
- return false;
-
- v = (*args)[++i];
- if (v->isNumber()) {
- *count = v->toInt32();
-
- if (++i == args->length())
- return false;
- v = (*args)[i];
- }
-
- *groups = QQmlDelegateModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
-
- return true;
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::addGroups(int index, int count, stringlist groups)
-
- Adds \a count items starting at \a index to \a groups.
-*/
-
-void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("addGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("addGroups: invalid count");
- } else {
- model->addGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::removeGroups(int index, int count, stringlist groups)
-
- Removes \a count items starting at \a index from \a groups.
-*/
-
-void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("removeGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("removeGroups: invalid count");
- } else {
- model->removeGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
-
- Sets the \a groups \a count items starting at \a index belong to.
-*/
-
-void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
- Compositor::Group group = d->group;
- int index = -1;
- int count = 1;
- int groups = 0;
-
- if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
- return;
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
- if (index < 0 || index >= model->m_compositor.count(group)) {
- qmlWarning(this) << tr("setGroups: index out of range");
- } else if (count != 0) {
- Compositor::iterator it = model->m_compositor.find(group, index);
- if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
- qmlWarning(this) << tr("setGroups: invalid count");
- } else {
- model->setGroups(it, count, d->group, groups);
- }
- }
-}
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
-
- Sets the \a groups \a count items starting at \a index belong to.
-*/
-
-/*!
- \qmlmethod QtQml.Models::DelegateModelGroup::move(var from, var to, int count)
-
- Moves \a count at \a from in a group \a to a new position.
-
- \note The DelegateModel acts as a proxy model: it holds the delegates in a
- different order than the \l{dm-model-property}{underlying model} has them.
- Any subsequent changes to the underlying model will not undo whatever
- reordering you have done via this function.
-*/
-
-void QQmlDelegateModelGroup::move(QQmlV4Function *args)
-{
- Q_D(QQmlDelegateModelGroup);
-
- if (args->length() < 2)
- return;
-
- Compositor::Group fromGroup = d->group;
- Compositor::Group toGroup = d->group;
- int from = -1;
- int to = -1;
- int count = 1;
-
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue v(scope, (*args)[0]);
- if (!d->parseIndex(v, &from, &fromGroup)) {
- qmlWarning(this) << tr("move: invalid from index");
- return;
- }
-
- v = (*args)[1];
- if (!d->parseIndex(v, &to, &toGroup)) {
- qmlWarning(this) << tr("move: invalid to index");
- return;
- }
-
- if (args->length() > 2) {
- v = (*args)[2];
- if (v->isNumber())
- count = v->toInt32();
- }
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
-
- if (count < 0) {
- qmlWarning(this) << tr("move: invalid count");
- } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
- qmlWarning(this) << tr("move: from index out of range");
- } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
- qmlWarning(this) << tr("move: to index out of range");
- } else if (count > 0) {
- QVector<Compositor::Remove> removes;
- QVector<Compositor::Insert> inserts;
-
- model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
- model->itemsMoved(removes, inserts);
- model->emitChanges();
- }
-
-}
-
-/*!
- \qmlsignal QtQml.Models::DelegateModelGroup::changed(array removed, array inserted)
-
- This signal is emitted when items have been removed from or inserted into the group.
-
- Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
- item inserted or removed and a \e count of the number of consecutive items inserted or removed.
-
- Each index is adjusted for previous changes with all removed items preceding any inserted
- items.
-
- The corresponding handler is \c onChanged.
-*/
-
-//============================================================================
-
-QQmlPartsModel::QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent)
- : QQmlInstanceModel(*new QObjectPrivate, parent)
- , m_model(model)
- , m_part(part)
- , m_compositorGroup(Compositor::Cache)
- , m_inheritGroup(true)
-{
- QQmlDelegateModelPrivate *d = QQmlDelegateModelPrivate::get(m_model);
- if (d->m_cacheMetaType) {
- QQmlDelegateModelGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
- m_compositorGroup = Compositor::Default;
- } else {
- d->m_pendingParts.insert(this);
- }
-}
-
-QQmlPartsModel::~QQmlPartsModel()
-{
-}
-
-QString QQmlPartsModel::filterGroup() const
-{
- if (m_inheritGroup)
- return m_model->filterGroup();
- return m_filterGroup;
-}
-
-void QQmlPartsModel::setFilterGroup(const QString &group)
-{
- if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) {
- qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
- return;
- }
-
- if (m_filterGroup != group || m_inheritGroup) {
- m_filterGroup = group;
- m_inheritGroup = false;
- updateFilterGroup();
-
- emit filterGroupChanged();
- }
-}
-
-void QQmlPartsModel::resetFilterGroup()
-{
- if (!m_inheritGroup) {
- m_inheritGroup = true;
- updateFilterGroup();
- emit filterGroupChanged();
- }
-}
-
-void QQmlPartsModel::updateFilterGroup()
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- if (!model->m_cacheMetaType)
- return;
-
- if (m_inheritGroup) {
- if (m_filterGroup == model->m_filterGroup)
- return;
- m_filterGroup = model->m_filterGroup;
- }
-
- QQmlListCompositor::Group previousGroup = m_compositorGroup;
- m_compositorGroup = Compositor::Default;
- QQmlDelegateModelGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
- for (int i = 1; i < model->m_groupCount; ++i) {
- if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
- m_compositorGroup = Compositor::Group(i);
- break;
- }
- }
-
- QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
- if (m_compositorGroup != previousGroup) {
- QVector<QQmlChangeSet::Change> removes;
- QVector<QQmlChangeSet::Change> inserts;
- model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
-
- QQmlChangeSet changeSet;
- changeSet.move(removes, inserts);
- if (!changeSet.isEmpty())
- emit modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit countChanged();
- }
-}
-
-void QQmlPartsModel::updateFilterGroup(
- Compositor::Group group, const QQmlChangeSet &changeSet)
-{
- if (!m_inheritGroup)
- return;
-
- m_compositorGroup = group;
- QQmlDelegateModelGroupPrivate::get(QQmlDelegateModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
-
- if (!changeSet.isEmpty())
- emit modelUpdated(changeSet, false);
-
- if (changeSet.difference() != 0)
- emit countChanged();
-
- emit filterGroupChanged();
-}
-
-int QQmlPartsModel::count() const
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- return model->m_delegate
- ? model->m_compositor.count(m_compositorGroup)
- : 0;
-}
-
-bool QQmlPartsModel::isValid() const
-{
- return m_model->isValid();
-}
-
-QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
-
- if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
- qWarning() << "DelegateModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
- return nullptr;
- }
-
- QObject *object = model->object(m_compositorGroup, index, incubationMode);
-
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
- QObject *part = package->part(m_part);
- if (!part)
- return nullptr;
- m_packaged.insertMulti(part, package);
- return part;
- }
-
- model->release(object);
- if (!model->m_delegateValidated) {
- if (object)
- qmlWarning(model->m_delegate) << tr("Delegate component must be Package type.");
- model->m_delegateValidated = true;
- }
-
- return nullptr;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item)
-{
- QQmlInstanceModel::ReleaseFlags flags = nullptr;
-
- QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
- if (it != m_packaged.end()) {
- QQuickPackage *package = *it;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- flags = model->release(package);
- m_packaged.erase(it);
- if (!m_packaged.contains(item))
- flags &= ~Referenced;
- if (flags & Destroyed)
- QQmlDelegateModelPrivate::get(m_model)->emitDestroyingPackage(package);
- }
- return flags;
-}
-
-QString QQmlPartsModel::stringValue(int index, const QString &role)
-{
- return QQmlDelegateModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
-}
-
-void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &roles)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
- m_watchedRoles = roles;
-}
-
-QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
-{
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- Compositor::iterator it = model->m_compositor.find(model->m_compositorGroup, index);
- if (!it->inCache())
- return QQmlIncubator::Null;
-
- if (auto incubationTask = model->m_cache.at(it.cacheIndex)->incubationTask)
- return incubationTask->status();
-
- return QQmlIncubator::Ready;
-}
-
-int QQmlPartsModel::indexOf(QObject *item, QObject *) const
-{
- QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
- if (it != m_packaged.end()) {
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(*it))
- return cacheItem->groupIndex(m_compositorGroup);
- }
- return -1;
-}
-
-void QQmlPartsModel::createdPackage(int index, QQuickPackage *package)
-{
- emit createdItem(index, package->part(m_part));
-}
-
-void QQmlPartsModel::initPackage(int index, QQuickPackage *package)
-{
- if (m_modelUpdatePending)
- m_pendingPackageInitializations << index;
- else
- emit initItem(index, package->part(m_part));
-}
-
-void QQmlPartsModel::destroyingPackage(QQuickPackage *package)
-{
- QObject *item = package->part(m_part);
- Q_ASSERT(!m_packaged.contains(item));
- emit destroyingItem(item);
-}
-
-void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- m_modelUpdatePending = false;
- emit modelUpdated(changeSet, reset);
- if (changeSet.difference() != 0)
- emit countChanged();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
- QVector<int> pendingPackageInitializations;
- qSwap(pendingPackageInitializations, m_pendingPackageInitializations);
- for (int index : pendingPackageInitializations) {
- if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup))
- continue;
- QObject *object = model->object(m_compositorGroup, index, QQmlIncubator::Asynchronous);
- if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
- emit initItem(index, package->part(m_part));
- model->release(object);
- }
-}
-
-//============================================================================
-
-struct QQmlDelegateModelGroupChange : QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelGroupChange, QV4::Object)
-
- static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
- return e->memoryManager->allocate<QQmlDelegateModelGroupChange>();
- }
-
- static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- return QV4::Encode(that->d()->change.index);
- }
- static QV4::ReturnedValue method_get_count(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- return QV4::Encode(that->d()->change.count);
- }
- static QV4::ReturnedValue method_get_moveId(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, thisObject->as<QQmlDelegateModelGroupChange>());
- if (!that)
- THROW_TYPE_ERROR();
- if (that->d()->change.moveId < 0)
- RETURN_UNDEFINED();
- return QV4::Encode(that->d()->change.moveId);
- }
-};
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChange);
-
-struct QQmlDelegateModelGroupChangeArray : public QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelGroupChangeArray, QV4::Object)
- V4_NEEDS_DESTROY
-public:
- static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
- {
- return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes);
- }
-
- quint32 count() const { return d()->changes->count(); }
- const QQmlChangeSet::Change &at(int index) const { return d()->changes->at(index); }
-
- static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
- {
- if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>());
- QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine();
- QV4::Scope scope(v4);
- QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, static_cast<const QQmlDelegateModelGroupChangeArray *>(m));
-
- if (index >= array->count()) {
- if (hasProperty)
- *hasProperty = false;
- return QV4::Value::undefinedValue().asReturnedValue();
- }
-
- const QQmlChangeSet::Change &change = array->at(index);
-
- QV4::ScopedObject changeProto(scope, engineData(v4)->changeProto.value());
- QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4));
- object->setPrototypeOf(changeProto);
- object->d()->change = change;
-
- if (hasProperty)
- *hasProperty = true;
- return object.asReturnedValue();
- }
-
- Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>());
- const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m);
-
- if (id == array->engine()->id_length()->propertyKey()) {
- if (hasProperty)
- *hasProperty = true;
- return QV4::Encode(array->count());
- }
-
- return Object::virtualGet(m, id, receiver, hasProperty);
- }
-};
-
-void QV4::Heap::QQmlDelegateModelGroupChangeArray::init(const QVector<QQmlChangeSet::Change> &changes)
-{
- Object::init();
- this->changes = new QVector<QQmlChangeSet::Change>(changes);
- QV4::Scope scope(internalClass->engine);
- QV4::ScopedObject o(scope, this);
- o->setArrayType(QV4::Heap::ArrayData::Custom);
-}
-
-DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChangeArray);
-
-QQmlDelegateModelEngineData::QQmlDelegateModelEngineData(QV4::ExecutionEngine *v4)
-{
- QV4::Scope scope(v4);
-
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), QQmlDelegateModelGroupChange::method_get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("count"), QQmlDelegateModelGroupChange::method_get_count, nullptr);
- proto->defineAccessorProperty(QStringLiteral("moveId"), QQmlDelegateModelGroupChange::method_get_moveId, nullptr);
- changeProto.set(v4, proto);
-}
-
-QQmlDelegateModelEngineData::~QQmlDelegateModelEngineData()
-{
-}
-
-QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV4::ExecutionEngine *v4,
- const QVector<QQmlChangeSet::Change> &changes)
-{
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, QQmlDelegateModelGroupChangeArray::create(v4, changes));
- return o.asReturnedValue();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmldelegatemodel_p.cpp"
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
deleted file mode 100644
index 0ad8939732..0000000000
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDATAMODEL_P_H
-#define QQMLDATAMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmllistcompositor_p.h>
-#include <private/qqmlobjectmodel_p.h>
-#include <private/qqmlincubator_p.h>
-
-#include <QtCore/qabstractitemmodel.h>
-#include <QtCore/qstringlist.h>
-
-#include <private/qv8engine_p.h>
-#include <private/qqmlglobal_p.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-class QQmlChangeSet;
-class QQuickPackage;
-class QQmlV4Function;
-class QQmlDelegateModelGroup;
-class QQmlDelegateModelAttached;
-class QQmlDelegateModelPrivate;
-
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQmlDelegateModel)
-
- Q_PROPERTY(QVariant model READ model WRITE setModel)
- Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate)
- Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
- Q_PROPERTY(QQmlDelegateModelGroup *items READ items CONSTANT) //TODO : worth renaming?
- Q_PROPERTY(QQmlDelegateModelGroup *persistedItems READ persistedItems CONSTANT)
- Q_PROPERTY(QQmlListProperty<QQmlDelegateModelGroup> groups READ groups CONSTANT)
- Q_PROPERTY(QObject *parts READ parts CONSTANT)
- Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
- Q_INTERFACES(QQmlParserStatus)
-public:
- QQmlDelegateModel();
- QQmlDelegateModel(QQmlContext *, QObject *parent=nullptr);
- ~QQmlDelegateModel();
-
- void classBegin() override;
- void componentComplete() override;
-
- QVariant model() const;
- void setModel(const QVariant &);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *);
-
- QVariant rootIndex() const;
- void setRootIndex(const QVariant &root);
-
- Q_INVOKABLE QVariant modelIndex(int idx) const;
- Q_INVOKABLE QVariant parentModelIndex() const;
-
- int count() const override;
- bool isValid() const override { return delegate() != nullptr; }
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
- void cancel(int index) override;
- QString stringValue(int index, const QString &role) override;
- void setWatchedRoles(const QList<QByteArray> &roles) override;
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *object, QObject *objectContext) const override;
-
- QString filterGroup() const;
- void setFilterGroup(const QString &group);
- void resetFilterGroup();
-
- QQmlDelegateModelGroup *items();
- QQmlDelegateModelGroup *persistedItems();
- QQmlListProperty<QQmlDelegateModelGroup> groups();
- QObject *parts();
-
- const QAbstractItemModel *abstractItemModel() const override;
-
- bool event(QEvent *) override;
-
- static QQmlDelegateModelAttached *qmlAttachedProperties(QObject *obj);
-
-Q_SIGNALS:
- void filterGroupChanged();
- void defaultGroupsChanged();
- void rootIndexChanged();
-
-private Q_SLOTS:
- void _q_itemsChanged(int index, int count, const QVector<int> &roles);
- void _q_itemsInserted(int index, int count);
- void _q_itemsRemoved(int index, int count);
- void _q_itemsMoved(int from, int to, int count);
- void _q_modelReset();
- void _q_rowsInserted(const QModelIndex &,int,int);
- void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end);
- void _q_rowsRemoved(const QModelIndex &,int,int);
- void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
- void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &);
- void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
-
-private:
- bool isDescendantOf(const QPersistentModelIndex &desc, const QList<QPersistentModelIndex> &parents) const;
-
- Q_DISABLE_COPY(QQmlDelegateModel)
-};
-
-class QQmlDelegateModelGroupPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
- Q_PROPERTY(bool includeByDefault READ defaultInclude WRITE setDefaultInclude NOTIFY defaultIncludeChanged)
-public:
- QQmlDelegateModelGroup(QObject *parent = nullptr);
- QQmlDelegateModelGroup(const QString &name, QQmlDelegateModel *model, int compositorType, QObject *parent = nullptr);
- ~QQmlDelegateModelGroup();
-
- QString name() const;
- void setName(const QString &name);
-
- int count() const;
-
- bool defaultInclude() const;
- void setDefaultInclude(bool include);
-
- Q_INVOKABLE QQmlV4Handle get(int index);
-
-public Q_SLOTS:
- void insert(QQmlV4Function *);
- void create(QQmlV4Function *);
- void resolve(QQmlV4Function *);
- void remove(QQmlV4Function *);
- void addGroups(QQmlV4Function *);
- void removeGroups(QQmlV4Function *);
- void setGroups(QQmlV4Function *);
- void move(QQmlV4Function *);
-
-Q_SIGNALS:
- void countChanged();
- void nameChanged();
- void defaultIncludeChanged();
- void changed(const QQmlV4Handle &removed, const QQmlV4Handle &inserted);
-private:
- Q_DECLARE_PRIVATE(QQmlDelegateModelGroup)
-};
-
-class QQmlDelegateModelItem;
-class QQmlDelegateModelAttachedMetaObject;
-class QQmlDelegateModelAttached : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QQmlDelegateModel *model READ model CONSTANT)
- Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged)
- Q_PROPERTY(bool isUnresolved READ isUnresolved NOTIFY unresolvedChanged)
-public:
- QQmlDelegateModelAttached(QObject *parent);
- QQmlDelegateModelAttached(QQmlDelegateModelItem *cacheItem, QObject *parent);
- ~QQmlDelegateModelAttached() {}
-
- void resetCurrentIndex();
- void setCacheItem(QQmlDelegateModelItem *item);
-
- QQmlDelegateModel *model() const;
-
- QStringList groups() const;
- void setGroups(const QStringList &groups);
-
- bool isUnresolved() const;
-
- void emitChanges();
-
- void emitUnresolvedChanged() { Q_EMIT unresolvedChanged(); }
-
-Q_SIGNALS:
- void groupsChanged();
- void unresolvedChanged();
-
-public:
- QQmlDelegateModelItem *m_cacheItem;
- int m_previousGroups;
- int m_currentIndex[QQmlListCompositor::MaximumGroupCount];
- int m_previousIndex[QQmlListCompositor::MaximumGroupCount];
-
- friend class QQmlDelegateModelAttachedMetaObject;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlDelegateModel)
-QML_DECLARE_TYPEINFO(QQmlDelegateModel, QML_HAS_ATTACHED_PROPERTIES)
-QML_DECLARE_TYPE(QQmlDelegateModelGroup)
-
-#endif // QQMLDATAMODEL_P_H
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
deleted file mode 100644
index 0028849828..0000000000
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLDATAMODEL_P_P_H
-#define QQMLDATAMODEL_P_P_H
-
-#include "qqmldelegatemodel_p.h"
-#include <private/qv4qobjectwrapper_p.h>
-
-#include <QtQml/qqmlcontext.h>
-#include <QtQml/qqmlincubator.h>
-
-#include <private/qqmladaptormodel_p.h>
-#include <private/qqmlopenmetaobject_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_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-typedef QQmlListCompositor Compositor;
-
-class QQmlDelegateModelAttachedMetaObject;
-class QQmlAbstractDelegateComponent;
-
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
-{
-public:
- QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
- ~QQmlDelegateModelItemMetaType();
-
- void initializeMetaObject();
- void initializePrototype();
-
- int parseGroups(const QStringList &groupNames) const;
- int parseGroups(const QV4::Value &groupNames) const;
-
- QPointer<QQmlDelegateModel> model;
- const int groupCount;
- QV4::ExecutionEngine * const v4Engine;
- QQmlDelegateModelAttachedMetaObject *metaObject;
- const QStringList groupNames;
- QV4::PersistentValue modelItemProto;
-};
-
-class QQmlAdaptorModel;
-class QQDMIncubationTask;
-
-class QQmlDelegateModelItem : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged)
- Q_PROPERTY(int row READ modelRow NOTIFY rowChanged REVISION 12)
- Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12)
- Q_PROPERTY(QObject *model READ modelObject CONSTANT)
-public:
- QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor, int modelIndex,
- int row, int column);
- ~QQmlDelegateModelItem();
-
- void referenceObject() { ++objectRef; }
- bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
- bool isObjectReferenced() const { return objectRef != 0 || (groups & Compositor::PersistedFlag); }
- void childContextObjectDestroyed(QObject *childContextObject);
-
- bool isReferenced() const {
- return scriptRef
- || incubationTask
- || ((groups & Compositor::UnresolvedFlag) && (groups & Compositor::GroupMask));
- }
-
- void Dispose();
-
- QObject *modelObject() { return this; }
-
- void destroyObject();
-
- static QQmlDelegateModelItem *dataForObject(QObject *object);
-
- int groupIndex(Compositor::Group group);
-
- int modelRow() const { return row; }
- int modelColumn() const { return column; }
- int modelIndex() const { return index; }
- virtual void setModelIndex(int idx, int newRow, int newColumn);
-
- virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(v4, this); }
-
- virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
- virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
-
- static QV4::ReturnedValue get_model(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue get_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue set_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
- static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
- static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
-
- QV4::ExecutionEngine *v4;
- QQmlDelegateModelItemMetaType * const metaType;
- QQmlContextDataRef contextData;
- QPointer<QObject> object;
- QPointer<QQmlDelegateModelAttached> attached;
- QQDMIncubationTask *incubationTask;
- QQmlComponent *delegate;
- int poolTime;
- int objectRef;
- int scriptRef;
- int groups;
- int index;
-
-Q_SIGNALS:
- void modelIndexChanged();
- Q_REVISION(12) void rowChanged();
- Q_REVISION(12) void columnChanged();
-
-protected:
- void objectDestroyed(QObject *);
- int row;
- int column;
-};
-
-namespace QV4 {
-namespace Heap {
-struct QQmlDelegateModelItemObject : Object {
- inline void init(QQmlDelegateModelItem *item);
- void destroy();
- QQmlDelegateModelItem *item;
-};
-
-}
-}
-
-struct QQmlDelegateModelItemObject : QV4::Object
-{
- V4_OBJECT2(QQmlDelegateModelItemObject, QV4::Object)
- V4_NEEDS_DESTROY
-};
-
-void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
-{
- Object::init();
- this->item = item;
-}
-
-
-
-class QQmlDelegateModelPrivate;
-class QQDMIncubationTask : public QQmlIncubator
-{
-public:
- QQDMIncubationTask(QQmlDelegateModelPrivate *l, IncubationMode mode)
- : QQmlIncubator(mode)
- , incubating(nullptr)
- , vdm(l) {}
-
- void statusChanged(Status) override;
- void setInitialState(QObject *) override;
-
- QQmlDelegateModelItem *incubating = nullptr;
- QQmlDelegateModelPrivate *vdm = nullptr;
- int index[QQmlListCompositor::MaximumGroupCount];
-};
-
-
-class QQmlDelegateModelGroupEmitter
-{
-public:
- virtual ~QQmlDelegateModelGroupEmitter() {}
- virtual void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) = 0;
- virtual void createdPackage(int, QQuickPackage *) {}
- virtual void initPackage(int, QQuickPackage *) {}
- virtual void destroyingPackage(QQuickPackage *) {}
-
- QIntrusiveListNode emitterNode;
-};
-
-typedef QIntrusiveList<QQmlDelegateModelGroupEmitter, &QQmlDelegateModelGroupEmitter::emitterNode> QQmlDelegateModelGroupEmitterList;
-
-class QQmlDelegateModelGroupPrivate : public QObjectPrivate
-{
-public:
- Q_DECLARE_PUBLIC(QQmlDelegateModelGroup)
-
- QQmlDelegateModelGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
-
- static QQmlDelegateModelGroupPrivate *get(QQmlDelegateModelGroup *group) {
- return static_cast<QQmlDelegateModelGroupPrivate *>(QObjectPrivate::get(group)); }
-
- void setModel(QQmlDelegateModel *model, Compositor::Group group);
- bool isChangedConnected();
- void emitChanges(QV4::ExecutionEngine *engine);
- void emitModelUpdated(bool reset);
-
- void createdPackage(int index, QQuickPackage *package);
- void initPackage(int index, QQuickPackage *package);
- void destroyingPackage(QQuickPackage *package);
-
- bool parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const;
- bool parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const;
-
- Compositor::Group group;
- QPointer<QQmlDelegateModel> model;
- QQmlDelegateModelGroupEmitterList emitters;
- QQmlChangeSet changeSet;
- QString name;
- bool defaultInclude;
-};
-
-class QQmlDelegateModelParts;
-
-class QQmlDelegateModelPrivate : public QObjectPrivate, public QQmlDelegateModelGroupEmitter
-{
- Q_DECLARE_PUBLIC(QQmlDelegateModel)
-public:
- QQmlDelegateModelPrivate(QQmlContext *);
- ~QQmlDelegateModelPrivate();
-
- static QQmlDelegateModelPrivate *get(QQmlDelegateModel *m) {
- return static_cast<QQmlDelegateModelPrivate *>(QObjectPrivate::get(m));
- }
-
- void init();
- void connectModel(QQmlAdaptorModel *model);
- void connectToAbstractItemModel();
- void disconnectFromAbstractItemModel();
-
- void requestMoreIfNecessary();
- QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
- QQmlDelegateModel::ReleaseFlags release(QObject *object);
- QString stringValue(Compositor::Group group, int index, const QString &name);
- void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
- void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
- void emitCreatedItem(QQDMIncubationTask *incubationTask, QObject *item) {
- Q_EMIT q_func()->createdItem(incubationTask->index[m_compositorGroup], item); }
- void emitInitItem(QQDMIncubationTask *incubationTask, QObject *item) {
- Q_EMIT q_func()->initItem(incubationTask->index[m_compositorGroup], item); }
- void emitDestroyingPackage(QQuickPackage *package);
- void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(item); }
- void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it);
- void removeCacheItem(QQmlDelegateModelItem *cacheItem);
-
- void updateFilterGroup();
-
- void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
- void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
- void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
-
- void itemsInserted(
- const QVector<Compositor::Insert> &inserts,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
- void itemsInserted(const QVector<Compositor::Insert> &inserts);
- void itemsRemoved(
- const QVector<Compositor::Remove> &removes,
- QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
- QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
- void itemsRemoved(const QVector<Compositor::Remove> &removes);
- void itemsMoved(
- const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts);
- void itemsChanged(const QVector<Compositor::Change> &changes);
- void emitChanges();
- void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
- void delegateChanged(bool add = true, bool remove = true);
-
- bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
-
- int adaptorModelCount() const;
-
- static void group_append(QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group);
- static int group_count(QQmlListProperty<QQmlDelegateModelGroup> *property);
- static QQmlDelegateModelGroup *group_at(QQmlListProperty<QQmlDelegateModelGroup> *property, int index);
-
- void releaseIncubator(QQDMIncubationTask *incubationTask);
- void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status);
- void setInitialState(QQDMIncubationTask *incubationTask, QObject *o);
-
- QQmlAdaptorModel m_adaptorModel;
- QQmlListCompositor m_compositor;
- QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
- QQmlAbstractDelegateComponent *m_delegateChooser;
- QMetaObject::Connection m_delegateChooserChanged;
- QQmlDelegateModelItemMetaType *m_cacheMetaType;
- QPointer<QQmlContext> m_context;
- QQmlDelegateModelParts *m_parts;
- QQmlDelegateModelGroupEmitterList m_pendingParts;
-
- QList<QQmlDelegateModelItem *> m_cache;
- QList<QQDMIncubationTask *> m_finishedIncubating;
- QList<QByteArray> m_watchedRoles;
-
- QString m_filterGroup;
-
- int m_count;
- int m_groupCount;
-
- QQmlListCompositor::Group m_compositorGroup;
- bool m_complete : 1;
- bool m_delegateValidated : 1;
- bool m_reset : 1;
- bool m_transaction : 1;
- bool m_incubatorCleanupScheduled : 1;
- bool m_waitingToFetchMore : 1;
-
- union {
- struct {
- QQmlDelegateModelGroup *m_cacheItems;
- QQmlDelegateModelGroup *m_items;
- QQmlDelegateModelGroup *m_persistedItems;
- };
- QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
- };
-};
-
-class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
-{
- Q_OBJECT
- Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
-public:
- QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent = nullptr);
- ~QQmlPartsModel();
-
- QString filterGroup() const;
- void setFilterGroup(const QString &group);
- void resetFilterGroup();
- void updateFilterGroup();
- void updateFilterGroup(Compositor::Group group, const QQmlChangeSet &changeSet);
-
- int count() const override;
- bool isValid() const override;
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *item) override;
- QString stringValue(int index, const QString &role) override;
- QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
- void setWatchedRoles(const QList<QByteArray> &roles) override;
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *item, QObject *objectContext) const override;
-
- void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
-
- void createdPackage(int index, QQuickPackage *package) override;
- void initPackage(int index, QQuickPackage *package) override;
- void destroyingPackage(QQuickPackage *package) override;
-
-Q_SIGNALS:
- void filterGroupChanged();
-
-private:
- QQmlDelegateModel *m_model;
- QHash<QObject *, QQuickPackage *> m_packaged;
- QString m_part;
- QString m_filterGroup;
- QList<QByteArray> m_watchedRoles;
- QVector<int> m_pendingPackageInitializations; // vector holds model indices
- Compositor::Group m_compositorGroup;
- bool m_inheritGroup;
- bool m_modelUpdatePending = true;
-};
-
-class QMetaPropertyBuilder;
-
-class QQmlDelegateModelPartsMetaObject : public QQmlOpenMetaObject
-{
-public:
- QQmlDelegateModelPartsMetaObject(QObject *parent)
- : QQmlOpenMetaObject(parent) {}
-
- void propertyCreated(int, QMetaPropertyBuilder &) override;
- QVariant initialValue(int) override;
-};
-
-class QQmlDelegateModelParts : public QObject
-{
-Q_OBJECT
-public:
- QQmlDelegateModelParts(QQmlDelegateModel *parent);
-
- QQmlDelegateModel *model;
- QList<QQmlPartsModel *> models;
-};
-
-class QQmlDelegateModelAttachedMetaObject : public QAbstractDynamicMetaObject, public QQmlRefCount
-{
-public:
- QQmlDelegateModelAttachedMetaObject(
- QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject);
- ~QQmlDelegateModelAttachedMetaObject();
-
- void objectDestroyed(QObject *) override;
- int metaCall(QObject *, QMetaObject::Call, int _id, void **) override;
-
-private:
- QQmlDelegateModelItemMetaType * const metaType;
- QMetaObject * const metaObject;
- const int memberPropertyOffset;
- const int indexPropertyOffset;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
deleted file mode 100644
index a23ec0f2b4..0000000000
--- a/src/qml/types/qqmlinstantiator.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlinstantiator_p.h"
-#include "qqmlinstantiator_p_p.h"
-#include <QtQml/QQmlContext>
-#include <QtQml/QQmlComponent>
-#include <QtQml/QQmlInfo>
-#include <QtQml/QQmlError>
-#include <QtQml/private/qqmlobjectmodel_p.h>
-#if QT_CONFIG(qml_delegate_model)
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-QQmlInstantiatorPrivate::QQmlInstantiatorPrivate()
- : componentComplete(true)
- , effectiveReset(false)
- , active(true)
- , async(false)
-#if QT_CONFIG(qml_delegate_model)
- , ownModel(false)
-#endif
- , requestedIndex(-1)
- , model(QVariant(1))
- , instanceModel(nullptr)
- , delegate(nullptr)
-{
-}
-
-QQmlInstantiatorPrivate::~QQmlInstantiatorPrivate()
-{
- qDeleteAll(objects);
-}
-
-void QQmlInstantiatorPrivate::clear()
-{
- Q_Q(QQmlInstantiator);
- if (!instanceModel)
- return;
- if (!objects.count())
- return;
-
- for (int i=0; i < objects.count(); i++) {
- q->objectRemoved(i, objects[i]);
- instanceModel->release(objects[i]);
- }
- objects.clear();
- q->objectChanged();
-}
-
-QObject *QQmlInstantiatorPrivate::modelObject(int index, bool async)
-{
- requestedIndex = index;
- QObject *o = instanceModel->object(index, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
- requestedIndex = -1;
- return o;
-}
-
-
-void QQmlInstantiatorPrivate::regenerate()
-{
- Q_Q(QQmlInstantiator);
- if (!componentComplete)
- return;
-
- int prevCount = q->count();
-
- clear();
-
- if (!active || !instanceModel || !instanceModel->count() || !instanceModel->isValid()) {
- if (prevCount)
- q->countChanged();
- return;
- }
-
- for (int i = 0; i < instanceModel->count(); i++) {
- QObject *object = modelObject(i, async);
- // If the item was already created we won't get a createdItem
- if (object)
- _q_createdItem(i, object);
- }
- if (q->count() != prevCount)
- q->countChanged();
-}
-
-void QQmlInstantiatorPrivate::_q_createdItem(int idx, QObject* item)
-{
- Q_Q(QQmlInstantiator);
- if (objects.contains(item)) //Case when it was created synchronously in regenerate
- return;
- if (requestedIndex != idx) // Asynchronous creation, reference the object
- (void)instanceModel->object(idx);
- item->setParent(q);
- if (objects.size() < idx + 1) {
- int modelCount = instanceModel->count();
- if (objects.capacity() < modelCount)
- objects.reserve(modelCount);
- objects.resize(idx + 1);
- }
- if (QObject *o = objects.at(idx))
- instanceModel->release(o);
- objects.replace(idx, item);
- if (objects.count() == 1)
- q->objectChanged();
- q->objectAdded(idx, item);
-}
-
-void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bool reset)
-{
- Q_Q(QQmlInstantiator);
-
- if (!componentComplete || effectiveReset)
- return;
-
- if (reset) {
- regenerate();
- if (changeSet.difference() != 0)
- q->countChanged();
- return;
- }
-
- int difference = 0;
- QHash<int, QVector<QPointer<QObject> > > moved;
- const QVector<QQmlChangeSet::Change> &removes = changeSet.removes();
- for (const QQmlChangeSet::Change &remove : removes) {
- int index = qMin(remove.index, objects.count());
- int count = qMin(remove.index + remove.count, objects.count()) - index;
- if (remove.isMove()) {
- moved.insert(remove.moveId, objects.mid(index, count));
- objects.erase(
- objects.begin() + index,
- objects.begin() + index + count);
- } else while (count--) {
- QObject *obj = objects.at(index);
- objects.remove(index);
- q->objectRemoved(index, obj);
- if (obj)
- instanceModel->release(obj);
- }
-
- difference -= remove.count;
- }
-
- const QVector<QQmlChangeSet::Change> &inserts = changeSet.inserts();
- for (const QQmlChangeSet::Change &insert : inserts) {
- int index = qMin(insert.index, objects.count());
- if (insert.isMove()) {
- QVector<QPointer<QObject> > movedObjects = moved.value(insert.moveId);
- objects = objects.mid(0, index) + movedObjects + objects.mid(index);
- } else {
- if (insert.index <= objects.size())
- objects.insert(insert.index, insert.count, nullptr);
- for (int i = 0; i < insert.count; ++i) {
- int modelIndex = index + i;
- QObject* obj = modelObject(modelIndex, async);
- if (obj)
- _q_createdItem(modelIndex, obj);
- }
- }
- difference += insert.count;
- }
-
- if (difference != 0)
- q->countChanged();
-}
-
-#if QT_CONFIG(qml_delegate_model)
-void QQmlInstantiatorPrivate::makeModel()
-{
- Q_Q(QQmlInstantiator);
- QQmlDelegateModel* delegateModel = new QQmlDelegateModel(qmlContext(q), q);
- instanceModel = delegateModel;
- ownModel = true;
- delegateModel->setDelegate(delegate);
- delegateModel->classBegin(); //Pretend it was made in QML
- if (componentComplete)
- delegateModel->componentComplete();
-}
-#endif
-
-
-/*!
- \qmltype Instantiator
- \instantiates QQmlInstantiator
- \inqmlmodule QtQml
- \brief Dynamically creates objects.
-
- A Instantiator can be used to control the dynamic creation of objects, or to dynamically
- create multiple objects from a template.
-
- The Instantiator element will manage the objects it creates. Those objects are parented to the
- Instantiator and can also be deleted by the Instantiator if the Instantiator's properties change. Objects
- can also be destroyed dynamically through other means, and the Instantiator will not recreate
- them unless the properties of the Instantiator change.
-
-*/
-QQmlInstantiator::QQmlInstantiator(QObject *parent)
- : QObject(*(new QQmlInstantiatorPrivate), parent)
-{
-}
-
-QQmlInstantiator::~QQmlInstantiator()
-{
-}
-
-/*!
- \qmlsignal QtQml::Instantiator::objectAdded(int index, QtObject object)
-
- This signal is emitted when an object is added to the Instantiator. The \a index
- parameter holds the index which the object has been given, and the \a object
- parameter holds the \l QtObject that has been added.
-
- The corresponding handler is \c onObjectAdded.
-*/
-
-/*!
- \qmlsignal QtQml::Instantiator::objectRemoved(int index, QtObject object)
-
- This signal is emitted when an object is removed from the Instantiator. The \a index
- parameter holds the index which the object had been given, and the \a object
- parameter holds the \l QtObject that has been removed.
-
- Do not keep a reference to \a object if it was created by this Instantiator, as
- in these cases it will be deleted shortly after the signal is handled.
-
- The corresponding handler is \c onObjectRemoved.
-*/
-/*!
- \qmlproperty bool QtQml::Instantiator::active
-
- When active is true, and the delegate component is ready, the Instantiator will
- create objects according to the model. When active is false, no objects
- will be created and any previously created objects will be destroyed.
-
- Default is true.
-*/
-bool QQmlInstantiator::isActive() const
-{
- Q_D(const QQmlInstantiator);
- return d->active;
-}
-
-void QQmlInstantiator::setActive(bool newVal)
-{
- Q_D(QQmlInstantiator);
- if (newVal == d->active)
- return;
- d->active = newVal;
- emit activeChanged();
- d->regenerate();
-}
-
-/*!
- \qmlproperty bool QtQml::Instantiator::asynchronous
-
- When asynchronous is true the Instantiator will attempt to create objects
- asynchronously. This means that objects may not be available immediately,
- even if active is set to true.
-
- You can use the objectAdded signal to respond to items being created.
-
- Default is false.
-*/
-bool QQmlInstantiator::isAsync() const
-{
- Q_D(const QQmlInstantiator);
- return d->async;
-}
-
-void QQmlInstantiator::setAsync(bool newVal)
-{
- Q_D(QQmlInstantiator);
- if (newVal == d->async)
- return;
- d->async = newVal;
- emit asynchronousChanged();
-}
-
-
-/*!
- \qmlproperty int QtQml::Instantiator::count
-
- The number of objects the Instantiator is currently managing.
-*/
-
-int QQmlInstantiator::count() const
-{
- Q_D(const QQmlInstantiator);
- return d->objects.count();
-}
-
-/*!
- \qmlproperty QtQml::Component QtQml::Instantiator::delegate
- \default
-
- The component used to create all objects.
-
- Note that an extra variable, index, will be available inside instances of the
- delegate. This variable refers to the index of the instance inside the Instantiator,
- and can be used to obtain the object through the objectAt method of the Instantiator.
-
- If this property is changed, all instances using the old delegate will be destroyed
- and new instances will be created using the new delegate.
-*/
-QQmlComponent* QQmlInstantiator::delegate()
-{
- Q_D(QQmlInstantiator);
- return d->delegate;
-}
-
-void QQmlInstantiator::setDelegate(QQmlComponent* c)
-{
- Q_D(QQmlInstantiator);
- if (c == d->delegate)
- return;
-
- d->delegate = c;
- emit delegateChanged();
-
-#if QT_CONFIG(qml_delegate_model)
- if (!d->ownModel)
- return;
-
- if (QQmlDelegateModel *dModel = qobject_cast<QQmlDelegateModel*>(d->instanceModel))
- dModel->setDelegate(c);
- if (d->componentComplete)
- d->regenerate();
-#endif
-}
-
-/*!
- \qmlproperty variant QtQml::Instantiator::model
-
- This property can be set to any of the supported \l {qml-data-models}{data models}:
-
- \list
- \li A number that indicates the number of delegates to be created by the repeater
- \li A model (e.g. a ListModel item, or a QAbstractItemModel subclass)
- \li A string list
- \li An object list
- \endlist
-
- The type of model affects the properties that are exposed to the \l delegate.
-
- Default value is 1, which creates a single delegate instance.
-
- \sa {qml-data-models}{Data Models}
-*/
-
-QVariant QQmlInstantiator::model() const
-{
- Q_D(const QQmlInstantiator);
- return d->model;
-}
-
-void QQmlInstantiator::setModel(const QVariant &v)
-{
- Q_D(QQmlInstantiator);
- if (d->model == v)
- return;
-
- d->model = v;
- //Don't actually set model until componentComplete in case it wants to create its delegates immediately
- if (!d->componentComplete)
- return;
-
- QQmlInstanceModel *prevModel = d->instanceModel;
- QObject *object = qvariant_cast<QObject*>(v);
- QQmlInstanceModel *vim = nullptr;
- if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
-#if QT_CONFIG(qml_delegate_model)
- if (d->ownModel) {
- delete d->instanceModel;
- prevModel = nullptr;
- d->ownModel = false;
- }
-#endif
- d->instanceModel = vim;
-#if QT_CONFIG(qml_delegate_model)
- } else if (v != QVariant(0)){
- if (!d->ownModel)
- d->makeModel();
-
- if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel *>(d->instanceModel)) {
- d->effectiveReset = true;
- dataModel->setModel(v);
- d->effectiveReset = false;
- }
-#endif
- }
-
- if (d->instanceModel != prevModel) {
- if (prevModel) {
- disconnect(prevModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- disconnect(prevModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //disconnect(prevModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
- }
-
- if (d->instanceModel) {
- connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
- }
- }
-
- d->regenerate();
- emit modelChanged();
-}
-
-/*!
- \qmlproperty QtObject QtQml::Instantiator::object
-
- This is a reference to the first created object, intended as a convenience
- for the case where only one object has been created.
-*/
-QObject *QQmlInstantiator::object() const
-{
- Q_D(const QQmlInstantiator);
- if (d->objects.count())
- return d->objects[0];
- return nullptr;
-}
-
-/*!
- \qmlmethod QtObject QtQml::Instantiator::objectAt(int index)
-
- Returns a reference to the object with the given \a index.
-*/
-QObject *QQmlInstantiator::objectAt(int index) const
-{
- Q_D(const QQmlInstantiator);
- if (index >= 0 && index < d->objects.count())
- return d->objects[index];
- return nullptr;
-}
-
-/*!
- \internal
-*/
-void QQmlInstantiator::classBegin()
-{
- Q_D(QQmlInstantiator);
- d->componentComplete = false;
-}
-
-/*!
- \internal
-*/
-void QQmlInstantiator::componentComplete()
-{
- Q_D(QQmlInstantiator);
- d->componentComplete = true;
-#if QT_CONFIG(qml_delegate_model)
- if (d->ownModel) {
- static_cast<QQmlDelegateModel*>(d->instanceModel)->componentComplete();
- d->regenerate();
- } else
-#endif
- {
- QVariant realModel = d->model;
- d->model = QVariant(0);
- setModel(realModel); //If realModel == d->model this won't do anything, but that's fine since the model's 0
- //setModel calls regenerate
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlinstantiator_p.cpp"
diff --git a/src/qml/types/qqmlinstantiator_p.h b/src/qml/types/qqmlinstantiator_p.h
deleted file mode 100644
index ca371adc23..0000000000
--- a/src/qml/types/qqmlinstantiator_p.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANTIATOR_P_H
-#define QQMLINSTANTIATOR_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 <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlInstantiatorPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
- Q_PROPERTY(bool asynchronous READ isAsync WRITE setAsync NOTIFY asynchronousChanged)
- Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
- Q_PROPERTY(QObject *object READ object NOTIFY objectChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
-
-public:
- QQmlInstantiator(QObject *parent = nullptr);
- ~QQmlInstantiator();
-
- bool isActive() const;
- void setActive(bool newVal);
-
- bool isAsync() const;
- void setAsync(bool newVal);
-
- int count() const;
-
- QQmlComponent* delegate();
- void setDelegate(QQmlComponent* c);
-
- QVariant model() const;
- void setModel(const QVariant &v);
-
- QObject *object() const;
-
- Q_INVOKABLE QObject *objectAt(int index) const;
-
- void classBegin() override;
- void componentComplete() override;
-
-Q_SIGNALS:
- void modelChanged();
- void delegateChanged();
- void countChanged();
- void objectChanged();
- void activeChanged();
- void asynchronousChanged();
-
- void objectAdded(int index, QObject* object);
- void objectRemoved(int index, QObject* object);
-
-private:
- Q_DISABLE_COPY(QQmlInstantiator)
- Q_DECLARE_PRIVATE(QQmlInstantiator)
- Q_PRIVATE_SLOT(d_func(), void _q_createdItem(int, QObject *))
- Q_PRIVATE_SLOT(d_func(), void _q_modelUpdated(const QQmlChangeSet &, bool))
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCREATOR_P_H
diff --git a/src/qml/types/qqmlinstantiator_p_p.h b/src/qml/types/qqmlinstantiator_p_p.h
deleted file mode 100644
index 4c76d5c689..0000000000
--- a/src/qml/types/qqmlinstantiator_p_p.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANTIATOR_P_P_H
-#define QQMLINSTANTIATOR_P_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 "qqmlinstantiator_p.h"
-#include <QObject>
-#include <private/qobject_p.h>
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlobjectmodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_PRIVATE_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QQmlInstantiator)
-
-public:
- QQmlInstantiatorPrivate();
- ~QQmlInstantiatorPrivate();
-
- void clear();
- void regenerate();
-#if QT_CONFIG(qml_delegate_model)
- void makeModel();
-#endif
- void _q_createdItem(int, QObject *);
- void _q_modelUpdated(const QQmlChangeSet &, bool);
- QObject *modelObject(int index, bool async);
-
- static QQmlInstantiatorPrivate *get(QQmlInstantiator *instantiator) { return instantiator->d_func(); }
- static const QQmlInstantiatorPrivate *get(const QQmlInstantiator *instantiator) { return instantiator->d_func(); }
-
- bool componentComplete:1;
- bool effectiveReset:1;
- bool active:1;
- bool async:1;
-#if QT_CONFIG(qml_delegate_model)
- bool ownModel:1;
-#endif
- int requestedIndex;
- QVariant model;
- QQmlInstanceModel *instanceModel;
- QQmlComponent *delegate;
- QVector<QPointer<QObject> > objects;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCREATOR_P_P_H
diff --git a/src/qml/types/qqmlitemmodels.qdoc b/src/qml/types/qqmlitemmodels.qdoc
deleted file mode 100644
index f6e1b0b1b9..0000000000
--- a/src/qml/types/qqmlitemmodels.qdoc
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU 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: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \page qmodelindex-and-related-classes-in-qml.html
- \title QModelIndex and related Classes in QML
-
- Since Qt 5.5, QModelIndex and QPersistentModelIndex are exposed in QML as
- value-based types. Also exposed in a similar fashion are QModelIndexList,
- QItemSelectionRange and QItemSelection. All objects from these types can
- be passed back and forth between QML and C++ as \c var properties or plain
- JavaScript variables.
-
- Below you will find an overview of the API exposed to QML for these classes.
- For more information, refer to their C++ documentation.
-
- \note Since all these types are exposed as \l{Q_GADGET}{gadgets}, there are no property
- change notification signals emitted. Therefore binding to their properties
- may not give the expected results. This is especially true for QPersistentModelIndex.
-
- \section1 QModelIndex and QPersistentModelIndex Types
-
- \list
- \li \b row : int
- \li \b column : int
- \li \b parent : QModelIndex
- \li \b valid : bool
- \li \b model : QAbstractItemModel
- \li \b internalId : quint64
- \endlist
-
- All these properties are read-only, as are their C++ counterparts.
-
- \note The usual caveats apply to QModelIndex in QML. If the underlying model changes
- or gets deleted, it may become dangerous to access its properties. Therefore, you
- should not store any QModelIndex objects. You can, however, store QPersistentModelIndexe
- objects in a safe way.
-
- \section1 QModelIndexList Type
-
- \l QModelIndexList is exposed in QML as a JavaScript array. Conversions are
- automatically made from and to C++. In fact, any JavaScript array can be
- converted back to QModelIndexList, with non-QModelIndex objects replaced by
- invalid \l{QModelIndex}es.
-
- \note QModelIndex to QPersistentModelIndex conversion happens when accessing
- the array elements because any QModelIndexList property retains reference
- semantics when exposed this way.
-
- \section1 \l QItemSelectionRange Type
-
- \list
- \li \b top : int
- \li \b left : int
- \li \b bottom : int
- \li \b right : int
- \li \b width : int
- \li \b height : int
- \li \b topLeft : QPersistentModelIndex
- \li \b bottomRight : QPersistentModelIndex
- \li \b parent : QModelIndex
- \li \b valid : bool
- \li \b empty : bool
- \li \b model : QAbstractItemModel
- \endlist
-
- All these properties are read-only, as are their C++ counterparts. In addition,
- we also expose the following functions:
-
- \list
- \li bool \b{contains}(QModelIndex \e index)
- \li bool \b{contains}(int \e row, int \e column, QModelIndex \e parentIndex)
- \li bool \b{intersects}(QItemSelectionRange \e other)
- \li QItemSelectionRange \b{intersected}(QItemSelectionRange \e other)
- \endlist
-
- \section1 QItemSelection Type
-
- Similarly to QModelIndexList, \l QItemSelection is exposed in QML as a JavaScript
- array of QItemSelectionRange objects. Conversions are automatically made from and to C++.
- In fact, any JavaScript array can be converted back to QItemSelection, with
- non-QItemSelectionRange objects replaced by empty \l {QItemSelectionRange}s.
-
-
- \sa ItemSelectionModel
-*/
diff --git a/src/qml/types/qqmlitemselectionmodel.qdoc b/src/qml/types/qqmlitemselectionmodel.qdoc
deleted file mode 100644
index 43da4f7a55..0000000000
--- a/src/qml/types/qqmlitemselectionmodel.qdoc
+++ /dev/null
@@ -1,239 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU 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: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \qmltype ItemSelectionModel
- \instantiates QItemSelectionModel
- \inqmlmodule QtQml.Models
- \since 5.5
- \ingroup qtquick-models
-
- \brief Instantiates a QItemSelectionModel to be used in conjunction
- with a QAbstractItemModel and any view supporting it.
-
- \sa QItemSelectionModel, {Models and Views in Qt Quick}
-*/
-
-
-/*!
- \qmlproperty QAbstractItemModel ItemSelectionModel::model
-
- This property's value must match the view's model.
-*/
-
-/*!
- \qmlproperty bool ItemSelectionModel::hasSelection
- \readonly
-
- It will trigger property binding updates every time \l selectionChanged()
- is emitted, even though its value hasn't changed.
-
- \sa selection, selectedIndexes, select(), selectionChanged()
-*/
-
-/*!
- \qmlproperty QModelIndex ItemSelectionModel::currentIndex
- \readonly
-
- Use \l setCurrentIndex() to set its value.
-
- \sa setCurrentIndex(), currentChanged()
-*/
-
-/*!
- \qmlproperty QModelIndexList ItemSelectionModel::selectedIndexes
- \readonly
-
- Contains the list of all the indexes in the selection model.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isSelected(QModelIndex index)
-
- Returns \c true if the given model item \a index is selected.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isRowSelected(int row, QModelIndex parent)
-
- Returns \c true if all items are selected in the \a row with the given
- \a parent.
-
- Note that this function is usually faster than calling isSelected()
- on all items in the same row, and that unselectable items are ignored.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::isColumnSelected(int column, QModelIndex parent)
-
- Returns \c true if all items are selected in the \a column with the given
- \a parent.
-
- Note that this function is usually faster than calling isSelected()
- on all items in the same column, and that unselectable items are ignored.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::rowIntersectsSelection(int row, QModelIndex parent)
-
- Returns \c true if there are any items selected in the \a row with the
- given \a parent.
-*/
-
-/*!
- \qmlmethod bool ItemSelectionModel::columnIntersectsSelection(int column, QModelIndex parent)
-
- Returns \c true if there are any items selected in the \a column with the
- given \a parent.
-*/
-
-/*!
- \qmlmethod QModelIndexList ItemSelectionModel::selectedRows(int column)
-
- Returns the indexes in the given \a column for the rows where all columns
- are selected.
-
- \sa selectedColumns()
-*/
-
-/*!
- \qmlmethod QModelIndexList ItemSelectionModel::selectedColumns(int row)
-
- Returns the indexes in the given \a row for columns where all rows are
- selected.
-
- \sa selectedRows()
-*/
-
-/*!
- \qmlproperty object ItemSelectionModel::selection
- \readonly
-
- Holds the selection ranges stored in the selection model.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::setCurrentIndex(QModelIndex index, SelectionFlags command)
-
- Sets the model item \a index to be the current item, and emits
- currentChanged(). The current item is used for keyboard navigation and
- focus indication; it is independent of any selected items, although a
- selected item can also be the current item.
-
- Depending on the specified \a command, the \a index can also become part
- of the current selection.
-
- Valid \a command values are described in \l {itemselectionmodelselectindex}
- {select(\e index, \e command)}.
-
- \sa select()
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::select(QModelIndex index, SelectionFlags command)
- \keyword itemselectionmodelselectindex
-
- Selects the model item \a index using the specified \a command, and emits
- selectionChanged().
-
- Valid values for the \a command parameter, are:
-
- \value NoUpdate No selection will be made.
- \value Clear The complete selection will be cleared.
- \value Select All specified indexes will be selected.
- \value Deselect All specified indexes will be deselected.
- \value Toggle All specified indexes will be selected or
- deselected depending on their current state.
- \value Current The current selection will be updated.
- \value Rows All indexes will be expanded to span rows.
- \value Columns All indexes will be expanded to span columns.
- \value SelectCurrent A combination of Select and Current, provided for
- convenience.
- \value ToggleCurrent A combination of Toggle and Current, provided for
- convenience.
- \value ClearAndSelect A combination of Clear and Select, provided for
- convenience.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::select(QItemSelection selection, SelectionFlags command)
-
- Selects the item \a selection using the specified \a command, and emits
- selectionChanged().
-
- Valid \a command values are described in \l {itemselectionmodelselectindex}
- {select(\e index, \e command)}.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clear()
-
- Clears the selection model. Emits selectionChanged() and currentChanged().
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::reset()
-
- Clears the selection model. Does not emit any signals.
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clearSelection()
-
- Clears the selection in the selection model. Emits selectionChanged().
-*/
-
-/*!
- \qmlmethod void ItemSelectionModel::clearCurrentIndex()
-
- Clears the current index. Emits currentChanged().
-*/
-
-/*!
- \qmlsignal ItemSelectionModel::selectionChanged(QItemSelection selected, QItemSelection deselected)
-
- This signal is emitted whenever the selection changes. The change in the
- selection is represented as an item selection of \a deselected items and
- an item selection of \a selected items.
-
- Note the that the current index changes independently from the selection.
- Also note that this signal will not be emitted when the item model is reset.
-
- \sa select(), currentChanged()
-*/
-
-/*!
- \qmlsignal ItemSelectionModel::currentChanged(QModelIndex current, QModelIndex previous)
-
- This signal is emitted whenever the current item changes. The \a previous
- model item index is replaced by the \a current index as the selection's
- current item.
-
- Note that this signal will not be emitted when the item model is reset.
-
- \sa currentIndex, setCurrentIndex(), selectionChanged()
-*/
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
deleted file mode 100644
index 565e60b3c1..0000000000
--- a/src/qml/types/qqmllistmodel.cpp
+++ /dev/null
@@ -1,2900 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistmodel_p_p.h"
-#include "qqmllistmodelworkeragent_p.h"
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmljsengine_p.h>
-#include <private/qjsvalue_p.h>
-
-#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlnotifier_p.h>
-
-#include <private/qv4object_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4alloca_p.h>
-#include <private/qv4lookup_p.h>
-
-#include <qqmlcontext.h>
-#include <qqmlinfo.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qstack.h>
-#include <QXmlStreamReader>
-#include <QtCore/qdatetime.h>
-#include <QScopedValueRollback>
-
-Q_DECLARE_METATYPE(const QV4::CompiledData::Binding*);
-
-QT_BEGIN_NAMESPACE
-
-// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models.
-enum { MIN_LISTMODEL_UID = 1024 };
-
-static QAtomicInt uidCounter(MIN_LISTMODEL_UID);
-
-template <typename T>
-static bool isMemoryUsed(const char *mem)
-{
- for (size_t i=0 ; i < sizeof(T) ; ++i) {
- if (mem[i] != 0)
- return true;
- }
-
- return false;
-}
-
-static QString roleTypeName(ListLayout::Role::DataType t)
-{
- static const QString roleTypeNames[] = {
- QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"),
- QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"),
- QStringLiteral("DateTime"), QStringLiteral("Function")
- };
-
- if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType)
- return roleTypeNames[t];
-
- return QString();
-}
-
-const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type)
-{
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node) {
- const Role &r = *node->value;
- if (type != r.type)
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
- return r;
- }
-
- return createRole(key, type);
-}
-
-const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::DataType type)
-{
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node) {
- const Role &r = *node->value;
- if (type != r.type)
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type));
- return r;
- }
-
- QString qkey = key->toQString();
-
- return createRole(qkey, type);
-}
-
-const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
-{
- const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
- const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
-
- Role *r = new Role;
- r->name = key;
- r->type = type;
-
- if (type == Role::List) {
- r->subLayout = new ListLayout;
- } else {
- r->subLayout = nullptr;
- }
-
- int dataSize = dataSizes[type];
- int dataAlignment = dataAlignments[type];
-
- int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1);
- if (dataOffset + dataSize > ListElement::BLOCK_SIZE) {
- r->blockIndex = ++currentBlock;
- r->blockOffset = 0;
- currentBlockOffset = dataSize;
- } else {
- r->blockIndex = currentBlock;
- r->blockOffset = dataOffset;
- currentBlockOffset = dataOffset + dataSize;
- }
-
- int roleIndex = roles.count();
- r->index = roleIndex;
-
- roles.append(r);
- roleHash.insert(key, r);
-
- return *r;
-}
-
-ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0)
-{
- const int otherRolesCount = other->roles.count();
- roles.reserve(otherRolesCount);
- for (int i=0 ; i < otherRolesCount; ++i) {
- Role *role = new Role(other->roles[i]);
- roles.append(role);
- roleHash.insert(role->name, role);
- }
- currentBlockOffset = other->currentBlockOffset;
- currentBlock = other->currentBlock;
-}
-
-ListLayout::~ListLayout()
-{
- qDeleteAll(roles);
-}
-
-void ListLayout::sync(ListLayout *src, ListLayout *target)
-{
- int roleOffset = target->roles.count();
- int newRoleCount = src->roles.count() - roleOffset;
-
- for (int i=0 ; i < newRoleCount ; ++i) {
- Role *role = new Role(src->roles[roleOffset + i]);
- target->roles.append(role);
- target->roleHash.insert(role->name, role);
- }
-
- target->currentBlockOffset = src->currentBlockOffset;
- target->currentBlock = src->currentBlock;
-}
-
-ListLayout::Role::Role(const Role *other)
-{
- name = other->name;
- type = other->type;
- blockIndex = other->blockIndex;
- blockOffset = other->blockOffset;
- index = other->index;
- if (other->subLayout)
- subLayout = new ListLayout(other->subLayout);
- else
- subLayout = nullptr;
-}
-
-ListLayout::Role::~Role()
-{
- delete subLayout;
-}
-
-const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data)
-{
- Role::DataType type;
-
- switch (data.type()) {
- case QVariant::Double: type = Role::Number; break;
- case QVariant::Int: type = Role::Number; break;
- case QVariant::Bool: type = Role::Bool; break;
- case QVariant::String: type = Role::String; break;
- case QVariant::Map: type = Role::VariantMap; break;
- case QVariant::DateTime: type = Role::DateTime; break;
- case QVariant::UserType: {
- if (data.userType() == qMetaTypeId<QJSValue>() &&
- data.value<QJSValue>().isCallable()) {
- type = Role::Function;
- break;
- } else if (data.userType() == qMetaTypeId<const QV4::CompiledData::Binding*>()
- && data.value<const QV4::CompiledData::Binding*>()->isTranslationBinding()) {
- type = Role::String;
- break;
- } else {
- type = Role::List;
- break;
- }
- }
- default: type = Role::Invalid; break;
- }
-
- if (type == Role::Invalid) {
- qmlWarning(nullptr) << "Can't create role for unsupported data type";
- return nullptr;
- }
-
- return &getRoleOrCreate(key, type);
-}
-
-const ListLayout::Role *ListLayout::getExistingRole(const QString &key) const
-{
- Role *r = nullptr;
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node)
- r = node->value;
- return r;
-}
-
-const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) const
-{
- Role *r = nullptr;
- QStringHash<Role *>::Node *node = roleHash.findNode(key);
- if (node)
- r = node->value;
- return r;
-}
-
-StringOrTranslation::StringOrTranslation(const QString &s)
-{
- d.setFlag();
- setString(s);
-}
-
-StringOrTranslation::StringOrTranslation(const QV4::CompiledData::Binding *binding)
-{
- d.setFlag();
- clear();
- d = binding;
-}
-
-StringOrTranslation::~StringOrTranslation()
-{
- clear();
-}
-
-void StringOrTranslation::setString(const QString &s)
-{
- d.setFlag();
- clear();
- QStringData *stringData = const_cast<QString &>(s).data_ptr();
- d = stringData;
- if (stringData)
- stringData->ref.ref();
-}
-
-void StringOrTranslation::setTranslation(const QV4::CompiledData::Binding *binding)
-{
- d.setFlag();
- clear();
- d = binding;
-}
-
-QString StringOrTranslation::toString(const QQmlListModel *owner) const
-{
- if (d.isNull())
- return QString();
- if (d.isT1()) {
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
- }
- if (!owner)
- return QString();
- return d.asT2()->valueAsString(owner->m_compilationUnit.data());
-}
-
-QString StringOrTranslation::asString() const
-{
- if (d.isNull())
- return QString();
- if (!d.isT1())
- return QString();
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
-}
-
-void StringOrTranslation::clear()
-{
- if (QStringData *strData = d.isT1() ? d.asT1() : nullptr) {
- if (!strData->ref.deref())
- QStringData::deallocate(strData);
- }
- d = static_cast<QStringData *>(nullptr);
-}
-
-QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementIndex)
-{
- ListElement *e = elements[elementIndex];
- if (e->m_objectCache == nullptr) {
- void *memory = operator new(sizeof(QObject) + sizeof(QQmlData));
- void *ddataMemory = ((char *)memory) + sizeof(QObject);
- e->m_objectCache = new (memory) QObject;
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate::get(e->m_objectCache)->declarativeData = ddata;
- (void)new ModelNodeMetaObject(e->m_objectCache, model, elementIndex);
- }
- return e->m_objectCache;
-}
-
-bool ListModel::sync(ListModel *src, ListModel *target)
-{
- // Sanity check
-
- bool hasChanges = false;
-
- // Build hash of elements <-> uid for each of the lists
- QHash<int, ElementSync> elementHash;
- for (int i = 0; i < target->elements.count(); ++i) {
- ListElement *e = target->elements.at(i);
- int uid = e->getUid();
- ElementSync sync;
- sync.target = e;
- sync.targetIndex = i;
- elementHash.insert(uid, sync);
- }
- for (int i = 0; i < src->elements.count(); ++i) {
- ListElement *e = src->elements.at(i);
- int uid = e->getUid();
-
- QHash<int, ElementSync>::iterator it = elementHash.find(uid);
- if (it == elementHash.end()) {
- ElementSync sync;
- sync.src = e;
- sync.srcIndex = i;
- elementHash.insert(uid, sync);
- } else {
- ElementSync &sync = it.value();
- sync.src = e;
- sync.srcIndex = i;
- }
- }
-
- QQmlListModel *targetModel = target->m_modelCache;
-
- // Get list of elements that are in the target but no longer in the source. These get deleted first.
- int rowsRemoved = 0;
- for (int i = 0 ; i < target->elements.count() ; ++i) {
- ListElement *element = target->elements.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.targetIndex >= 0);
- // need to update the targetIndex, to keep it correct after removals
- s.targetIndex -= rowsRemoved;
- if (s.src == nullptr) {
- Q_ASSERT(s.targetIndex == i);
- hasChanges = true;
- if (targetModel)
- targetModel->beginRemoveRows(QModelIndex(), i, i);
- s.target->destroy(target->m_layout);
- target->elements.removeOne(s.target);
- delete s.target;
- if (targetModel)
- targetModel->endRemoveRows();
- ++rowsRemoved;
- --i;
- continue;
- }
- }
-
- // Sync the layouts
- ListLayout::sync(src->m_layout, target->m_layout);
-
- // Clear the target list, and append in correct order from the source
- target->elements.clear();
- for (int i = 0; i < src->elements.count(); ++i) {
- ListElement *srcElement = src->elements.at(i);
- ElementSync &s = elementHash.find(srcElement->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- ListElement *targetElement = s.target;
- if (targetElement == nullptr) {
- targetElement = new ListElement(srcElement->getUid());
- }
- s.changedRoles = ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout);
- target->elements.append(targetElement);
- }
-
- target->updateCacheIndices();
-
- // Update values stored in target meta objects
- for (int i=0 ; i < target->elements.count() ; ++i) {
- ListElement *e = target->elements[i];
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->updateValues();
- }
-
- // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts,
- // so the model indices can't be out of bounds
- //
- // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
- // model indices are updated correctly
- int rowsInserted = 0;
- for (int i = 0 ; i < target->elements.count() ; ++i) {
- ListElement *element = target->elements.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- s.srcIndex += rowsInserted;
- if (s.srcIndex != s.targetIndex) {
- if (targetModel) {
- if (s.targetIndex == -1) {
- targetModel->beginInsertRows(QModelIndex(), i, i);
- targetModel->endInsertRows();
- } else {
- targetModel->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex);
- targetModel->endMoveRows();
- }
- }
- hasChanges = true;
- ++rowsInserted;
- }
- if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) {
- QModelIndex idx = targetModel->createIndex(i, 0);
- if (targetModel)
- targetModel->dataChanged(idx, idx, s.changedRoles);
- hasChanges = true;
- }
- }
- return hasChanges;
-}
-
-ListModel::ListModel(ListLayout *layout, QQmlListModel *modelCache) : m_layout(layout), m_modelCache(modelCache)
-{
-}
-
-void ListModel::destroy()
-{
- for (const auto &destroyer : remove(0, elements.count()))
- destroyer();
-
- m_layout = nullptr;
- if (m_modelCache && m_modelCache->m_primary == false)
- delete m_modelCache;
- m_modelCache = nullptr;
-}
-
-int ListModel::appendElement()
-{
- int elementIndex = elements.count();
- newElement(elementIndex);
- return elementIndex;
-}
-
-void ListModel::insertElement(int index)
-{
- newElement(index);
- updateCacheIndices(index);
-}
-
-void ListModel::move(int from, int to, int n)
-{
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- from = tto;
- to = tto+n;
- n = tfrom-tto;
- }
-
- QPODVector<ListElement *, 4> store;
- for (int i=0 ; i < (to-from) ; ++i)
- store.append(elements[from+n+i]);
- for (int i=0 ; i < n ; ++i)
- store.append(elements[from+i]);
- for (int i=0 ; i < store.count() ; ++i)
- elements[from+i] = store[i];
-
- updateCacheIndices(from, to + n);
-}
-
-void ListModel::newElement(int index)
-{
- ListElement *e = new ListElement;
- elements.insert(index, e);
-}
-
-void ListModel::updateCacheIndices(int start, int end)
-{
- int count = elements.count();
-
- if (end < 0 || end > count)
- end = count;
-
- for (int i = start; i < end; ++i) {
- ListElement *e = elements.at(i);
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->m_elementIndex = i;
- }
-}
-
-QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng)
-{
- if (roleIndex >= m_layout->roleCount())
- return QVariant();
- ListElement *e = elements[elementIndex];
- const ListLayout::Role &r = m_layout->getExistingRole(roleIndex);
- return e->getProperty(r, owner, eng);
-}
-
-ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role)
-{
- ListElement *e = elements[elementIndex];
- return e->getListProperty(role);
-}
-
-void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
-{
- ListElement *e = elements[elementIndex];
-
- QV4::ExecutionEngine *v4 = object->engine();
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope);
-
- QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedString propertyName(scope);
- QV4::ScopedValue propertyValue(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(propertyValue);
- if (!propertyName)
- break;
-
- // Check if this key exists yet
- int roleIndex = -1;
-
- // Add the value now
- if (const QV4::String *s = propertyValue->as<QV4::String>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
- roleIndex = e->setStringProperty(r, s->toQString());
- } else if (propertyValue->isNumber()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
- roleIndex = e->setDoubleProperty(r, propertyValue->asDouble());
- } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- roleIndex = e->setListProperty(r, subModel);
- } else if (propertyValue->isBoolean()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
- roleIndex = e->setBoolProperty(r, propertyValue->booleanValue());
- } else if (QV4::DateObject *dd = propertyValue->as<QV4::DateObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
- QDateTime dt = dd->toQDateTime();
- roleIndex = e->setDateTimeProperty(r, dt);
- } else if (QV4::FunctionObject *f = propertyValue->as<QV4::FunctionObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Function);
- QV4::ScopedFunctionObject func(scope, f);
- QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, v4, func);
- roleIndex = e->setFunctionProperty(r, jsv);
- } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
- if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
- if (role.type == ListLayout::Role::QObject)
- roleIndex = e->setQObjectProperty(role, o);
- } else {
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap) {
- QV4::ScopedObject obj(scope, o);
- roleIndex = e->setVariantMapProperty(role, obj);
- }
- }
- } else if (propertyValue->isNullOrUndefined()) {
- const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
- if (r)
- e->clearProperty(*r);
- }
-
- if (roleIndex != -1)
- roles->append(roleIndex);
- }
-
- if (ModelNodeMetaObject *mo = e->objectCache())
- mo->updateValues(*roles);
-}
-
-void ListModel::set(int elementIndex, QV4::Object *object)
-{
- if (!object)
- return;
-
- ListElement *e = elements[elementIndex];
-
- QV4::ExecutionEngine *v4 = object->engine();
- QV4::Scope scope(v4);
-
- QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedString propertyName(scope);
- QV4::ScopedValue propertyValue(scope);
- QV4::ScopedObject o(scope);
- while (1) {
- propertyName = it.nextPropertyNameAsString(propertyValue);
- if (!propertyName)
- break;
-
- // Add the value now
- if (QV4::String *s = propertyValue->stringValue()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String);
- if (r.type == ListLayout::Role::String)
- e->setStringPropertyFast(r, s->toQString());
- } else if (propertyValue->isNumber()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number);
- if (r.type == ListLayout::Role::Number) {
- e->setDoublePropertyFast(r, propertyValue->asDouble());
- }
- } else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- if (r.type == ListLayout::Role::List) {
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- e->setListPropertyFast(r, subModel);
- }
- } else if (propertyValue->isBoolean()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
- if (r.type == ListLayout::Role::Bool) {
- e->setBoolPropertyFast(r, propertyValue->booleanValue());
- }
- } else if (QV4::DateObject *date = propertyValue->as<QV4::DateObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
- if (r.type == ListLayout::Role::DateTime) {
- QDateTime dt = date->toQDateTime();;
- e->setDateTimePropertyFast(r, dt);
- }
- } else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
- if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
- if (r.type == ListLayout::Role::QObject)
- e->setQObjectPropertyFast(r, o);
- } else {
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap)
- e->setVariantMapFast(role, o);
- }
- } else if (propertyValue->isNullOrUndefined()) {
- const ListLayout::Role *r = m_layout->getExistingRole(propertyName);
- if (r)
- e->clearProperty(*r);
- }
- }
-}
-
-QVector<std::function<void()>> ListModel::remove(int index, int count)
-{
- QVector<std::function<void()>> toDestroy;
- auto layout = m_layout;
- for (int i=0 ; i < count ; ++i) {
- auto element = elements[index+i];
- toDestroy.append([element, layout](){
- element->destroy(layout);
- delete element;
- });
- }
- elements.remove(index, count);
- updateCacheIndices(index);
- return toDestroy;
-}
-
-void ListModel::insert(int elementIndex, QV4::Object *object)
-{
- insertElement(elementIndex);
- set(elementIndex, object);
-}
-
-int ListModel::append(QV4::Object *object)
-{
- int elementIndex = appendElement();
- set(elementIndex, object);
- return elementIndex;
-}
-
-int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data)
-{
- int roleIndex = -1;
-
- if (elementIndex >= 0 && elementIndex < elements.count()) {
- ListElement *e = elements[elementIndex];
-
- const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data);
- if (r) {
- roleIndex = e->setVariantProperty(*r, data);
-
- ModelNodeMetaObject *cache = e->objectCache();
-
- if (roleIndex != -1 && cache)
- cache->updateValues(QVector<int>(1, roleIndex));
- }
- }
-
- return roleIndex;
-}
-
-int ListModel::setExistingProperty(int elementIndex, const QString &key, const QV4::Value &data, QV4::ExecutionEngine *eng)
-{
- int roleIndex = -1;
-
- if (elementIndex >= 0 && elementIndex < elements.count()) {
- ListElement *e = elements[elementIndex];
- const ListLayout::Role *r = m_layout->getExistingRole(key);
- if (r)
- roleIndex = e->setJsProperty(*r, data, eng);
- }
-
- return roleIndex;
-}
-
-inline char *ListElement::getPropertyMemory(const ListLayout::Role &role)
-{
- ListElement *e = this;
- int blockIndex = 0;
- while (blockIndex < role.blockIndex) {
- if (e->next == nullptr) {
- e->next = new ListElement;
- e->next->uid = uid;
- }
- e = e->next;
- ++blockIndex;
- }
-
- char *mem = &e->data[role.blockOffset];
- return mem;
-}
-
-ModelNodeMetaObject *ListElement::objectCache()
-{
- if (!m_objectCache)
- return nullptr;
- return ModelNodeMetaObject::get(m_objectCache);
-}
-
-StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem);
- return s;
-}
-
-QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- QPointer<QObject> *o = reinterpret_cast<QPointer<QObject> *>(mem);
- return o->data();
-}
-
-QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
-{
- QVariantMap *map = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem))
- map = reinterpret_cast<QVariantMap *>(mem);
-
- return map;
-}
-
-QDateTime *ListElement::getDateTimeProperty(const ListLayout::Role &role)
-{
- QDateTime *dt = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QDateTime>(mem))
- dt = reinterpret_cast<QDateTime *>(mem);
-
- return dt;
-}
-
-QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
-{
- QJSValue *f = nullptr;
-
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QJSValue>(mem))
- f = reinterpret_cast<QJSValue *>(mem);
-
- return f;
-}
-
-QPointer<QObject> *ListElement::getGuardProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
-
- bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
-
- QPointer<QObject> *o = nullptr;
-
- if (existingGuard)
- o = reinterpret_cast<QPointer<QObject> *>(mem);
-
- return o;
-}
-
-ListModel *ListElement::getListProperty(const ListLayout::Role &role)
-{
- char *mem = getPropertyMemory(role);
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- return *value;
-}
-
-QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng)
-{
- char *mem = getPropertyMemory(role);
-
- QVariant data;
-
- switch (role.type) {
- case ListLayout::Role::Number:
- {
- double *value = reinterpret_cast<double *>(mem);
- data = *value;
- }
- break;
- case ListLayout::Role::String:
- {
- StringOrTranslation *value = reinterpret_cast<StringOrTranslation *>(mem);
- if (value->isSet())
- data = value->toString(owner);
- }
- break;
- case ListLayout::Role::Bool:
- {
- bool *value = reinterpret_cast<bool *>(mem);
- data = *value;
- }
- break;
- case ListLayout::Role::List:
- {
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- ListModel *model = *value;
-
- if (model) {
- if (model->m_modelCache == nullptr) {
- model->m_modelCache = new QQmlListModel(owner, model, eng);
- QQmlEngine::setContextForObject(model->m_modelCache, QQmlEngine::contextForObject(owner));
- }
-
- QObject *object = model->m_modelCache;
- data = QVariant::fromValue(object);
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QPointer<QObject> *guard = reinterpret_cast<QPointer<QObject> *>(mem);
- QObject *object = guard->data();
- if (object)
- data = QVariant::fromValue(object);
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- data = *map;
- }
- }
- break;
- case ListLayout::Role::DateTime:
- {
- if (isMemoryUsed<QDateTime>(mem)) {
- QDateTime *dt = reinterpret_cast<QDateTime *>(mem);
- data = *dt;
- }
- }
- break;
- case ListLayout::Role::Function:
- {
- if (isMemoryUsed<QJSValue>(mem)) {
- QJSValue *func = reinterpret_cast<QJSValue *>(mem);
- data = QVariant::fromValue(*func);
- }
- }
- break;
- default:
- break;
- }
-
- return data;
-}
-
-int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::String) {
- char *mem = getPropertyMemory(role);
- StringOrTranslation *c = reinterpret_cast<StringOrTranslation *>(mem);
- bool changed;
- if (!c->isSet() || c->isTranslation())
- changed = true;
- else
- changed = c->asString().compare(s) != 0;
- c->setString(s);
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setDoubleProperty(const ListLayout::Role &role, double d)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Number) {
- char *mem = getPropertyMemory(role);
- double *value = reinterpret_cast<double *>(mem);
- bool changed = *value != d;
- *value = d;
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setBoolProperty(const ListLayout::Role &role, bool b)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Bool) {
- char *mem = getPropertyMemory(role);
- bool *value = reinterpret_cast<bool *>(mem);
- bool changed = *value != b;
- *value = b;
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::List) {
- char *mem = getPropertyMemory(role);
- ListModel **value = reinterpret_cast<ListModel **>(mem);
- if (*value && *value != m) {
- (*value)->destroy();
- delete *value;
- }
- *value = m;
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::QObject) {
- char *mem = getPropertyMemory(role);
- QPointer<QObject> *g = reinterpret_cast<QPointer<QObject> *>(mem);
- bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
- bool changed;
- if (existingGuard) {
- changed = g->data() != o;
- g->~QPointer();
- } else {
- changed = true;
- }
- new (mem) QPointer<QObject>(o);
- if (changed)
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::VariantMap) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- map->~QMap();
- }
- new (mem) QVariantMap(o->engine()->variantMapFromJS(o));
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::VariantMap) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QVariantMap>(mem)) {
- QVariantMap *map = reinterpret_cast<QVariantMap *>(mem);
- if (m && map->isSharedWith(*m))
- return roleIndex;
- map->~QMap();
- } else if (!m) {
- return roleIndex;
- }
- if (m)
- new (mem) QVariantMap(*m);
- else
- new (mem) QVariantMap;
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::DateTime) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QDateTime>(mem)) {
- QDateTime *dt = reinterpret_cast<QDateTime *>(mem);
- dt->~QDateTime();
- }
- new (mem) QDateTime(dt);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValue &f)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::Function) {
- char *mem = getPropertyMemory(role);
- if (isMemoryUsed<QJSValue>(mem)) {
- QJSValue *f = reinterpret_cast<QJSValue *>(mem);
- f->~QJSValue();
- }
- new (mem) QJSValue(f);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-int ListElement::setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b)
-{
- int roleIndex = -1;
-
- if (role.type == ListLayout::Role::String) {
- char *mem = getPropertyMemory(role);
- StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem);
- s->setTranslation(b);
- roleIndex = role.index;
- }
-
- return roleIndex;
-}
-
-
-void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s)
-{
- char *mem = getPropertyMemory(role);
- new (mem) StringOrTranslation(s);
-}
-
-void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d)
-{
- char *mem = getPropertyMemory(role);
- double *value = new (mem) double;
- *value = d;
-}
-
-void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
-{
- char *mem = getPropertyMemory(role);
- bool *value = new (mem) bool;
- *value = b;
-}
-
-void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QPointer<QObject>(o);
-}
-
-void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
-{
- char *mem = getPropertyMemory(role);
- ListModel **value = new (mem) ListModel *;
- *value = m;
-}
-
-void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::Object *o)
-{
- char *mem = getPropertyMemory(role);
- QVariantMap *map = new (mem) QVariantMap;
- *map = o->engine()->variantMapFromJS(o);
-}
-
-void ListElement::setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QDateTime(dt);
-}
-
-void ListElement::setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f)
-{
- char *mem = getPropertyMemory(role);
- new (mem) QJSValue(f);
-}
-
-void ListElement::clearProperty(const ListLayout::Role &role)
-{
- switch (role.type) {
- case ListLayout::Role::String:
- setStringProperty(role, QString());
- break;
- case ListLayout::Role::Number:
- setDoubleProperty(role, 0.0);
- break;
- case ListLayout::Role::Bool:
- setBoolProperty(role, false);
- break;
- case ListLayout::Role::List:
- setListProperty(role, nullptr);
- break;
- case ListLayout::Role::QObject:
- setQObjectProperty(role, nullptr);
- break;
- case ListLayout::Role::DateTime:
- setDateTimeProperty(role, QDateTime());
- break;
- case ListLayout::Role::VariantMap:
- setVariantMapProperty(role, (QVariantMap *)nullptr);
- break;
- case ListLayout::Role::Function:
- setFunctionProperty(role, QJSValue());
- break;
- default:
- break;
- }
-}
-
-ListElement::ListElement()
-{
- m_objectCache = nullptr;
- uid = uidCounter.fetchAndAddOrdered(1);
- next = nullptr;
- memset(data, 0, sizeof(data));
-}
-
-ListElement::ListElement(int existingUid)
-{
- m_objectCache = nullptr;
- uid = existingUid;
- next = nullptr;
- memset(data, 0, sizeof(data));
-}
-
-ListElement::~ListElement()
-{
- delete next;
-}
-
-QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout)
-{
- QVector<int> changedRoles;
- for (int i=0 ; i < srcLayout->roleCount() ; ++i) {
- const ListLayout::Role &srcRole = srcLayout->getExistingRole(i);
- const ListLayout::Role &targetRole = targetLayout->getExistingRole(i);
-
- int roleIndex = -1;
- switch (srcRole.type) {
- case ListLayout::Role::List:
- {
- ListModel *srcSubModel = src->getListProperty(srcRole);
- ListModel *targetSubModel = target->getListProperty(targetRole);
-
- if (srcSubModel) {
- if (targetSubModel == nullptr) {
- targetSubModel = new ListModel(targetRole.subLayout, nullptr);
- target->setListPropertyFast(targetRole, targetSubModel);
- }
- if (ListModel::sync(srcSubModel, targetSubModel))
- roleIndex = targetRole.index;
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QObject *object = src->getQObjectProperty(srcRole);
- roleIndex = target->setQObjectProperty(targetRole, object);
- }
- break;
- case ListLayout::Role::String:
- case ListLayout::Role::Number:
- case ListLayout::Role::Bool:
- case ListLayout::Role::DateTime:
- case ListLayout::Role::Function:
- {
- QVariant v = src->getProperty(srcRole, nullptr, nullptr);
- roleIndex = target->setVariantProperty(targetRole, v);
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- QVariantMap *map = src->getVariantMapProperty(srcRole);
- roleIndex = target->setVariantMapProperty(targetRole, map);
- }
- break;
- default:
- break;
- }
- if (roleIndex >= 0)
- changedRoles << roleIndex;
- }
-
- return changedRoles;
-}
-
-void ListElement::destroy(ListLayout *layout)
-{
- if (layout) {
- for (int i=0 ; i < layout->roleCount() ; ++i) {
- const ListLayout::Role &r = layout->getExistingRole(i);
-
- switch (r.type) {
- case ListLayout::Role::String:
- {
- StringOrTranslation *string = getStringProperty(r);
- if (string)
- string->~StringOrTranslation();
- }
- break;
- case ListLayout::Role::List:
- {
- ListModel *model = getListProperty(r);
- if (model) {
- model->destroy();
- delete model;
- }
- }
- break;
- case ListLayout::Role::QObject:
- {
- QPointer<QObject> *guard = getGuardProperty(r);
- if (guard)
- guard->~QPointer();
- }
- break;
- case ListLayout::Role::VariantMap:
- {
- QVariantMap *map = getVariantMapProperty(r);
- if (map)
- map->~QMap();
- }
- break;
- case ListLayout::Role::DateTime:
- {
- QDateTime *dt = getDateTimeProperty(r);
- if (dt)
- dt->~QDateTime();
- }
- break;
- case ListLayout::Role::Function:
- {
- QJSValue *f = getFunctionProperty(r);
- if (f)
- f->~QJSValue();
- }
- break;
- default:
- // other types don't need explicit cleanup.
- break;
- }
- }
-
- if (m_objectCache) {
- m_objectCache->~QObject();
- operator delete(m_objectCache);
- }
- }
-
- if (next)
- next->destroy(nullptr);
- uid = -1;
-}
-
-int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d)
-{
- int roleIndex = -1;
-
- switch (role.type) {
- case ListLayout::Role::Number:
- roleIndex = setDoubleProperty(role, d.toDouble());
- break;
- case ListLayout::Role::String:
- if (d.userType() == qMetaTypeId<const QV4::CompiledData::Binding *>())
- roleIndex = setTranslationProperty(role, d.value<const QV4::CompiledData::Binding*>());
- else
- roleIndex = setStringProperty(role, d.toString());
- break;
- case ListLayout::Role::Bool:
- roleIndex = setBoolProperty(role, d.toBool());
- break;
- case ListLayout::Role::List:
- roleIndex = setListProperty(role, d.value<ListModel *>());
- break;
- case ListLayout::Role::VariantMap: {
- QVariantMap map = d.toMap();
- roleIndex = setVariantMapProperty(role, &map);
- }
- break;
- case ListLayout::Role::DateTime:
- roleIndex = setDateTimeProperty(role, d.toDateTime());
- break;
- case ListLayout::Role::Function:
- roleIndex = setFunctionProperty(role, d.value<QJSValue>());
- break;
- default:
- break;
- }
-
- return roleIndex;
-}
-
-int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d, QV4::ExecutionEngine *eng)
-{
- // Check if this key exists yet
- int roleIndex = -1;
-
- QV4::Scope scope(eng);
-
- // Add the value now
- if (d.isString()) {
- QString qstr = d.toQString();
- roleIndex = setStringProperty(role, qstr);
- } else if (d.isNumber()) {
- roleIndex = setDoubleProperty(role, d.asDouble());
- } else if (d.as<QV4::ArrayObject>()) {
- QV4::ScopedArrayObject a(scope, d);
- if (role.type == ListLayout::Role::List) {
- QV4::Scope scope(a->engine());
- QV4::ScopedObject o(scope);
-
- ListModel *subModel = new ListModel(role.subLayout, nullptr);
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
- roleIndex = setListProperty(role, subModel);
- } else {
- qmlWarning(nullptr) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List));
- }
- } else if (d.isBoolean()) {
- roleIndex = setBoolProperty(role, d.booleanValue());
- } else if (d.as<QV4::DateObject>()) {
- QV4::Scoped<QV4::DateObject> dd(scope, d);
- QDateTime dt = dd->toQDateTime();
- roleIndex = setDateTimeProperty(role, dt);
- } else if (d.as<QV4::FunctionObject>()) {
- QV4::ScopedFunctionObject f(scope, d);
- QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, eng, f);
- roleIndex = setFunctionProperty(role, jsv);
- } else if (d.isObject()) {
- QV4::ScopedObject o(scope, d);
- QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>();
- if (role.type == ListLayout::Role::QObject && wrapper) {
- QObject *o = wrapper->object();
- roleIndex = setQObjectProperty(role, o);
- } else if (role.type == ListLayout::Role::VariantMap) {
- roleIndex = setVariantMapProperty(role, o);
- }
- } else if (d.isNullOrUndefined()) {
- clearProperty(role);
- }
-
- return roleIndex;
-}
-
-ModelNodeMetaObject::ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex)
-: QQmlOpenMetaObject(object), m_enabled(false), m_model(model), m_elementIndex(elementIndex), m_initialized(false)
-{}
-
-void ModelNodeMetaObject::initialize()
-{
- const int roleCount = m_model->m_listModel->roleCount();
- QVector<QByteArray> properties;
- properties.reserve(roleCount);
- for (int i = 0 ; i < roleCount ; ++i) {
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i);
- QByteArray name = role.name.toUtf8();
- properties << name;
- }
- type()->createProperties(properties);
- updateValues();
- m_enabled = true;
-}
-
-ModelNodeMetaObject::~ModelNodeMetaObject()
-{
-}
-
-QAbstractDynamicMetaObject *ModelNodeMetaObject::toDynamicMetaObject(QObject *object)
-{
- if (!m_initialized) {
- m_initialized = true;
- initialize();
- }
- return QQmlOpenMetaObject::toDynamicMetaObject(object);
-}
-
-ModelNodeMetaObject *ModelNodeMetaObject::get(QObject *obj)
-{
- QObjectPrivate *op = QObjectPrivate::get(obj);
- return static_cast<ModelNodeMetaObject*>(op->metaObject);
-}
-
-void ModelNodeMetaObject::updateValues()
-{
- const int roleCount = m_model->m_listModel->roleCount();
- if (!m_initialized) {
- if (roleCount) {
- Q_ALLOCA_VAR(int, changedRoles, roleCount * sizeof(int));
- for (int i = 0; i < roleCount; ++i)
- changedRoles[i] = i;
- emitDirectNotifies(changedRoles, roleCount);
- }
- return;
- }
- for (int i=0 ; i < roleCount ; ++i) {
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i);
- QByteArray name = role.name.toUtf8();
- const QVariant &data = m_model->data(m_elementIndex, i);
- setValue(name, data, role.type == ListLayout::Role::List);
- }
-}
-
-void ModelNodeMetaObject::updateValues(const QVector<int> &roles)
-{
- if (!m_initialized) {
- emitDirectNotifies(roles.constData(), roles.count());
- return;
- }
- int roleCount = roles.count();
- for (int i=0 ; i < roleCount ; ++i) {
- int roleIndex = roles.at(i);
- const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex);
- QByteArray name = role.name.toUtf8();
- const QVariant &data = m_model->data(m_elementIndex, roleIndex);
- setValue(name, data, role.type == ListLayout::Role::List);
- }
-}
-
-void ModelNodeMetaObject::propertyWritten(int index)
-{
- if (!m_enabled)
- return;
-
- QString propName = QString::fromUtf8(name(index));
- const QVariant value = this->value(index);
-
- QV4::Scope scope(m_model->engine());
- QV4::ScopedValue v(scope, scope.engine->fromVariant(value));
-
- int roleIndex = m_model->m_listModel->setExistingProperty(m_elementIndex, propName, v, scope.engine);
- if (roleIndex != -1)
- m_model->emitItemsChanged(m_elementIndex, 1, QVector<int>(1, roleIndex));
-}
-
-// Does the emission of the notifiers when we haven't created the meta-object yet
-void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCount)
-{
- Q_ASSERT(!m_initialized);
- QQmlData *ddata = QQmlData::get(object(), /*create*/false);
- if (!ddata)
- return;
- // There's nothing to emit if we're a list model in a worker thread.
- if (!qmlEngine(m_model))
- return;
- for (int i = 0; i < roleCount; ++i) {
- const int changedRole = changedRoles[i];
- QQmlNotifier::notify(ddata, changedRole);
- }
-}
-
-namespace QV4 {
-
-bool ModelObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
-{
- if (!id.isString())
- return Object::virtualPut(m, id, value, receiver);
- QString propName = id.toQString();
-
- ModelObject *that = static_cast<ModelObject*>(m);
-
- ExecutionEngine *eng = that->engine();
- const int elementIndex = that->d()->elementIndex();
- int roleIndex = that->d()->m_model->m_listModel->setExistingProperty(elementIndex, propName, value, eng);
- if (roleIndex != -1)
- that->d()->m_model->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
-
- ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
- if (mo->initialized())
- mo->emitPropertyNotification(propName.toUtf8());
- return true;
-}
-
-ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
-{
- if (!id.isString())
- return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
-
- const ModelObject *that = static_cast<const ModelObject*>(m);
- Scope scope(that);
- ScopedString name(scope, id.asStringOrSymbol());
- const ListLayout::Role *role = that->d()->m_model->m_listModel->getExistingRole(name);
- if (!role)
- return QObjectWrapper::virtualGet(m, id, receiver, hasProperty);
- if (hasProperty)
- *hasProperty = true;
-
- if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
- if (ep && ep->propertyCapture)
- ep->propertyCapture->captureProperty(that->object(), -1, role->index, /*doNotify=*/ false);
- }
-
- const int elementIndex = that->d()->elementIndex();
- QVariant value = that->d()->m_model->data(elementIndex, role->index);
- return that->engine()->fromVariant(value);
-}
-
-ReturnedValue ModelObject::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
-{
- lookup->getter = Lookup::getterFallback;
- return lookup->getter(lookup, engine, *object);
-}
-
-struct ModelObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
-{
- int roleNameIndex = 0;
- ~ModelObjectOwnPropertyKeyIterator() override = default;
- PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
-
-};
-
-PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
-{
- const ModelObject *that = static_cast<const ModelObject *>(o);
-
- ExecutionEngine *v4 = that->engine();
- if (roleNameIndex < that->listModel()->roleCount()) {
- Scope scope(that->engine());
- const ListLayout::Role &role = that->listModel()->getExistingRole(roleNameIndex);
- ++roleNameIndex;
- ScopedString roleName(scope, v4->newString(role.name));
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd) {
- QVariant value = that->d()->m_model->data(that->d()->elementIndex(), role.index);
- pd->value = v4->fromVariant(value);
- }
- return roleName->toPropertyKey();
- }
-
- // Fall back to QV4::Object as opposed to QV4::QObjectWrapper otherwise it will add
- // unnecessary entries that relate to the roles used. These just create extra work
- // later on as they will just be ignored.
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
-}
-
-OwnPropertyKeyIterator *ModelObject::virtualOwnPropertyKeys(const Object *m, Value *target)
-{
- *target = *m;
- return new ModelObjectOwnPropertyKeyIterator;
-}
-
-DEFINE_OBJECT_VTABLE(ModelObject);
-
-} // namespace QV4
-
-DynamicRoleModelNode::DynamicRoleModelNode(QQmlListModel *owner, int uid) : m_owner(owner), m_uid(uid), m_meta(new DynamicRoleModelNodeMetaObject(this))
-{
- setNodeUpdatesEnabled(true);
-}
-
-DynamicRoleModelNode *DynamicRoleModelNode::create(const QVariantMap &obj, QQmlListModel *owner)
-{
- DynamicRoleModelNode *object = new DynamicRoleModelNode(owner, uidCounter.fetchAndAddOrdered(1));
- QVector<int> roles;
- object->updateValues(obj, roles);
- return object;
-}
-
-QVector<int> DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target)
-{
- QVector<int> changedRoles;
- for (int i = 0; i < src->m_meta->count(); ++i) {
- const QByteArray &name = src->m_meta->name(i);
- QVariant value = src->m_meta->value(i);
-
- QQmlListModel *srcModel = qobject_cast<QQmlListModel *>(value.value<QObject *>());
- QQmlListModel *targetModel = qobject_cast<QQmlListModel *>(target->m_meta->value(i).value<QObject *>());
-
- bool modelHasChanges = false;
- if (srcModel) {
- if (targetModel == nullptr)
- targetModel = QQmlListModel::createWithOwner(target->m_owner);
-
- modelHasChanges = QQmlListModel::sync(srcModel, targetModel);
-
- QObject *targetModelObject = targetModel;
- value = QVariant::fromValue(targetModelObject);
- } else if (targetModel) {
- delete targetModel;
- }
-
- if (target->setValue(name, value) || modelHasChanges)
- changedRoles << target->m_owner->m_roles.indexOf(QString::fromUtf8(name));
- }
- return changedRoles;
-}
-
-void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int> &roles)
-{
- for (auto it = object.cbegin(), end = object.cend(); it != end; ++it) {
- const QString &key = it.key();
-
- int roleIndex = m_owner->m_roles.indexOf(key);
- if (roleIndex == -1) {
- roleIndex = m_owner->m_roles.count();
- m_owner->m_roles.append(key);
- }
-
- QVariant value = it.value();
-
- // A JS array/object is translated into a (hierarchical) QQmlListModel,
- // so translate to a variant map/list first with toVariant().
- if (value.userType() == qMetaTypeId<QJSValue>())
- value = value.value<QJSValue>().toVariant();
-
- if (value.type() == QVariant::List) {
- QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner);
-
- QVariantList subArray = value.toList();
- QVariantList::const_iterator subIt = subArray.cbegin();
- QVariantList::const_iterator subEnd = subArray.cend();
- while (subIt != subEnd) {
- const QVariantMap &subObject = subIt->toMap();
- subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
- ++subIt;
- }
-
- QObject *subModelObject = subModel;
- value = QVariant::fromValue(subModelObject);
- }
-
- const QByteArray &keyUtf8 = key.toUtf8();
-
- QQmlListModel *existingModel = qobject_cast<QQmlListModel *>(m_meta->value(keyUtf8).value<QObject *>());
- delete existingModel;
-
- if (m_meta->setValue(keyUtf8, value))
- roles << roleIndex;
- }
-}
-
-DynamicRoleModelNodeMetaObject::DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object)
- : QQmlOpenMetaObject(object), m_enabled(false), m_owner(object)
-{
-}
-
-DynamicRoleModelNodeMetaObject::~DynamicRoleModelNodeMetaObject()
-{
- for (int i=0 ; i < count() ; ++i) {
- QQmlListModel *subModel = qobject_cast<QQmlListModel *>(value(i).value<QObject *>());
- delete subModel;
- }
-}
-
-void DynamicRoleModelNodeMetaObject::propertyWrite(int index)
-{
- if (!m_enabled)
- return;
-
- QVariant v = value(index);
- QQmlListModel *model = qobject_cast<QQmlListModel *>(v.value<QObject *>());
- delete model;
-}
-
-void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
-{
- if (!m_enabled)
- return;
-
- QQmlListModel *parentModel = m_owner->m_owner;
-
- QVariant v = value(index);
-
- // A JS array/object is translated into a (hierarchical) QQmlListModel,
- // so translate to a variant map/list first with toVariant().
- if (v.userType() == qMetaTypeId<QJSValue>())
- v= v.value<QJSValue>().toVariant();
-
- if (v.type() == QVariant::List) {
- QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel);
-
- QVariantList subArray = v.toList();
- QVariantList::const_iterator subIt = subArray.cbegin();
- QVariantList::const_iterator subEnd = subArray.cend();
- while (subIt != subEnd) {
- const QVariantMap &subObject = subIt->toMap();
- subModel->m_modelObjects.append(DynamicRoleModelNode::create(subObject, subModel));
- ++subIt;
- }
-
- QObject *subModelObject = subModel;
- v = QVariant::fromValue(subModelObject);
-
- setValue(index, v);
- }
-
- int elementIndex = parentModel->m_modelObjects.indexOf(m_owner);
- if (elementIndex != -1) {
- int roleIndex = parentModel->m_roles.indexOf(QString::fromLatin1(name(index).constData()));
- if (roleIndex != -1)
- parentModel->emitItemsChanged(elementIndex, 1, QVector<int>(1, roleIndex));
- }
-}
-
-/*!
- \qmltype ListModel
- \instantiates QQmlListModel
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Defines a free-form list data source.
-
- The ListModel is a simple container of ListElement definitions, each
- containing data roles. The contents can be defined dynamically, or
- explicitly in QML.
-
- The number of elements in the model can be obtained from its \l count property.
- A number of familiar methods are also provided to manipulate the contents of the
- model, including append(), insert(), move(), remove() and set(). These methods
- accept dictionaries as their arguments; these are translated to ListElement objects
- by the model.
-
- Elements can be manipulated via the model using the setProperty() method, which
- allows the roles of the specified element to be set and changed.
-
- \section1 Example Usage
-
- The following example shows a ListModel containing three elements, with the roles
- "name" and "cost".
-
- \div {class="float-right"}
- \inlineimage listmodel.png
- \enddiv
-
- \snippet qml/listmodel/listmodel.qml 0
-
- Roles (properties) in each element must begin with a lower-case letter and
- should be common to all elements in a model. The ListElement documentation
- provides more guidelines for how elements should be defined.
-
- Since the example model contains an \c id property, it can be referenced
- by views, such as the ListView in this example:
-
- \snippet qml/listmodel/listmodel-simple.qml 0
- \dots 8
- \snippet qml/listmodel/listmodel-simple.qml 1
-
- It is possible for roles to contain list data. In the following example we
- create a list of fruit attributes:
-
- \snippet qml/listmodel/listmodel-nested.qml model
-
- The delegate displays all the fruit attributes:
-
- \div {class="float-right"}
- \inlineimage listmodel-nested.png
- \enddiv
-
- \snippet qml/listmodel/listmodel-nested.qml delegate
-
- \section1 Modifying List Models
-
- The content of a ListModel may be created and modified using the clear(),
- append(), set(), insert() and setProperty() methods. For example:
-
- \snippet qml/listmodel/listmodel-modify.qml delegate
-
- Note that when creating content dynamically the set of available properties
- cannot be changed once set. Whatever properties are first added to the model
- are the only permitted properties in the model.
-
- \section1 Using Threaded List Models with WorkerScript
-
- ListModel can be used together with WorkerScript access a list model
- from multiple threads. This is useful if list modifications are
- synchronous and take some time: the list operations can be moved to a
- different thread to avoid blocking of the main GUI thread.
-
- Here is an example that uses WorkerScript to periodically append the
- current time to a list model:
-
- \snippet ../quick/threading/threadedlistmodel/timedisplay.qml 0
-
- The included file, \tt dataloader.mjs, looks like this:
-
- \snippet ../quick/threading/threadedlistmodel/dataloader.mjs 0
-
- The timer in the main example sends messages to the worker script by calling
- \l WorkerScript::sendMessage(). When this message is received,
- \c WorkerScript.onMessage() is invoked in \c dataloader.mjs,
- which appends the current time to the list model.
-
- Note the call to sync() from the external thread.
- You must call sync() or else the changes made to the list from that
- thread will not be reflected in the list model in the main thread.
-
- \sa {qml-data-models}{Data Models}, {Qt Quick Examples - Threading}, {Qt QML}
-*/
-
-QQmlListModel::QQmlListModel(QObject *parent)
-: QAbstractListModel(parent)
-{
- m_mainThread = true;
- m_primary = true;
- m_agent = nullptr;
- m_dynamicRoles = false;
-
- m_layout = new ListLayout;
- m_listModel = new ListModel(m_layout, this);
-
- m_engine = nullptr;
-}
-
-QQmlListModel::QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::ExecutionEngine *engine, QObject *parent)
-: QAbstractListModel(parent)
-{
- m_mainThread = owner->m_mainThread;
- m_primary = false;
- m_agent = owner->m_agent;
-
- Q_ASSERT(owner->m_dynamicRoles == false);
- m_dynamicRoles = false;
- m_layout = nullptr;
- m_listModel = data;
-
- m_engine = engine;
- m_compilationUnit = owner->m_compilationUnit;
-}
-
-QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent)
-: QAbstractListModel(agent)
-{
- m_mainThread = false;
- m_primary = true;
- m_agent = agent;
- m_dynamicRoles = orig->m_dynamicRoles;
-
- m_layout = new ListLayout(orig->m_layout);
- m_listModel = new ListModel(m_layout, this);
-
- if (m_dynamicRoles)
- sync(orig, this);
- else
- ListModel::sync(orig->m_listModel, m_listModel);
-
- m_engine = nullptr;
- m_compilationUnit = orig->m_compilationUnit;
-}
-
-QQmlListModel::~QQmlListModel()
-{
- qDeleteAll(m_modelObjects);
-
- if (m_primary) {
- m_listModel->destroy();
- delete m_listModel;
-
- if (m_mainThread && m_agent) {
- m_agent->modelDestroyed();
- m_agent->release();
- }
- }
-
- m_listModel = nullptr;
-
- delete m_layout;
- m_layout = nullptr;
-}
-
-QQmlListModel *QQmlListModel::createWithOwner(QQmlListModel *newOwner)
-{
- QQmlListModel *model = new QQmlListModel;
-
- model->m_mainThread = newOwner->m_mainThread;
- model->m_engine = newOwner->m_engine;
- model->m_agent = newOwner->m_agent;
- model->m_dynamicRoles = newOwner->m_dynamicRoles;
-
- if (model->m_mainThread && model->m_agent)
- model->m_agent->addref();
-
- QQmlEngine::setContextForObject(model, QQmlEngine::contextForObject(newOwner));
-
- return model;
-}
-
-QV4::ExecutionEngine *QQmlListModel::engine() const
-{
- if (m_engine == nullptr) {
- m_engine = qmlEngine(this)->handle();
- }
-
- return m_engine;
-}
-
-bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
-{
- Q_ASSERT(src->m_dynamicRoles && target->m_dynamicRoles);
-
- bool hasChanges = false;
-
- target->m_roles = src->m_roles;
-
- // Build hash of elements <-> uid for each of the lists
- QHash<int, ElementSync> elementHash;
- for (int i = 0 ; i < target->m_modelObjects.count(); ++i) {
- DynamicRoleModelNode *e = target->m_modelObjects.at(i);
- int uid = e->getUid();
- ElementSync sync;
- sync.target = e;
- sync.targetIndex = i;
- elementHash.insert(uid, sync);
- }
- for (int i = 0 ; i < src->m_modelObjects.count(); ++i) {
- DynamicRoleModelNode *e = src->m_modelObjects.at(i);
- int uid = e->getUid();
-
- QHash<int, ElementSync>::iterator it = elementHash.find(uid);
- if (it == elementHash.end()) {
- ElementSync sync;
- sync.src = e;
- sync.srcIndex = i;
- elementHash.insert(uid, sync);
- } else {
- ElementSync &sync = it.value();
- sync.src = e;
- sync.srcIndex = i;
- }
- }
-
- // Get list of elements that are in the target but no longer in the source. These get deleted first.
- int rowsRemoved = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = target->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.targetIndex >= 0);
- // need to update the targetIndex, to keep it correct after removals
- s.targetIndex -= rowsRemoved;
- if (s.src == nullptr) {
- Q_ASSERT(s.targetIndex == i);
- hasChanges = true;
- target->beginRemoveRows(QModelIndex(), i, i);
- target->m_modelObjects.remove(i, 1);
- target->endRemoveRows();
- delete s.target;
- ++rowsRemoved;
- --i;
- continue;
- }
- }
-
- // Clear the target list, and append in correct order from the source
- target->m_modelObjects.clear();
- for (int i = 0 ; i < src->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = src->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- DynamicRoleModelNode *targetElement = s.target;
- if (targetElement == nullptr) {
- targetElement = new DynamicRoleModelNode(target, element->getUid());
- }
- s.changedRoles = DynamicRoleModelNode::sync(element, targetElement);
- target->m_modelObjects.append(targetElement);
- }
-
- // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts,
- // so the model indices can't be out of bounds
- //
- // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
- // model indices are updated correctly
- int rowsInserted = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
- DynamicRoleModelNode *element = target->m_modelObjects.at(i);
- ElementSync &s = elementHash.find(element->getUid()).value();
- Q_ASSERT(s.srcIndex >= 0);
- s.srcIndex += rowsInserted;
- if (s.srcIndex != s.targetIndex) {
- if (s.targetIndex == -1) {
- target->beginInsertRows(QModelIndex(), i, i);
- target->endInsertRows();
- } else {
- target->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex);
- target->endMoveRows();
- }
- hasChanges = true;
- ++rowsInserted;
- }
- if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) {
- QModelIndex idx = target->createIndex(i, 0);
- emit target->dataChanged(idx, idx, s.changedRoles);
- hasChanges = true;
- }
- }
- return hasChanges;
-}
-
-void QQmlListModel::emitItemsChanged(int index, int count, const QVector<int> &roles)
-{
- if (count <= 0)
- return;
-
- if (m_mainThread)
- emit dataChanged(createIndex(index, 0), createIndex(index + count - 1, 0), roles);;
-}
-
-void QQmlListModel::emitItemsAboutToBeInserted(int index, int count)
-{
- Q_ASSERT(index >= 0 && count >= 0);
- if (m_mainThread)
- beginInsertRows(QModelIndex(), index, index + count - 1);
-}
-
-void QQmlListModel::emitItemsInserted()
-{
- if (m_mainThread) {
- endInsertRows();
- emit countChanged();
- }
-}
-
-QQmlListModelWorkerAgent *QQmlListModel::agent()
-{
- if (m_agent)
- return m_agent;
-
- m_agent = new QQmlListModelWorkerAgent(this);
- return m_agent;
-}
-
-QModelIndex QQmlListModel::index(int row, int column, const QModelIndex &parent) const
-{
- return row >= 0 && row < count() && column == 0 && !parent.isValid()
- ? createIndex(row, column)
- : QModelIndex();
-}
-
-int QQmlListModel::rowCount(const QModelIndex &parent) const
-{
- return !parent.isValid() ? count() : 0;
-}
-
-QVariant QQmlListModel::data(const QModelIndex &index, int role) const
-{
- return data(index.row(), role);
-}
-
-bool QQmlListModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- const int row = index.row();
- if (row >= count() || row < 0)
- return false;
-
- if (m_dynamicRoles) {
- const QByteArray property = m_roles.at(role).toUtf8();
- if (m_modelObjects[row]->setValue(property, value)) {
- emitItemsChanged(row, 1, QVector<int>(1, role));
- return true;
- }
- } else {
- const ListLayout::Role &r = m_listModel->getExistingRole(role);
- const int roleIndex = m_listModel->setOrCreateProperty(row, r.name, value);
- if (roleIndex != -1) {
- emitItemsChanged(row, 1, QVector<int>(1, role));
- return true;
- }
- }
-
- return false;
-}
-
-QVariant QQmlListModel::data(int index, int role) const
-{
- QVariant v;
-
- if (index >= count() || index < 0)
- return v;
-
- if (m_dynamicRoles)
- v = m_modelObjects[index]->getValue(m_roles[role]);
- else
- v = m_listModel->getProperty(index, role, this, engine());
-
- return v;
-}
-
-QHash<int, QByteArray> QQmlListModel::roleNames() const
-{
- QHash<int, QByteArray> roleNames;
-
- if (m_dynamicRoles) {
- for (int i = 0 ; i < m_roles.count() ; ++i)
- roleNames.insert(i, m_roles.at(i).toUtf8());
- } else {
- for (int i = 0 ; i < m_listModel->roleCount() ; ++i) {
- const ListLayout::Role &r = m_listModel->getExistingRole(i);
- roleNames.insert(i, r.name.toUtf8());
- }
- }
-
- return roleNames;
-}
-
-/*!
- \qmlproperty bool ListModel::dynamicRoles
-
- By default, the type of a role is fixed the first time
- the role is used. For example, if you create a role called
- "data" and assign a number to it, you can no longer assign
- a string to the "data" role. However, when the dynamicRoles
- property is enabled, the type of a given role is not fixed
- and can be different between elements.
-
- The dynamicRoles property must be set before any data is
- added to the ListModel, and must be set from the main
- thread.
-
- A ListModel that has data statically defined (via the
- ListElement QML syntax) cannot have the dynamicRoles
- property enabled.
-
- There is a significant performance cost to using a
- ListModel with dynamic roles enabled. The cost varies
- from platform to platform but is typically somewhere
- between 4-6x slower than using static role types.
-
- Due to the performance cost of using dynamic roles,
- they are disabled by default.
-*/
-void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
-{
- if (m_mainThread && m_agent == nullptr) {
- if (enableDynamicRoles) {
- if (m_layout->roleCount())
- qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty");
- else
- m_dynamicRoles = true;
- } else {
- if (m_roles.count()) {
- qmlWarning(this) << tr("unable to enable static roles as this model is not empty");
- } else {
- m_dynamicRoles = false;
- }
- }
- } else {
- qmlWarning(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created");
- }
-}
-
-/*!
- \qmlproperty int ListModel::count
- The number of data entries in the model.
-*/
-int QQmlListModel::count() const
-{
- return m_dynamicRoles ? m_modelObjects.count() : m_listModel->elementCount();
-}
-
-/*!
- \qmlmethod ListModel::clear()
-
- Deletes all content from the model.
-
- \sa append(), remove()
-*/
-void QQmlListModel::clear()
-{
- removeElements(0, count());
-}
-
-/*!
- \qmlmethod ListModel::remove(int index, int count = 1)
-
- Deletes the content at \a index from the model.
-
- \sa clear()
-*/
-void QQmlListModel::remove(QQmlV4Function *args)
-{
- int argLength = args->length();
-
- if (argLength == 1 || argLength == 2) {
- QV4::Scope scope(args->v4engine());
- int index = QV4::ScopedValue(scope, (*args)[0])->toInt32();
- int removeCount = (argLength == 2 ? QV4::ScopedValue(scope, (*args)[1])->toInt32() : 1);
-
- if (index < 0 || index+removeCount > count() || removeCount <= 0) {
- qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count());
- return;
- }
-
- removeElements(index, removeCount);
- } else {
- qmlWarning(this) << tr("remove: incorrect number of arguments");
- }
-}
-
-void QQmlListModel::removeElements(int index, int removeCount)
-{
- Q_ASSERT(index >= 0 && removeCount >= 0);
-
- if (!removeCount)
- return;
-
- if (m_mainThread)
- beginRemoveRows(QModelIndex(), index, index + removeCount - 1);
-
- QVector<std::function<void()>> toDestroy;
- if (m_dynamicRoles) {
- for (int i=0 ; i < removeCount ; ++i) {
- auto modelObject = m_modelObjects[index+i];
- toDestroy.append([modelObject](){
- delete modelObject;
- });
- }
- m_modelObjects.remove(index, removeCount);
- } else {
- toDestroy = m_listModel->remove(index, removeCount);
- }
-
- if (m_mainThread) {
- endRemoveRows();
- emit countChanged();
- }
- for (const auto &destroyer : toDestroy)
- destroyer();
-}
-
-/*!
- \qmlmethod ListModel::insert(int index, jsobject dict)
-
- Adds a new item to the list model at position \a index, with the
- values in \a dict.
-
- \code
- fruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
- \endcode
-
- The \a index must be to an existing item in the list, or one past
- the end of the list (equivalent to append).
-
- \sa set(), append()
-*/
-
-void QQmlListModel::insert(QQmlV4Function *args)
-{
- if (args->length() == 2) {
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue arg0(scope, (*args)[0]);
- int index = arg0->toInt32();
-
- if (index < 0 || index > count()) {
- qmlWarning(this) << tr("insert: index %1 out of range").arg(index);
- return;
- }
-
- QV4::ScopedObject argObject(scope, (*args)[1]);
- QV4::ScopedArrayObject objectArray(scope, (*args)[1]);
- if (objectArray) {
- QV4::ScopedObject argObject(scope);
-
- int objectArrayLength = objectArray->getLength();
- emitItemsAboutToBeInserted(index, objectArrayLength);
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->get(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.insert(index+i, DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->insert(index+i, argObject);
- }
- }
- emitItemsInserted();
- } else if (argObject) {
- emitItemsAboutToBeInserted(index, 1);
-
- if (m_dynamicRoles) {
- m_modelObjects.insert(index, DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->insert(index, argObject);
- }
-
- emitItemsInserted();
- } else {
- qmlWarning(this) << tr("insert: value is not an object");
- }
- } else {
- qmlWarning(this) << tr("insert: value is not an object");
- }
-}
-
-/*!
- \qmlmethod ListModel::move(int from, int to, int n)
-
- Moves \a n items \a from one position \a to another.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the list:
-
- \code
- fruitModel.move(0, fruitModel.count - 3, 3)
- \endcode
-
- \sa append()
-*/
-void QQmlListModel::move(int from, int to, int n)
-{
- if (n == 0 || from == to)
- return;
- if (!canMove(from, to, n)) {
- qmlWarning(this) << tr("move: out of range");
- return;
- }
-
- if (m_mainThread)
- beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to);
-
- if (m_dynamicRoles) {
-
- int realFrom = from;
- int realTo = to;
- int realN = n;
-
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- realFrom = tto;
- realTo = tto+n;
- realN = tfrom-tto;
- }
-
- QPODVector<DynamicRoleModelNode *, 4> store;
- for (int i=0 ; i < (realTo-realFrom) ; ++i)
- store.append(m_modelObjects[realFrom+realN+i]);
- for (int i=0 ; i < realN ; ++i)
- store.append(m_modelObjects[realFrom+i]);
- for (int i=0 ; i < store.count() ; ++i)
- m_modelObjects[realFrom+i] = store[i];
-
- } else {
- m_listModel->move(from, to, n);
- }
-
- if (m_mainThread)
- endMoveRows();
-}
-
-/*!
- \qmlmethod ListModel::append(jsobject dict)
-
- Adds a new item to the end of the list model, with the
- values in \a dict.
-
- \code
- fruitModel.append({"cost": 5.95, "name":"Pizza"})
- \endcode
-
- \sa set(), remove()
-*/
-void QQmlListModel::append(QQmlV4Function *args)
-{
- if (args->length() == 1) {
- QV4::Scope scope(args->v4engine());
- QV4::ScopedObject argObject(scope, (*args)[0]);
- QV4::ScopedArrayObject objectArray(scope, (*args)[0]);
-
- if (objectArray) {
- QV4::ScopedObject argObject(scope);
-
- int objectArrayLength = objectArray->getLength();
- if (objectArrayLength > 0) {
- int index = count();
- emitItemsAboutToBeInserted(index, objectArrayLength);
-
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->get(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->append(argObject);
- }
- }
-
- emitItemsInserted();
- }
- } else if (argObject) {
- int index;
-
- if (m_dynamicRoles) {
- index = m_modelObjects.count();
- emitItemsAboutToBeInserted(index, 1);
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- index = m_listModel->elementCount();
- emitItemsAboutToBeInserted(index, 1);
- m_listModel->append(argObject);
- }
-
- emitItemsInserted();
- } else {
- qmlWarning(this) << tr("append: value is not an object");
- }
- } else {
- qmlWarning(this) << tr("append: value is not an object");
- }
-}
-
-/*!
- \qmlmethod object ListModel::get(int index)
-
- Returns the item at \a index in the list model. This allows the item
- data to be accessed or modified from JavaScript:
-
- \code
- Component.onCompleted: {
- fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
- console.log(fruitModel.get(0).cost);
- fruitModel.get(0).cost = 10.95;
- }
- \endcode
-
- The \a index must be an element in the list.
-
- Note that properties of the returned object that are themselves objects
- will also be models, and this get() method is used to access elements:
-
- \code
- fruitModel.append(..., "attributes":
- [{"name":"spikes","value":"7mm"},
- {"name":"color","value":"green"}]);
- fruitModel.get(0).attributes.get(1).value; // == "green"
- \endcode
-
- \warning The returned object is not guaranteed to remain valid. It
- should not be used in \l{Property Binding}{property bindings}.
-
- \sa append()
-*/
-QQmlV4Handle QQmlListModel::get(int index) const
-{
- QV4::Scope scope(engine());
- QV4::ScopedValue result(scope, QV4::Value::undefinedValue());
-
- if (index >= 0 && index < count()) {
-
- if (m_dynamicRoles) {
- DynamicRoleModelNode *object = m_modelObjects[index];
- result = QV4::QObjectWrapper::wrap(scope.engine, object);
- } else {
- QObject *object = m_listModel->getOrCreateModelObject(const_cast<QQmlListModel *>(this), index);
- QQmlData *ddata = QQmlData::get(object);
- if (ddata->jsWrapper.isNullOrUndefined()) {
- result = scope.engine->memoryManager->allocate<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this));
- // Keep track of the QObjectWrapper in persistent value storage
- ddata->jsWrapper.set(scope.engine, result);
- } else {
- result = ddata->jsWrapper.value();
- }
- }
- }
-
- return QQmlV4Handle(result);
-}
-
-/*!
- \qmlmethod ListModel::set(int index, jsobject dict)
-
- Changes the item at \a index in the list model with the
- values in \a dict. Properties not appearing in \a dict
- are left unchanged.
-
- \code
- fruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
- \endcode
-
- If \a index is equal to count() then a new item is appended to the
- list. Otherwise, \a index must be an element in the list.
-
- \sa append()
-*/
-void QQmlListModel::set(int index, const QQmlV4Handle &handle)
-{
- QV4::Scope scope(engine());
- QV4::ScopedObject object(scope, handle);
-
- if (!object) {
- qmlWarning(this) << tr("set: value is not an object");
- return;
- }
- if (index > count() || index < 0) {
- qmlWarning(this) << tr("set: index %1 out of range").arg(index);
- return;
- }
-
-
- if (index == count()) {
- emitItemsAboutToBeInserted(index, 1);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(object), this));
- } else {
- m_listModel->insert(index, object);
- }
-
- emitItemsInserted();
- } else {
-
- QVector<int> roles;
-
- if (m_dynamicRoles) {
- m_modelObjects[index]->updateValues(scope.engine->variantMapFromJS(object), roles);
- } else {
- m_listModel->set(index, object, &roles);
- }
-
- if (roles.count())
- emitItemsChanged(index, 1, roles);
- }
-}
-
-/*!
- \qmlmethod ListModel::setProperty(int index, string property, variant value)
-
- Changes the \a property of the item at \a index in the list model to \a value.
-
- \code
- fruitModel.setProperty(3, "cost", 5.95)
- \endcode
-
- The \a index must be an element in the list.
-
- \sa append()
-*/
-void QQmlListModel::setProperty(int index, const QString& property, const QVariant& value)
-{
- if (count() == 0 || index >= count() || index < 0) {
- qmlWarning(this) << tr("set: index %1 out of range").arg(index);
- return;
- }
-
- if (m_dynamicRoles) {
- int roleIndex = m_roles.indexOf(property);
- if (roleIndex == -1) {
- roleIndex = m_roles.count();
- m_roles.append(property);
- }
- if (m_modelObjects[index]->setValue(property.toUtf8(), value))
- emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
- } else {
- int roleIndex = m_listModel->setOrCreateProperty(index, property, value);
- if (roleIndex != -1)
- emitItemsChanged(index, 1, QVector<int>(1, roleIndex));
- }
-}
-
-/*!
- \qmlmethod ListModel::sync()
-
- Writes any unsaved changes to the list model after it has been modified
- from a worker script.
-*/
-void QQmlListModel::sync()
-{
- // This is just a dummy method to make it look like sync() exists in
- // ListModel (and not just QQmlListModelWorkerAgent) and to let
- // us document sync().
- qmlWarning(this) << "List sync() can only be called from a WorkerScript";
-}
-
-bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
-{
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- const quint32 targetObjectIndex = binding->value.objectIndex;
- const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
- QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex);
- if (objName != listElementTypeName) {
- const QMetaObject *mo = resolveType(objName);
- if (mo != &QQmlListElement::staticMetaObject) {
- error(target, QQmlListModel::tr("ListElement: cannot contain nested elements"));
- return false;
- }
- listElementTypeName = objName; // cache right name for next time
- }
-
- if (!compilationUnit->stringAt(target->idNameIndex).isEmpty()) {
- error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
- return false;
- }
-
- const QV4::CompiledData::Binding *binding = target->bindingTable();
- for (quint32 i = 0; i < target->nBindings; ++i, ++binding) {
- QString propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (propName.isEmpty()) {
- error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements"));
- return false;
- }
- if (!verifyProperty(compilationUnit, binding))
- return false;
- }
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QString scriptStr = binding->valueAsScriptString(compilationUnit.data());
- if (!binding->isFunctionExpression() && !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;
- }
- }
- }
-
- return true;
-}
-
-bool QQmlListModelParser::applyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex)
-{
- const QString elementName = compilationUnit->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 = compilationUnit->objectAt(targetObjectIndex);
-
- ListModel *subModel = nullptr;
- 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 == nullptr) {
- subModel = new ListModel(role.subLayout, nullptr);
- QVariant vModel = QVariant::fromValue(subModel);
- model->setOrCreateProperty(outterElementIndex, elementName, vModel);
- }
- }
- }
-
- int elementIndex = subModel ? subModel->appendElement() : -1;
-
- const QV4::CompiledData::Binding *subBinding = target->bindingTable();
- for (quint32 i = 0; i < target->nBindings; ++i, ++subBinding) {
- roleSet |= applyProperty(compilationUnit, subBinding, subModel, elementIndex);
- }
-
- } else {
- QVariant value;
-
- if (binding->isTranslationBinding()) {
- value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
- } else if (binding->evaluatesToString()) {
- value = binding->valueAsString(compilationUnit.data());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- value = binding->valueAsNumber(compilationUnit->constants);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
- value = binding->valueAsBoolean();
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- value = QVariant::fromValue(nullptr);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QString scriptStr = binding->valueAsScriptString(compilationUnit.data());
- if (definesEmptyList(scriptStr)) {
- const ListLayout::Role &role = model->getOrCreateListRole(elementName);
- ListModel *emptyModel = new ListModel(role.subLayout, nullptr);
- value = QVariant::fromValue(emptyModel);
- } else if (binding->isFunctionExpression()) {
- QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
- Q_ASSERT(id != QQmlBinding::Invalid);
-
- auto v4 = compilationUnit->engine;
- QV4::Scope scope(v4);
- // for now we do not provide a context object; data from the ListElement must be passed to the function
- QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr));
- QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id]));
-
- QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0);
-
- QJSValue v;
- QJSValuePrivate::setValue(&v, v4, result);
- value.setValue<QJSValue>(v);
- } else {
- QByteArray script = scriptStr.toUtf8();
- bool ok;
- value = evaluateEnum(script, &ok);
- }
- } else {
- Q_UNREACHABLE();
- }
-
- model->setOrCreateProperty(outterElementIndex, elementName, value);
- roleSet = true;
- }
- return roleSet;
-}
-
-void QQmlListModelParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- listElementTypeName = QString(); // unknown
-
- for (const QV4::CompiledData::Binding *binding : bindings) {
- QString propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (!propName.isEmpty()) { // isn't default property
- error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName));
- return;
- }
- if (!verifyProperty(compilationUnit, binding))
- return;
- }
-}
-
-void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
-{
- QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
-
- rv->m_engine = qmlEngine(rv)->handle();
- rv->m_compilationUnit = compilationUnit;
-
- bool setRoles = false;
-
- for (const QV4::CompiledData::Binding *binding : bindings) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1);
- }
-
- if (setRoles == false)
- qmlWarning(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set.";
-}
-
-bool QQmlListModelParser::definesEmptyList(const QString &s)
-{
- if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
- for (int i=1; i<s.length()-1; i++) {
- if (!s[i].isSpace())
- return false;
- }
- return true;
- }
- return false;
-}
-
-
-/*!
- \qmltype ListElement
- \instantiates QQmlListElement
- \inqmlmodule QtQml.Models
- \brief Defines a data item in a ListModel.
- \ingroup qtquick-models
-
- List elements are defined inside ListModel definitions, and represent items in a
- list that will be displayed using ListView or \l Repeater items.
-
- List elements are defined like other QML elements except that they contain
- a collection of \e role definitions instead of properties. Using the same
- syntax as property definitions, roles both define how the data is accessed
- and include the data itself.
-
- The names used for roles must begin with a lower-case letter and should be
- common to all elements in a given model. Values must be simple constants; either
- strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
- (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
-
- Beginning with Qt 5.11 ListElement also allows assigning a function declaration to
- a role. This allows the definition of ListElements with callable actions.
-
- \section1 Referencing Roles
-
- The role names are used by delegates to obtain data from list elements.
- Each role name is accessible in the delegate's scope, and refers to the
- corresponding role in the current element. Where a role name would be
- ambiguous to use, it can be accessed via the \l{ListView::}{model}
- property (e.g., \c{model.cost} instead of \c{cost}).
-
- \section1 Example Usage
-
- The following model defines a series of list elements, each of which
- contain "name" and "cost" roles and their associated values.
-
- \snippet qml/listmodel/listelements.qml model
-
- The delegate obtains the name and cost for each element by simply referring
- to \c name and \c cost:
-
- \snippet qml/listmodel/listelements.qml view
-
- \sa ListModel
-*/
-
-QT_END_NAMESPACE
-
-#include "moc_qqmllistmodel_p.cpp"
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
deleted file mode 100644
index 95b797c898..0000000000
--- a/src/qml/types/qqmllistmodel_p.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTMODEL_H
-#define QQMLLISTMODEL_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 <qqml.h>
-#include <private/qqmlcustomparser_p.h>
-
-#include <QtCore/QObject>
-#include <QtCore/QStringList>
-#include <QtCore/QHash>
-#include <QtCore/QList>
-#include <QtCore/QVariant>
-#include <QtCore/qabstractitemmodel.h>
-
-#include <private/qv4engine_p.h>
-#include <private/qpodvector_p.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class QQmlListModelWorkerAgent;
-class ListModel;
-class ListLayout;
-
-namespace QV4 {
-struct ModelObject;
-}
-
-class Q_QML_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
-
-public:
- QQmlListModel(QObject *parent=nullptr);
- ~QQmlListModel();
-
- QModelIndex index(int row, int column, const QModelIndex &parent) const override;
- int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- QHash<int,QByteArray> roleNames() const override;
-
- QVariant data(int index, int role) const;
- int count() const;
-
- Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QQmlV4Handle get(int index) const;
- Q_INVOKABLE void set(int index, const QQmlV4Handle &);
- Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
- Q_INVOKABLE void move(int from, int to, int count);
- Q_INVOKABLE void sync();
-
- QQmlListModelWorkerAgent *agent();
-
- bool dynamicRoles() const { return m_dynamicRoles; }
- void setDynamicRoles(bool enableDynamicRoles);
-
-Q_SIGNALS:
- void countChanged();
-
-private:
- friend class QQmlListModelParser;
- friend class QQmlListModelWorkerAgent;
- friend class ModelObject;
- friend struct QV4::ModelObject;
- friend class ModelNodeMetaObject;
- friend class ListModel;
- friend class ListElement;
- friend class DynamicRoleModelNode;
- friend class DynamicRoleModelNodeMetaObject;
- friend struct StringOrTranslation;
-
- // Constructs a flat list model for a worker agent
- QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent);
- QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::ExecutionEngine *engine, QObject *parent=nullptr);
-
- QV4::ExecutionEngine *engine() const;
-
- inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
-
- QQmlListModelWorkerAgent *m_agent;
- mutable QV4::ExecutionEngine *m_engine;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
- bool m_mainThread;
- bool m_primary;
-
- bool m_dynamicRoles;
-
- ListLayout *m_layout;
- ListModel *m_listModel;
-
- QVector<class DynamicRoleModelNode *> m_modelObjects;
- QVector<QString> m_roles;
-
- struct ElementSync
- {
- DynamicRoleModelNode *src = nullptr;
- DynamicRoleModelNode *target = nullptr;
- int srcIndex = -1;
- int targetIndex = -1;
- QVector<int> changedRoles;
- };
-
- static bool sync(QQmlListModel *src, QQmlListModel *target);
- static QQmlListModel *createWithOwner(QQmlListModel *newOwner);
-
- void emitItemsChanged(int index, int count, const QVector<int> &roles);
- void emitItemsAboutToBeInserted(int index, int count);
- void emitItemsInserted();
-
- void removeElements(int index, int removeCount);
-};
-
-// ### FIXME
-class QQmlListElement : public QObject
-{
-Q_OBJECT
-};
-
-class QQmlListModelParser : public QQmlCustomParser
-{
-public:
- enum PropertyType {
- Invalid,
- Boolean,
- Number,
- String,
- Script
- };
-
-
- QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
-
- void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
- void applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
-
-private:
- bool verifyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding);
- // returns true if a role was set
- bool applyProperty(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex);
-
- static bool definesEmptyList(const QString &);
-
- QString listElementTypeName;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlListModel)
-QML_DECLARE_TYPE(QQmlListElement)
-
-#endif // QQMLLISTMODEL_H
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
deleted file mode 100644
index 2876c71de6..0000000000
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTMODEL_P_P_H
-#define QQMLLISTMODEL_P_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 "qqmllistmodel_p.h"
-#include <private/qqmlengine_p.h>
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <qqml.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class DynamicRoleModelNode;
-
-class DynamicRoleModelNodeMetaObject : public QQmlOpenMetaObject
-{
-public:
- DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object);
- ~DynamicRoleModelNodeMetaObject();
-
- bool m_enabled;
-
-protected:
- void propertyWrite(int index) override;
- void propertyWritten(int index) override;
-
-private:
- DynamicRoleModelNode *m_owner;
-};
-
-class DynamicRoleModelNode : public QObject
-{
- Q_OBJECT
-public:
- DynamicRoleModelNode(QQmlListModel *owner, int uid);
-
- static DynamicRoleModelNode *create(const QVariantMap &obj, QQmlListModel *owner);
-
- void updateValues(const QVariantMap &object, QVector<int> &roles);
-
- QVariant getValue(const QString &name) const
- {
- return m_meta->value(name.toUtf8());
- }
-
- bool setValue(const QByteArray &name, const QVariant &val)
- {
- return m_meta->setValue(name, val);
- }
-
- void setNodeUpdatesEnabled(bool enable)
- {
- m_meta->m_enabled = enable;
- }
-
- int getUid() const
- {
- return m_uid;
- }
-
- static QVector<int> sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target);
-
-private:
- QQmlListModel *m_owner;
- int m_uid;
- DynamicRoleModelNodeMetaObject *m_meta;
-
- friend class DynamicRoleModelNodeMetaObject;
-};
-
-class ModelNodeMetaObject : public QQmlOpenMetaObject
-{
-public:
- ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex);
- ~ModelNodeMetaObject();
-
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *object) override;
-
- static ModelNodeMetaObject *get(QObject *obj);
-
- bool m_enabled;
- QQmlListModel *m_model;
- int m_elementIndex;
-
- void updateValues();
- void updateValues(const QVector<int> &roles);
-
- bool initialized() const { return m_initialized; }
-
-protected:
- void propertyWritten(int index) override;
-
-private:
- using QQmlOpenMetaObject::setValue;
-
- void emitDirectNotifies(const int *changedRoles, int roleCount);
-
- void initialize();
- bool m_initialized;
-};
-
-namespace QV4 {
-
-namespace Heap {
-
-struct ModelObject : public QObjectWrapper {
- void init(QObject *object, QQmlListModel *model)
- {
- QObjectWrapper::init(object);
- m_model = model;
- QObjectPrivate *op = QObjectPrivate::get(object);
- m_nodeModelMetaObject = static_cast<ModelNodeMetaObject *>(op->metaObject);
- }
- void destroy() { QObjectWrapper::destroy(); }
- int elementIndex() const { return m_nodeModelMetaObject->m_elementIndex; }
- QQmlListModel *m_model;
- ModelNodeMetaObject *m_nodeModelMetaObject;
-};
-
-}
-
-struct ModelObject : public QObjectWrapper
-{
- V4_OBJECT2(ModelObject, QObjectWrapper)
- V4_NEEDS_DESTROY
-
- ListModel *listModel() const { return d()->m_model->m_listModel; }
-
-protected:
- static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
- static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
- static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
- static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
-};
-
-} // namespace QV4
-
-class ListLayout
-{
-public:
- ListLayout() : currentBlock(0), currentBlockOffset(0) {}
- ListLayout(const ListLayout *other);
- ~ListLayout();
-
- class Role
- {
- public:
-
- Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {}
- explicit Role(const Role *other);
- ~Role();
-
- // This enum must be kept in sync with the roleTypeNames variable in qqmllistmodel.cpp
- enum DataType
- {
- Invalid = -1,
-
- String,
- Number,
- Bool,
- List,
- QObject,
- VariantMap,
- DateTime,
- Function,
-
- MaxDataType
- };
-
- QString name;
- DataType type;
- int blockIndex;
- int blockOffset;
- int index;
- ListLayout *subLayout;
- };
-
- const Role *getRoleOrCreate(const QString &key, const QVariant &data);
- const Role &getRoleOrCreate(QV4::String *key, Role::DataType type);
- const Role &getRoleOrCreate(const QString &key, Role::DataType type);
-
- const Role &getExistingRole(int index) const { return *roles.at(index); }
- const Role *getExistingRole(const QString &key) const;
- const Role *getExistingRole(QV4::String *key) const;
-
- int roleCount() const { return roles.count(); }
-
- static void sync(ListLayout *src, ListLayout *target);
-
-private:
- const Role &createRole(const QString &key, Role::DataType type);
-
- int currentBlock;
- int currentBlockOffset;
- QVector<Role *> roles;
- QStringHash<Role *> roleHash;
-};
-
-struct StringOrTranslation
-{
- explicit StringOrTranslation(const QString &s);
- explicit StringOrTranslation(const QV4::CompiledData::Binding *binding);
- ~StringOrTranslation();
- bool isSet() const { return d.flag(); }
- bool isTranslation() const { return d.isT2(); }
- void setString(const QString &s);
- void setTranslation(const QV4::CompiledData::Binding *binding);
- QString toString(const QQmlListModel *owner) const;
- QString asString() const;
-private:
- void clear();
- QBiPointer<QStringData, const QV4::CompiledData::Binding> d;
-};
-
-/*!
-\internal
-*/
-class ListElement
-{
-public:
-
- ListElement();
- ListElement(int existingUid);
- ~ListElement();
-
- static QVector<int> sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout);
-
- enum
- {
- BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelNodeMetaObject *)
- };
-
-private:
-
- void destroy(ListLayout *layout);
-
- int setVariantProperty(const ListLayout::Role &role, const QVariant &d);
-
- int setJsProperty(const ListLayout::Role &role, const QV4::Value &d, QV4::ExecutionEngine *eng);
-
- int setStringProperty(const ListLayout::Role &role, const QString &s);
- int setDoubleProperty(const ListLayout::Role &role, double n);
- 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::Object *o);
- int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
- int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
- int setFunctionProperty(const ListLayout::Role &role, const QJSValue &f);
- int setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b);
-
- void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
- void setDoublePropertyFast(const ListLayout::Role &role, double n);
- 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::Object *o);
- void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
- void setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f);
-
- void clearProperty(const ListLayout::Role &role);
-
- QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
- ListModel *getListProperty(const ListLayout::Role &role);
- StringOrTranslation *getStringProperty(const ListLayout::Role &role);
- QObject *getQObjectProperty(const ListLayout::Role &role);
- QPointer<QObject> *getGuardProperty(const ListLayout::Role &role);
- QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
- QDateTime *getDateTimeProperty(const ListLayout::Role &role);
- QJSValue *getFunctionProperty(const ListLayout::Role &role);
-
- inline char *getPropertyMemory(const ListLayout::Role &role);
-
- int getUid() const { return uid; }
-
- ModelNodeMetaObject *objectCache();
-
- char data[BLOCK_SIZE];
- ListElement *next;
-
- int uid;
- QObject *m_objectCache;
-
- friend class ListModel;
-};
-
-/*!
-\internal
-*/
-class ListModel
-{
-public:
-
- ListModel(ListLayout *layout, QQmlListModel *modelCache);
- ~ListModel() {}
-
- void destroy();
-
- int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data);
- int setExistingProperty(int uid, const QString &key, const QV4::Value &data, QV4::ExecutionEngine *eng);
-
- QVariant getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
- ListModel *getListProperty(int elementIndex, const ListLayout::Role &role);
-
- int roleCount() const
- {
- return m_layout->roleCount();
- }
-
- const ListLayout::Role &getExistingRole(int index) const
- {
- return m_layout->getExistingRole(index);
- }
-
- const ListLayout::Role *getExistingRole(QV4::String *key) const
- {
- return m_layout->getExistingRole(key);
- }
-
- const ListLayout::Role &getOrCreateListRole(const QString &name)
- {
- return m_layout->getRoleOrCreate(name, ListLayout::Role::List);
- }
-
- int elementCount() const
- {
- return elements.count();
- }
-
- void set(int elementIndex, QV4::Object *object, QVector<int> *roles);
- void set(int elementIndex, QV4::Object *object);
-
- int append(QV4::Object *object);
- void insert(int elementIndex, QV4::Object *object);
-
- Q_REQUIRED_RESULT QVector<std::function<void()>> remove(int index, int count);
-
- int appendElement();
- void insertElement(int index);
-
- void move(int from, int to, int n);
-
- static bool sync(ListModel *src, ListModel *target);
-
- QObject *getOrCreateModelObject(QQmlListModel *model, int elementIndex);
-
-private:
- QPODVector<ListElement *, 4> elements;
- ListLayout *m_layout;
-
- QQmlListModel *m_modelCache;
-
- struct ElementSync
- {
- ListElement *src = nullptr;
- ListElement *target = nullptr;
- int srcIndex = -1;
- int targetIndex = -1;
- QVector<int> changedRoles;
- };
-
- void newElement(int index);
-
- void updateCacheIndices(int start = 0, int end = -1);
-
- friend class ListElement;
- friend class QQmlListModelWorkerAgent;
- friend class QQmlListModelParser;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(ListModel *);
-
-#endif // QQUICKLISTMODEL_P_P_H
diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qml/types/qqmllistmodelworkeragent.cpp
deleted file mode 100644
index fe3eaa3198..0000000000
--- a/src/qml/types/qqmllistmodelworkeragent.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistmodelworkeragent_p.h"
-#include "qqmllistmodel_p_p.h"
-#include <private/qqmldata_p.h>
-#include <private/qqmlengine_p.h>
-#include <qqmlinfo.h>
-
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-
-
-QT_BEGIN_NAMESPACE
-
-QQmlListModelWorkerAgent::Sync::~Sync()
-{
-}
-
-QQmlListModelWorkerAgent::QQmlListModelWorkerAgent(QQmlListModel *model)
-: m_ref(1), m_orig(model), m_copy(new QQmlListModel(model, this))
-{
-}
-
-QQmlListModelWorkerAgent::~QQmlListModelWorkerAgent()
-{
- mutex.lock();
- syncDone.wakeAll();
- mutex.unlock();
-}
-
-void QQmlListModelWorkerAgent::setEngine(QV4::ExecutionEngine *eng)
-{
- m_copy->m_engine = eng;
-}
-
-void QQmlListModelWorkerAgent::addref()
-{
- m_ref.ref();
-}
-
-void QQmlListModelWorkerAgent::release()
-{
- bool del = !m_ref.deref();
-
- if (del)
- deleteLater();
-}
-
-void QQmlListModelWorkerAgent::modelDestroyed()
-{
- m_orig = nullptr;
-}
-
-int QQmlListModelWorkerAgent::count() const
-{
- return m_copy->count();
-}
-
-void QQmlListModelWorkerAgent::clear()
-{
- m_copy->clear();
-}
-
-void QQmlListModelWorkerAgent::remove(QQmlV4Function *args)
-{
- m_copy->remove(args);
-}
-
-void QQmlListModelWorkerAgent::append(QQmlV4Function *args)
-{
- m_copy->append(args);
-}
-
-void QQmlListModelWorkerAgent::insert(QQmlV4Function *args)
-{
- m_copy->insert(args);
-}
-
-QQmlV4Handle QQmlListModelWorkerAgent::get(int index) const
-{
- return m_copy->get(index);
-}
-
-void QQmlListModelWorkerAgent::set(int index, const QQmlV4Handle &value)
-{
- m_copy->set(index, value);
-}
-
-void QQmlListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
-{
- m_copy->setProperty(index, property, value);
-}
-
-void QQmlListModelWorkerAgent::move(int from, int to, int count)
-{
- m_copy->move(from, to, count);
-}
-
-void QQmlListModelWorkerAgent::sync()
-{
- Sync *s = new Sync(m_copy);
-
- mutex.lock();
- QCoreApplication::postEvent(this, s);
- syncDone.wait(&mutex);
- mutex.unlock();
-}
-
-bool QQmlListModelWorkerAgent::event(QEvent *e)
-{
- if (e->type() == QEvent::User) {
- bool cc = false;
- QMutexLocker locker(&mutex);
- if (m_orig) {
- Sync *s = static_cast<Sync *>(e);
-
- cc = (m_orig->count() != s->list->count());
-
- Q_ASSERT(m_orig->m_dynamicRoles == s->list->m_dynamicRoles);
- if (m_orig->m_dynamicRoles)
- QQmlListModel::sync(s->list, m_orig);
- else
- ListModel::sync(s->list->m_listModel, m_orig->m_listModel);
- }
-
- syncDone.wakeAll();
- locker.unlock();
-
- if (cc)
- emit m_orig->countChanged();
- return true;
- }
-
- return QObject::event(e);
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmllistmodelworkeragent_p.cpp"
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
deleted file mode 100644
index ae2d4b11e0..0000000000
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKLISTMODELWORKERAGENT_P_H
-#define QQUICKLISTMODELWORKERAGENT_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 <qqml.h>
-
-#include <QEvent>
-#include <QMutex>
-#include <QWaitCondition>
-
-#include <private/qv8engine_p.h>
-
-QT_REQUIRE_CONFIG(qml_list_model);
-
-QT_BEGIN_NAMESPACE
-
-
-class QQmlListModel;
-
-class QQmlListModelWorkerAgent : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count)
-
-public:
- QQmlListModelWorkerAgent(QQmlListModel *);
- ~QQmlListModelWorkerAgent();
- void setEngine(QV4::ExecutionEngine *eng);
-
- void addref();
- void release();
-
- int count() const;
-
- Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QQmlV4Handle get(int index) const;
- Q_INVOKABLE void set(int index, const QQmlV4Handle &);
- Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
- Q_INVOKABLE void move(int from, int to, int count);
- Q_INVOKABLE void sync();
-
- struct VariantRef
- {
- VariantRef() : a(nullptr) {}
- VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
- VariantRef(QQmlListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
- ~VariantRef() { if (a) a->release(); }
-
- VariantRef &operator=(const VariantRef &o) {
- if (o.a) o.a->addref();
- if (a) a->release();
- a = o.a;
- return *this;
- }
-
- QQmlListModelWorkerAgent *a;
- };
-
- void modelDestroyed();
-protected:
- bool event(QEvent *) override;
-
-private:
- friend class QQuickWorkerScriptEnginePrivate;
- friend class QQmlListModel;
-
- struct Sync : public QEvent {
- Sync(QQmlListModel *l)
- : QEvent(QEvent::User)
- , list(l)
- {}
- ~Sync();
- QQmlListModel *list;
- };
-
- QAtomicInt m_ref;
- QQmlListModel *m_orig;
- QQmlListModel *m_copy;
- QMutex mutex;
- QWaitCondition syncDone;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QQmlListModelWorkerAgent::VariantRef)
-
-#endif // QQUICKLISTMODELWORKERAGENT_P_H
-
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
deleted file mode 100644
index bb72771cd9..0000000000
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlmodelsmodule_p.h"
-#include <QtCore/qitemselectionmodel.h>
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#endif
-#if QT_CONFIG(qml_delegate_model)
-#include <private/qqmldelegatemodel_p.h>
-#include <private/qqmldelegatecomponent_p.h>
-#endif
-#include <private/qqmlobjectmodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-void QQmlModelsModule::defineModule()
-{
- const char uri[] = "QtQml.Models";
-
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
-#endif
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
-#endif
- qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
- qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
-
- qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
-}
-
-void QQmlModelsModule::defineLabsModule()
-{
- const char uri[] = "Qt.labs.qmlmodels";
-
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterUncreatableType<QQmlAbstractDelegateComponent>(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent."));
- qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
- qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
-#endif
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
deleted file mode 100644
index 525920c6e0..0000000000
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlobjectmodel_p.h"
-
-#include <QtCore/qcoreapplication.h>
-#include <QtQml/qqmlcontext.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlinfo.h>
-
-#include <private/qqmlchangeset_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qobject_p.h>
-#include <private/qpodvector_p.h>
-
-#include <QtCore/qhash.h>
-#include <QtCore/qlist.h>
-
-QT_BEGIN_NAMESPACE
-
-QHash<QObject*, QQmlObjectModelAttached*> QQmlObjectModelAttached::attachedProperties;
-
-
-class QQmlObjectModelPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QQmlObjectModel)
-public:
- class Item {
- public:
- Item(QObject *i) : item(i), ref(0) {}
-
- void addRef() { ++ref; }
- bool deref() { return --ref == 0; }
-
- QObject *item;
- int ref;
- };
-
- QQmlObjectModelPrivate() : QObjectPrivate(), moveId(0) {}
-
- static void children_append(QQmlListProperty<QObject> *prop, QObject *item) {
- int index = static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count();
- static_cast<QQmlObjectModelPrivate *>(prop->data)->insert(index, item);
- }
-
- static int children_count(QQmlListProperty<QObject> *prop) {
- return static_cast<QQmlObjectModelPrivate *>(prop->data)->children.count();
- }
-
- static QObject *children_at(QQmlListProperty<QObject> *prop, int index) {
- return static_cast<QQmlObjectModelPrivate *>(prop->data)->children.at(index).item;
- }
-
- static void children_clear(QQmlListProperty<QObject> *prop) {
- static_cast<QQmlObjectModelPrivate *>(prop->data)->clear();
- }
-
- void insert(int index, QObject *item) {
- Q_Q(QQmlObjectModel);
- children.insert(index, Item(item));
- for (int i = index; i < children.count(); ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(i);
- }
- QQmlChangeSet changeSet;
- changeSet.insert(index, 1);
- emit q->modelUpdated(changeSet, false);
- emit q->countChanged();
- emit q->childrenChanged();
- }
-
- void move(int from, int to, int n) {
- Q_Q(QQmlObjectModel);
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- from = tto;
- to = tto+n;
- n = tfrom-tto;
- }
-
- QPODVector<QQmlObjectModelPrivate::Item, 4> store;
- for (int i = 0; i < to - from; ++i)
- store.append(children[from + n + i]);
- for (int i = 0; i < n; ++i)
- store.append(children[from + i]);
-
- for (int i = 0; i < store.count(); ++i) {
- children[from + i] = store[i];
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(from + i).item);
- attached->setIndex(from + i);
- }
-
- QQmlChangeSet changeSet;
- changeSet.move(from, to, n, ++moveId);
- emit q->modelUpdated(changeSet, false);
- emit q->childrenChanged();
- }
-
- void remove(int index, int n) {
- Q_Q(QQmlObjectModel);
- for (int i = index; i < index + n; ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(-1);
- }
- children.erase(children.begin() + index, children.begin() + index + n);
- for (int i = index; i < children.count(); ++i) {
- QQmlObjectModelAttached *attached = QQmlObjectModelAttached::properties(children.at(i).item);
- attached->setIndex(i);
- }
- QQmlChangeSet changeSet;
- changeSet.remove(index, n);
- emit q->modelUpdated(changeSet, false);
- emit q->countChanged();
- emit q->childrenChanged();
- }
-
- void clear() {
- Q_Q(QQmlObjectModel);
- for (const Item &child : qAsConst(children))
- emit q->destroyingItem(child.item);
- remove(0, children.count());
- }
-
- int indexOf(QObject *item) const {
- for (int i = 0; i < children.count(); ++i)
- if (children.at(i).item == item)
- return i;
- return -1;
- }
-
- uint moveId;
- QList<Item> children;
-};
-
-
-/*!
- \qmltype ObjectModel
- \instantiates QQmlObjectModel
- \inqmlmodule QtQml.Models
- \ingroup qtquick-models
- \brief Defines a set of items to be used as a model.
-
- An ObjectModel contains the visual items to be used in a view.
- When an ObjectModel is used in a view, the view does not require
- a delegate since the ObjectModel already contains the visual
- delegate (items).
-
- An item can determine its index within the
- model via the \l{ObjectModel::index}{index} attached property.
-
- The example below places three colored rectangles in a ListView.
- \code
- import QtQuick 2.0
- import QtQml.Models 2.1
-
- Rectangle {
- ObjectModel {
- id: itemModel
- Rectangle { height: 30; width: 80; color: "red" }
- Rectangle { height: 30; width: 80; color: "green" }
- Rectangle { height: 30; width: 80; color: "blue" }
- }
-
- ListView {
- anchors.fill: parent
- model: itemModel
- }
- }
- \endcode
-
- \image objectmodel.png
-
- \sa {Qt Quick Examples - Views}
-*/
-
-QQmlObjectModel::QQmlObjectModel(QObject *parent)
- : QQmlInstanceModel(*(new QQmlObjectModelPrivate), parent)
-{
-}
-
-/*!
- \qmlattachedproperty int QtQml.Models::ObjectModel::index
- This attached property holds the index of this delegate's item within the model.
-
- It is attached to each instance of the delegate.
-*/
-
-QQmlListProperty<QObject> QQmlObjectModel::children()
-{
- Q_D(QQmlObjectModel);
- return QQmlListProperty<QObject>(this,
- d,
- d->children_append,
- d->children_count,
- d->children_at,
- d->children_clear);
-}
-
-/*!
- \qmlproperty int QtQml.Models::ObjectModel::count
-
- The number of items in the model. This property is readonly.
-*/
-int QQmlObjectModel::count() const
-{
- Q_D(const QQmlObjectModel);
- return d->children.count();
-}
-
-bool QQmlObjectModel::isValid() const
-{
- return true;
-}
-
-QObject *QQmlObjectModel::object(int index, QQmlIncubator::IncubationMode)
-{
- Q_D(QQmlObjectModel);
- QQmlObjectModelPrivate::Item &item = d->children[index];
- item.addRef();
- if (item.ref == 1) {
- emit initItem(index, item.item);
- emit createdItem(index, item.item);
- }
- return item.item;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
-{
- Q_D(QQmlObjectModel);
- int idx = d->indexOf(item);
- if (idx >= 0) {
- if (!d->children[idx].deref())
- return QQmlInstanceModel::Referenced;
- }
- return nullptr;
-}
-
-QString QQmlObjectModel::stringValue(int index, const QString &name)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || index >= d->children.count())
- return QString();
- return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString();
-}
-
-QQmlIncubator::Status QQmlObjectModel::incubationStatus(int)
-{
- return QQmlIncubator::Ready;
-}
-
-int QQmlObjectModel::indexOf(QObject *item, QObject *) const
-{
- Q_D(const QQmlObjectModel);
- return d->indexOf(item);
-}
-
-QQmlObjectModelAttached *QQmlObjectModel::qmlAttachedProperties(QObject *obj)
-{
- return QQmlObjectModelAttached::properties(obj);
-}
-
-/*!
- \qmlmethod object QtQml.Models::ObjectModel::get(int index)
- \since 5.6
-
- Returns the item at \a index in the model. This allows the item
- to be accessed or modified from JavaScript:
-
- \code
- Component.onCompleted: {
- objectModel.append(objectComponent.createObject())
- console.log(objectModel.get(0).objectName);
- objectModel.get(0).objectName = "first";
- }
- \endcode
-
- The \a index must be an element in the list.
-
- \sa append()
-*/
-QObject *QQmlObjectModel::get(int index) const
-{
- Q_D(const QQmlObjectModel);
- if (index < 0 || index >= d->children.count())
- return nullptr;
- return d->children.at(index).item;
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::append(object item)
- \since 5.6
-
- Appends a new \a item to the end of the model.
-
- \code
- objectModel.append(objectComponent.createObject())
- \endcode
-
- \sa insert(), remove()
-*/
-void QQmlObjectModel::append(QObject *object)
-{
- Q_D(QQmlObjectModel);
- d->insert(count(), object);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::insert(int index, object item)
- \since 5.6
-
- Inserts a new \a item to the model at position \a index.
-
- \code
- objectModel.insert(2, objectComponent.createObject())
- \endcode
-
- The \a index must be to an existing item in the list, or one past
- the end of the list (equivalent to append).
-
- \sa append(), remove()
-*/
-void QQmlObjectModel::insert(int index, QObject *object)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || index > count()) {
- qmlWarning(this) << tr("insert: index %1 out of range").arg(index);
- return;
- }
- d->insert(index, object);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::move(int from, int to, int n = 1)
- \since 5.6
-
- Moves \e n items \a from one position \a to another.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the model:
-
- \code
- objectModel.move(0, objectModel.count - 3, 3)
- \endcode
-
- \sa append()
-*/
-void QQmlObjectModel::move(int from, int to, int n)
-{
- Q_D(QQmlObjectModel);
- if (n <= 0 || from == to)
- return;
- if (from < 0 || to < 0 || from + n > count() || to + n > count()) {
- qmlWarning(this) << tr("move: out of range");
- return;
- }
- d->move(from, to, n);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::remove(int index, int n = 1)
- \since 5.6
-
- Removes \e n items at \a index from the model.
-
- \sa clear()
-*/
-void QQmlObjectModel::remove(int index, int n)
-{
- Q_D(QQmlObjectModel);
- if (index < 0 || n <= 0 || index + n > count()) {
- qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count());
- return;
- }
- d->remove(index, n);
-}
-
-/*!
- \qmlmethod QtQml.Models::ObjectModel::clear()
- \since 5.6
-
- Clears all items from the model.
-
- \sa append(), remove()
-*/
-void QQmlObjectModel::clear()
-{
- Q_D(QQmlObjectModel);
- d->clear();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlobjectmodel_p.cpp"
diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h
deleted file mode 100644
index 4ac4f1c65b..0000000000
--- a/src/qml/types/qqmlobjectmodel_p.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLINSTANCEMODEL_P_H
-#define QQMLINSTANCEMODEL_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmlincubator_p.h>
-#include <QtQml/qqml.h>
-#include <QtCore/qobject.h>
-
-QT_BEGIN_NAMESPACE
-
-class QObject;
-class QQmlChangeSet;
-class QAbstractItemModel;
-
-class Q_QML_PRIVATE_EXPORT QQmlInstanceModel : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(int count READ count NOTIFY countChanged)
-
-public:
- virtual ~QQmlInstanceModel() {}
-
- enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
- Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
-
- virtual int count() const = 0;
- virtual bool isValid() const = 0;
- virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0;
- virtual ReleaseFlags release(QObject *object) = 0;
- virtual void cancel(int) {}
- virtual QString stringValue(int, const QString &) = 0;
- virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0;
- virtual QQmlIncubator::Status incubationStatus(int index) = 0;
-
- virtual int indexOf(QObject *object, QObject *objectContext) const = 0;
- virtual const QAbstractItemModel *abstractItemModel() const { return nullptr; }
-
-Q_SIGNALS:
- void countChanged();
- void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
- void createdItem(int index, QObject *object);
- void initItem(int index, QObject *object);
- void destroyingItem(QObject *object);
-
-protected:
- QQmlInstanceModel(QObjectPrivate &dd, QObject *parent = nullptr)
- : QObject(dd, parent) {}
-
-private:
- Q_DISABLE_COPY(QQmlInstanceModel)
-};
-
-class QQmlObjectModelAttached;
-class QQmlObjectModelPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QQmlObjectModel)
-
- Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged DESIGNABLE false)
- Q_CLASSINFO("DefaultProperty", "children")
-
-public:
- QQmlObjectModel(QObject *parent=nullptr);
- ~QQmlObjectModel() {}
-
- int count() const override;
- bool isValid() const override;
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
- QString stringValue(int index, const QString &role) override;
- void setWatchedRoles(const QList<QByteArray> &) override {}
- QQmlIncubator::Status incubationStatus(int index) override;
-
- int indexOf(QObject *object, QObject *objectContext) const override;
-
- QQmlListProperty<QObject> children();
-
- static QQmlObjectModelAttached *qmlAttachedProperties(QObject *obj);
-
- Q_REVISION(3) Q_INVOKABLE QObject *get(int index) const;
- Q_REVISION(3) Q_INVOKABLE void append(QObject *object);
- Q_REVISION(3) Q_INVOKABLE void insert(int index, QObject *object);
- Q_REVISION(3) Q_INVOKABLE void move(int from, int to, int n = 1);
- Q_REVISION(3) Q_INVOKABLE void remove(int index, int n = 1);
-
-public Q_SLOTS:
- Q_REVISION(3) void clear();
-
-Q_SIGNALS:
- void childrenChanged();
-
-private:
- Q_DISABLE_COPY(QQmlObjectModel)
-};
-
-class QQmlObjectModelAttached : public QObject
-{
- Q_OBJECT
-
-public:
- QQmlObjectModelAttached(QObject *parent)
- : QObject(parent), m_index(-1) {}
- ~QQmlObjectModelAttached() {
- attachedProperties.remove(parent());
- }
-
- Q_PROPERTY(int index READ index NOTIFY indexChanged)
- int index() const { return m_index; }
- void setIndex(int idx) {
- if (m_index != idx) {
- m_index = idx;
- Q_EMIT indexChanged();
- }
- }
-
- static QQmlObjectModelAttached *properties(QObject *obj) {
- QQmlObjectModelAttached *rv = attachedProperties.value(obj);
- if (!rv) {
- rv = new QQmlObjectModelAttached(obj);
- attachedProperties.insert(obj, rv);
- }
- return rv;
- }
-
-Q_SIGNALS:
- void indexChanged();
-
-public:
- int m_index;
-
- static QHash<QObject*, QQmlObjectModelAttached*> attachedProperties;
-};
-
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlInstanceModel)
-QML_DECLARE_TYPE(QQmlObjectModel)
-QML_DECLARE_TYPEINFO(QQmlObjectModel, QML_HAS_ATTACHED_PROPERTIES)
-
-#endif // QQMLINSTANCEMODEL_P_H
diff --git a/src/qml/types/qqmltableinstancemodel.cpp b/src/qml/types/qqmltableinstancemodel.cpp
deleted file mode 100644
index 2170e2daec..0000000000
--- a/src/qml/types/qqmltableinstancemodel.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltableinstancemodel_p.h"
-#include "qqmldelegatecomponent_p.h"
-
-#include <QtCore/QTimer>
-
-#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
-#include <QtQml/private/qqmlcomponent_p.h>
-
-QT_BEGIN_NAMESPACE
-
-const char* kModelItemTag = "_tableinstancemodel_modelItem";
-
-bool QQmlTableInstanceModel::isDoneIncubating(QQmlDelegateModelItem *modelItem)
-{
- if (!modelItem->incubationTask)
- return true;
-
- const auto status = modelItem->incubationTask->status();
- return (status == QQmlIncubator::Ready) || (status == QQmlIncubator::Error);
-}
-
-void QQmlTableInstanceModel::deleteModelItemLater(QQmlDelegateModelItem *modelItem)
-{
- Q_ASSERT(modelItem);
-
- delete modelItem->object;
- modelItem->object = nullptr;
-
- if (modelItem->contextData) {
- modelItem->contextData->invalidate();
- Q_ASSERT(modelItem->contextData->refCount == 1);
- modelItem->contextData = nullptr;
- }
-
- modelItem->deleteLater();
-}
-
-QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent)
- : QQmlInstanceModel(*(new QObjectPrivate()), parent)
- , m_qmlContext(qmlContext)
- , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList()))
-{
-}
-
-void QQmlTableInstanceModel::useImportVersion(int minorVersion)
-{
- m_adaptorModel.useImportVersion(minorVersion);
-}
-
-QQmlTableInstanceModel::~QQmlTableInstanceModel()
-{
- for (const auto modelItem : m_modelItems) {
- // No item in m_modelItems should be referenced at this point. The view
- // should release all its items before it deletes this model. Only model items
- // that are still being incubated should be left for us to delete.
- Q_ASSERT(modelItem->objectRef == 0);
- Q_ASSERT(modelItem->incubationTask);
- // Check that we are not being deleted while we're
- // in the process of e.g emitting a created signal.
- Q_ASSERT(modelItem->scriptRef == 0);
-
- if (modelItem->object) {
- delete modelItem->object;
- modelItem->object = nullptr;
- modelItem->contextData->invalidate();
- modelItem->contextData = nullptr;
- }
- }
-
- deleteAllFinishedIncubationTasks();
- qDeleteAll(m_modelItems);
- drainReusableItemsPool(0);
-}
-
-QQmlComponent *QQmlTableInstanceModel::resolveDelegate(int index)
-{
- if (m_delegateChooser) {
- const int row = m_adaptorModel.rowAt(index);
- const int column = m_adaptorModel.columnAt(index);
- QQmlComponent *delegate = nullptr;
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, row, column);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- return delegate;
- }
-
- return m_delegate;
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
-{
- // Check if an item for the given index is already loaded and ready
- QQmlDelegateModelItem *modelItem = m_modelItems.value(index, nullptr);
- if (modelItem)
- return modelItem;
-
- QQmlComponent *delegate = resolveDelegate(index);
- if (!delegate)
- return nullptr;
-
- // Check if the pool contains an item that can be reused
- modelItem = takeFromReusableItemsPool(delegate);
- if (modelItem) {
- reuseItem(modelItem, index);
- m_modelItems.insert(index, modelItem);
- return modelItem;
- }
-
- // Create a new item from scratch
- modelItem = m_adaptorModel.createItem(m_metaType, index);
- if (modelItem) {
- modelItem->delegate = delegate;
- m_modelItems.insert(index, modelItem);
- return modelItem;
- }
-
- qWarning() << Q_FUNC_INFO << "failed creating a model item for index: " << index;
- return nullptr;
-}
-
-QObject *QQmlTableInstanceModel::object(int index, QQmlIncubator::IncubationMode incubationMode)
-{
- Q_ASSERT(m_delegate);
- Q_ASSERT(index >= 0 && index < m_adaptorModel.count());
- Q_ASSERT(m_qmlContext && m_qmlContext->isValid());
-
- QQmlDelegateModelItem *modelItem = resolveModelItem(index);
- if (!modelItem)
- return nullptr;
-
- if (modelItem->object) {
- // The model item has already been incubated. So
- // just bump the ref-count and return it.
- modelItem->referenceObject();
- return modelItem->object;
- }
-
- // The object is not ready, and needs to be incubated
- incubateModelItem(modelItem, incubationMode);
- if (!isDoneIncubating(modelItem))
- return nullptr;
-
- // Incubation is done, so the task should be removed
- Q_ASSERT(!modelItem->incubationTask);
-
- if (!modelItem->object) {
- // The object was incubated synchronously (otherwise we would return above). But since
- // we have no object, the incubation must have failed. And when we have no object, there
- // should be no object references either. And there should also not be any internal script
- // refs at this point. So we delete the model item.
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- m_modelItems.remove(modelItem->index);
- delete modelItem;
- return nullptr;
- }
-
- // Incubation was completed sync and successful
- modelItem->referenceObject();
- return modelItem->object;
-}
-
-QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object, ReusableFlag reusable)
-{
- Q_ASSERT(object);
- auto modelItem = qvariant_cast<QQmlDelegateModelItem *>(object->property(kModelItemTag));
- Q_ASSERT(modelItem);
-
- if (!modelItem->releaseObject())
- return QQmlDelegateModel::Referenced;
-
- if (modelItem->isReferenced()) {
- // We still have an internal reference to this object, which means that we are told to release an
- // object while the createdItem signal for it is still on the stack. This can happen when objects
- // are e.g delivered async, and the user flicks back and forth quicker than the loading can catch
- // up with. The view might then find that the object is no longer visible and should be released.
- // We detect this case in incubatorStatusChanged(), and delete it there instead. But from the callers
- // point of view, it should consider it destroyed.
- return QQmlDelegateModel::Destroyed;
- }
-
- // The item is not referenced by anyone
- m_modelItems.remove(modelItem->index);
-
- if (reusable == Reusable) {
- insertIntoReusableItemsPool(modelItem);
- return QQmlInstanceModel::Referenced;
- }
-
- // The item is not reused or referenced by anyone, so just delete it
- modelItem->destroyObject();
- emit destroyingItem(object);
-
- delete modelItem;
- return QQmlInstanceModel::Destroyed;
-}
-
-void QQmlTableInstanceModel::cancel(int index)
-{
- auto modelItem = m_modelItems.value(index);
- Q_ASSERT(modelItem);
-
- // Since the view expects the item to be incubating, there should be
- // an incubation task. And since the incubation is not done, no-one
- // should yet have received, and therfore hold a reference to, the object.
- Q_ASSERT(modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
-
- m_modelItems.remove(index);
-
- if (modelItem->object)
- delete modelItem->object;
-
- // modelItem->incubationTask will be deleted from the modelItems destructor
- delete modelItem;
-}
-
-void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem)
-{
- // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release()
- // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released
- // item is no longer referenced, it will be added to the pool. Reusing of items can be specified
- // per item, in case certain items cannot be recycled.
- // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are
- // about to create a new item, we first check if the pool contains an item based on the same
- // delegate from before. If so, we take it out of the pool (instead of creating a new item), and
- // update all its context-, and attached properties.
- // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool()
- // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only
- // meant to rest there for a short while, ideally only from the time e.g a row is unloaded
- // on one side of the view, and until a new row is loaded on the opposite side. In-between
- // this time, the application will see the item as fully functional and 'alive' (just not
- // visible on screen). Since this time is supposed to be short, we don't take any action to
- // notify the application about it, since we don't want to trigger any bindings that can
- // disturb performance.
- // A recommended time for calling drainReusableItemsPool() is each time a view has finished
- // loading e.g a new row or column. If there are more items in the pool after that, it means
- // that the view most likely doesn't need them anytime soon. Those items should be destroyed to
- // not consume resources.
- // Depending on if a view is a list or a table, it can sometimes be performant to keep
- // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the
- // number of visible rows in a view is much larger than the number of visible columns.
- // In that case, if you flick out a row, and then flick in a column, you would throw away a lot
- // of items in the pool if completely draining it. The reason is that unloading a row places more
- // items in the pool than what ends up being recycled when loading a new column. And then, when you
- // next flick in a new row, you would need to load all those drained items again from scratch. For
- // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep
- // items in the pool for a bit longer, effectively keeping more items in circulation.
- // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which
- // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained.
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
-
- modelItem->poolTime = 0;
- m_reusableItemsPool.append(modelItem);
- emit itemPooled(modelItem->index, modelItem->object);
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate)
-{
- // Find the oldest item in the pool that was made from the same delegate as
- // the given argument, remove it from the pool, and return it.
- if (m_reusableItemsPool.isEmpty())
- return nullptr;
-
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
- if ((*it)->delegate != delegate)
- continue;
- auto modelItem = *it;
- m_reusableItemsPool.erase(it);
- return modelItem;
- }
-
- return nullptr;
-}
-
-void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime)
-{
- // Rather than releasing all pooled items upon a call to this function, each
- // item has a poolTime. The poolTime specifies for how many loading cycles an item
- // has been resting in the pool. And for each invocation of this function, poolTime
- // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
- // from the pool and released. This way, the view can tweak a bit for how long
- // items should stay in "circulation", even if they are not recycled right away.
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
- auto modelItem = *it;
- modelItem->poolTime++;
- if (modelItem->poolTime <= maxPoolTime) {
- ++it;
- } else {
- it = m_reusableItemsPool.erase(it);
- release(modelItem->object, NotReusable);
- }
- }
-}
-
-void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex)
-{
- // Update the context properties index, row and column on
- // the delegate item, and inform the application about it.
- const int newRow = m_adaptorModel.rowAt(newModelIndex);
- const int newColumn = m_adaptorModel.columnAt(newModelIndex);
- item->setModelIndex(newModelIndex, newRow, newColumn);
-
- // Notify the application that all 'dynamic'/role-based context data has
- // changed as well (their getter function will use the updated index).
- auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
- auto const updateAllRoles = QVector<int>();
- m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
-
- // Inform the view that the item is recycled. This will typically result
- // in the view updating its own attached delegate item properties.
- emit itemReused(newModelIndex, item->object);
-}
-
-void QQmlTableInstanceModel::incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode)
-{
- // Guard the model item temporarily so that it's not deleted from
- // incubatorStatusChanged(), in case the incubation is done synchronously.
- modelItem->scriptRef++;
-
- if (modelItem->incubationTask) {
- // We're already incubating the model item from a previous request. If the previous call requested
- // the item async, but the current request needs it sync, we need to force-complete the incubation.
- const bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
- if (sync && modelItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous)
- modelItem->incubationTask->forceCompletion();
- } else {
- modelItem->incubationTask = new QQmlTableInstanceModelIncubationTask(this, modelItem, incubationMode);
-
- QQmlContextData *ctxt = new QQmlContextData;
- QQmlContext *creationContext = modelItem->delegate->creationContext();
- ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_qmlContext.data()));
- ctxt->contextObject = modelItem;
- modelItem->contextData = ctxt;
-
- QQmlComponentPrivate::get(modelItem->delegate)->incubateObject(
- modelItem->incubationTask,
- modelItem->delegate,
- m_qmlContext->engine(),
- ctxt,
- QQmlContextData::get(m_qmlContext));
- }
-
- // Remove the temporary guard
- modelItem->scriptRef--;
-}
-
-void QQmlTableInstanceModel::incubatorStatusChanged(QQmlTableInstanceModelIncubationTask *incubationTask, QQmlIncubator::Status status)
-{
- QQmlDelegateModelItem *modelItem = incubationTask->modelItemToIncubate;
- Q_ASSERT(modelItem->incubationTask);
-
- modelItem->incubationTask = nullptr;
- incubationTask->modelItemToIncubate = nullptr;
-
- if (status == QQmlIncubator::Ready) {
- // Tag the incubated object with the model item for easy retrieval upon release etc.
- modelItem->object->setProperty(kModelItemTag, QVariant::fromValue(modelItem));
-
- // Emit that the item has been created. What normally happens next is that the view
- // upon receiving the signal asks for the model item once more. And since the item is
- // now in the map, it will be returned directly.
- Q_ASSERT(modelItem->object);
- modelItem->scriptRef++;
- emit createdItem(modelItem->index, modelItem->object);
- modelItem->scriptRef--;
- } else if (status == QQmlIncubator::Error) {
- qWarning() << "Error incubating delegate:" << incubationTask->errors();
- }
-
- if (!modelItem->isReferenced() && !modelItem->isObjectReferenced()) {
- // We have no internal reference to the model item, and the view has no
- // reference to the incubated object. So just delete the model item.
- // Note that being here means that the object was incubated _async_
- // (otherwise modelItem->isReferenced() would be true).
- m_modelItems.remove(modelItem->index);
-
- if (modelItem->object) {
- modelItem->scriptRef++;
- emit destroyingItem(modelItem->object);
- modelItem->scriptRef--;
- Q_ASSERT(!modelItem->isReferenced());
- }
-
- deleteModelItemLater(modelItem);
- }
-
- deleteIncubationTaskLater(incubationTask);
-}
-
-QQmlIncubator::Status QQmlTableInstanceModel::incubationStatus(int index) {
- const auto modelItem = m_modelItems.value(index, nullptr);
- if (!modelItem)
- return QQmlIncubator::Null;
-
- if (modelItem->incubationTask)
- return modelItem->incubationTask->status();
-
- // Since we clear the incubation task when we're done
- // incubating, it means that the status is Ready.
- return QQmlIncubator::Ready;
-}
-
-void QQmlTableInstanceModel::deleteIncubationTaskLater(QQmlIncubator *incubationTask)
-{
- // We often need to post-delete incubation tasks, since we cannot
- // delete them while we're in the middle of an incubation change callback.
- Q_ASSERT(!m_finishedIncubationTasks.contains(incubationTask));
- m_finishedIncubationTasks.append(incubationTask);
- if (m_finishedIncubationTasks.count() == 1)
- QTimer::singleShot(1, this, &QQmlTableInstanceModel::deleteAllFinishedIncubationTasks);
-}
-
-void QQmlTableInstanceModel::deleteAllFinishedIncubationTasks()
-{
- qDeleteAll(m_finishedIncubationTasks);
- m_finishedIncubationTasks.clear();
-}
-
-QVariant QQmlTableInstanceModel::model() const
-{
- return m_adaptorModel.model();
-}
-
-void QQmlTableInstanceModel::setModel(const QVariant &model)
-{
- // Pooled items are still accessible/alive for the application, and
- // needs to stay in sync with the model. So we need to drain the pool
- // completely when the model changes.
- drainReusableItemsPool(0);
- if (auto const aim = abstractItemModel())
- disconnect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
- m_adaptorModel.setModel(model, this, m_qmlContext->engine());
- if (auto const aim = abstractItemModel())
- connect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
-}
-
-void QQmlTableInstanceModel::dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
-{
- // This function is called when model data has changed. In that case, we tell the adaptor model
- // to go through all the items we have created, find the ones that are affected, and notify that
- // their model data has changed. This will in turn update QML bindings inside the delegate items.
- int numberOfRowsChanged = end.row() - begin.row() + 1;
- int numberOfColumnsChanged = end.column() - begin.column() + 1;
-
- for (int column = 0; column < numberOfColumnsChanged; ++column) {
- const int columnIndex = begin.column() + column;
- const int rowIndex = begin.row() + (columnIndex * rows());
- m_adaptorModel.notify(m_modelItems.values(), rowIndex, numberOfRowsChanged, roles);
- }
-}
-
-QQmlComponent *QQmlTableInstanceModel::delegate() const
-{
- return m_delegate;
-}
-
-void QQmlTableInstanceModel::setDelegate(QQmlComponent *delegate)
-{
- if (m_delegate == delegate)
- return;
-
- m_delegateChooser = nullptr;
- if (delegate) {
- QQmlAbstractDelegateComponent *adc =
- qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc)
- m_delegateChooser = adc;
- }
-
- m_delegate = delegate;
-}
-
-const QAbstractItemModel *QQmlTableInstanceModel::abstractItemModel() const
-{
- return m_adaptorModel.adaptsAim() ? m_adaptorModel.aim() : nullptr;
-}
-
-// --------------------------------------------------------
-
-void QQmlTableInstanceModelIncubationTask::setInitialState(QObject *object)
-{
- modelItemToIncubate->object = object;
- emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
-}
-
-void QQmlTableInstanceModelIncubationTask::statusChanged(QQmlIncubator::Status status)
-{
- if (!QQmlTableInstanceModel::isDoneIncubating(modelItemToIncubate))
- return;
-
- // We require the view to cancel any ongoing load
- // requests before the tableInstanceModel is destructed.
- Q_ASSERT(tableInstanceModel);
-
- tableInstanceModel->incubatorStatusChanged(this, status);
-}
-
-#include "moc_qqmltableinstancemodel_p.cpp"
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/types/qqmltableinstancemodel_p.h b/src/qml/types/qqmltableinstancemodel_p.h
deleted file mode 100644
index 3dd5c4e4ce..0000000000
--- a/src/qml/types/qqmltableinstancemodel_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEINSTANCEMODEL_P_H
-#define QQMLTABLEINSTANCEMODEL_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 <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlTableInstanceModel;
-class QQmlAbstractDelegateComponent;
-
-class QQmlTableInstanceModelIncubationTask : public QQDMIncubationTask
-{
-public:
- QQmlTableInstanceModelIncubationTask(
- QQmlTableInstanceModel *tableInstanceModel
- , QQmlDelegateModelItem* modelItemToIncubate
- , IncubationMode mode)
- : QQDMIncubationTask(nullptr, mode)
- , modelItemToIncubate(modelItemToIncubate)
- , tableInstanceModel(tableInstanceModel) {
- clear();
- }
-
- void statusChanged(Status status) override;
- void setInitialState(QObject *object) override;
-
- QQmlDelegateModelItem *modelItemToIncubate = nullptr;
- QQmlTableInstanceModel *tableInstanceModel = nullptr;
-};
-
-class Q_QML_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
-{
- Q_OBJECT
-
-public:
-
- enum ReusableFlag {
- NotReusable,
- Reusable
- };
-
- QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent = nullptr);
- ~QQmlTableInstanceModel() override;
-
- void useImportVersion(int minorVersion);
-
- int count() const override { return m_adaptorModel.count(); }
- int rows() const { return m_adaptorModel.rowCount(); }
- int columns() const { return m_adaptorModel.columnCount(); }
-
- bool isValid() const override { return true; }
-
- QVariant model() const;
- void setModel(const QVariant &model);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *);
-
- const QAbstractItemModel *abstractItemModel() const override;
-
- QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override { return release(object, NotReusable); }
- ReleaseFlags release(QObject *object, ReusableFlag reusable);
- void cancel(int) override;
-
- void insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem);
- QQmlDelegateModelItem *takeFromReusableItemsPool(const QQmlComponent *delegate);
- void drainReusableItemsPool(int maxPoolTime);
- int poolSize() { return m_reusableItemsPool.size(); }
- void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
-
- QQmlIncubator::Status incubationStatus(int index) override;
-
- QString stringValue(int, const QString &) override { Q_UNREACHABLE(); return QString(); }
- void setWatchedRoles(const QList<QByteArray> &) override { Q_UNREACHABLE(); }
- int indexOf(QObject *, QObject *) const override { Q_UNREACHABLE(); return 0; }
-
-Q_SIGNALS:
- void itemPooled(int index, QObject *object);
- void itemReused(int index, QObject *object);
-
-private:
- QQmlComponent *resolveDelegate(int index);
-
- QQmlAdaptorModel m_adaptorModel;
- QQmlAbstractDelegateComponent *m_delegateChooser = nullptr;
- QQmlComponent *m_delegate = nullptr;
- QPointer<QQmlContext> m_qmlContext;
- QQmlDelegateModelItemMetaType *m_metaType;
-
- QHash<int, QQmlDelegateModelItem *> m_modelItems;
- QList<QQmlDelegateModelItem *> m_reusableItemsPool;
- QList<QQmlIncubator *> m_finishedIncubationTasks;
-
- void incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode);
- void incubatorStatusChanged(QQmlTableInstanceModelIncubationTask *dmIncubationTask, QQmlIncubator::Status status);
- void deleteIncubationTaskLater(QQmlIncubator *incubationTask);
- void deleteAllFinishedIncubationTasks();
- QQmlDelegateModelItem *resolveModelItem(int index);
-
- void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles);
-
- static bool isDoneIncubating(QQmlDelegateModelItem *modelItem);
- static void deleteModelItemLater(QQmlDelegateModelItem *modelItem);
-
- friend class QQmlTableInstanceModelIncubationTask;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTABLEINSTANCEMODEL_P_H
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
deleted file mode 100644
index 03539d8737..0000000000
--- a/src/qml/types/qquickpackage.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qquickpackage_p.h"
-
-#include <private/qobject_p.h>
-#include <private/qqmlguard_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype Package
- \instantiates QQuickPackage
- \inqmlmodule QtQuick
- \ingroup qtquick-views
- \brief Specifies a collection of named items.
-
- The Package type is used in conjunction with
- DelegateModel to enable delegates with a shared context
- to be provided to multiple views.
-
- Any item within a Package may be assigned a name via the
- \l{Package::name}{Package.name} attached property.
-
- The example below creates a Package containing two named items;
- \e list and \e grid. The third item in the package (the \l Rectangle) is parented to whichever
- delegate it should appear in. This allows an item to move
- between views.
-
- \snippet package/Delegate.qml 0
-
- These named items are used as the delegates by the two views who
- reference the special \l{DelegateModel::parts} property to select
- a model which provides the chosen delegate.
-
- \snippet package/view.qml 0
-
- \sa {Qt Quick Examples - Views}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
-*/
-
-/*!
- \qmlattachedproperty string QtQuick::Package::name
- This attached property holds the name of an item within a Package.
-*/
-
-
-class QQuickPackagePrivate : public QObjectPrivate
-{
-public:
- QQuickPackagePrivate() {}
-
- struct DataGuard : public QQmlGuard<QObject>
- {
- DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QQmlGuard<QObject>&)*this = obj; }
- QList<DataGuard> *list;
- void objectDestroyed(QObject *) override {
- // we assume priv will always be destroyed after objectDestroyed calls
- list->removeOne(*this);
- }
- };
-
- QList<DataGuard> dataList;
- static void data_append(QQmlListProperty<QObject> *prop, QObject *o) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- list->append(DataGuard(o, list));
- }
- static void data_clear(QQmlListProperty<QObject> *prop) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- list->clear();
- }
- static QObject *data_at(QQmlListProperty<QObject> *prop, int index) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- return list->at(index);
- }
- static int data_count(QQmlListProperty<QObject> *prop) {
- QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
- return list->count();
- }
-};
-
-QHash<QObject *, QQuickPackageAttached *> QQuickPackageAttached::attached;
-
-QQuickPackageAttached::QQuickPackageAttached(QObject *parent)
-: QObject(parent)
-{
- attached.insert(parent, this);
-}
-
-QQuickPackageAttached::~QQuickPackageAttached()
-{
- attached.remove(parent());
-}
-
-QString QQuickPackageAttached::name() const
-{
- return _name;
-}
-
-void QQuickPackageAttached::setName(const QString &n)
-{
- _name = n;
-}
-
-QQuickPackage::QQuickPackage(QObject *parent)
- : QObject(*(new QQuickPackagePrivate), parent)
-{
-}
-
-QQuickPackage::~QQuickPackage()
-{
-}
-
-QQmlListProperty<QObject> QQuickPackage::data()
-{
- Q_D(QQuickPackage);
- return QQmlListProperty<QObject>(this, &d->dataList, QQuickPackagePrivate::data_append,
- QQuickPackagePrivate::data_count,
- QQuickPackagePrivate::data_at,
- QQuickPackagePrivate::data_clear);
-}
-
-bool QQuickPackage::hasPart(const QString &name)
-{
- Q_D(QQuickPackage);
- for (int ii = 0; ii < d->dataList.count(); ++ii) {
- QObject *obj = d->dataList.at(ii);
- QQuickPackageAttached *a = QQuickPackageAttached::attached.value(obj);
- if (a && a->name() == name)
- return true;
- }
- return false;
-}
-
-QObject *QQuickPackage::part(const QString &name)
-{
- Q_D(QQuickPackage);
- if (name.isEmpty() && !d->dataList.isEmpty())
- return d->dataList.at(0);
-
- for (int ii = 0; ii < d->dataList.count(); ++ii) {
- QObject *obj = d->dataList.at(ii);
- QQuickPackageAttached *a = QQuickPackageAttached::attached.value(obj);
- if (a && a->name() == name)
- return obj;
- }
-
- if (name == QLatin1String("default") && !d->dataList.isEmpty())
- return d->dataList.at(0);
-
- return nullptr;
-}
-
-QQuickPackageAttached *QQuickPackage::qmlAttachedProperties(QObject *o)
-{
- return new QQuickPackageAttached(o);
-}
-
-
-
-QT_END_NAMESPACE
-
-#include "moc_qquickpackage_p.cpp"
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
deleted file mode 100644
index edb112276c..0000000000
--- a/src/qml/types/qquickworkerscript.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qtqmlglobal_p.h"
-#include "qquickworkerscript_p.h"
-#if QT_CONFIG(qml_list_model)
-#include "qqmllistmodel_p.h"
-#include "qqmllistmodelworkeragent_p.h"
-#endif
-#include <private/qqmlengine_p.h>
-#include <private/qqmlexpression_p.h>
-
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtQml/qjsengine.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qwaitcondition.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qdatetime.h>
-#include <QtQml/qqmlinfo.h>
-#include <QtQml/qqmlfile.h>
-#if QT_CONFIG(qml_network)
-#include <QtNetwork/qnetworkaccessmanager.h>
-#include "qqmlnetworkaccessmanagerfactory.h"
-#endif
-
-#include <private/qv8engine_p.h>
-#include <private/qv4serialize_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4script_p.h>
-#include <private/qv4scopedvalue_p.h>
-#include <private/qv4jscall_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class WorkerDataEvent : public QEvent
-{
-public:
- enum Type { WorkerData = QEvent::User };
-
- WorkerDataEvent(int workerId, const QByteArray &data);
- virtual ~WorkerDataEvent();
-
- int workerId() const;
- QByteArray data() const;
-
-private:
- int m_id;
- QByteArray m_data;
-};
-
-class WorkerLoadEvent : public QEvent
-{
-public:
- enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 };
-
- WorkerLoadEvent(int workerId, const QUrl &url);
-
- int workerId() const;
- QUrl url() const;
-
-private:
- int m_id;
- QUrl m_url;
-};
-
-class WorkerRemoveEvent : public QEvent
-{
-public:
- enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 };
-
- WorkerRemoveEvent(int workerId);
-
- int workerId() const;
-
-private:
- int m_id;
-};
-
-class WorkerErrorEvent : public QEvent
-{
-public:
- enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 };
-
- WorkerErrorEvent(const QQmlError &error);
-
- QQmlError error() const;
-
-private:
- QQmlError m_error;
-};
-
-class QQuickWorkerScriptEnginePrivate : public QObject
-{
- Q_OBJECT
-public:
- enum WorkerEventTypes {
- WorkerDestroyEvent = QEvent::User + 100
- };
-
- QQuickWorkerScriptEnginePrivate(QQmlEngine *eng);
-
- QQmlEngine *qmlengine;
-
- QMutex m_lock;
- QWaitCondition m_wait;
-
- struct WorkerScript : public QV8Engine {
- WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent);
- ~WorkerScript() override;
-
-#if QT_CONFIG(qml_network)
- QNetworkAccessManager *networkAccessManager() override;
-#endif
-
- QQuickWorkerScriptEnginePrivate *p = nullptr;
- QUrl source;
- QQuickWorkerScript *owner = nullptr;
-#if QT_CONFIG(qml_network)
- QScopedPointer<QNetworkAccessManager> accessManager;
-#endif
- int id = -1;
- };
-
- QHash<int, WorkerScript *> workers;
- QV4::ReturnedValue getWorker(WorkerScript *);
-
- int m_nextId;
-
- static QV4::ReturnedValue method_sendMessage(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
-signals:
- void stopThread();
-
-protected:
- bool event(QEvent *) override;
-
-private:
- void processMessage(int, const QByteArray &);
- void processLoad(int, const QUrl &);
- void reportScriptException(WorkerScript *, const QQmlError &error);
-};
-
-QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine)
-: qmlengine(engine), m_nextId(0)
-{
-}
-
-QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(const QV4::FunctionObject *b,
- const QV4::Value *, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- WorkerScript *script = static_cast<WorkerScript *>(scope.engine->v8Engine);
-
- QV4::ScopedValue v(scope, argc > 0 ? argv[0] : QV4::Value::undefinedValue());
- QByteArray data = QV4::Serialize::serialize(v, scope.engine);
-
- QMutexLocker locker(&script->p->m_lock);
- if (script && script->owner)
- QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
-
- return QV4::Encode::undefined();
-}
-
-bool QQuickWorkerScriptEnginePrivate::event(QEvent *event)
-{
- if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
- WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- processMessage(workerEvent->workerId(), workerEvent->data());
- return true;
- } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) {
- WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event);
- processLoad(workerEvent->workerId(), workerEvent->url());
- return true;
- } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) {
- emit stopThread();
- return true;
- } else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) {
- QMutexLocker locker(&m_lock);
- WorkerRemoveEvent *workerEvent = static_cast<WorkerRemoveEvent *>(event);
- QHash<int, WorkerScript *>::iterator itr = workers.find(workerEvent->workerId());
- if (itr != workers.end()) {
- delete itr.value();
- workers.erase(itr);
- }
- return true;
- } else {
- return QObject::event(event);
- }
-}
-
-void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
-{
- WorkerScript *script = workers.value(id);
- if (!script)
- return;
-
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(script);
- QV4::Scope scope(v4);
- QV4::ScopedString v(scope);
- QV4::ScopedObject worker(scope, v4->globalObject->get((v = v4->newString(QStringLiteral("WorkerScript")))));
- QV4::ScopedFunctionObject onmessage(scope);
- if (worker)
- onmessage = worker->get((v = v4->newString(QStringLiteral("onMessage"))));
-
- if (!onmessage)
- return;
-
- QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, v4));
-
- QV4::JSCallData jsCallData(scope, 1);
- *jsCallData->thisObject = v4->global();
- jsCallData->args[0] = value;
- onmessage->call(jsCallData);
- if (scope.hasException()) {
- QQmlError error = scope.engine->catchExceptionAsQmlError();
- reportScriptException(script, error);
- }
-}
-
-void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
-{
- if (url.isRelative())
- return;
-
- QString fileName = QQmlFile::urlToLocalFileOrQrc(url);
-
- WorkerScript *script = workers.value(id);
- if (!script)
- return;
-
- QV4::ExecutionEngine *v4 = QV8Engine::getV4(script);
-
- script->source = url;
-
- if (fileName.endsWith(QLatin1String(".mjs"))) {
- auto moduleUnit = v4->loadModule(url);
- if (moduleUnit) {
- if (moduleUnit->instantiate(v4))
- moduleUnit->evaluate();
- } else {
- v4->throwError(QStringLiteral("Could not load module file"));
- }
- } else {
- QString error;
- QV4::Scope scope(v4);
- QScopedPointer<QV4::Script> program;
- program.reset(QV4::Script::createFromFileOrCache(v4, /*qmlContext*/nullptr, fileName, url, &error));
- if (program.isNull()) {
- if (!error.isEmpty())
- qWarning().nospace() << error;
- return;
- }
-
- if (!v4->hasException)
- program->run();
- }
-
- if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- reportScriptException(script, error);
- }
-}
-
-void QQuickWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script,
- const QQmlError &error)
-{
- QMutexLocker locker(&script->p->m_lock);
- if (script->owner)
- QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
-}
-
-WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
-: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
-{
-}
-
-WorkerDataEvent::~WorkerDataEvent()
-{
-}
-
-int WorkerDataEvent::workerId() const
-{
- return m_id;
-}
-
-QByteArray WorkerDataEvent::data() const
-{
- return m_data;
-}
-
-WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url)
-: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url)
-{
-}
-
-int WorkerLoadEvent::workerId() const
-{
- return m_id;
-}
-
-QUrl WorkerLoadEvent::url() const
-{
- return m_url;
-}
-
-WorkerRemoveEvent::WorkerRemoveEvent(int workerId)
-: QEvent((QEvent::Type)WorkerRemove), m_id(workerId)
-{
-}
-
-int WorkerRemoveEvent::workerId() const
-{
- return m_id;
-}
-
-WorkerErrorEvent::WorkerErrorEvent(const QQmlError &error)
-: QEvent((QEvent::Type)WorkerError), m_error(error)
-{
-}
-
-QQmlError WorkerErrorEvent::error() const
-{
- return m_error;
-}
-
-QQuickWorkerScriptEngine::QQuickWorkerScriptEngine(QQmlEngine *parent)
-: QThread(parent), d(new QQuickWorkerScriptEnginePrivate(parent))
-{
- d->m_lock.lock();
- connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection);
- start(QThread::LowestPriority);
- d->m_wait.wait(&d->m_lock);
- d->moveToThread(this);
- d->m_lock.unlock();
-}
-
-QQuickWorkerScriptEngine::~QQuickWorkerScriptEngine()
-{
- d->m_lock.lock();
- QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QQuickWorkerScriptEnginePrivate::WorkerDestroyEvent));
- d->m_lock.unlock();
-
- //We have to force to cleanup the main thread's event queue here
- //to make sure the main GUI release all pending locks/wait conditions which
- //some worker script/agent are waiting for (QQmlListModelWorkerAgent::sync() for example).
- while (!isFinished()) {
- // We can't simply wait here, because the worker thread will not terminate
- // until the main thread processes the last data event it generates
- QCoreApplication::processEvents();
- yieldCurrentThread();
- }
-
- d->deleteLater();
-}
-
-QQuickWorkerScriptEnginePrivate::WorkerScript::WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent)
- : QV8Engine(new QV4::ExecutionEngine)
- , p(parent)
- , id(id)
-{
- m_v4Engine->v8Engine = this;
-
- initQmlGlobalObject();
-
- QV4::Scope scope(m_v4Engine);
- QV4::ScopedObject api(scope, scope.engine->newObject());
- QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage")));
- QV4::ScopedValue sendMessage(scope, QV4::FunctionObject::createBuiltinFunction(m_v4Engine, name, method_sendMessage, 1));
- api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), sendMessage);
- m_v4Engine->globalObject->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api);
-}
-
-QQuickWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
-{
- delete m_v4Engine;
-}
-
-#if QT_CONFIG(qml_network)
-QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerScript::networkAccessManager()
-{
- if (!accessManager) {
- if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
- accessManager.reset(p->qmlengine->networkAccessManagerFactory()->create(p));
- } else {
- accessManager.reset(new QNetworkAccessManager(p));
- }
- }
- return accessManager.data();
-}
-#endif
-
-int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner)
-{
- typedef QQuickWorkerScriptEnginePrivate::WorkerScript WorkerScript;
- WorkerScript *script = new WorkerScript(d->m_nextId++, d);
-
- script->owner = owner;
-
- d->m_lock.lock();
- d->workers.insert(script->id, script);
- d->m_lock.unlock();
-
- return script->id;
-}
-
-void QQuickWorkerScriptEngine::removeWorkerScript(int id)
-{
- QQuickWorkerScriptEnginePrivate::WorkerScript* script = d->workers.value(id);
- if (script) {
- script->owner = nullptr;
- QCoreApplication::postEvent(d, new WorkerRemoveEvent(id));
- }
-}
-
-void QQuickWorkerScriptEngine::executeUrl(int id, const QUrl &url)
-{
- QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
-}
-
-void QQuickWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
-{
- QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
-}
-
-void QQuickWorkerScriptEngine::run()
-{
- d->m_lock.lock();
-
- d->m_wait.wakeAll();
-
- d->m_lock.unlock();
-
- exec();
-
- qDeleteAll(d->workers);
- d->workers.clear();
-}
-
-
-/*!
- \qmltype WorkerScript
- \instantiates QQuickWorkerScript
- \ingroup qtquick-threading
- \inqmlmodule QtQml
- \brief Enables the use of threads in a Qt Quick application.
-
- Use WorkerScript to run operations in a new thread.
- This is useful for running operations in the background so
- that the main GUI thread is not blocked.
-
- Messages can be passed between the new thread and the parent thread
- using \l sendMessage() and the \c onMessage() handler.
-
- An example:
-
- \snippet qml/workerscript/workerscript.qml 0
-
- The above worker script specifies a JavaScript file, "script.mjs", that handles
- the operations to be performed in the new thread. Here is \c script.mjs:
-
- \quotefile qml/workerscript/script.mjs
-
- When the user clicks anywhere within the rectangle, \c sendMessage() is
- called, triggering the \tt WorkerScript.onMessage() handler in
- \tt script.mjs. This in turn sends a reply message that is then received
- by the \tt onMessage() handler of \tt myWorker.
-
- The example uses a script that is an ECMAScript module, because it has the ".mjs" extension.
- It can use import statements to access functionality from other modules and it is run in JavaScript
- strict mode.
-
- If a worker script has the extension ".js" instead, then it is considered to contain plain JavaScript
- statements and it is run in non-strict mode.
-
- \note Each WorkerScript element will instantiate a separate JavaScript engine to ensure perfect
- isolation and thread-safety. If the impact of that results in a memory consumption that is too
- high for your environment, then consider sharing a WorkerScript element.
-
- \section3 Restrictions
-
- Since the \c WorkerScript.onMessage() function is run in a separate thread, the
- JavaScript file is evaluated in a context separate from the main QML engine. This means
- that unlike an ordinary JavaScript file that is imported into QML, the \c script.mjs
- in the above example cannot access the properties, methods or other attributes
- of the QML item, nor can it access any context properties set on the QML object
- through QQmlContext.
-
- Additionally, there are restrictions on the types of values that can be passed to and
- from the worker script. See the sendMessage() documentation for details.
-
- Worker scripts that are plain JavaScript sources can not use \l {qtqml-javascript-imports.html}{.import} syntax.
- Scripts that are ECMAScript modules can freely use import and export statements.
-
- \sa {Qt Quick Examples - Threading},
- {Threaded ListModel Example}
-*/
-QQuickWorkerScript::QQuickWorkerScript(QObject *parent)
-: QObject(parent), m_engine(nullptr), m_scriptId(-1), m_componentComplete(true)
-{
-}
-
-QQuickWorkerScript::~QQuickWorkerScript()
-{
- if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId);
-}
-
-/*!
- \qmlproperty url WorkerScript::source
-
- This holds the url of the JavaScript file that implements the
- \tt WorkerScript.onMessage() handler for threaded operations.
-
- If the file name component of the url ends with ".mjs", then the script
- is parsed as an ECMAScript module and run in strict mode. Otherwise it is considered to be
- plain script.
-*/
-QUrl QQuickWorkerScript::source() const
-{
- return m_source;
-}
-
-void QQuickWorkerScript::setSource(const QUrl &source)
-{
- if (m_source == source)
- return;
-
- m_source = source;
-
- if (engine())
- m_engine->executeUrl(m_scriptId, m_source);
-
- emit sourceChanged();
-}
-
-/*!
- \qmlmethod WorkerScript::sendMessage(jsobject message)
-
- Sends the given \a message to a worker script handler in another
- thread. The other worker script handler can receive this message
- through the onMessage() handler.
-
- The \c message object may only contain values of the following
- types:
-
- \list
- \li boolean, number, string
- \li JavaScript objects and arrays
- \li ListModel objects (any other type of QObject* is not allowed)
- \endlist
-
- All objects and arrays are copied to the \c message. With the exception
- of ListModel objects, any modifications by the other thread to an object
- passed in \c message will not be reflected in the original object.
-*/
-void QQuickWorkerScript::sendMessage(QQmlV4Function *args)
-{
- if (!engine()) {
- qWarning("QQuickWorkerScript: Attempt to send message before WorkerScript establishment");
- return;
- }
-
- QV4::Scope scope(args->v4engine());
- QV4::ScopedValue argument(scope, QV4::Value::undefinedValue());
- if (args->length() != 0)
- argument = (*args)[0];
-
- m_engine->sendMessage(m_scriptId, QV4::Serialize::serialize(argument, scope.engine));
-}
-
-void QQuickWorkerScript::classBegin()
-{
- m_componentComplete = false;
-}
-
-QQuickWorkerScriptEngine *QQuickWorkerScript::engine()
-{
- if (m_engine) return m_engine;
- if (m_componentComplete) {
- QQmlEngine *engine = qmlEngine(this);
- if (!engine) {
- qWarning("QQuickWorkerScript: engine() called without qmlEngine() set");
- return nullptr;
- }
-
- m_engine = QQmlEnginePrivate::get(engine)->getWorkerScriptEngine();
- m_scriptId = m_engine->registerWorkerScript(this);
-
- if (m_source.isValid())
- m_engine->executeUrl(m_scriptId, m_source);
-
- return m_engine;
- }
- return nullptr;
-}
-
-void QQuickWorkerScript::componentComplete()
-{
- m_componentComplete = true;
- engine(); // Get it started now.
-}
-
-/*!
- \qmlsignal WorkerScript::message(jsobject msg)
-
- This signal is emitted when a message \a msg is received from a worker
- script in another thread through a call to sendMessage().
-
- The corresponding handler is \c onMessage.
-*/
-
-bool QQuickWorkerScript::event(QEvent *event)
-{
- if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
- QQmlEngine *engine = qmlEngine(this);
- if (engine) {
- WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue value(scope, QV4::Serialize::deserialize(workerEvent->data(), scope.engine));
- emit message(QQmlV4Handle(value));
- }
- return true;
- } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
- WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event);
- QQmlEnginePrivate::warning(qmlEngine(this), workerEvent->error());
- return true;
- } else {
- return QObject::event(event);
- }
-}
-
-QT_END_NAMESPACE
-
-#include <qquickworkerscript.moc>
-
-#include "moc_qquickworkerscript_p.cpp"
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index e74c89b1f1..54cd8710b6 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,51 +1,16 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
- $$PWD/qqmlconnections.cpp \
- $$PWD/qqmlmodelsmodule.cpp \
- $$PWD/qqmlmodelindexvaluetype.cpp \
- $$PWD/qqmlobjectmodel.cpp \
- $$PWD/qquickpackage.cpp \
- $$PWD/qqmlinstantiator.cpp \
- $$PWD/qqmltableinstancemodel.cpp
+ $$PWD/qqmlconnections.cpp
HEADERS += \
$$PWD/qqmlbind_p.h \
- $$PWD/qqmlconnections_p.h \
- $$PWD/qqmlmodelsmodule_p.h \
- $$PWD/qqmlmodelindexvaluetype_p.h \
- $$PWD/qqmlobjectmodel_p.h \
- $$PWD/qquickpackage_p.h \
- $$PWD/qqmlinstantiator_p.h \
- $$PWD/qqmlinstantiator_p_p.h \
- $$PWD/qqmltableinstancemodel_p.h
+ $$PWD/qqmlconnections_p.h
-qtConfig(qml-worker-script) {
+qtConfig(qml-itemmodel) {
SOURCES += \
- $$PWD/qquickworkerscript.cpp
+ $$PWD/qqmlmodelindexvaluetype.cpp
HEADERS += \
- $$PWD/qquickworkerscript_p.h
-}
-
-qtConfig(qml-list-model) {
- SOURCES += \
- $$PWD/qqmllistmodel.cpp \
- $$PWD/qqmllistmodelworkeragent.cpp
-
- HEADERS += \
- $$PWD/qqmllistmodel_p.h \
- $$PWD/qqmllistmodel_p_p.h \
- $$PWD/qqmllistmodelworkeragent_p.h
-}
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmldelegatecomponent.cpp
-
- HEADERS += \
- $$PWD/qqmldelegatemodel_p.h \
- $$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmldelegatecomponent_p.h
+ $$PWD/qqmlmodelindexvaluetype_p.h
}
qtConfig(qml-animation) {
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
deleted file mode 100644
index 1ff866eb74..0000000000
--- a/src/qml/util/qqmladaptormodel.cpp
+++ /dev/null
@@ -1,1044 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmladaptormodel_p.h"
-
-#include <private/qqmldelegatemodel_p_p.h>
-#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmlproperty_p.h>
-#include <private/qv8engine_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlAdaptorModelEngineData : public QV8Engine::Deletable
-{
-public:
- QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4);
- ~QQmlAdaptorModelEngineData();
-
- QV4::ExecutionEngine *v4;
- QV4::PersistentValue listItemProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
-
-static QV4::ReturnedValue get_index(const QV4::FunctionObject *f, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(f);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- RETURN_RESULT(QV4::Encode(o->d()->item->index));
-}
-
-template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
-{
- builder->setFlags(QMetaObjectBuilder::DynamicMetaObject);
- builder->setClassName(T::staticMetaObject.className());
- builder->setSuperClass(&T::staticMetaObject);
- metaType->propertyOffset = T::staticMetaObject.propertyCount();
- metaType->signalOffset = T::staticMetaObject.methodCount();
-}
-
-static void addProperty(QMetaObjectBuilder *builder, int propertyId, const QByteArray &propertyName, const QByteArray &propertyType)
-{
- builder->addSignal("__" + QByteArray::number(propertyId) + "()");
- QMetaPropertyBuilder property = builder->addProperty(
- propertyName, propertyType, propertyId);
- property.setWritable(true);
-}
-
-class VDMModelDelegateDataType;
-
-class QQmlDMCachedModelData : public QQmlDelegateModelItem
-{
-public:
- QQmlDMCachedModelData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column);
-
- int metaCall(QMetaObject::Call call, int id, void **arguments);
-
- virtual QVariant value(int role) const = 0;
- virtual void setValue(int role, const QVariant &value) = 0;
-
- void setValue(const QString &role, const QVariant &value) override;
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
-
- static QV4::ReturnedValue get_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue set_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- VDMModelDelegateDataType *type;
- QVector<QVariant> cachedData;
-};
-
-class VDMModelDelegateDataType
- : public QQmlRefCount
- , public QQmlAdaptorModel::Accessors
- , public QAbstractDynamicMetaObject
-{
-public:
- VDMModelDelegateDataType(QQmlAdaptorModel *model)
- : model(model)
- , propertyOffset(0)
- , signalOffset(0)
- , hasModelData(false)
- {
- }
-
- bool notify(
- const QQmlAdaptorModel &,
- const QList<QQmlDelegateModelItem *> &items,
- int index,
- int count,
- const QVector<int> &roles) const override
- {
- bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
- if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
- QList<int> roleIds;
- for (const QByteArray &r : watchedRoles) {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
- if (it != roleNames.end())
- roleIds << it.value();
- }
- const_cast<VDMModelDelegateDataType *>(this)->watchedRoleIds = roleIds;
- }
-
- QVector<int> signalIndexes;
- for (int i = 0; i < roles.count(); ++i) {
- const int role = roles.at(i);
- if (!changed && watchedRoleIds.contains(role))
- changed = true;
-
- int propertyId = propertyRoles.indexOf(role);
- if (propertyId != -1)
- signalIndexes.append(propertyId + signalOffset);
- }
- if (roles.isEmpty()) {
- const int propertyRolesCount = propertyRoles.count();
- signalIndexes.reserve(propertyRolesCount);
- for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
- signalIndexes.append(propertyId + signalOffset);
- }
-
- QVarLengthArray<QQmlGuard<QQmlDelegateModelItem>> guardedItems;
- for (const auto item : items)
- guardedItems.append(item);
-
- for (const auto &item : qAsConst(guardedItems)) {
- if (item.isNull())
- continue;
-
- const int idx = item->modelIndex();
- if (idx >= index && idx < index + count) {
- for (int i = 0; i < signalIndexes.count(); ++i)
- QMetaObject::activate(item, signalIndexes.at(i), nullptr);
- }
- }
- return changed;
- }
-
- void replaceWatchedRoles(
- QQmlAdaptorModel &,
- const QList<QByteArray> &oldRoles,
- const QList<QByteArray> &newRoles) const override
- {
- VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
-
- dataType->watchedRoleIds.clear();
- for (const QByteArray &oldRole : oldRoles)
- dataType->watchedRoles.removeOne(oldRole);
- dataType->watchedRoles += newRoles;
- }
-
- static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- 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_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
- } else {
- RETURN_RESULT(QV4::Encode(false));
- }
- }
-
-
- void initializeConstructor(QQmlAdaptorModelEngineData *const data)
- {
- QV4::ExecutionEngine *v4 = data->v4;
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
- QV4::ScopedProperty p(scope);
-
- typedef QHash<QByteArray, int>::const_iterator iterator;
- for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
- const int propertyId = propertyRoles.indexOf(it.value());
- const QByteArray &propertyName = it.key();
-
- QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));
- p->setGetter(g);
- p->setSetter(s);
- proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
- }
- prototype.set(v4, proto);
- }
-
- // QAbstractDynamicMetaObject
-
- void objectDestroyed(QObject *) override
- {
- release();
- }
-
- int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
- {
- return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments);
- }
-
- QV4::PersistentValue prototype;
- QList<int> propertyRoles;
- QList<int> watchedRoleIds;
- QList<QByteArray> watchedRoles;
- QHash<QByteArray, int> roleNames;
- QQmlAdaptorModel *model;
- int propertyOffset;
- int signalOffset;
- bool hasModelData;
-};
-
-QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index, int row, int column)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , type(dataType)
-{
- if (index == -1)
- cachedData.resize(type->hasModelData ? 1 : type->propertyRoles.count());
-
- QObjectPrivate::get(this)->metaObject = type;
-
- type->addref();
-}
-
-int QQmlDMCachedModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
-{
- if (call == QMetaObject::ReadProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- if (!cachedData.isEmpty()) {
- *static_cast<QVariant *>(arguments[0]) = cachedData.at(
- type->hasModelData ? 0 : propertyIndex);
- }
- } else if (*type->model) {
- *static_cast<QVariant *>(arguments[0]) = value(type->propertyRoles.at(propertyIndex));
- }
- return -1;
- } else if (call == QMetaObject::WriteProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- const QMetaObject *meta = metaObject();
- if (cachedData.count() > 1) {
- cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, propertyIndex, nullptr);
- } else if (cachedData.count() == 1) {
- cachedData[0] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, 0, nullptr);
- QMetaObject::activate(this, meta, 1, nullptr);
- }
- } else if (*type->model) {
- setValue(type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
- }
- return -1;
- } else {
- return qt_metacall(call, id, arguments);
- }
-}
-
-void QQmlDMCachedModelData::setValue(const QString &role, const QVariant &value)
-{
- QHash<QByteArray, int>::iterator it = type->roleNames.find(role.toUtf8());
- if (it != type->roleNames.end()) {
- for (int i = 0; i < type->propertyRoles.count(); ++i) {
- if (type->propertyRoles.at(i) == *it) {
- cachedData[i] = value;
- return;
- }
- }
- }
-}
-
-bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &adaptorModel, int idx)
-{
- if (index == -1) {
- Q_ASSERT(idx >= 0);
- cachedData.clear();
- setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
- const QMetaObject *meta = metaObject();
- const int propertyCount = type->propertyRoles.count();
- for (int i = 0; i < propertyCount; ++i)
- QMetaObject::activate(this, meta, i, nullptr);
- return true;
- } else {
- return false;
- }
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
- if (o->d()->item->index == -1) {
- if (!modelData->cachedData.isEmpty()) {
- return scope.engine->fromVariant(
- modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId));
- }
- } else if (*modelData->type->model) {
- return scope.engine->fromVariant(
- modelData->value(modelData->type->propertyRoles.at(propertyId)));
- }
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return scope.engine->throwTypeError();
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- 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] = scope.engine->toVariant(argv[0], QVariant::Invalid);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
- } else if (modelData->cachedData.count() == 1) {
- modelData->cachedData[0] = scope.engine->toVariant(argv[0], QVariant::Invalid);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
- }
- }
- }
- return QV4::Encode::undefined();
-}
-
-//-----------------------------------------------------------------
-// QAbstractItemModel
-//-----------------------------------------------------------------
-
-class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
-{
- Q_OBJECT
- Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
-
-public:
- QQmlDMAbstractItemModelData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column)
- : QQmlDMCachedModelData(metaType, dataType, index, row, column)
- {
- }
-
- bool hasModelChildren() const
- {
- if (index >= 0 && *type->model) {
- const QAbstractItemModel * const model = type->model->aim();
- return model->hasChildren(model->index(row, column, type->model->rootIndex));
- } else {
- return false;
- }
- }
-
- QVariant value(int role) const override
- {
- return type->model->aim()->index(row, column, type->model->rootIndex).data(role);
- }
-
- void setValue(int role, const QVariant &value) override
- {
- type->model->aim()->setData(
- type->model->aim()->index(row, column, type->model->rootIndex), value, role);
- }
-
- QV4::ReturnedValue get() override
- {
- if (type->prototype.isUndefined()) {
- QQmlAdaptorModelEngineData * const data = engineData(v4);
- type->initializeConstructor(data);
- }
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, type->prototype.value());
- QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- o->setPrototypeOf(proto);
- ++scriptRef;
- return o.asReturnedValue();
- }
-};
-
-class VDMAbstractItemModelDataType : public VDMModelDelegateDataType
-{
-public:
- VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
- : VDMModelDelegateDataType(model)
- {
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.aim()->rowCount(model.rootIndex);
- }
-
- int columnCount(const QQmlAdaptorModel &model) const override
- {
- return model.aim()->columnCount(model.rootIndex);
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMAbstractItemModelDataType *>(this)->release();
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
- if (it != roleNames.end()) {
- return model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex).data(*it);
- } else if (role == QLatin1String("hasModelChildren")) {
- return QVariant(model.aim()->hasChildren(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex)));
- } else {
- return QVariant();
- }
- }
-
- QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
- {
- return model
- ? QVariant::fromValue(model.aim()->parent(model.rootIndex))
- : QVariant();
- }
-
- QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
- {
- return model
- ? QVariant::fromValue(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex))
- : QVariant();
- }
-
- bool canFetchMore(const QQmlAdaptorModel &model) const override
- {
- return model && model.aim()->canFetchMore(model.rootIndex);
- }
-
- void fetchMore(QQmlAdaptorModel &model) const override
- {
- if (model)
- model.aim()->fetchMore(model.rootIndex);
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return new QQmlDMAbstractItemModelData(metaType, dataType, index, row, column);
- }
-
- void initializeMetaType(QQmlAdaptorModel &model)
- {
- QMetaObjectBuilder builder;
- setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
-
- const QByteArray propertyType = QByteArrayLiteral("QVariant");
- const QHash<int, QByteArray> names = model.aim()->roleNames();
- for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
- const int propertyId = propertyRoles.count();
- propertyRoles.append(it.key());
- roleNames.insert(it.value(), it.key());
- addProperty(&builder, propertyId, it.value(), propertyType);
- }
- if (propertyRoles.count() == 1) {
- hasModelData = true;
- const int role = names.begin().key();
- const QByteArray propertyName = QByteArrayLiteral("modelData");
-
- propertyRoles.append(role);
- roleNames.insert(propertyName, role);
- addProperty(&builder, 1, propertyName, propertyType);
- }
-
- metaObject.reset(builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *metaObject;
- propertyCache.adopt(new QQmlPropertyCache(metaObject.data(), model.modelItemRevision));
- }
-};
-
-//-----------------------------------------------------------------
-// QQmlListAccessor
-//-----------------------------------------------------------------
-
-class QQmlDMListAccessorData : public QQmlDelegateModelItem
-{
- Q_OBJECT
- Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
-public:
- QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int index, int row, int column, const QVariant &value)
- : QQmlDelegateModelItem(metaType, accessor, index, row, column)
- , cachedData(value)
- {
- }
-
- QVariant modelData() const
- {
- return cachedData;
- }
-
- void setModelData(const QVariant &data)
- {
- if (data == cachedData)
- return;
-
- cachedData = data;
- emit modelDataChanged();
- }
-
- static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
- }
-
- static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return v4->throwTypeError();
-
- static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QVariant::Invalid));
- return QV4::Encode::undefined();
- }
-
- QV4::ReturnedValue get() override
- {
- QQmlAdaptorModelEngineData *data = engineData(v4);
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- QV4::ScopedObject p(scope, data->listItemProto.value());
- o->setPrototypeOf(p);
- ++scriptRef;
- return o.asReturnedValue();
- }
-
- void setValue(const QString &role, const QVariant &value) override
- {
- if (role == QLatin1String("modelData"))
- cachedData = value;
- }
-
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override
- {
- if (index == -1) {
- index = idx;
- cachedData = model.list.at(idx);
- emit modelIndexChanged();
- emit modelDataChanged();
- return true;
- } else {
- return false;
- }
- }
-
-
-Q_SIGNALS:
- void modelDataChanged();
-
-private:
- QVariant cachedData;
-};
-
-
-class VDMListDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- VDMListDelegateDataType()
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- {}
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMListDelegateDataType *>(this)->release();
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- return role == QLatin1String("modelData")
- ? model.list.at(index)
- : QVariant();
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
- if (!propertyCache) {
- dataType->propertyCache.adopt(new QQmlPropertyCache(
- &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision));
- }
-
- return new QQmlDMListAccessorData(
- metaType,
- dataType,
- index, row, column,
- index >= 0 && index < model.list.count() ? model.list.at(index) : QVariant());
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
- QVariant updatedModelData = model.list.at(listModelItem->index);
- listModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-//-----------------------------------------------------------------
-// QObject
-//-----------------------------------------------------------------
-
-class VDMObjectDelegateDataType;
-class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
-{
- Q_OBJECT
- Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
- Q_INTERFACES(QQmlAdaptorModelProxyInterface)
-public:
- QQmlDMObjectData(
- QQmlDelegateModelItemMetaType *metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object);
-
- void setModelData(QObject *modelData)
- {
- if (modelData == object)
- return;
-
- object = modelData;
- emit modelDataChanged();
- }
-
- QObject *modelData() const { return object; }
- QObject *proxiedObject() override { return object; }
-
- QPointer<QObject> object;
-
-Q_SIGNALS:
- void modelDataChanged();
-};
-
-class VDMObjectDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- int propertyOffset;
- int signalOffset;
- bool shared;
- QMetaObjectBuilder builder;
-
- VDMObjectDelegateDataType()
- : propertyOffset(0)
- , signalOffset(0)
- , shared(true)
- {
- }
-
- VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- , propertyOffset(type.propertyOffset)
- , signalOffset(type.signalOffset)
- , shared(false)
- , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
- | QMetaObjectBuilder::Signals
- | QMetaObjectBuilder::SuperClass
- | QMetaObjectBuilder::ClassName)
- {
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- if (QObject *object = model.list.at(index).value<QObject *>())
- return object->property(role.toUtf8());
- return QVariant();
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
- int index, int row, int column) const override
- {
- VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return index >= 0 && index < model.list.count()
- ? new QQmlDMObjectData(metaType, dataType, index, row, column, qvariant_cast<QObject *>(model.list.at(index)))
- : nullptr;
- }
-
- void initializeMetaType(QQmlAdaptorModel &model)
- {
- Q_UNUSED(model);
- setModelDataType<QQmlDMObjectData>(&builder, this);
-
- metaObject.reset(builder.toMetaObject());
- // Note: ATM we cannot create a shared property cache for this class, since each model
- // object can have different properties. And to make those properties available to the
- // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass
- // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache.
- // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem
- // will always be available to the delegate, regardless of the import version.
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMObjectDelegateDataType *>(this)->release();
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
- QObject *updatedModelData = qvariant_cast<QObject *>(model.list.at(objectModelItem->index));
- objectModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
-{
-public:
- QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
- : m_data(data)
- , m_type(type)
- {
- QObjectPrivate *op = QObjectPrivate::get(m_data);
- *static_cast<QMetaObject *>(this) = *type->metaObject;
- op->metaObject = this;
- m_type->addref();
- }
-
- ~QQmlDMObjectDataMetaObject()
- {
- m_type->release();
- }
-
- int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
- {
- Q_ASSERT(o == m_data);
- Q_UNUSED(o);
-
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
- if (id >= m_type->propertyOffset
- && (call == QMetaObject::ReadProperty
- || call == QMetaObject::WriteProperty
- || call == QMetaObject::ResetProperty)) {
- if (m_data->object)
- QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
- return -1;
- } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
- QMetaObject::activate(m_data, this, id - m_type->signalOffset, nullptr);
- return -1;
- } else {
- return m_data->qt_metacall(call, id, arguments);
- }
- }
-
- int createProperty(const char *name, const char *) override
- {
- if (!m_data->object)
- return -1;
- const QMetaObject *metaObject = m_data->object->metaObject();
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
-
- const int previousPropertyCount = propertyCount() - propertyOffset();
- int propertyIndex = metaObject->indexOfProperty(name);
- if (propertyIndex == -1)
- return -1;
- if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
-
- if (m_type->shared) {
- VDMObjectDelegateDataType *type = m_type;
- m_type = new VDMObjectDelegateDataType(*m_type);
- type->release();
- }
-
- const int previousMethodCount = methodCount();
- int notifierId = previousMethodCount - methodOffset();
- for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
- QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
- QMetaPropertyBuilder propertyBuilder;
- if (property.hasNotifySignal()) {
- m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
- ++notifierId;
- } else {
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
- }
- propertyBuilder.setWritable(property.isWritable());
- propertyBuilder.setResettable(property.isResettable());
- propertyBuilder.setConstant(property.isConstant());
- }
-
- m_type->metaObject.reset(m_type->builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *m_type->metaObject;
-
- notifierId = previousMethodCount;
- for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
- QMetaProperty property = metaObject->property(i + objectPropertyOffset);
- if (property.hasNotifySignal()) {
- QQmlPropertyPrivate::connect(
- m_data->object, property.notifySignalIndex(), m_data, notifierId);
- ++notifierId;
- }
- }
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
- }
-
- QQmlDMObjectData *m_data;
- VDMObjectDelegateDataType *m_type;
-};
-
-QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , object(object)
-{
- new QQmlDMObjectDataMetaObject(this, dataType);
-}
-
-//-----------------------------------------------------------------
-// QQmlAdaptorModel
-//-----------------------------------------------------------------
-
-static const QQmlAdaptorModel::Accessors qt_vdm_null_accessors;
-
-QQmlAdaptorModel::Accessors::~Accessors()
-{
-}
-
-QQmlAdaptorModel::QQmlAdaptorModel()
- : accessors(&qt_vdm_null_accessors)
-{
-}
-
-QQmlAdaptorModel::~QQmlAdaptorModel()
-{
- accessors->cleanup(*this);
-}
-
-void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine)
-{
- accessors->cleanup(*this);
-
- list.setList(variant, engine);
-
- if (QObject *object = qvariant_cast<QObject *>(list.list())) {
- setObject(object, parent);
- if (qobject_cast<QAbstractItemModel *>(object))
- accessors = new VDMAbstractItemModelDataType(this);
- else
- accessors = new VDMObjectDelegateDataType;
- } else if (list.type() == QQmlListAccessor::ListProperty) {
- setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), parent);
- accessors = new VDMObjectDelegateDataType;
- } else if (list.type() != QQmlListAccessor::Invalid
- && list.type() != QQmlListAccessor::Instance) { // Null QObject
- setObject(nullptr, parent);
- accessors = new VDMListDelegateDataType;
- } else {
- setObject(nullptr, parent);
- accessors = &qt_vdm_null_accessors;
- }
-}
-
-void QQmlAdaptorModel::invalidateModel()
-{
- accessors->cleanup(*this);
- accessors = &qt_vdm_null_accessors;
- // Don't clear the model object as we still need the guard to clear the list variant if the
- // object is destroyed.
-}
-
-bool QQmlAdaptorModel::isValid() const
-{
- return accessors != &qt_vdm_null_accessors;
-}
-
-int QQmlAdaptorModel::count() const
-{
- return rowCount() * columnCount();
-}
-
-int QQmlAdaptorModel::rowCount() const
-{
- return qMax(0, accessors->rowCount(*this));
-}
-
-int QQmlAdaptorModel::columnCount() const
-{
- return qMax(0, accessors->columnCount(*this));
-}
-
-int QQmlAdaptorModel::rowAt(int index) const
-{
- int count = rowCount();
- return count <= 0 ? -1 : index % count;
-}
-
-int QQmlAdaptorModel::columnAt(int index) const
-{
- int count = rowCount();
- return count <= 0 ? -1 : index / count;
-}
-
-int QQmlAdaptorModel::indexAt(int row, int column) const
-{
- return column * rowCount() + row;
-}
-
-void QQmlAdaptorModel::useImportVersion(int minorVersion)
-{
- modelItemRevision = minorVersion;
-}
-
-void QQmlAdaptorModel::objectDestroyed(QObject *)
-{
- setModel(QVariant(), nullptr, nullptr);
-}
-
-QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4)
- : v4(v4)
-{
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("modelData"),
- QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
- listItemProto.set(v4, proto);
-}
-
-QQmlAdaptorModelEngineData::~QQmlAdaptorModelEngineData()
-{
-}
-
-QT_END_NAMESPACE
-
-#include <qqmladaptormodel.moc>
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
deleted file mode 100644
index 8c18466ab5..0000000000
--- a/src/qml/util/qqmladaptormodel_p.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLADAPTORMODEL_P_H
-#define QQMLADAPTORMODEL_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/qabstractitemmodel.h>
-
-#include "private/qqmllistaccessor_p.h"
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlguard_p.h>
-#include <private/qqmlnullablevalue_p.h>
-
-QT_REQUIRE_CONFIG(qml_delegate_model);
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-class QQmlDelegateModel;
-class QQmlDelegateModelItem;
-class QQmlDelegateModelItemMetaType;
-
-class Q_QML_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
-{
-public:
- class Accessors
- {
- public:
- inline Accessors() {}
- virtual ~Accessors();
- virtual int rowCount(const QQmlAdaptorModel &) const { return 0; }
- virtual int columnCount(const QQmlAdaptorModel &) const { return 0; }
- virtual void cleanup(QQmlAdaptorModel &) const {}
-
- virtual QVariant value(const QQmlAdaptorModel &, int, const QString &) const {
- return QVariant(); }
-
- virtual QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &,
- QQmlDelegateModelItemMetaType *,
- int, int, int) const { return nullptr; }
-
- virtual bool notify(
- const QQmlAdaptorModel &,
- const QList<QQmlDelegateModelItem *> &,
- int,
- int,
- const QVector<int> &) const { return false; }
- virtual void replaceWatchedRoles(
- QQmlAdaptorModel &,
- const QList<QByteArray> &,
- const QList<QByteArray> &) const {}
- virtual QVariant parentModelIndex(const QQmlAdaptorModel &) const {
- return QVariant(); }
- virtual QVariant modelIndex(const QQmlAdaptorModel &, int) const {
- return QVariant(); }
- virtual bool canFetchMore(const QQmlAdaptorModel &) const { return false; }
- virtual void fetchMore(QQmlAdaptorModel &) const {}
-
- QScopedPointer<QMetaObject, QScopedPointerPodDeleter> metaObject;
- QQmlRefPointer<QQmlPropertyCache> propertyCache;
- };
-
- const Accessors *accessors;
- QPersistentModelIndex rootIndex;
- QQmlListAccessor list;
-
- int modelItemRevision = 0;
-
- QQmlAdaptorModel();
- ~QQmlAdaptorModel();
-
- inline QVariant model() const { return list.list(); }
- void setModel(const QVariant &variant, QObject *parent, QQmlEngine *engine);
- void invalidateModel();
-
- bool isValid() const;
- int count() const;
- int rowCount() const;
- int columnCount() const;
- int rowAt(int index) const;
- int columnAt(int index) const;
- int indexAt(int row, int column) const;
-
- void useImportVersion(int minorVersion);
-
- inline bool adaptsAim() const { return qobject_cast<QAbstractItemModel *>(object()); }
- inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); }
- inline const QAbstractItemModel *aim() const { return static_cast<const QAbstractItemModel *>(object()); }
-
- inline QVariant value(int index, const QString &role) const {
- return accessors->value(*this, index, role); }
- inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) {
- return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); }
- inline bool hasProxyObject() const {
- return list.type() == QQmlListAccessor::Instance || list.type() == QQmlListAccessor::ListProperty; }
-
- inline bool notify(
- const QList<QQmlDelegateModelItem *> &items,
- int index,
- int count,
- const QVector<int> &roles) const {
- return accessors->notify(*this, items, index, count, roles); }
- inline void replaceWatchedRoles(
- const QList<QByteArray> &oldRoles, const QList<QByteArray> &newRoles) {
- accessors->replaceWatchedRoles(*this, oldRoles, newRoles); }
-
- inline QVariant modelIndex(int index) const { return accessors->modelIndex(*this, index); }
- inline QVariant parentModelIndex() const { return accessors->parentModelIndex(*this); }
- inline bool canFetchMore() const { return accessors->canFetchMore(*this); }
- inline void fetchMore() { return accessors->fetchMore(*this); }
-
-protected:
- void objectDestroyed(QObject *) override;
-};
-
-class QQmlAdaptorModelProxyInterface
-{
-public:
- virtual ~QQmlAdaptorModelProxyInterface() {}
-
- virtual QObject *proxiedObject() = 0;
-};
-
-#define QQmlAdaptorModelProxyInterface_iid "org.qt-project.Qt.QQmlAdaptorModelProxyInterface"
-
-Q_DECLARE_INTERFACE(QQmlAdaptorModelProxyInterface, QQmlAdaptorModelProxyInterface_iid)
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qml/util/qqmlchangeset.cpp
deleted file mode 100644
index ba876b42e2..0000000000
--- a/src/qml/util/qqmlchangeset.cpp
+++ /dev/null
@@ -1,583 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlchangeset_p.h"
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \class QQmlChangeSet
- \brief The QQmlChangeSet class stores an ordered list of notifications about
- changes to a linear data set.
- \internal
-
- QQmlChangeSet can be used to record a series of notifications about items in an indexed list
- being inserted, removed, moved, and changed. Notifications in the set are re-ordered so that
- all notifications of a single type are grouped together and sorted in order of ascending index,
- with remove notifications preceding all others, followed by insert notification, and then
- change notifications.
-
- Moves in a change set are represented by a remove notification paired with an insert
- notification by way of a shared unique moveId. Re-ordering may result in one or both of the
- paired notifications being divided, when this happens the offset member of the notification
- will indicate the relative offset of the divided notification from the beginning of the
- original.
-*/
-
-/*!
- Constructs an empty change set.
-*/
-
-QQmlChangeSet::QQmlChangeSet()
- : m_difference(0)
-{
-}
-
-/*!
- Constructs a copy of a \a changeSet.
-*/
-
-QQmlChangeSet::QQmlChangeSet(const QQmlChangeSet &changeSet)
- : m_removes(changeSet.m_removes)
- , m_inserts(changeSet.m_inserts)
- , m_changes(changeSet.m_changes)
- , m_difference(changeSet.m_difference)
-{
-}
-
-/*!
- Destroys a change set.
-*/
-
-QQmlChangeSet::~QQmlChangeSet()
-{
-}
-
-/*!
- Assigns the value of a \a changeSet to another.
-*/
-
-QQmlChangeSet &QQmlChangeSet::operator =(const QQmlChangeSet &changeSet)
-{
- m_removes = changeSet.m_removes;
- m_inserts = changeSet.m_inserts;
- m_changes = changeSet.m_changes;
- m_difference = changeSet.m_difference;
- return *this;
-}
-
-/*!
- Appends a notification that \a count items were inserted at \a index.
-*/
-
-void QQmlChangeSet::insert(int index, int count)
-{
- insert(QVector<Change>() << Change(index, count));
-}
-
-/*!
- Appends a notification that \a count items were removed at \a index.
-*/
-
-void QQmlChangeSet::remove(int index, int count)
-{
- QVector<Change> removes;
- removes.append(Change(index, count));
- remove(&removes, nullptr);
-}
-
-/*!
- Appends a notification that \a count items were moved \a from one index \a to another.
-
- The \a moveId must be unique across the lifetime of the change set and any related
- change sets.
-*/
-
-void QQmlChangeSet::move(int from, int to, int count, int moveId)
-{
- QVector<Change> removes;
- removes.append(Change(from, count, moveId));
- QVector<Change> inserts;
- inserts.append(Change(to, count, moveId));
- remove(&removes, &inserts);
- insert(inserts);
-}
-
-/*!
- Appends a notification that \a count items were changed at \a index.
-*/
-
-void QQmlChangeSet::change(int index, int count)
-{
- QVector<Change> changes;
- changes.append(Change(index, count));
- change(changes);
-}
-
-/*!
- Applies the changes in a \a changeSet to another.
-*/
-
-void QQmlChangeSet::apply(const QQmlChangeSet &changeSet)
-{
- QVector<Change> r = changeSet.m_removes;
- QVector<Change> i = changeSet.m_inserts;
- QVector<Change> c = changeSet.m_changes;
- remove(&r, &i);
- insert(i);
- change(c);
-}
-
-/*!
- Applies a list of \a removes to a change set.
-
- If a remove contains a moveId then any intersecting insert in the set will replace the
- corresponding intersection in the optional \a inserts list.
-*/
-
-void QQmlChangeSet::remove(const QVector<Change> &removes, QVector<Change> *inserts)
-{
- QVector<Change> r = removes;
- remove(&r, inserts);
-}
-
-void QQmlChangeSet::remove(QVector<Change> *removes, QVector<Change> *inserts)
-{
- int removeCount = 0;
- int insertCount = 0;
- QVector<Change>::iterator insert = m_inserts.begin();
- QVector<Change>::iterator change = m_changes.begin();
- QVector<Change>::iterator rit = removes->begin();
- for (; rit != removes->end(); ++rit) {
- int index = rit->index + removeCount;
- int count = rit->count;
-
- // Decrement the accumulated remove count from the indexes of any changes prior to the
- // current remove.
- for (; change != m_changes.end() && change->end() < rit->index; ++change)
- change->index -= removeCount;
- // Remove any portion of a change notification that intersects the current remove.
- for (; change != m_changes.end() && change->index > rit->end(); ++change) {
- change->count -= qMin(change->end(), rit->end()) - qMax(change->index, rit->index);
- if (change->count == 0) {
- change = m_changes.erase(change);
- } else if (rit->index < change->index) {
- change->index = rit->index;
- }
- }
-
- // Decrement the accumulated remove count from the indexes of any inserts prior to the
- // current remove.
- for (; insert != m_inserts.end() && insert->end() <= index; ++insert) {
- insertCount += insert->count;
- insert->index -= removeCount;
- }
-
- rit->index -= insertCount;
-
- // Remove any portion of a insert notification that intersects the current remove.
- while (insert != m_inserts.end() && insert->index < index + count) {
- int offset = index - insert->index;
- const int difference = qMin(insert->end(), index + count) - qMax(insert->index, index);
-
- // If part of the remove or insert that precedes the intersection has a moveId create
- // 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, Change(
- rit->index, -offset, rit->moveId, rit->offset));
- ++rit;
- rit->count -= -offset;
- rit->offset += -offset;
- index += -offset;
- count -= -offset;
- removeCount += -offset;
- offset = 0;
- } else if (offset > 0 && insert->moveId != -1) {
- insert = m_inserts.insert(insert, Change(
- insert->index - removeCount, offset, insert->moveId, insert->offset));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- insert->offset += offset;
- rit->index -= offset;
- insertCount += offset;
- }
-
- // 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<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) {
- continue;
- }
- // If the intersecting insert starts before the replacement one create
- // 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, Change(
- iit->index, overlapOffset, iit->moveId, iit->offset));
- ++iit;
- iit->index += overlapOffset;
- iit->count -= overlapOffset;
- iit->offset += overlapOffset;
- }
- if (iit->offset >= rit->offset
- && iit->offset + iit->count <= rit->offset + difference) {
- // If the replacement insert completely encapsulates the existing
- // one just change the moveId.
- iit->moveId = insert->moveId;
- iit->offset = insert->offset + qMax(0, -overlapOffset);
- } else {
- // Create a new insertion before the intersecting one with the number of intersecting
- // items and remove that number from that insert.
- const int count
- = qMin(iit->offset + iit->count, rit->offset + difference)
- - qMax(iit->offset, rit->offset);
- iit = inserts->insert(iit, Change(
- iit->index,
- count,
- insert->moveId,
- insert->offset + qMax(0, -overlapOffset)));
- ++iit;
- iit->index += count;
- iit->count -= count;
- iit->offset += count;
- }
- }
- }
-
- // Subtract the number of intersecting items from the current remove and insert.
- insert->count -= difference;
- insert->offset += difference;
- rit->count -= difference;
- rit->offset += difference;
-
- index += difference;
- count -= difference;
- removeCount += difference;
-
- if (insert->count == 0) {
- insert = m_inserts.erase(insert);
- } else if (rit->count == -offset || rit->count == 0) {
- insert->index += difference;
- break;
- } else {
- insert->index -= removeCount - difference;
- rit->index -= insert->count;
- insertCount += insert->count;
- ++insert;
- }
- }
- removeCount += rit->count;
- }
- for (; insert != m_inserts.end(); ++insert)
- insert->index -= removeCount;
-
- removeCount = 0;
- 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<Change>::iterator next = rit + 1; next != removes->end()
- && next->index == rit->index
- && next->moveId == -1
- && rit->moveId == -1; ++next) {
- next->count += rit->count;
- rit = next;
- }
- int index = rit->index + removeCount;
- // Decrement the accumulated remove count from the indexes of any inserts prior to the
- // current remove.
- for (; remove != m_removes.end() && index > remove->index; ++remove)
- remove->index -= removeCount;
- while (remove != m_removes.end() && index + rit->count >= remove->index) {
- int count = 0;
- const int offset = remove->index - index;
- QVector<Change>::iterator rend = remove;
- for (; rend != m_removes.end()
- && rit->moveId == -1
- && rend->moveId == -1
- && index + rit->count >= rend->index; ++rend) {
- count += rend->count;
- }
- if (remove != rend) {
- // Accumulate all existing non-move removes that are encapsulated by or immediately
- // follow the current remove into it.
- int difference = 0;
- if (rend == m_removes.end()) {
- difference = rit->count;
- } else if (rit->index + rit->count < rend->index - removeCount) {
- difference = rit->count;
- } else if (rend->moveId != -1) {
- difference = rend->index - removeCount - rit->index;
- index += difference;
- }
- count += difference;
-
- rit->count -= difference;
- removeCount += difference;
- remove->index = rit->index;
- remove->count = count;
- remove = m_removes.erase(++remove, rend);
- } else {
- // 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, Change(
- rit->index, offset, rit->moveId, rit->offset));
- ++remove;
- rit->count -= offset;
- rit->offset += offset;
- removeCount += offset;
- index += offset;
- }
- remove->index = rit->index;
-
- ++remove;
- }
- }
-
- if (rit->count > 0) {
- remove = m_removes.insert(remove, *rit);
- ++remove;
- }
- removeCount += rit->count;
- }
- for (; remove != m_removes.end(); ++remove)
- remove->index -= removeCount;
- m_difference -= removeCount;
-}
-
-/*!
- Applies a list of \a inserts to a change set.
-*/
-
-void QQmlChangeSet::insert(const QVector<Change> &inserts)
-{
- int insertCount = 0;
- QVector<Change>::iterator insert = m_inserts.begin();
- QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Change>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) {
- if (iit->count == 0)
- continue;
- int index = iit->index - insertCount;
-
- Change current = *iit;
- // Accumulate consecutive inserts into a single delta before attempting to insert.
- for (QVector<Change>::const_iterator next = iit + 1; next != inserts.end()
- && next->index == iit->index + iit->count
- && next->moveId == -1
- && iit->moveId == -1; ++next) {
- current.count += next->count;
- iit = next;
- }
-
- // Increment the index of any changes before the current insert by the accumlated insert
- // count.
- for (; change != m_changes.end() && change->index >= index; ++change)
- change->index += insertCount;
- // If the current insert index is in the middle of a change split it in two at that
- // point and increment the index of the latter half.
- if (change != m_changes.end() && change->index < index + iit->count) {
- int offset = index - change->index;
- change = m_changes.insert(change, Change(change->index + insertCount, offset));
- ++change;
- change->index += iit->count + offset;
- change->count -= offset;
- }
-
- // Increment the index of any inserts before the current insert by the accumlated insert
- // count.
- for (; insert != m_inserts.end() && index > insert->index + insert->count; ++insert)
- insert->index += insertCount;
- if (insert == m_inserts.end()) {
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else {
- const int offset = index - insert->index;
-
- if (offset < 0) {
- // If the current insert is before an existing insert and not adjacent just insert
- // it into the list.
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else if (iit->moveId == -1 && insert->moveId == -1) {
- // If neither the current nor existing insert has a moveId add the current insert
- // to the existing one.
- if (offset < insert->count) {
- insert->index -= current.count;
- insert->count += current.count;
- } else {
- insert->index += insertCount;
- insert->count += current.count;
- ++insert;
- }
- } else if (offset < insert->count) {
- // 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, Change(
- insert->index + insertCount, offset, insert->moveId, insert->offset));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- insert->offset += offset;
- }
- insert = m_inserts.insert(insert, current);
- ++insert;
- } else {
- insert->index += insertCount;
- ++insert;
- insert = m_inserts.insert(insert, current);
- ++insert;
- }
- }
- insertCount += current.count;
- }
- for (; insert != m_inserts.end(); ++insert)
- insert->index += insertCount;
- m_difference += insertCount;
-}
-
-/*!
- Applies a combined list of \a removes and \a inserts to a change set. This is equivalent
- calling \l remove() followed by \l insert() with the same lists.
-*/
-
-void QQmlChangeSet::move(const QVector<Change> &removes, const QVector<Change> &inserts)
-{
- QVector<Change> r = removes;
- QVector<Change> i = inserts;
- remove(&r, &i);
- insert(i);
-}
-
-/*!
- Applies a list of \a changes to a change set.
-*/
-
-void QQmlChangeSet::change(const QVector<Change> &changes)
-{
- QVector<Change> c = changes;
- change(&c);
-}
-
-void QQmlChangeSet::change(QVector<Change> *changes)
-{
- 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) {}
- for (; insert != m_inserts.end() && insert->index < cit->end(); ++insert) {
- const int offset = insert->index - cit->index;
- const int count = cit->count + cit->index - insert->index - insert->count;
- if (offset == 0) {
- cit->index = insert->index + insert->count;
- cit->count = count;
- } else {
- cit = changes->insert(++cit, Change(insert->index + insert->count, count));
- --cit;
- cit->count = offset;
- }
- }
-
- for (; change != m_changes.end() && change->index + change->count < cit->index; ++change) {}
- if (change == m_changes.end() || change->index > cit->index + cit->count) {
- if (cit->count > 0) {
- change = m_changes.insert(change, *cit);
- ++change;
- }
- } else {
- if (cit->index < change->index) {
- change->count += change->index - cit->index;
- change->index = cit->index;
- }
-
- if (cit->index + cit->count > change->index + change->count) {
- change->count = cit->index + cit->count - change->index;
- QVector<Change>::iterator cbegin = change;
- QVector<Change>::iterator cend = ++cbegin;
- for (; cend != m_changes.end() && cend->index <= change->index + change->count; ++cend) {
- if (cend->index + cend->count > change->index + change->count)
- change->count = cend->index + cend->count - change->index;
- }
- if (cbegin != cend) {
- change = m_changes.erase(cbegin, cend);
- --change;
- }
- }
- }
- }
-}
-
-/*!
- Prints the contents of a change \a set to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
-{
- debug.nospace() << "QQmlChangeSet(";
- const QVector<QQmlChangeSet::Change> &removes = set.removes();
- for (const QQmlChangeSet::Change &remove : removes)
- debug << remove;
- const QVector<QQmlChangeSet::Change> &inserts = set.inserts();
- for (const QQmlChangeSet::Change &insert : inserts)
- debug << insert;
- const QVector<QQmlChangeSet::Change> &changes = set.changes();
- for (const QQmlChangeSet::Change &change : changes)
- debug << change;
- return debug.nospace() << ')';
-}
-
-/*!
- Prints a \a change to the \a debug stream.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change)
-{
- return (debug.nospace() << "Change(" << change.index << ',' << change.count << ')').space();
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qml/util/qqmlchangeset_p.h
deleted file mode 100644
index 8347a3ff19..0000000000
--- a/src/qml/util/qqmlchangeset_p.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLCHANGESET_P_H
-#define QQMLCHANGESET_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/qdebug.h>
-#include <QtCore/qvector.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_QML_PRIVATE_EXPORT QQmlChangeSet
-{
-public:
- struct MoveKey
- {
- MoveKey() {}
- MoveKey(int moveId, int offset) : moveId(moveId), offset(offset) {}
- int moveId = -1;
- int offset = 0;
- };
-
- // The storrage for Change (below). This struct is trivial, which it has to be in order to store
- // it in a QV4::Heap::Base object. The Change struct doesn't add any storage fields, so it is
- // safe to cast ChangeData to/from Change.
- struct ChangeData
- {
- int index;
- int count;
- int moveId;
- int offset;
- };
-
- struct Change: ChangeData
- {
- Change() {
- index = 0;
- count = 0;
- moveId = -1;
- offset = 0;
- }
- Change(int index, int count, int moveId = -1, int offset = 0) {
- this->index = index;
- this->count = count;
- this->moveId = moveId;
- this->offset = offset;
- }
-
- bool isMove() const { return moveId >= 0; }
-
- MoveKey moveKey(int index) const {
- return MoveKey(moveId, index - Change::index + offset); }
-
- int start() const { return index; }
- int end() const { return index + count; }
- };
-
- QQmlChangeSet();
- QQmlChangeSet(const QQmlChangeSet &changeSet);
- ~QQmlChangeSet();
-
- QQmlChangeSet &operator =(const QQmlChangeSet &changeSet);
-
- 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);
- void remove(int index, int count);
- void move(int from, int to, int count, int moveId);
- void change(int index, int count);
-
- void insert(const QVector<Change> &inserts);
- void remove(const QVector<Change> &removes, QVector<Change> *inserts = nullptr);
- void move(const QVector<Change> &removes, const QVector<Change> &inserts);
- void change(const QVector<Change> &changes);
- void apply(const QQmlChangeSet &changeSet);
-
- bool isEmpty() const { return m_removes.empty() && m_inserts.empty() && m_changes.isEmpty(); }
-
- void clear()
- {
- m_removes.clear();
- m_inserts.clear();
- m_changes.clear();
- m_difference = 0;
- }
-
- int difference() const { return m_difference; }
-
-private:
- void remove(QVector<Change> *removes, QVector<Change> *inserts);
- void change(QVector<Change> *changes);
-
- 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::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::Change &change);
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/qqmllistaccessor.cpp b/src/qml/util/qqmllistaccessor.cpp
deleted file mode 100644
index 46a11e2bc2..0000000000
--- a/src/qml/util/qqmllistaccessor.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistaccessor_p.h"
-
-#include <private/qqmlmetatype_p.h>
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qdebug.h>
-
-// ### Remove me
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlListAccessor::QQmlListAccessor()
-: m_type(Invalid)
-{
-}
-
-QQmlListAccessor::~QQmlListAccessor()
-{
-}
-
-QVariant QQmlListAccessor::list() const
-{
- return d;
-}
-
-void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
-{
- d = v;
-
- // An incoming JS array as model is treated as a variant list, so we need to
- // convert it first with toVariant().
- if (d.userType() == qMetaTypeId<QJSValue>())
- d = d.value<QJSValue>().toVariant();
-
- QQmlEnginePrivate *enginePrivate = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- if (!d.isValid()) {
- m_type = Invalid;
- } else if (d.userType() == QVariant::StringList) {
- m_type = StringList;
- } else if (d.userType() == QMetaType::QVariantList) {
- m_type = VariantList;
- } else if (d.canConvert(QVariant::Int)) {
- // Here we have to check for an upper limit, because down the line code might (well, will)
- // allocate memory depending on the number of elements. The upper limit cannot be INT_MAX:
- // QVector<QPointer<QQuickItem>> something;
- // something.resize(count());
- // (See e.g. QQuickRepeater::regenerate())
- // This will allocate data along the lines of:
- // sizeof(QPointer<QQuickItem>) * count() + QVector::headerSize
- // So, doing an approximate round-down-to-nice-number, we get:
- const int upperLimit = 100 * 1000 * 1000;
-
- int i = v.toInt();
- if (i < 0) {
- qWarning("Model size of %d is less than 0", i);
- m_type = Invalid;
- } else if (i > upperLimit) {
- qWarning("Model size of %d is bigger than the upper limit %d", i, upperLimit);
- m_type = Invalid;
- } else {
- m_type = Integer;
- }
- } else if ((!enginePrivate && QQmlMetaType::isQObject(d.userType())) ||
- (enginePrivate && enginePrivate->isQObject(d.userType()))) {
- QObject *data = enginePrivate?enginePrivate->toQObject(d):QQmlMetaType::toQObject(d);
- d = QVariant::fromValue(data);
- m_type = Instance;
- } else if (d.userType() == qMetaTypeId<QQmlListReference>()) {
- m_type = ListProperty;
- } else {
- m_type = Instance;
- }
-}
-
-int QQmlListAccessor::count() const
-{
- switch(m_type) {
- case StringList:
- return qvariant_cast<QStringList>(d).count();
- case VariantList:
- return qvariant_cast<QVariantList>(d).count();
- case ListProperty:
- return ((const QQmlListReference *)d.constData())->count();
- case Instance:
- return 1;
- case Integer:
- return d.toInt();
- default:
- case Invalid:
- return 0;
- }
-}
-
-QVariant QQmlListAccessor::at(int idx) const
-{
- Q_ASSERT(idx >= 0 && idx < count());
- switch(m_type) {
- case StringList:
- return QVariant::fromValue(qvariant_cast<QStringList>(d).at(idx));
- case VariantList:
- return qvariant_cast<QVariantList>(d).at(idx);
- case ListProperty:
- return QVariant::fromValue(((const QQmlListReference *)d.constData())->at(idx));
- case Instance:
- return d;
- case Integer:
- return QVariant(idx);
- default:
- case Invalid:
- return QVariant();
- }
-}
-
-bool QQmlListAccessor::isValid() const
-{
- return m_type != Invalid;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp
deleted file mode 100644
index 921e86f355..0000000000
--- a/src/qml/util/qqmllistcompositor.cpp
+++ /dev/null
@@ -1,1482 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmllistcompositor_p.h"
-
-#include <QtCore/qvarlengtharray.h>
-
-//#define QT_QML_VERIFY_MINIMAL
-//#define QT_QML_VERIFY_INTEGRITY
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QQmlListCompositor
- \brief The QQmlListCompositor class provides a lookup table for filtered, or re-ordered list
- indexes.
- \internal
-
- QQmlListCompositor is intended as an aid for developing proxy models. It doesn't however
- directly proxy a list or model, instead a range of indexes from one or many lists can be
- inserted into the compositor and then categorized and shuffled around and it will manage the
- task of translating from an index in the combined space into an index in a particular list.
-
- Within a compositor indexes are categorized into groups where a group is a sub-set of the
- total indexes referenced by the compositor, each with an address space ranging from 0 to
- the number of indexes in the group - 1. Group memberships are independent of each other with
- the one exception that items always retain the same order so if an index is moved within a
- group, its position in other groups will change as well.
-
- The iterator classes encapsulate information about a specific position in a compositor group.
- This includes a source list, the index of an item within that list and the groups that item
- is a member of. The iterator for a specific position in a group can be retrieved with the
- find() function and the addition and subtraction operators of the iterators can be used to
- navigate to adjacent items in the same group.
-
- Items can be added to the compositor with the append() and insert() functions, group
- membership can be changed with the setFlags() and clearFlags() functions, and the position
- of items in the compositor can be changed with the move() function. Each of these functions
- optionally returns a list of the changes made to indexes within each group which can then
- be propagated to view so that it can correctly refresh its contents; e.g. 3 items
- removed at index 6, and 5 items inserted at index 1. The notification changes are always
- ordered from the start of the list to the end and accumulate, so if 5 items are removed at
- index 4, one is skipped and then 3 move are removed, the changes returned are 5 items removed
- at index 4, followed by 3 items removed at index 4.
-
- When the contents of a source list change, the mappings within the compositor can be updated
- with the listItemsInserted(), listItemsRemoved(), listItemsMoved(), and listItemsChanged()
- functions. Like the direct manipulation functions these too return a list of group indexes
- affected by the change. If items are removed from a source list they are also removed from
- any groups they belong to with the one exception being items belonging to the \l Cache group.
- When items belonging to this group are removed the list, index, and other group membership
- information are discarded but Cache membership is retained until explicitly removed. This
- allows the cache index to be retained until cached resources for that item are actually
- released.
-
- Internally the index mapping is stored as a list of Range objects, each has a list identifier,
- a start index, a count, and a set of flags which represent group membership and some other
- properties. The group index of a range is the sum of all preceding ranges that are members of
- that group. To avoid the inefficiency of iterating over potentially all ranges when looking
- for a specific index, each time a lookup is done the range and its indexes are cached and the
- next lookup is done relative to this. This works out to near constant time in most relevant
- use cases because successive index lookups are most frequently adjacent. The total number of
- ranges is often quite small, which helps as well. If there is a need for faster random access
- then a skip list like index may be an appropriate addition.
-
- \sa DelegateModel
-*/
-
-#ifdef QT_QML_VERIFY_MINIMAL
-#define QT_QML_VERIFY_INTEGRITY
-/*
- Diagnostic to verify there are no consecutive ranges, or that the compositor contains the
- most compact representation possible.
-
- Returns false and prints a warning if any range has a starting index equal to the end
- (index + count) index of the previous range, and both ranges also have the same flags and list
- property.
-
- If there are no consecutive ranges this will return true.
-*/
-
-static bool qt_verifyMinimal(
- const QQmlListCompositor::iterator &begin,
- const QQmlListCompositor::iterator &end)
-{
- bool minimal = true;
- int index = 0;
-
- for (const QQmlListCompositor::Range *range = begin->next; range != *end; range = range->next, ++index) {
- if (range->previous->list == range->list
- && range->previous->flags == (range->flags & ~QQmlListCompositor::AppendFlag)
- && range->previous->end() == range->index) {
- qWarning() << index << "Consecutive ranges";
- qWarning() << *range->previous;
- qWarning() << *range;
- minimal = false;
- }
- }
-
- return minimal;
-}
-
-#endif
-
-#ifdef QT_QML_VERIFY_INTEGRITY
-static bool qt_printInfo(const QQmlListCompositor &compositor)
-{
- qWarning() << compositor;
- return true;
-}
-
-/*
- Diagnostic to verify the integrity of a compositor.
-
- Per range this verifies there are no invalid range combinations, that non-append ranges have
- positive non-zero counts, and that list ranges have non-negative indexes.
-
- Accumulatively this verifies that the cached total group counts match the sum of counts
- of member ranges.
-*/
-
-static bool qt_verifyIntegrity(
- const QQmlListCompositor::iterator &begin,
- const QQmlListCompositor::iterator &end,
- const QQmlListCompositor::iterator &cachedIt)
-{
- bool valid = true;
-
- int index = 0;
- QQmlListCompositor::iterator it;
- for (it = begin; *it != *end; *it = it->next) {
- if (it->count == 0 && !it->append()) {
- qWarning() << index << "Empty non-append range";
- valid = false;
- }
- if (it->count < 0) {
- qWarning() << index << "Negative count";
- valid = false;
- }
- if (it->list && it->flags != QQmlListCompositor::CacheFlag && it->index < 0) {
- qWarning() << index <<"Negative index";
- valid = false;
- }
- if (it->previous->next != it.range) {
- qWarning() << index << "broken list: it->previous->next != it.range";
- valid = false;
- }
- if (it->next->previous != it.range) {
- qWarning() << index << "broken list: it->next->previous != it.range";
- valid = false;
- }
- if (*it == *cachedIt) {
- for (int i = 0; i < end.groupCount; ++i) {
- int groupIndex = it.index[i];
- if (cachedIt->flags & (1 << i))
- groupIndex += cachedIt.offset;
- if (groupIndex != cachedIt.index[i]) {
- qWarning() << index
- << "invalid cached index"
- << QQmlListCompositor::Group(i)
- << "Expected:"
- << groupIndex
- << "Actual"
- << cachedIt.index[i]
- << cachedIt;
- valid = false;
- }
- }
- }
- it.incrementIndexes(it->count);
- ++index;
- }
-
- for (int i = 0; i < end.groupCount; ++i) {
- if (end.index[i] != it.index[i]) {
- qWarning() << "Group" << i << "count invalid. Expected:" << end.index[i] << "Actual:" << it.index[i];
- valid = false;
- }
- }
- return valid;
-}
-#endif
-
-#if defined(QT_QML_VERIFY_MINIMAL)
-# define QT_QML_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!(qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
- && qt_verifyMinimal(iterator(m_ranges.next, 0, Default, m_groupCount), m_end)) \
- && qt_printInfo(*this)));
-#elif defined(QT_QML_VERIFY_INTEGRITY)
-# define QT_QML_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
- && qt_printInfo(*this)));
-#else
-# define QT_QML_VERIFY_LISTCOMPOSITOR
-#endif
-
-//#define QT_QML_TRACE_LISTCOMPOSITOR(args) qDebug() << m_end.index[1] << m_end.index[0] << Q_FUNC_INFO args;
-#define QT_QML_TRACE_LISTCOMPOSITOR(args)
-
-QQmlListCompositor::iterator &QQmlListCompositor::iterator::operator +=(int difference)
-{
- // Update all indexes to the start of the range.
- decrementIndexes(offset);
-
- // If the iterator group isn't a member of the current range ignore the current offset.
- if (!(range->flags & groupFlag))
- offset = 0;
-
- offset += difference;
-
- // Iterate backwards looking for a range with a positive offset.
- while (offset <= 0 && range->previous->flags) {
- range = range->previous;
- if (range->flags & groupFlag)
- offset += range->count;
- decrementIndexes(range->count);
- }
-
- // Iterate forwards looking for the first range which contains both the offset and the
- // iterator group.
- while (range->flags && (offset >= range->count || !(range->flags & groupFlag))) {
- if (range->flags & groupFlag)
- offset -= range->count;
- incrementIndexes(range->count);
- range = range->next;
- }
-
- // Update all the indexes to inclue the remaining offset.
- incrementIndexes(offset);
-
- return *this;
-}
-
-QQmlListCompositor::insert_iterator &QQmlListCompositor::insert_iterator::operator +=(int difference)
-{
- iterator::operator +=(difference);
-
- // If the previous range contains the append flag move the iterator to the tail of the previous
- // range so that appended appear after the insert position.
- if (offset == 0 && range->previous->append()) {
- range = range->previous;
- offset = range->inGroup() ? range->count : 0;
- }
-
- return *this;
-}
-
-
-/*!
- Constructs an empty list compositor.
-*/
-
-QQmlListCompositor::QQmlListCompositor()
- : m_end(m_ranges.next, 0, Default, 2)
- , m_cacheIt(m_end)
- , m_groupCount(2)
- , m_defaultFlags(PrependFlag | DefaultFlag)
- , m_removeFlags(AppendFlag | PrependFlag | GroupMask)
- , m_moveId(0)
-{
-}
-
-/*!
- Destroys a list compositor.
-*/
-
-QQmlListCompositor::~QQmlListCompositor()
-{
- for (Range *next, *range = m_ranges.next; range != &m_ranges; range = next) {
- next = range->next;
- delete range;
- }
-}
-
-/*!
- Inserts a range with the given source \a list, start \a index, \a count and \a flags, in front
- of the existing range \a before.
-*/
-
-inline QQmlListCompositor::Range *QQmlListCompositor::insert(
- Range *before, void *list, int index, int count, uint flags)
-{
- return new Range(before, list, index, count, flags);
-}
-
-/*!
- Erases a \a range from the compositor.
-
- Returns a pointer to the next range in the compositor.
-*/
-
-inline QQmlListCompositor::Range *QQmlListCompositor::erase(
- Range *range)
-{
- Range *next = range->next;
- next->previous = range->previous;
- next->previous->next = range->next;
- delete range;
- return next;
-}
-
-/*!
- Sets the number (\a count) of possible groups that items may belong to in a compositor.
-*/
-
-void QQmlListCompositor::setGroupCount(int count)
-{
- m_groupCount = count;
- m_end = iterator(&m_ranges, 0, Default, m_groupCount);
- m_cacheIt = m_end;
-}
-
-/*!
- Returns the number of items that belong to a \a group.
-*/
-
-int QQmlListCompositor::count(Group group) const
-{
- return m_end.index[group];
-}
-
-/*!
- Returns an iterator representing the item at \a index in a \a group.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::find(Group group, int index)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index)
- Q_ASSERT(index >=0 && index < count(group));
- if (m_cacheIt == m_end) {
- m_cacheIt = iterator(m_ranges.next, 0, group, m_groupCount);
- m_cacheIt += index;
- } else {
- const int offset = index - m_cacheIt.index[group];
- m_cacheIt.setGroup(group);
- m_cacheIt += offset;
- }
- Q_ASSERT(m_cacheIt.index[group] == index);
- Q_ASSERT(m_cacheIt->inGroup(group));
- QT_QML_VERIFY_LISTCOMPOSITOR
- return m_cacheIt;
-}
-
-/*!
- Returns an iterator representing the item at \a index in a \a group.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::find(Group group, int index) const
-{
- return const_cast<QQmlListCompositor *>(this)->find(group, index);
-}
-
-/*!
- Returns an iterator representing an insert position in front of the item at \a index in a
- \a group.
-
- The iterator for an insert position can sometimes resolve to a different Range than a regular
- iterator. This is because when items are inserted on a boundary between Ranges, if the first
- range has the Append flag set then the items should be inserted into that range to ensure
- that the append position for the existing range remains after the insert position.
-
- The index must be between 0 and count(group) - 1.
-*/
-
-QQmlListCompositor::insert_iterator QQmlListCompositor::findInsertPosition(Group group, int index)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index)
- Q_ASSERT(index >=0 && index <= count(group));
- insert_iterator it;
- if (m_cacheIt == m_end) {
- it = iterator(m_ranges.next, 0, group, m_groupCount);
- it += index;
- } else {
- const int offset = index - m_cacheIt.index[group];
- it = m_cacheIt;
- it.setGroup(group);
- it += offset;
- }
- Q_ASSERT(it.index[group] == index);
- return it;
-}
-
-/*!
- Appends a range of \a count indexes starting at \a index from a \a list into a compositor
- with the given \a flags.
-
- If supplied the \a inserts list will be populated with the positions of the inserted items
- in each group.
-*/
-
-void QQmlListCompositor::append(
- void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count << flags)
- insert(m_end, list, index, count, flags, inserts);
-}
-
-/*!
- Inserts a range of \a count indexes starting at \a index from a \a list with the given \a flags
- into a \a group at index \a before.
-
- If supplied the \a inserts list will be populated with the positions of items inserted into
- each group.
-*/
-
-void QQmlListCompositor::insert(
- Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << before << list << index << count << flags)
- insert(findInsertPosition(group, before), list, index, count, flags, inserts);
-}
-
-/*!
- Inserts a range of \a count indexes starting at \a index from a \a list with the given \a flags
- into a compositor at position \a before.
-
- If supplied the \a inserts list will be populated with the positions of items inserted into
- each group.
-*/
-
-QQmlListCompositor::iterator QQmlListCompositor::insert(
- iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< before << list << index << count << flags)
- if (inserts) {
- inserts->append(Insert(before, count, flags & GroupMask));
- }
- if (before.offset > 0) {
- // Inserting into the middle of a range. Split it two and update the iterator so it's
- // positioned at the start of the second half.
- *before = insert(
- *before, before->list, before->index, before.offset, before->flags & ~AppendFlag)->next;
- before->index += before.offset;
- before->count -= before.offset;
- before.offset = 0;
- }
-
-
- if (!(flags & AppendFlag) && *before != m_ranges.next
- && before->previous->list == list
- && before->previous->flags == flags
- && (!list || before->previous->end() == index)) {
- // The insert arguments represent a continuation of the previous range so increment
- // its count instead of inserting a new range.
- before->previous->count += count;
- before.incrementIndexes(count, flags);
- } else {
- *before = insert(*before, list, index, count, flags);
- before.offset = 0;
- }
-
- if (!(flags & AppendFlag) && before->next != &m_ranges
- && before->list == before->next->list
- && before->flags == before->next->flags
- && (!list || before->end() == before->next->index)) {
- // The current range and the next are continuous so add their counts and delete one.
- before->next->index = before->index;
- before->next->count += before->count;
- *before = erase(*before);
- }
-
- m_end.incrementIndexes(count, flags);
- m_cacheIt = before;
- QT_QML_VERIFY_LISTCOMPOSITOR
- return before;
-}
-
-/*!
- Sets the given flags \a flags on \a count items belonging to \a group starting at the position
- identified by \a fromGroup and the index \a from.
-
- If supplied the \a inserts list will be populated with insert notifications for affected groups.
-*/
-
-void QQmlListCompositor::setFlags(
- Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
- setFlags(find(fromGroup, from), count, group, flags, inserts);
-}
-
-/*!
- Sets the given flags \a flags on \a count items belonging to \a group starting at the position
- \a from.
-
- If supplied the \a inserts list will be populated with insert notifications for affected groups.
-*/
-
-void QQmlListCompositor::setFlags(
- iterator from, int count, Group group, uint flags, QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< from << count << flags)
- if (!flags || !count)
- return;
-
- if (from != group) {
- // Skip to the next full range if the start one is not a member of the target group.
- from.incrementIndexes(from->count - from.offset);
- from.offset = 0;
- *from = from->next;
- } else if (from.offset > 0) {
- // If the start position is mid range split off the portion unaffected.
- *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
- from->index += from.offset;
- from->count -= from.offset;
- from.offset = 0;
- }
-
- for (; count > 0; *from = from->next) {
- if (from != from.group) {
- // Skip ranges that are not members of the target group.
- from.incrementIndexes(from->count);
- continue;
- }
- // Find the number of items affected in the current range.
- const int difference = qMin(count, from->count);
- count -= difference;
-
- // Determine the actual changes made to the range and increment counts accordingly.
- const uint insertFlags = ~from->flags & flags;
- const uint setFlags = (from->flags | flags) & ~AppendFlag;
- if (insertFlags && inserts)
- inserts->append(Insert(from, difference, insertFlags | (from->flags & CacheFlag)));
- m_end.incrementIndexes(difference, insertFlags);
- from.incrementIndexes(difference, setFlags);
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == setFlags) {
- // If the additional flags make the current range a continuation of the previous
- // then move the affected items over to the previous range.
- from->previous->count += difference;
- from->index += difference;
- from->count -= difference;
- if (from->count == 0) {
- // Delete the current range if it is now empty, preserving the append flag
- // in the previous range.
- if (from->append())
- from->previous->flags |= AppendFlag;
- *from = erase(*from)->previous;
- continue;
- } else {
- break;
- }
- } else if (!insertFlags) {
- // No new flags, so roll onto the next range.
- from.incrementIndexes(from->count - difference);
- continue;
- } else if (difference < from->count) {
- // Create a new range with the updated flags, and remove the affected items
- // from the current range.
- *from = insert(*from, from->list, from->index, difference, setFlags)->next;
- from->index += difference;
- from->count -= difference;
- } else {
- // The whole range is affected so simply update the flags.
- from->flags |= flags;
- continue;
- }
- from.incrementIndexes(from->count);
- }
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == (from->flags & ~AppendFlag)) {
- // If the following range is now a continuation, merge it with its previous range.
- from.offset = from->previous->count;
- from->previous->count += from->count;
- from->previous->flags = from->flags;
- *from = erase(*from)->previous;
- }
- m_cacheIt = from;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Clears the given flags \a flags on \a count items belonging to \a group starting at the position
- \a from.
-
- If supplied the \a removes list will be populated with remove notifications for affected groups.
-*/
-
-void QQmlListCompositor::clearFlags(
- Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
- clearFlags(find(fromGroup, from), count, group, flags, removes);
-}
-
-/*!
- Clears the given flags \a flags on \a count items belonging to \a group starting at the position
- identified by \a fromGroup and the index \a from.
-
- If supplied the \a removes list will be populated with remove notifications for affected groups.
-*/
-
-void QQmlListCompositor::clearFlags(
- iterator from, int count, Group group, uint flags, QVector<Remove> *removes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< from << count << flags)
- if (!flags || !count)
- return;
-
- const bool clearCache = flags & CacheFlag;
-
- if (from != group) {
- // Skip to the next full range if the start one is not a member of the target group.
- from.incrementIndexes(from->count - from.offset);
- from.offset = 0;
- *from = from->next;
- } else if (from.offset > 0) {
- // If the start position is mid range split off the portion unaffected.
- *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
- from->index += from.offset;
- from->count -= from.offset;
- from.offset = 0;
- }
-
- for (; count > 0; *from = from->next) {
- if (from != group) {
- // Skip ranges that are not members of the target group.
- from.incrementIndexes(from->count);
- continue;
- }
- // Find the number of items affected in the current range.
- const int difference = qMin(count, from->count);
- count -= difference;
-
-
- // Determine the actual changes made to the range and decrement counts accordingly.
- const uint removeFlags = from->flags & flags & ~(AppendFlag | PrependFlag);
- const uint clearedFlags = from->flags & ~(flags | AppendFlag | UnresolvedFlag);
- if (removeFlags && removes) {
- const int maskedFlags = clearCache
- ? (removeFlags & ~CacheFlag)
- : (removeFlags | (from->flags & CacheFlag));
- if (maskedFlags)
- removes->append(Remove(from, difference, maskedFlags));
- }
- m_end.decrementIndexes(difference, removeFlags);
- from.incrementIndexes(difference, clearedFlags);
-
- if (from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || clearedFlags == CacheFlag || from->previous->end() == from->index)
- && from->previous->flags == clearedFlags) {
- // If the removed flags make the current range a continuation of the previous
- // then move the affected items over to the previous range.
- from->previous->count += difference;
- from->index += difference;
- from->count -= difference;
- if (from->count == 0) {
- // Delete the current range if it is now empty, preserving the append flag
- if (from->append())
- from->previous->flags |= AppendFlag;
- *from = erase(*from)->previous;
- } else {
- from.incrementIndexes(from->count);
- }
- } else if (difference < from->count) {
- // Create a new range with the reduced flags, and remove the affected items from
- // the current range.
- if (clearedFlags)
- *from = insert(*from, from->list, from->index, difference, clearedFlags)->next;
- from->index += difference;
- from->count -= difference;
- from.incrementIndexes(from->count);
- } else if (clearedFlags) {
- // The whole range is affected so simply update the flags.
- from->flags &= ~flags;
- } else {
- // All flags have been removed from the range so remove it.
- *from = erase(*from)->previous;
- }
- }
-
- if (*from != &m_ranges && from->previous != &m_ranges
- && from->previous->list == from->list
- && (!from->list || from->previous->end() == from->index)
- && from->previous->flags == (from->flags & ~AppendFlag)) {
- // If the following range is now a continuation, merge it with its previous range.
- from.offset = from->previous->count;
- from->previous->count += from->count;
- from->previous->flags = from->flags;
- *from = erase(*from)->previous;
- }
- m_cacheIt = from;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-bool QQmlListCompositor::verifyMoveTo(
- Group fromGroup, int from, Group toGroup, int to, int count, Group group) const
-{
- if (group != toGroup) {
- // determine how many items from the destination group intersect with the source group.
- iterator fromIt = find(fromGroup, from);
-
- int intersectingCount = 0;
-
- for (; count > 0; *fromIt = fromIt->next) {
- if (*fromIt == &m_ranges)
- return false;
- if (!fromIt->inGroup(group))
- continue;
- if (fromIt->inGroup(toGroup))
- intersectingCount += qMin(count, fromIt->count - fromIt.offset);
- count -= fromIt->count - fromIt.offset;
- fromIt.offset = 0;
- }
- count = intersectingCount;
- }
-
- return to >= 0 && to + count <= m_end.index[toGroup];
-}
-
-/*!
- \internal
-
- Moves \a count items belonging to \a moveGroup from the index \a from in \a fromGroup
- to the index \a to in \a toGroup.
-
- If \a removes and \a inserts are not null they will be populated with per group notifications
- of the items moved.
- */
-
-void QQmlListCompositor::move(
- Group fromGroup,
- int from,
- Group toGroup,
- int to,
- int count,
- Group moveGroup,
- QVector<Remove> *removes,
- QVector<Insert> *inserts)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << toGroup << to << count)
- Q_ASSERT(count > 0);
- Q_ASSERT(from >=0);
- Q_ASSERT(verifyMoveTo(fromGroup, from, toGroup, to, count, moveGroup));
-
- // Find the position of the first item to move.
- iterator fromIt = find(fromGroup, from);
-
- if (fromIt != moveGroup) {
- // If the range at the from index doesn't contain items from the move group; skip
- // to the next range.
- fromIt.incrementIndexes(fromIt->count - fromIt.offset);
- fromIt.offset = 0;
- *fromIt = fromIt->next;
- } else if (fromIt.offset > 0) {
- // If the range at the from index contains items from the move group and the index isn't
- // at the start of the range; split the range at the index and move the iterator to start
- // of the second range.
- *fromIt = insert(
- *fromIt, fromIt->list, fromIt->index, fromIt.offset, fromIt->flags & ~AppendFlag)->next;
- fromIt->index += fromIt.offset;
- fromIt->count -= fromIt.offset;
- fromIt.offset = 0;
- }
-
- // Remove count items belonging to the move group from the list.
- Range movedFlags;
- for (int moveId = m_moveId; count > 0;) {
- if (fromIt != moveGroup) {
- // Skip ranges not containing items from the move group.
- fromIt.incrementIndexes(fromIt->count);
- *fromIt = fromIt->next;
- continue;
- }
- int difference = qMin(count, fromIt->count);
-
- // Create a new static range containing the moved items from an existing range.
- new Range(
- &movedFlags,
- fromIt->list,
- fromIt->index,
- difference,
- fromIt->flags & ~(PrependFlag | AppendFlag));
- // Remove moved items from the count, the existing range, and a remove notification.
- if (removes)
- removes->append(Remove(fromIt, difference, fromIt->flags, ++moveId));
- count -= difference;
- fromIt->count -= difference;
-
- // If the existing range contains the prepend flag replace the removed items with
- // a placeholder range for new items inserted into the source model.
- int removeIndex = fromIt->index;
- if (fromIt->prepend()
- && fromIt->previous != &m_ranges
- && fromIt->previous->flags == PrependFlag
- && fromIt->previous->list == fromIt->list
- && fromIt->previous->end() == fromIt->index) {
- // Grow the previous range instead of creating a new one if possible.
- fromIt->previous->count += difference;
- } else if (fromIt->prepend()) {
- *fromIt = insert(*fromIt, fromIt->list, removeIndex, difference, PrependFlag)->next;
- }
- fromIt->index += difference;
-
- if (fromIt->count == 0) {
- // If the existing range has no items remaining; remove it from the list.
- if (fromIt->append())
- fromIt->previous->flags |= AppendFlag;
- *fromIt = erase(*fromIt);
-
- // If the ranges before and after the removed range can be joined, do so.
- if (*fromIt != m_ranges.next && fromIt->flags == PrependFlag
- && fromIt->previous != &m_ranges
- && fromIt->previous->flags == PrependFlag
- && fromIt->previous->list == fromIt->list
- && fromIt->previous->end() == fromIt->index) {
- fromIt.incrementIndexes(fromIt->count);
- fromIt->previous->count += fromIt->count;
- *fromIt = erase(*fromIt);
- }
- } else if (count > 0) {
- *fromIt = fromIt->next;
- }
- }
-
- // Try and join the range following the removed items to the range preceding it.
- if (*fromIt != m_ranges.next
- && *fromIt != &m_ranges
- && fromIt->previous->list == fromIt->list
- && (!fromIt->list || fromIt->previous->end() == fromIt->index)
- && fromIt->previous->flags == (fromIt->flags & ~AppendFlag)) {
- if (fromIt == fromIt.group)
- fromIt.offset = fromIt->previous->count;
- fromIt.offset = fromIt->previous->count;
- fromIt->previous->count += fromIt->count;
- fromIt->previous->flags = fromIt->flags;
- *fromIt = erase(*fromIt)->previous;
- }
-
- // Find the destination position of the move.
- insert_iterator toIt = fromIt;
- toIt.setGroup(toGroup);
-
- const int difference = to - toIt.index[toGroup];
- toIt += difference;
-
- // If the insert position is part way through a range; split it and move the iterator to the
- // start of the second range.
- if (toIt.offset > 0) {
- *toIt = insert(*toIt, toIt->list, toIt->index, toIt.offset, toIt->flags & ~AppendFlag)->next;
- toIt->index += toIt.offset;
- toIt->count -= toIt.offset;
- toIt.offset = 0;
- }
-
- // Insert the moved ranges before the insert iterator, growing the previous range if that
- // is an option.
- for (Range *range = movedFlags.previous; range != &movedFlags; range = range->previous) {
- if (*toIt != &m_ranges
- && range->list == toIt->list
- && (!range->list || range->end() == toIt->index)
- && range->flags == (toIt->flags & ~AppendFlag)) {
- toIt->index -= range->count;
- toIt->count += range->count;
- } else {
- *toIt = insert(*toIt, range->list, range->index, range->count, range->flags);
- }
- }
-
- // Try and join the range after the inserted ranges to the last range inserted.
- if (*toIt != m_ranges.next
- && toIt->previous->list == toIt->list
- && (!toIt->list || (toIt->previous->end() == toIt->index && toIt->previous->flags == (toIt->flags & ~AppendFlag)))) {
- toIt.offset = toIt->previous->count;
- toIt->previous->count += toIt->count;
- toIt->previous->flags = toIt->flags;
- *toIt = erase(*toIt)->previous;
- }
- // Create insert notification for the ranges moved.
- Insert insert(toIt, 0, 0, 0);
- for (Range *next, *range = movedFlags.next; range != &movedFlags; range = next) {
- insert.count = range->count;
- insert.flags = range->flags;
- if (inserts) {
- insert.moveId = ++m_moveId;
- inserts->append(insert);
- }
- for (int i = 0; i < m_groupCount; ++i) {
- if (insert.inGroup(i))
- insert.index[i] += range->count;
- }
-
- next = range->next;
- delete range;
- }
-
- m_cacheIt = toIt;
-
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Clears the contents of a compositor.
-*/
-
-void QQmlListCompositor::clear()
-{
- QT_QML_TRACE_LISTCOMPOSITOR("")
- for (Range *range = m_ranges.next; range != &m_ranges; range = erase(range)) {}
- m_end = iterator(m_ranges.next, 0, Default, m_groupCount);
- m_cacheIt = m_end;
-}
-
-void QQmlListCompositor::listItemsInserted(
- QVector<Insert> *translatedInsertions,
- void *list,
- const QVector<QQmlChangeSet::Change> &insertions,
- const QVector<MovedFlags> *movedFlags)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << insertions)
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- // Skip ranges that don't reference list.
- it.incrementIndexes(it->count);
- continue;
- } else if (it->flags & MovedFlag) {
- // Skip ranges that were already moved in listItemsRemoved.
- it->flags &= ~MovedFlag;
- it.incrementIndexes(it->count);
- continue;
- }
- for (const QQmlChangeSet::Change &insertion : insertions) {
- int offset = insertion.index - it->index;
- if ((offset > 0 && offset < it->count)
- || (offset == 0 && it->prepend())
- || (offset == it->count && it->append())) {
- // The insert index is within the current range.
- if (it->prepend()) {
- // The range has the prepend flag set so we insert new items into the range.
- uint flags = m_defaultFlags;
- if (insertion.isMove()) {
- // If the insert was part of a move replace the default flags with
- // the flags from the source range.
- for (QVector<MovedFlags>::const_iterator move = movedFlags->begin();
- move != movedFlags->end();
- ++move) {
- if (move->moveId == insertion.moveId) {
- flags = move->flags;
- break;
- }
- }
- }
- if (flags & ~(AppendFlag | PrependFlag)) {
- // If any items are added to groups append an insert notification.
- Insert translatedInsert(it, insertion.count, flags, insertion.moveId);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedInsert.index[i] += offset;
- }
- translatedInsertions->append(translatedInsert);
- }
- if ((it->flags & ~AppendFlag) == flags) {
- // Accumulate items on the current range it its flags are the same as
- // the insert flags.
- it->count += insertion.count;
- } else if (offset == 0
- && it->previous != &m_ranges
- && it->previous->list == list
- && it->previous->end() == insertion.index
- && it->previous->flags == flags) {
- // Attempt to append to the previous range if the insert position is at
- // the start of the current range.
- it->previous->count += insertion.count;
- it->index += insertion.count;
- it.incrementIndexes(insertion.count);
- } else {
- if (offset > 0) {
- // Divide the current range at the insert position.
- it.incrementIndexes(offset);
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- }
- // Insert a new range, and increment the start index of the current range.
- *it = insert(*it, it->list, insertion.index, insertion.count, flags)->next;
- it.incrementIndexes(insertion.count, flags);
- it->index += offset + insertion.count;
- it->count -= offset;
- }
- m_end.incrementIndexes(insertion.count, flags);
- } else {
- // The range doesn't have the prepend flag set so split the range into parts;
- // one before the insert position and one after the last inserted item.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags)->next;
- it->index += offset;
- it->count -= offset;
- }
- it->index += insertion.count;
- }
- } else if (offset <= 0) {
- // The insert position was before the current range so increment the start index.
- it->index += insertion.count;
- }
- }
- it.incrementIndexes(it->count);
- }
- m_cacheIt = m_end;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-/*!
- Updates the contents of a compositor when \a count items are inserted into a \a list at
- \a index.
-
- This corrects the indexes of each range for that list in the compositor, splitting the range
- in two if the insert index is in the middle of that range. If a range at the insert position
- has the Prepend flag set then a new range will be inserted at that position with the groups
- specified in defaultGroups(). If the insert index corresponds to the end of a range with
- the Append flag set a new range will be inserted before the end of the append range.
-
- The \a translatedInsertions list is populated with insert notifications for affected
- groups.
-*/
-
-void QQmlListCompositor::listItemsInserted(
- void *list, int index, int count, QVector<Insert> *translatedInsertions)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count > 0);
-
- QVector<QQmlChangeSet::Change> insertions;
- insertions.append(QQmlChangeSet::Change(index, count));
-
- listItemsInserted(translatedInsertions, list, insertions);
-}
-
-void QQmlListCompositor::listItemsRemoved(
- QVector<Remove> *translatedRemovals,
- void *list,
- QVector<QQmlChangeSet::Change> *removals,
- QVector<QQmlChangeSet::Change> *insertions,
- QVector<MovedFlags> *movedFlags)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << *removals)
-
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- // Skip ranges that don't reference list.
- it.incrementIndexes(it->count);
- continue;
- }
- bool removed = false;
- for (QVector<QQmlChangeSet::Change>::iterator removal = removals->begin();
- !removed && removal != removals->end();
- ++removal) {
- int relativeIndex = removal->index - it->index;
- int itemsRemoved = removal->count;
- if (relativeIndex + removal->count > 0 && relativeIndex < it->count) {
- // If the current range intersects the remove; remove the intersecting items.
- const int offset = qMax(0, relativeIndex);
- int removeCount = qMin(it->count, relativeIndex + removal->count) - offset;
- it->count -= removeCount;
- int removeFlags = it->flags & m_removeFlags;
- Remove translatedRemoval(it, removeCount, it->flags);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedRemoval.index[i] += offset;
- }
- if (removal->isMove()) {
- // If the removal was part of a move find the corresponding insert.
- QVector<QQmlChangeSet::Change>::iterator insertion = insertions->begin();
- for (; insertion != insertions->end() && insertion->moveId != removal->moveId;
- ++insertion) {}
- Q_ASSERT(insertion != insertions->end());
- Q_ASSERT(insertion->count == removal->count);
-
- if (relativeIndex < 0) {
- // 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::Change(
- removal->index, -relativeIndex, splitMoveId));
- ++removal;
- removal->count -= -relativeIndex;
- insertion = insertions->insert(insertion, QQmlChangeSet::Change(
- insertion->index, -relativeIndex, splitMoveId));
- ++insertion;
- insertion->index += -relativeIndex;
- insertion->count -= -relativeIndex;
- }
-
- if (it->prepend()) {
- // If the current range has the prepend flag preserve its flags to transfer
- // to its new location.
- removeFlags |= it->flags & CacheFlag;
- translatedRemoval.moveId = ++m_moveId;
- movedFlags->append(MovedFlags(m_moveId, it->flags & ~AppendFlag));
-
- 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::Change(
- removal->index, removeCount, translatedRemoval.moveId));
- ++removal;
- insertion = insertions->insert(insertion, QQmlChangeSet::Change(
- insertion->index, removeCount, translatedRemoval.moveId));
- ++insertion;
-
- removal->count -= removeCount;
- insertion->index += removeCount;
- insertion->count -= removeCount;
- } else {
- // If there's no need to split the move simply replace its moveId
- // with that of the translated move.
- removal->moveId = translatedRemoval.moveId;
- insertion->moveId = translatedRemoval.moveId;
- }
- } else {
- // If the current range doesn't have prepend flags then insert a new range
- // with list indexes from the corresponding insert location. The MoveFlag
- // is to notify listItemsInserted that it can skip evaluation of that range.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- it->index += offset;
- it->count -= offset;
- it.incrementIndexes(offset);
- }
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->end() == insertion->index
- && it->previous->flags == (it->flags | MovedFlag)) {
- it->previous->count += removeCount;
- } else {
- *it = insert(*it, it->list, insertion->index, removeCount, it->flags | MovedFlag)->next;
- }
- // Clear the changed flags as the item hasn't been removed.
- translatedRemoval.flags = 0;
- removeFlags = 0;
- }
- } else if (it->inCache()) {
- // If not moving and the current range has the cache flag, insert a new range
- // with just the cache flag set to retain caching information for the removed
- // range.
- if (offset > 0) {
- *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
- it->index += offset;
- it->count -= offset;
- it.incrementIndexes(offset);
- }
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->previous->flags == CacheFlag) {
- it->previous->count += removeCount;
- } else {
- *it = insert(*it, it->list, -1, removeCount, CacheFlag)->next;
- }
- it.index[Cache] += removeCount;
- }
- if (removeFlags & GroupMask)
- translatedRemovals->append(translatedRemoval);
- m_end.decrementIndexes(removeCount, removeFlags);
- if (it->count == 0 && !it->append()) {
- // Erase empty non-append ranges.
- *it = erase(*it)->previous;
- removed = true;
- } else if (relativeIndex <= 0) {
- // If the remove started before the current range move the start index of
- // the range to the remove index.
- it->index = removal->index;
- }
- } else if (relativeIndex < 0) {
- // If the remove was before the current range decrement the start index by the
- // number of items removed.
- it->index -= itemsRemoved;
-
- if (it->previous != &m_ranges
- && it->previous->list == it->list
- && it->previous->end() == it->index
- && it->previous->flags == (it->flags & ~AppendFlag)) {
- // Compress ranges made continuous by the removal of separating ranges.
- it.decrementIndexes(it->previous->count);
- it->previous->count += it->count;
- it->previous->flags = it->flags;
- *it = erase(*it)->previous;
- }
- }
- }
- if (it->flags == CacheFlag && it->next->flags == CacheFlag && it->next->list == it->list) {
- // Compress consecutive cache only ranges.
- it.index[Cache] += it->next->count;
- it->count += it->next->count;
- erase(it->next);
- } else if (!removed) {
- it.incrementIndexes(it->count);
- }
- }
- m_cacheIt = m_end;
- QT_QML_VERIFY_LISTCOMPOSITOR
-}
-
-
-/*!
- Updates the contents of a compositor when \a count items are removed from a \a list at
- \a index.
-
- Ranges that intersect the specified range are removed from the compositor and the indexes of
- ranges after index + count are updated.
-
- The \a translatedRemovals list is populated with remove notifications for the affected
- groups.
-*/
-
-
-void QQmlListCompositor::listItemsRemoved(
- void *list, int index, int count, QVector<Remove> *translatedRemovals)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count >= 0);
-
- QVector<QQmlChangeSet::Change> removals;
- removals.append(QQmlChangeSet::Change(index, count));
- listItemsRemoved(translatedRemovals, list, &removals, nullptr, nullptr);
-}
-
-/*!
- Updates the contents of a compositor when \a count items are removed from a \a list at
- \a index.
-
- Ranges that intersect the specified range are removed from the compositor and the indexes of
- ranges after index + count are updated.
-
- The \a translatedRemovals and translatedInserts lists are populated with move
- notifications for the affected groups.
-*/
-
-void QQmlListCompositor::listItemsMoved(
- void *list,
- int from,
- int to,
- int count,
- QVector<Remove> *translatedRemovals,
- QVector<Insert> *translatedInsertions)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << from << to << count)
- Q_ASSERT(count >= 0);
-
- QVector<QQmlChangeSet::Change> removals;
- QVector<QQmlChangeSet::Change> insertions;
- QVector<MovedFlags> movedFlags;
- 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);
-}
-
-void QQmlListCompositor::listItemsChanged(
- QVector<Change> *translatedChanges,
- void *list,
- const QVector<QQmlChangeSet::Change> &changes)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << changes)
- for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
- if (it->list != list || it->flags == CacheFlag) {
- it.incrementIndexes(it->count);
- continue;
- } else if (!it->inGroup()) {
- continue;
- }
- for (const QQmlChangeSet::Change &change : changes) {
- const int offset = change.index - it->index;
- if (offset + change.count > 0 && offset < it->count) {
- const int changeOffset = qMax(0, offset);
- const int changeCount = qMin(it->count, offset + change.count) - changeOffset;
-
- Change translatedChange(it, changeCount, it->flags);
- for (int i = 0; i < m_groupCount; ++i) {
- if (it->inGroup(i))
- translatedChange.index[i] += changeOffset;
- }
- translatedChanges->append(translatedChange);
- }
- }
- it.incrementIndexes(it->count);
- }
-}
-
-
-/*!
- Translates the positions of \a count changed items at \a index in a \a list.
-
- The \a translatedChanges list is populated with change notifications for the
- affected groups.
-*/
-
-void QQmlListCompositor::listItemsChanged(
- void *list, int index, int count, QVector<Change> *translatedChanges)
-{
- QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count)
- Q_ASSERT(count >= 0);
- QVector<QQmlChangeSet::Change> changes;
- changes.append(QQmlChangeSet::Change(index, count));
- listItemsChanged(translatedChanges, list, changes);
-}
-
-void QQmlListCompositor::transition(
- Group from,
- Group to,
- 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::Change(it.index[from]- removeCount, it->count));
- removeCount += it->count;
- } else if (it != from && it == to) {
- inserts->append(QQmlChangeSet::Change(it.index[to], it->count));
- }
- it.incrementIndexes(it->count);
- }
-}
-
-/*!
- \internal
- Writes the name of \a group to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group)
-{
- switch (group) {
- case QQmlListCompositor::Cache: return debug << "Cache";
- case QQmlListCompositor::Default: return debug << "Default";
- default: return (debug.nospace() << "Group" << int(group)).space();
- }
-
-}
-
-/*!
- \internal
- Writes the contents of \a range to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range)
-{
- (debug.nospace()
- << "Range("
- << range.list) << ' '
- << range.index << ' '
- << range.count << ' '
- << (range.isUnresolved() ? 'U' : '0')
- << (range.append() ? 'A' : '0')
- << (range.prepend() ? 'P' : '0');
- for (int i = QQmlListCompositor::MaximumGroupCount - 1; i >= 2; --i)
- debug << (range.inGroup(i) ? '1' : '0');
- return (debug
- << (range.inGroup(QQmlListCompositor::Default) ? 'D' : '0')
- << (range.inGroup(QQmlListCompositor::Cache) ? 'C' : '0'));
-}
-
-static void qt_print_indexes(QDebug &debug, int count, const int *indexes)
-{
- for (int i = count - 1; i >= 0; --i)
- debug << indexes[i];
-}
-
-/*!
- \internal
- Writes the contents of \a it to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it)
-{
- (debug.nospace() << "iterator(" << it.group).space() << "offset:" << it.offset;
- qt_print_indexes(debug, it.groupCount, it.index);
- return ((debug << **it).nospace() << ')').space();
-}
-
-static QDebug qt_print_change(QDebug debug, const char *name, const QQmlListCompositor::Change &change)
-{
- debug.nospace() << name << '(' << change.moveId << ' ' << change.count << ' ';
- for (int i = QQmlListCompositor::MaximumGroupCount - 1; i >= 2; --i)
- debug << (change.inGroup(i) ? '1' : '0');
- debug << (change.inGroup(QQmlListCompositor::Default) ? 'D' : '0')
- << (change.inGroup(QQmlListCompositor::Cache) ? 'C' : '0');
- int i = QQmlListCompositor::MaximumGroupCount - 1;
- for (; i >= 0 && !change.inGroup(i); --i) {}
- for (; i >= 0; --i)
- debug << ' ' << change.index[i];
- return (debug << ')').maybeSpace();
-}
-
-/*!
- \internal
- Writes the contents of \a change to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change)
-{
- return qt_print_change(debug, "Change", change);
-}
-
-/*!
- \internal
- Writes the contents of \a remove to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove)
-{
- return qt_print_change(debug, "Remove", remove);
-}
-
-/*!
- \internal
- Writes the contents of \a insert to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert)
-{
- return qt_print_change(debug, "Insert", insert);
-}
-
-/*!
- \internal
- Writes the contents of \a list to \a debug.
-*/
-
-QDebug operator <<(QDebug debug, const QQmlListCompositor &list)
-{
- int indexes[QQmlListCompositor::MaximumGroupCount];
- for (int i = 0; i < QQmlListCompositor::MaximumGroupCount; ++i)
- indexes[i] = 0;
- debug.nospace() << "QQmlListCompositor(";
- qt_print_indexes(debug, list.m_groupCount, list.m_end.index);
- for (QQmlListCompositor::Range *range = list.m_ranges.next; range != &list.m_ranges; range = range->next) {
- (debug << '\n').space();
- qt_print_indexes(debug, list.m_groupCount, indexes);
- debug << ' ' << *range;
-
- for (int i = 0; i < list.m_groupCount; ++i) {
- if (range->inGroup(i))
- indexes[i] += range->count;
- }
- }
- return (debug << ')').maybeSpace();
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qml/util/qqmllistcompositor_p.h
deleted file mode 100644
index 172040559c..0000000000
--- a/src/qml/util/qqmllistcompositor_p.h
+++ /dev/null
@@ -1,372 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLLISTCOMPOSITOR_P_H
-#define QQMLLISTCOMPOSITOR_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/qglobal.h>
-#include <QtCore/qvector.h>
-
-#include <private/qqmlchangeset_p.h>
-
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT QQmlListCompositor
-{
-public:
- enum { MinimumGroupCount = 3, MaximumGroupCount = 11 };
-
- enum Group
- {
- Cache = 0,
- Default = 1,
- Persisted = 2
- };
-
- enum Flag
- {
- CacheFlag = 1 << Cache,
- DefaultFlag = 1 << Default,
- PersistedFlag = 1 << Persisted,
- PrependFlag = 0x10000000,
- AppendFlag = 0x20000000,
- UnresolvedFlag = 0x40000000,
- MovedFlag = 0x80000000,
- GroupMask = ~(PrependFlag | AppendFlag | UnresolvedFlag | MovedFlag | CacheFlag)
- };
-
- class Range
- {
- public:
- Range() : next(this), previous(this) {}
- Range(Range *next, void *list, int index, int count, uint flags)
- : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) {
- next->previous = this; previous->next = this; }
-
- Range *next;
- Range *previous;
- void *list = nullptr;
- int index = 0;
- int count = 0;
- uint flags = 0;
-
- inline int start() const { return index; }
- inline int end() const { return index + count; }
-
- inline int groups() const { return flags & GroupMask; }
-
- inline bool inGroup() const { return flags & GroupMask; }
- inline bool inCache() const { return flags & CacheFlag; }
- inline bool inGroup(int group) const { return flags & (1 << group); }
- inline bool isUnresolved() const { return flags & UnresolvedFlag; }
-
- inline bool prepend() const { return flags & PrependFlag; }
- inline bool append() const { return flags & AppendFlag; }
- };
-
- class Q_AUTOTEST_EXPORT iterator
- {
- public:
- inline iterator();
- inline iterator(const iterator &it);
- inline iterator(Range *range, int offset, Group group, int groupCount);
- inline ~iterator() {}
-
- bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; }
- bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; }
-
- bool operator ==(Group group) const { return range->flags & (1 << group); }
- bool operator !=(Group group) const { return !(range->flags & (1 << group)); }
-
- Range *&operator *() { return range; }
- Range * const &operator *() const { return range; }
- Range *operator ->() { return range; }
- const Range *operator ->() const { return range; }
-
- iterator &operator +=(int difference);
-
- template<typename T> T *list() const { return static_cast<T *>(range->list); }
- int modelIndex() const { return range->index + offset; }
-
- void incrementIndexes(int difference) { incrementIndexes(difference, range->flags); }
- void decrementIndexes(int difference) { decrementIndexes(difference, range->flags); }
-
- inline void incrementIndexes(int difference, uint flags);
- inline void decrementIndexes(int difference, uint flags);
-
- void setGroup(Group g) { group = g; groupFlag = 1 << g; }
-
- Range *range = nullptr;
- int offset = 0;
- Group group = Default;
- int groupFlag;
- int groupCount = 0;
- union {
- struct {
- int cacheIndex;
- };
- int index[MaximumGroupCount];
- };
- };
-
- class Q_AUTOTEST_EXPORT insert_iterator : public iterator
- {
- public:
- inline insert_iterator() {}
- inline insert_iterator(const iterator &it) : iterator(it) {}
- inline insert_iterator(Range *, int, Group, int);
- inline ~insert_iterator() {}
-
- insert_iterator &operator +=(int difference);
- };
-
- struct Change
- {
- inline Change() {}
- inline Change(const iterator &it, int count, uint flags, int moveId = -1);
- int count;
- uint flags;
- int moveId;
- union {
- struct {
- int cacheIndex;
- };
- int index[MaximumGroupCount];
- };
-
- inline bool isMove() const { return moveId >= 0; }
- inline bool inCache() const { return flags & CacheFlag; }
- inline bool inGroup() const { return flags & GroupMask; }
- inline bool inGroup(int group) const { return flags & (CacheFlag << group); }
-
- inline int groups() const { return flags & GroupMask; }
- };
-
- struct Insert : public Change
- {
- Insert() {}
- Insert(const iterator &it, int count, uint flags, int moveId = -1)
- : Change(it, count, flags, moveId) {}
- };
-
- struct Remove : public Change
- {
- Remove() {}
- Remove(const iterator &it, int count, uint flags, int moveId = -1)
- : Change(it, count, flags, moveId) {}
- };
-
- QQmlListCompositor();
- ~QQmlListCompositor();
-
- int defaultGroups() const { return m_defaultFlags & ~PrependFlag; }
- void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
- void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
- void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
- void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
- void setGroupCount(int count);
-
- int count(Group group) const;
- iterator find(Group group, int index);
- iterator find(Group group, int index) const;
- insert_iterator findInsertPosition(Group group, int index);
-
- const iterator &end() { return m_end; }
-
- void append(void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
- void insert(Group group, int before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
- iterator insert(iterator before, void *list, int index, int count, uint flags, QVector<Insert> *inserts = nullptr);
-
- void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts = nullptr);
- void setFlags(iterator from, int count, Group group, uint flags, QVector<Insert> *inserts = nullptr);
- void setFlags(Group fromGroup, int from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
- setFlags(fromGroup, from, count, fromGroup, flags, inserts); }
- void setFlags(const iterator from, int count, uint flags, QVector<Insert> *inserts = nullptr) {
- setFlags(from, count, from.group, flags, inserts); }
-
- void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
- void clearFlags(iterator from, int count, Group group, uint flags, QVector<Remove> *removals = nullptr);
- void clearFlags(Group fromGroup, int from, int count, uint flags, QVector<Remove> *removals = nullptr) {
- clearFlags(fromGroup, from, count, fromGroup, flags, removals); }
- void clearFlags(const iterator &from, int count, uint flags, QVector<Remove> *removals = nullptr) {
- clearFlags(from, count, from.group, flags, removals); }
-
- bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count, Group group) const;
-
- void move(
- Group fromGroup,
- int from,
- Group toGroup,
- int to,
- int count,
- Group group,
- QVector<Remove> *removals = nullptr,
- QVector<Insert> *inserts = nullptr);
- void clear();
-
- void listItemsInserted(void *list, int index, int count, QVector<Insert> *inserts);
- void listItemsRemoved(void *list, int index, int count, QVector<Remove> *removals);
- void listItemsMoved(void *list, int from, int to, int count, QVector<Remove> *removals, QVector<Insert> *inserts);
- void listItemsChanged(void *list, int index, int count, QVector<Change> *changes);
-
- void transition(
- Group from,
- Group to,
- QVector<QQmlChangeSet::Change> *removes,
- QVector<QQmlChangeSet::Change> *inserts);
-
-private:
- Range m_ranges;
- iterator m_end;
- iterator m_cacheIt;
- int m_groupCount;
- int m_defaultFlags;
- int m_removeFlags;
- int m_moveId;
-
- inline Range *insert(Range *before, void *list, int index, int count, uint flags);
- inline Range *erase(Range *range);
-
- struct MovedFlags
- {
- MovedFlags() {}
- MovedFlags(int moveId, uint flags) : moveId(moveId), flags(flags) {}
-
- int moveId;
- uint flags;
- };
-
- void listItemsRemoved(
- QVector<Remove> *translatedRemovals,
- void *list,
- QVector<QQmlChangeSet::Change> *removals,
- QVector<QQmlChangeSet::Change> *insertions = nullptr,
- QVector<MovedFlags> *movedFlags = nullptr);
- void listItemsInserted(
- QVector<Insert> *translatedInsertions,
- void *list,
- const QVector<QQmlChangeSet::Change> &insertions,
- const QVector<MovedFlags> *movedFlags = nullptr);
- void listItemsChanged(
- QVector<Change> *translatedChanges,
- void *list,
- const QVector<QQmlChangeSet::Change> &changes);
-
- friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
-};
-
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Change, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Remove, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
-
-inline QQmlListCompositor::iterator::iterator() {}
-inline QQmlListCompositor::iterator::iterator(const iterator &it)
- : range(it.range)
- , offset(it.offset)
- , group(it.group)
- , groupFlag(it.groupFlag)
- , groupCount(it.groupCount)
-{
- for (int i = 0; i < groupCount; ++i)
- index[i] = it.index[i];
-}
-
-inline QQmlListCompositor::iterator::iterator(
- Range *range, int offset, Group group, int groupCount)
- : range(range)
- , offset(offset)
- , group(group)
- , groupFlag(1 << group)
- , groupCount(groupCount)
-{
- for (int i = 0; i < groupCount; ++i)
- index[i] = 0;
-}
-
-inline void QQmlListCompositor::iterator::incrementIndexes(int difference, uint flags)
-{
- for (int i = 0; i < groupCount; ++i) {
- if (flags & (1 << i))
- index[i] += difference;
- }
-}
-
-inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint flags)
-{
- for (int i = 0; i < groupCount; ++i) {
- if (flags & (1 << i))
- index[i] -= difference;
- }
-}
-
-inline QQmlListCompositor::insert_iterator::insert_iterator(
- Range *range, int offset, Group group, int groupCount)
- : iterator(range, offset, group, groupCount) {}
-
-inline QQmlListCompositor::Change::Change(const iterator &it, int count, uint flags, int moveId)
- : count(count), flags(flags), moveId(moveId)
-{
- for (int i = 0; i < MaximumGroupCount; ++i)
- index[i] = it.index[i];
-}
-
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Group &group);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Range &range);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::iterator &it);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Change &change);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Remove &remove);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor::Insert &insert);
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQmlListCompositor &list);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
index bebb271f1b..3b121ba3cb 100644
--- a/src/qml/util/util.pri
+++ b/src/qml/util/util.pri
@@ -1,19 +1,5 @@
SOURCES += \
- $$PWD/qqmlchangeset.cpp \
- $$PWD/qqmllistaccessor.cpp \
- $$PWD/qqmllistcompositor.cpp \
$$PWD/qqmlpropertymap.cpp
HEADERS += \
- $$PWD/qqmlchangeset_p.h \
- $$PWD/qqmllistaccessor_p.h \
- $$PWD/qqmllistcompositor_p.h \
$$PWD/qqmlpropertymap.h
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmladaptormodel.cpp
-
- HEADERS += \
- $$PWD/qqmladaptormodel_p.h
-}