aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules2
-rw-r--r--.qmake.conf2
-rw-r--r--examples/quick/window/window.qml2
-rw-r--r--src/3rdparty/masm/assembler/AssemblerBuffer.h2
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.h4
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h20
-rw-r--r--src/3rdparty/masm/masm.pri5
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorPosix.cpp87
-rw-r--r--src/3rdparty/masm/wtf/VMTags.h8
-rw-r--r--src/imports/folderlistmodel/plugin.cpp9
-rw-r--r--src/imports/handlers/plugin.cpp9
-rw-r--r--src/imports/imports.pro7
-rw-r--r--src/imports/layouts/plugin.cpp8
-rw-r--r--src/imports/localstorage/plugin.cpp10
-rw-r--r--src/imports/models/plugin.cpp9
-rw-r--r--src/imports/particles/plugin.cpp9
-rw-r--r--src/imports/qtquick2/plugin.cpp9
-rw-r--r--src/imports/settings/plugin.cpp10
-rw-r--r--src/imports/settings/plugins.qmltypes11
-rw-r--r--src/imports/settings/qqmlsettings.cpp71
-rw-r--r--src/imports/settings/qqmlsettings_p.h7
-rw-r--r--src/imports/settings/settings.pro2
-rw-r--r--src/imports/shapes/plugin.cpp17
-rw-r--r--src/imports/shapes/shapes.pro24
-rw-r--r--src/imports/statemachine/plugin.cpp9
-rw-r--r--src/imports/tableview/plugin.cpp64
-rw-r--r--src/imports/tableview/plugins.qmltypes33
-rw-r--r--src/imports/tableview/qmldir5
-rw-r--r--src/imports/tableview/tableview.pro10
-rw-r--r--src/imports/testlib/TestCase.qml18
-rw-r--r--src/imports/testlib/main.cpp9
-rw-r--r--src/imports/window/plugin.cpp9
-rw-r--r--src/imports/xmllistmodel/plugin.cpp9
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel.cpp32
-rw-r--r--src/imports/xmllistmodel/qqmlxmllistmodel_p.h2
-rw-r--r--src/imports/xmllistmodel/xmllistmodel.pro3
-rw-r--r--src/particles/qquickv4particledata.cpp2
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp66
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp9
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp19
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h3
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp17
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h1
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp20
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h3
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp52
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp14
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h2
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp2
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h2
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qanimationjobutil_p.h2
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h2
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h2
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h2
-rw-r--r--src/qml/compiler/compiler.pri6
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp109
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h23
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h28
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp9
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator_p.h3
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp23
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp19
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h74
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp520
-rw-r--r--src/qml/compiler/qv4bytecodehandler_p.h113
-rw-r--r--src/qml/compiler/qv4codegen.cpp1708
-rw-r--r--src/qml/compiler/qv4codegen_p.h86
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp12
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp20
-rw-r--r--src/qml/compiler/qv4compileddata.cpp117
-rw-r--r--src/qml/compiler/qv4compileddata_p.h107
-rw-r--r--src/qml/compiler/qv4compiler.cpp102
-rw-r--r--src/qml/compiler/qv4compiler_p.h5
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp251
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h99
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h412
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp462
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h44
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp117
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h83
-rw-r--r--src/qml/configure.json45
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h6
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp2
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp9
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc4
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc46
-rw-r--r--src/qml/jit/jit.pri4
-rw-r--r--src/qml/jit/qv4assembler.cpp157
-rw-r--r--src/qml/jit/qv4assembler_p.h15
-rw-r--r--src/qml/jit/qv4baselinejit.cpp (renamed from src/qml/jit/qv4jit.cpp)742
-rw-r--r--src/qml/jit/qv4baselinejit_p.h (renamed from src/qml/jit/qv4jit_p.h)103
-rw-r--r--src/qml/jsapi/qjsengine.cpp10
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp10
-rw-r--r--src/qml/jsruntime/jsruntime.pri34
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp25
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h11
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp10
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp70
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h30
-rw-r--r--src/qml/jsruntime/qv4arrayiterator.cpp106
-rw-r--r--src/qml/jsruntime/qv4arrayiterator_p.h106
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp442
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4context.cpp103
-rw-r--r--src/qml/jsruntime/qv4context_p.h46
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp54
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp125
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp425
-rw-r--r--src/qml/jsruntime/qv4engine_p.h120
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h11
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h21
-rw-r--r--src/qml/jsruntime/qv4function.cpp19
-rw-r--r--src/qml/jsruntime/qv4function_p.h11
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp133
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h30
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp248
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h136
-rw-r--r--src/qml/jsruntime/qv4global_p.h21
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp92
-rw-r--r--src/qml/jsruntime/qv4identifier_p.h61
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp194
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h42
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp560
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h126
-rw-r--r--src/qml/jsruntime/qv4iterator.cpp64
-rw-r--r--src/qml/jsruntime/qv4iterator_p.h82
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h5
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp5
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp85
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h50
-rw-r--r--src/qml/jsruntime/qv4managed.cpp41
-rw-r--r--src/qml/jsruntime/qv4managed_p.h60
-rw-r--r--src/qml/jsruntime/qv4mapiterator.cpp109
-rw-r--r--src/qml/jsruntime/qv4mapiterator_p.h104
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp354
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h117
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp235
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h12
-rw-r--r--src/qml/jsruntime/qv4object.cpp152
-rw-r--r--src/qml/jsruntime/qv4object_p.h116
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp26
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h25
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp127
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h19
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp6
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp9
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h2
-rw-r--r--src/qml/jsruntime/qv4property_p.h13
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp43
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp45
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp270
-rw-r--r--src/qml/jsruntime/qv4reflect_p.h89
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp574
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h25
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp9
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h73
-rw-r--r--src/qml/jsruntime/qv4script.cpp17
-rw-r--r--src/qml/jsruntime/qv4script_p.h17
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp35
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp18
-rw-r--r--src/qml/jsruntime/qv4setiterator.cpp100
-rw-r--r--src/qml/jsruntime/qv4setiterator_p.h103
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp297
-rw-r--r--src/qml/jsruntime/qv4setobject_p.h113
-rw-r--r--src/qml/jsruntime/qv4sparsearray.cpp2
-rw-r--r--src/qml/jsruntime/qv4sparsearray_p.h3
-rw-r--r--src/qml/jsruntime/qv4string.cpp26
-rw-r--r--src/qml/jsruntime/qv4string_p.h102
-rw-r--r--src/qml/jsruntime/qv4stringiterator.cpp95
-rw-r--r--src/qml/jsruntime/qv4stringiterator_p.h103
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp265
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h11
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp182
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h129
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp132
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h35
-rw-r--r--src/qml/jsruntime/qv4value.cpp47
-rw-r--r--src/qml/jsruntime/qv4value_p.h142
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp373
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h1
-rw-r--r--src/qml/memory/qv4heap_p.h102
-rw-r--r--src/qml/memory/qv4mm.cpp62
-rw-r--r--src/qml/memory/qv4mm_p.h228
-rw-r--r--src/qml/parser/parser.pri16
-rw-r--r--src/qml/parser/qqmljs.g4567
-rw-r--r--src/qml/parser/qqmljsast.cpp516
-rw-r--r--src/qml/parser/qqmljsast_p.h880
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h29
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h68
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp7
-rw-r--r--src/qml/parser/qqmljsengine_p.h28
-rw-r--r--src/qml/parser/qqmljsgrammar.cpp1167
-rw-r--r--src/qml/parser/qqmljsgrammar_p.h215
-rw-r--r--src/qml/parser/qqmljskeywords_p.h131
-rw-r--r--src/qml/parser/qqmljslexer.cpp762
-rw-r--r--src/qml/parser/qqmljslexer_p.h88
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h8
-rw-r--r--src/qml/parser/qqmljsparser.cpp2010
-rw-r--r--src/qml/parser/qqmljsparser_p.h258
-rw-r--r--src/qml/qml.pro2
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h8
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h20
-rw-r--r--src/qml/qml/qml.pri21
-rw-r--r--src/qml/qml/qqml.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp11
-rw-r--r--src/qml/qml/qqmlbinding_p.h3
-rw-r--r--src/qml/qml/qqmlcomponent.cpp28
-rw-r--r--src/qml/qml/qqmlcomponent_p.h7
-rw-r--r--src/qml/qml/qqmldata_p.h2
-rw-r--r--src/qml/qml/qqmldirparser.cpp9
-rw-r--r--src/qml/qml/qqmldirparser_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp90
-rw-r--r--src/qml/qml/qqmlengine.h16
-rw-r--r--src/qml/qml/qqmlguard_p.h28
-rw-r--r--src/qml/qml/qqmlimport.cpp20
-rw-r--r--src/qml/qml/qqmlimport_p.h3
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp10
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h17
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp13
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h4
-rw-r--r--src/qml/qml/qqmllocale.cpp4
-rw-r--r--src/qml/qml/qqmllocale_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp59
-rw-r--r--src/qml/qml/qqmlmetatype_p.h7
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp35
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h4
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp122
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h5
-rw-r--r--src/qml/qml/qqmlproperty.cpp2
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h6
-rw-r--r--src/qml/qml/qqmltypeloader.cpp128
-rw-r--r--src/qml/qml/qqmltypeloader_p.h41
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp51
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h10
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp25
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h6
-rw-r--r--src/qml/qml/qqmlvme_p.h4
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp6
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h6
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp29
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h4
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp28
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h4
-rw-r--r--src/qml/qml/v8/qv8engine.cpp33
-rw-r--r--src/qml/qml/v8/qv8engine_p.h9
-rw-r--r--src/qml/qtqmlglobal.h1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp192
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h8
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h16
-rw-r--r--src/qml/types/qqmllistmodel.cpp151
-rw-r--r--src/qml/types/qqmllistmodel_p.h4
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h35
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h2
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp5
-rw-r--r--src/qml/types/qqmltimer_p.h2
-rw-r--r--src/qml/types/qquickworkerscript.cpp12
-rw-r--r--src/qml/types/types.pri18
-rw-r--r--src/qml/util/qqmladaptormodel.cpp85
-rw-r--r--src/qml/util/qqmladaptormodel_p.h13
-rw-r--r--src/qml/util/qqmlpropertymap.cpp4
-rw-r--r--src/qmldebug/qqmldebugclient.cpp5
-rw-r--r--src/qmldebug/qqmldebugclient_p.h5
-rw-r--r--src/qmldebug/qqmldebugconnection.cpp4
-rw-r--r--src/qmldebug/qqmldebugmessageclient.cpp5
-rw-r--r--src/qmldebug/qqmldebugmessageclient_p.h5
-rw-r--r--src/qmldebug/qqmlenginecontrolclient.cpp6
-rw-r--r--src/qmldebug/qqmlprofilerclient.cpp7
-rw-r--r--src/qmldebug/qqmlprofilerclient_p.h2
-rw-r--r--src/qmldebug/qqmlprofilerclient_p_p.h3
-rw-r--r--src/qmltest/qtestoptions_p.h6
-rw-r--r--src/qmltest/quicktest.cpp23
-rw-r--r--src/qmltest/quicktestresult.cpp14
-rw-r--r--src/qmltest/quicktestresult_p.h2
-rw-r--r--src/quick/configure.json12
-rw-r--r--src/quick/designer/qqmldesignermetaobject.cpp4
-rw-r--r--src/quick/doc/snippets/qml/pathview/pathview.qml4
-rw-r--r--src/quick/handlers/handlers.pri5
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp351
-rw-r--r--src/quick/handlers/qquickhandlerpoint_p.h120
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp35
-rw-r--r--src/quick/handlers/qquickmultipointhandler_p.h10
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp37
-rw-r--r--src/quick/handlers/qquickpinchhandler_p.h8
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp58
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler_p.h22
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler_p_p.h74
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp131
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h30
-rw-r--r--src/quick/handlers/qquickpointerhandler_p_p.h84
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp258
-rw-r--r--src/quick/handlers/qquicksinglepointhandler_p.h55
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp16
-rw-r--r--src/quick/items/items.pri10
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp11
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp214
-rw-r--r--src/quick/items/qquickevents_p_p.h108
-rw-r--r--src/quick/items/qquickitem.cpp2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp3
-rw-r--r--src/quick/items/qquickitemview.cpp106
-rw-r--r--src/quick/items/qquickitemview_p_p.h37
-rw-r--r--src/quick/items/qquickitemviewfxitem.cpp165
-rw-r--r--src/quick/items/qquickitemviewfxitem_p_p.h108
-rw-r--r--src/quick/items/qquickloader.cpp15
-rw-r--r--src/quick/items/qquickloader_p_p.h3
-rw-r--r--src/quick/items/qquickrectangle.cpp36
-rw-r--r--src/quick/items/qquickrectangle_p.h10
-rw-r--r--src/quick/items/qquickrendercontrol.cpp1
-rw-r--r--src/quick/items/qquickscalegrid.cpp4
-rw-r--r--src/quick/items/qquickscalegrid_p_p.h12
-rw-r--r--src/quick/items/qquicktableview.cpp1474
-rw-r--r--src/quick/items/qquicktableview_p.h216
-rw-r--r--src/quick/items/qquicktableview_p_p.h342
-rw-r--r--src/quick/items/qquicktext.cpp47
-rw-r--r--src/quick/items/qquicktext_p_p.h1
-rw-r--r--src/quick/items/qquickwindow.cpp147
-rw-r--r--src/quick/items/qquickwindow_p.h7
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp5
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp12
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h4
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h1
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp225
-rw-r--r--src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h2
-rw-r--r--src/quick/util/qquickanimation.cpp22
-rw-r--r--src/quick/util/qquickanimation_p.h1
-rw-r--r--src/quick/util/qquickimageprovider.cpp5
-rw-r--r--src/quick/util/qquickimageprovider.h6
-rw-r--r--src/quick/util/qquickimageprovider_p.h72
-rw-r--r--src/quick/util/qquickpixmapcache.cpp19
-rw-r--r--src/quick/util/qquickprofiler.cpp3
-rw-r--r--src/quick/util/qquickprofiler_p.h2
-rw-r--r--src/quick/util/qquickstate.cpp2
-rw-r--r--src/quick/util/qquickstate_p_p.h4
-rw-r--r--src/quick/util/qquicksvgparser.cpp3
-rw-r--r--src/quick/util/qquickutilmodule.cpp3
-rw-r--r--src/quick/util/util.pri1
-rw-r--r--src/quickshapes/qquicknvprfunctions.cpp (renamed from src/imports/shapes/qquicknvprfunctions.cpp)0
-rw-r--r--src/quickshapes/qquicknvprfunctions_p.h (renamed from src/imports/shapes/qquicknvprfunctions_p.h)1
-rw-r--r--src/quickshapes/qquicknvprfunctions_p_p.h (renamed from src/imports/shapes/qquicknvprfunctions_p_p.h)3
-rw-r--r--src/quickshapes/qquickshape.cpp (renamed from src/imports/shapes/qquickshape.cpp)13
-rw-r--r--src/quickshapes/qquickshape_p.h (renamed from src/imports/shapes/qquickshape_p.h)15
-rw-r--r--src/quickshapes/qquickshape_p_p.h (renamed from src/imports/shapes/qquickshape_p_p.h)5
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp (renamed from src/imports/shapes/qquickshapegenericrenderer.cpp)0
-rw-r--r--src/quickshapes/qquickshapegenericrenderer_p.h (renamed from src/imports/shapes/qquickshapegenericrenderer_p.h)3
-rw-r--r--src/quickshapes/qquickshapenvprrenderer.cpp (renamed from src/imports/shapes/qquickshapenvprrenderer.cpp)0
-rw-r--r--src/quickshapes/qquickshapenvprrenderer_p.h (renamed from src/imports/shapes/qquickshapenvprrenderer_p.h)5
-rw-r--r--src/quickshapes/qquickshapesglobal.h56
-rw-r--r--src/quickshapes/qquickshapesglobal_p.h63
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp (renamed from src/imports/shapes/qquickshapesoftwarerenderer.cpp)0
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer_p.h (renamed from src/imports/shapes/qquickshapesoftwarerenderer_p.h)3
-rw-r--r--src/quickshapes/qtquickshapes.qrc (renamed from src/imports/shapes/qtquickshapesplugin.qrc)0
-rw-r--r--src/quickshapes/quickshapes.pro33
-rw-r--r--src/quickshapes/shaders/blit.frag (renamed from src/imports/shapes/shaders/blit.frag)0
-rw-r--r--src/quickshapes/shaders/blit.vert (renamed from src/imports/shapes/shaders/blit.vert)0
-rw-r--r--src/quickshapes/shaders/blit_core.frag (renamed from src/imports/shapes/shaders/blit_core.frag)0
-rw-r--r--src/quickshapes/shaders/blit_core.vert (renamed from src/imports/shapes/shaders/blit_core.vert)0
-rw-r--r--src/quickshapes/shaders/conicalgradient.frag (renamed from src/imports/shapes/shaders/conicalgradient.frag)0
-rw-r--r--src/quickshapes/shaders/conicalgradient.vert (renamed from src/imports/shapes/shaders/conicalgradient.vert)0
-rw-r--r--src/quickshapes/shaders/conicalgradient_core.frag (renamed from src/imports/shapes/shaders/conicalgradient_core.frag)0
-rw-r--r--src/quickshapes/shaders/conicalgradient_core.vert (renamed from src/imports/shapes/shaders/conicalgradient_core.vert)0
-rw-r--r--src/quickshapes/shaders/lineargradient.frag (renamed from src/imports/shapes/shaders/lineargradient.frag)0
-rw-r--r--src/quickshapes/shaders/lineargradient.vert (renamed from src/imports/shapes/shaders/lineargradient.vert)0
-rw-r--r--src/quickshapes/shaders/lineargradient_core.frag (renamed from src/imports/shapes/shaders/lineargradient_core.frag)0
-rw-r--r--src/quickshapes/shaders/lineargradient_core.vert (renamed from src/imports/shapes/shaders/lineargradient_core.vert)0
-rw-r--r--src/quickshapes/shaders/radialgradient.frag (renamed from src/imports/shapes/shaders/radialgradient.frag)0
-rw-r--r--src/quickshapes/shaders/radialgradient.vert (renamed from src/imports/shapes/shaders/radialgradient.vert)0
-rw-r--r--src/quickshapes/shaders/radialgradient_core.frag (renamed from src/imports/shapes/shaders/radialgradient_core.frag)0
-rw-r--r--src/quickshapes/shaders/radialgradient_core.vert (renamed from src/imports/shapes/shaders/radialgradient_core.vert)0
-rw-r--r--src/src.pro18
-rw-r--r--sync.profile4
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp9
-rw-r--r--tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp4
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp6
-rw-r--r--tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp2
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp22
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp31
-rw-r--r--tests/auto/qml/debugger/shared/debugutil.cpp96
-rw-r--r--tests/auto/qml/debugger/shared/debugutil_p.h29
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugprocess.cpp8
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugprocess_p.h4
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp1
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugtestservice.h3
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations4835
-rw-r--r--tests/auto/qml/ecmascripttests/ecmascripttests.pro15
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/main.cpp114
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/qjstest.pro13
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp758
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.h131
m---------tests/auto/qml/ecmascripttests/test2620
-rwxr-xr-xtests/auto/qml/ecmascripttests/test262.py91
-rw-r--r--tests/auto/qml/ecmascripttests/testcase.pro15
-rw-r--r--tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp48
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp115
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp12
-rw-r--r--tests/auto/qml/qmlmin/tst_qmlmin.cpp2
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp24
-rw-r--r--tests/auto/qml/qqmlconsole/data/logging.qml2
-rw-r--r--tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js (renamed from tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir (renamed from tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/ScriptAPI.js (renamed from tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/ScriptAPI.js)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir (renamed from tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir)0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp389
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp117
-rw-r--r--tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/property.4.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonTest18.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp9
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp50
-rw-r--r--tests/auto/qml/qqmllistmodel/data/dynamicroles.qml21
-rw-r--r--tests/auto/qml/qqmllistmodel/data/qtbug38907.qml25
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp111
-rw-r--r--tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp2
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp82
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp6
-rw-r--r--tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp2
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp10
-rw-r--r--tests/auto/qml/qqmltranslation/data/translationChange.qml8
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp6
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp2
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp4
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp11
-rw-r--r--tests/auto/qmltest/rectangle/tst_rectangle.qml23
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml38
-rw-r--r--tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp33
-rw-r--r--tests/auto/quick/qquickanimations/data/finished.qml95
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp74
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/TestComponent.qml4
-rw-r--r--tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp4
-rw-r--r--tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp65
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp33
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp4
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp8
-rw-r--r--tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp20
-rw-r--r--tests/auto/quick/qquickrepeater/data/ownership.qml4
-rw-r--r--tests/auto/quick/qquickrepeater/data/package.qml35
-rw-r--r--tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp88
-rw-r--r--tests/auto/quick/qquickshape/qquickshape.pro24
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp2
-rw-r--r--tests/auto/quick/qquicktableview/data/countingtableview.qml85
-rw-r--r--tests/auto/quick/qquicktableview/data/plaintableview.qml80
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml66
-rw-r--r--tests/auto/quick/qquicktableview/qquicktableview.pro14
-rw-r--r--tests/auto/quick/qquicktableview/testmodel.h89
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp822
-rw-r--r--tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml27
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp23
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp2
-rw-r--r--tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp13
-rw-r--r--tests/auto/quick/quick.pro3
-rw-r--r--tests/auto/quick/shared/viewtestutil.cpp8
-rw-r--r--tests/auto/quick/shared/viewtestutil.h3
-rw-r--r--tests/auto/quicktest/quicktest.pro3
-rw-r--r--tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.cpp29
-rw-r--r--tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.pro11
-rw-r--r--tests/auto/quicktest/testfiltering/quicktestmain/tst_first.qml38
-rw-r--r--tests/auto/quicktest/testfiltering/quicktestmain/tst_second.qml38
-rw-r--r--tests/auto/quicktest/testfiltering/test/test.pro5
-rw-r--r--tests/auto/quicktest/testfiltering/testfiltering.pro4
-rw-r--r--tests/auto/quicktest/testfiltering/tst_testfiltering.cpp135
-rw-r--r--tests/manual/pointer/pinchDragFlingMPTA.qml2
-rw-r--r--tests/manual/pointer/pinchHandler.qml6
-rw-r--r--tests/manual/pointer/singlePointHandlerProperties.qml5
-rw-r--r--tests/manual/tableview/abstracttablemodel/abstracttablemodel.pro10
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.cpp100
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.qml91
-rw-r--r--tests/manual/tableview/listmodel/listmodel.pro10
-rw-r--r--tests/manual/tableview/listmodel/main.cpp52
-rw-r--r--tests/manual/tableview/listmodel/main.qml86
-rw-r--r--tests/manual/tableview/storagemodel/main.cpp56
-rw-r--r--tests/manual/tableview/storagemodel/main.qml75
-rw-r--r--tests/manual/tableview/storagemodel/storagemodel.cpp226
-rw-r--r--tests/manual/tableview/storagemodel/storagemodel.h93
-rw-r--r--tests/manual/tableview/storagemodel/storagemodel.pro11
-rw-r--r--tests/manual/tableview/tableview.pro4
-rw-r--r--tools/qml/main.cpp6
-rw-r--r--tools/qml/qml.pro2
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp7
-rw-r--r--tools/qmljs/qmljs.cpp11
-rw-r--r--tools/qmlmin/main.cpp104
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.cpp6
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.cpp4
-rw-r--r--tools/qmlprofiler/qmlprofilerclient.h2
-rw-r--r--tools/tools.pro21
524 files changed, 30527 insertions, 12886 deletions
diff --git a/.gitmodules b/.gitmodules
index e6e5650150..e93f38f128 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
[submodule "tests/auto/qml/ecmascripttests/test262"]
path = tests/auto/qml/ecmascripttests/test262
url = ../qtdeclarative-testsuites.git
- branch = snapshot-20150317-8f6a508-based
+ branch = snapshot-20180312-3c69133-based
diff --git a/.qmake.conf b/.qmake.conf
index db74e7164b..81caa27c53 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,4 +1,4 @@
load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.11.1
+MODULE_VERSION = 5.12.0
diff --git a/examples/quick/window/window.qml b/examples/quick/window/window.qml
index a1223da866..2ee7fb6e09 100644
--- a/examples/quick/window/window.qml
+++ b/examples/quick/window/window.qml
@@ -187,7 +187,7 @@ QtObject {
anchors.margins: defaultSpacing
text: "X"
width: 30
- onClicked: testWindow.visible = false
+ onClicked: testWindow.close()
}
}
}
diff --git a/src/3rdparty/masm/assembler/AssemblerBuffer.h b/src/3rdparty/masm/assembler/AssemblerBuffer.h
index 277ec1043c..45874235b6 100644
--- a/src/3rdparty/masm/assembler/AssemblerBuffer.h
+++ b/src/3rdparty/masm/assembler/AssemblerBuffer.h
@@ -102,7 +102,7 @@ namespace JSC {
void putIntegralUnchecked(IntegralType value)
{
ASSERT(isAvailable(sizeof(IntegralType)));
- *reinterpret_cast_ptr<IntegralType*>(m_buffer + m_index) = value;
+ memcpy(m_buffer + m_index, &value, sizeof(IntegralType));
m_index += sizeof(IntegralType);
}
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.h b/src/3rdparty/masm/assembler/LinkBuffer.h
index bfd0e402ca..75b9a5c0bd 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.h
+++ b/src/3rdparty/masm/assembler/LinkBuffer.h
@@ -350,8 +350,8 @@ inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::performF
#endif
ASSERT(m_size <= INT_MAX);
- ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
MacroAssembler::cacheFlush(code(), m_size);
+ ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
}
template <typename MacroAssembler>
@@ -418,8 +418,8 @@ inline void BranchCompactingLinkBuffer<MacroAssembler>::performFinalization()
this->m_completed = true;
#endif
- ExecutableAllocator::makeExecutable(code(), m_initialSize);
MacroAssembler::cacheFlush(code(), m_size);
+ ExecutableAllocator::makeExecutable(code(), m_initialSize);
}
template <typename MacroAssembler>
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index b71cf290f8..6fa66e0dd7 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -1892,9 +1892,18 @@ public:
ASSERT(to.isSet());
char* code = reinterpret_cast<char*>(m_formatter.data());
- ASSERT(!reinterpret_cast<int32_t*>(code + from.m_offset)[-1]);
+ ASSERT(!loadPossiblyUnaligned<int32_t>(code, from.m_offset, -1));
setRel32(code + from.m_offset, code + to.m_offset);
}
+
+ template<typename T>
+ T loadPossiblyUnaligned(char *ptr, size_t offset, int idx)
+ {
+ T *t_ptr = &reinterpret_cast<T*>(ptr + offset)[idx];
+ T val;
+ memcpy(&val, t_ptr, sizeof(T));
+ return val;
+ }
static void linkJump(void* code, AssemblerLabel from, void* to)
{
@@ -2095,7 +2104,14 @@ private:
static void setInt32(void* where, int32_t value)
{
- reinterpret_cast<int32_t*>(where)[-1] = value;
+ storePossiblyUnaligned<int32_t>(where, -1, value);
+ }
+
+ template <typename T>
+ static void storePossiblyUnaligned(void *where, int idx, T value)
+ {
+ T *ptr = &reinterpret_cast<T*>(where)[idx];
+ memcpy(ptr, &value, sizeof(T));
}
static void setInt8(void* where, int8_t value)
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index 7dfb24f4b8..f7cdae7421 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -125,3 +125,8 @@ QMAKE_EXTRA_COMPILERS += retgen
}
}
}
+
+linux {
+ requires(qtConfig(dlopen))
+ QMAKE_USE_PRIVATE += libdl
+}
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
index 0c902c7172..3b2a73a39a 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
@@ -31,13 +31,82 @@
#include <cstdlib>
#include "PageAllocation.h"
+#include <dlfcn.h>
#include <errno.h>
#include <sys/mman.h>
#include <wtf/Assertions.h>
#include <wtf/UnusedParam.h>
+#if OS(LINUX)
+#include <sys/syscall.h>
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
+#endif
+#endif
+
+#if defined(__ANDROID__) && defined(SYS_memfd_create)
+ // On Android it's been observed that permissions of memory mappings
+ // backed by a memfd could not be changed via mprotect for no obvious
+ // reason.
+# undef SYS_memfd_create
+#endif
+
namespace WTF {
+#ifdef SYS_memfd_create
+static int memfdForUsage(size_t bytes, OSAllocator::Usage usage)
+{
+ const char *type = "unknown-usage:";
+ switch (usage) {
+ case OSAllocator::UnknownUsage:
+ break;
+ case OSAllocator::FastMallocPages:
+ type = "fastmalloc:";
+ break;
+ case OSAllocator::JSGCHeapPages:
+ type = "JSGCHeap:";
+ break;
+ case OSAllocator::JSVMStackPages:
+ type = "JSVMStack:";
+ break;
+ case OSAllocator::JSJITCodePages:
+ type = "JITCode:";
+ break;
+ }
+
+ // try to get our own library name by giving dladdr a pointer pointing to
+ // something we know to be in it (using a pointer to string data)
+ static const char *libname = [=]() {
+ Dl_info info;
+ if (dladdr(type, &info) == 0)
+ info.dli_fname = nullptr;
+ return info.dli_fname;
+ }();
+
+ char buf[PATH_MAX];
+ strcpy(buf, type);
+ if (libname)
+ strcat(buf, libname);
+ else
+ strcat(buf, "QtQml");
+
+ int fd = syscall(SYS_memfd_create, buf, MFD_CLOEXEC);
+ if (fd != -1) {
+ if (ftruncate(fd, bytes) == 0)
+ return fd;
+ }
+ close(fd);
+ return -1;
+}
+#elif OS(LINUX)
+static int memfdForUsage(size_t bytes, OSAllocator::Usage usage)
+{
+ UNUSED_PARAM(bytes);
+ UNUSED_PARAM(usage);
+ return -1;
+}
+#endif
+
void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
{
#if OS(QNX)
@@ -46,14 +115,18 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
if (result == MAP_FAILED)
CRASH();
#elif OS(LINUX)
- UNUSED_PARAM(usage);
UNUSED_PARAM(writable);
UNUSED_PARAM(executable);
+ int fd = memfdForUsage(bytes, usage);
- void* result = mmap(0, bytes, PROT_NONE, MAP_NORESERVE | MAP_PRIVATE | MAP_ANON, -1, 0);
+ void* result = mmap(0, bytes, PROT_NONE, MAP_NORESERVE | MAP_PRIVATE |
+ (fd == -1 ? MAP_ANON : 0), fd, 0);
if (result == MAP_FAILED)
CRASH();
madvise(result, bytes, MADV_DONTNEED);
+
+ if (fd != -1)
+ close(fd);
#else
void* result = reserveAndCommit(bytes, usage, writable, executable);
#if HAVE(MADV_FREE_REUSE)
@@ -83,6 +156,10 @@ void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bo
#if OS(DARWIN)
int fd = usage;
+#elif OS(LINUX)
+ int fd = memfdForUsage(bytes, usage);
+ if (fd != -1)
+ flags &= ~MAP_ANON;
#else
UNUSED_PARAM(usage);
int fd = -1;
@@ -126,6 +203,12 @@ void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bo
mmap(result, pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
mmap(static_cast<char*>(result) + bytes - pageSize(), pageSize(), PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, fd, 0);
}
+
+#if OS(LINUX)
+ if (fd != -1)
+ close(fd);
+#endif
+
return result;
}
diff --git a/src/3rdparty/masm/wtf/VMTags.h b/src/3rdparty/masm/wtf/VMTags.h
index 117bc3721e..af5352e471 100644
--- a/src/3rdparty/masm/wtf/VMTags.h
+++ b/src/3rdparty/masm/wtf/VMTags.h
@@ -62,6 +62,14 @@
#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY VM_MAKE_TAG(69)
#endif // defined(VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS)
+#elif OS(LINUX)
+
+#define VM_TAG_FOR_TCMALLOC_MEMORY 0
+#define VM_TAG_FOR_COLLECTOR_MEMORY 1
+#define VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY 2
+#define VM_TAG_FOR_REGISTERFILE_MEMORY 3
+#define VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY 4
+
#else // OS(DARWIN)
#define VM_TAG_FOR_TCMALLOC_MEMORY -1
diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp
index 5e8b41401f..7089fed4ad 100644
--- a/src/imports/folderlistmodel/plugin.cpp
+++ b/src/imports/folderlistmodel/plugin.cpp
@@ -42,13 +42,6 @@
#include "qquickfolderlistmodel.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_Qt_labs_folderlistmodel);
-#endif
-}
-
QT_BEGIN_NAMESPACE
//![class decl]
@@ -58,7 +51,7 @@ class QmlFolderListModelPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QmlFolderListModelPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QmlFolderListModelPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel"));
diff --git a/src/imports/handlers/plugin.cpp b/src/imports/handlers/plugin.cpp
index d1041d6539..a98bbad9c0 100644
--- a/src/imports/handlers/plugin.cpp
+++ b/src/imports/handlers/plugin.cpp
@@ -41,13 +41,6 @@
#include <private/qquickhandlersmodule_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_Qt_labs_handlers);
-#endif
-}
-
QT_BEGIN_NAMESPACE
//![class decl]
@@ -56,7 +49,7 @@ class QtQuickHandlersPlugin : public QQmlExtensionPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuickHandlersPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuickHandlersPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.handlers"));
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index e188602277..80f493da85 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,7 +1,5 @@
TEMPLATE = subdirs
-QT_FOR_CONFIG += quick-private
-
SUBDIRS += \
builtins \
qtqml \
@@ -13,11 +11,14 @@ qtConfig(settings): SUBDIRS += settings
qtConfig(statemachine): SUBDIRS += statemachine
qtHaveModule(quick) {
+ QT_FOR_CONFIG += quick-private
+
SUBDIRS += \
handlers \
layouts \
qtquick2 \
- window
+ window \
+ tableview
qtHaveModule(testlib): SUBDIRS += testlib
qtConfig(systemsemaphore): SUBDIRS += sharedimage
diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp
index c805c9fb43..80799e8859 100644
--- a/src/imports/layouts/plugin.cpp
+++ b/src/imports/layouts/plugin.cpp
@@ -42,13 +42,6 @@
#include "qquicklinearlayout_p.h"
#include "qquickstacklayout_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Layouts);
-#endif
-}
-
QT_BEGIN_NAMESPACE
//![class decl]
@@ -59,7 +52,6 @@ class QtQuickLayoutsPlugin : public QQmlExtensionPlugin
public:
QtQuickLayoutsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent)
{
- initResources();
}
void registerTypes(const char *uri) override
{
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 9cca11ac5d..fb20a1c457 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -61,13 +61,6 @@
#include <private/qv4jscall_p.h>
#include <private/qv4objectiterator_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_LocalStorage);
-#endif
-}
-
QT_BEGIN_NAMESPACE
#define V4THROW_SQL(error, desc) { \
@@ -148,7 +141,7 @@ public:
static Heap::QQmlSqlDatabaseWrapper *create(QV4::ExecutionEngine *engine)
{
- return engine->memoryManager->allocObject<QQmlSqlDatabaseWrapper>();
+ return engine->memoryManager->allocate<QQmlSqlDatabaseWrapper>();
}
~QQmlSqlDatabaseWrapper() {
@@ -814,7 +807,6 @@ class QQmlLocalStoragePlugin : public QQmlExtensionPlugin
public:
QQmlLocalStoragePlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent)
{
- initResources();
}
void registerTypes(const char *uri) override
{
diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp
index 83f8597408..49e94c13aa 100644
--- a/src/imports/models/plugin.cpp
+++ b/src/imports/models/plugin.cpp
@@ -42,13 +42,6 @@
#include <private/qqmlmodelsmodule_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQml_Models_2);
-#endif
-}
-
QT_BEGIN_NAMESPACE
/*!
@@ -78,7 +71,7 @@ class QtQmlModelsPlugin : public QQmlExtensionPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQmlModelsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQmlModelsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQml.Models"));
diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp
index d548f26599..e2b8712599 100644
--- a/src/imports/particles/plugin.cpp
+++ b/src/imports/particles/plugin.cpp
@@ -42,13 +42,6 @@
#include <private/qquickparticlesmodule_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Particles_2);
-#endif
-}
-
QT_BEGIN_NAMESPACE
//![class decl]
@@ -57,7 +50,7 @@ class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2ParticlesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuick2ParticlesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Particles"));
diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp
index 147f01e81b..d73a8b3688 100644
--- a/src/imports/qtquick2/plugin.cpp
+++ b/src/imports/qtquick2/plugin.cpp
@@ -41,13 +41,6 @@
#include <private/qtquick2_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_2);
-#endif
-}
-
QT_BEGIN_NAMESPACE
//![class decl]
@@ -56,7 +49,7 @@ class QtQuick2Plugin : public QQmlExtensionPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2Plugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuick2Plugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick"));
diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp
index 65de78a2f1..3ac0ad4653 100644
--- a/src/imports/settings/plugin.cpp
+++ b/src/imports/settings/plugin.cpp
@@ -42,13 +42,6 @@
#include "qqmlsettings_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_Qt_labs_settings);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QmlSettingsPlugin : public QQmlExtensionPlugin
@@ -57,11 +50,12 @@ class QmlSettingsPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QmlSettingsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QmlSettingsPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QByteArray(uri) == QByteArray("Qt.labs.settings"));
qmlRegisterType<QQmlSettings>(uri, 1, 0, "Settings");
+ qmlRegisterType<QQmlSettings,1>(uri, 1, 1, "Settings");
}
};
diff --git a/src/imports/settings/plugins.qmltypes b/src/imports/settings/plugins.qmltypes
index 40d8746525..ae3de3dfff 100644
--- a/src/imports/settings/plugins.qmltypes
+++ b/src/imports/settings/plugins.qmltypes
@@ -4,15 +4,20 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable -noforceqtquick Qt.labs.settings 1.0'
+// 'qmlplugindump -nonrelocatable -noforceqtquick Qt.labs.settings 1.1'
Module {
dependencies: []
Component {
name: "QQmlSettings"
prototype: "QObject"
- exports: ["Qt.labs.settings/Settings 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "Qt.labs.settings/Settings 1.0",
+ "Qt.labs.settings/Settings 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "category"; type: "string" }
+ Property { name: "fileName"; revision: 1; type: "string" }
}
}
+
diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp
index 2271774643..6b3904909a 100644
--- a/src/imports/settings/qqmlsettings.cpp
+++ b/src/imports/settings/qqmlsettings.cpp
@@ -156,7 +156,8 @@ QT_BEGIN_NAMESPACE
Application specific settings are identified by providing application
\l {QCoreApplication::applicationName}{name},
\l {QCoreApplication::organizationName}{organization} and
- \l {QCoreApplication::organizationDomain}{domain}.
+ \l {QCoreApplication::organizationDomain}{domain}, or by specifying
+ \l fileName.
\code
#include <QGuiApplication>
@@ -258,6 +259,7 @@ public:
int timerId = 0;
bool initialized = false;
QString category;
+ QString fileName;
mutable QPointer<QSettings> settings;
QHash<const char *, QVariant> changedProperties;
};
@@ -268,7 +270,7 @@ QSettings *QQmlSettingsPrivate::instance() const
{
if (!settings) {
QQmlSettings *q = const_cast<QQmlSettings*>(q_func());
- settings = new QSettings(q);
+ settings = fileName.isEmpty() ? new QSettings(q) : new QSettings(fileName, QSettings::IniFormat, q);
if (!category.isEmpty())
settings->beginGroup(category);
if (initialized)
@@ -299,6 +301,11 @@ void QQmlSettingsPrivate::load()
const QMetaObject *mo = q->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
+
+ // don't save built-in properties if there aren't any qml properties
+ if (offset == 1)
+ return;
+
for (int i = offset; i < count; ++i) {
QMetaProperty property = mo->property(i);
@@ -398,6 +405,66 @@ void QQmlSettings::setCategory(const QString &category)
}
}
+/*!
+ \qmlproperty string Settings::fileName
+
+ This property holds the path to the settings file. If the file doesn't
+ already exist, it is created.
+
+ \sa QSettings::fileName, QSettings::IniFormat
+
+ \since Qt.labs.settings 1.1
+*/
+QString QQmlSettings::fileName() const
+{
+ Q_D(const QQmlSettings);
+ return d->fileName;
+}
+
+void QQmlSettings::setFileName(const QString &fileName)
+{
+ Q_D(QQmlSettings);
+ if (d->fileName != fileName) {
+ d->reset();
+ d->fileName = fileName;
+ if (d->initialized)
+ d->load();
+ }
+}
+
+/*!
+ \qmlmethod var Settings::value(string key, var defaultValue)
+
+ Returns the value for setting \a key. If the setting doesn't exist,
+ returns \a defaultValue.
+
+ \sa QSettings::value
+
+ \since Qt.labs.settings 1.1
+*/
+QVariant QQmlSettings::value(const QString &key, const QVariant &defaultValue) const
+{
+ Q_D(const QQmlSettings);
+ return d->instance()->value(key, defaultValue);
+}
+
+/*!
+ \qmlmethod Settings::setValue(string key, var value)
+
+ Sets the value of setting key to value. If the key already exists,
+ the previous value is overwritten.
+
+ \sa QSettings::setValue
+
+ \since Qt.labs.settings 1.1
+*/
+void QQmlSettings::setValue(const QString &key, const QVariant &value)
+{
+ Q_D(const QQmlSettings);
+ d->instance()->setValue(key, value);
+ qCDebug(lcSettings) << "QQmlSettings: setValue" << key << ":" << value;
+}
+
void QQmlSettings::classBegin()
{
}
diff --git a/src/imports/settings/qqmlsettings_p.h b/src/imports/settings/qqmlsettings_p.h
index ce942d7564..f73e595557 100644
--- a/src/imports/settings/qqmlsettings_p.h
+++ b/src/imports/settings/qqmlsettings_p.h
@@ -65,6 +65,7 @@ class QQmlSettings : public QObject, public QQmlParserStatus
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString category READ category WRITE setCategory FINAL)
+ Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL REVISION 1)
public:
explicit QQmlSettings(QObject *parent = 0);
@@ -73,6 +74,12 @@ public:
QString category() const;
void setCategory(const QString &category);
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ Q_REVISION(1) Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
+ Q_REVISION(1) Q_INVOKABLE void setValue(const QString &key, const QVariant &value);
+
protected:
void timerEvent(QTimerEvent *event) override;
diff --git a/src/imports/settings/settings.pro b/src/imports/settings/settings.pro
index 29229f59cb..816a6a9fef 100644
--- a/src/imports/settings/settings.pro
+++ b/src/imports/settings/settings.pro
@@ -1,7 +1,7 @@
CXX_MODULE = qml
TARGET = qmlsettingsplugin
TARGETPATH = Qt/labs/settings
-IMPORT_VERSION = 1.0
+IMPORT_VERSION = 1.1
QT = core qml
diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp
index f0e66479b6..e3a9017681 100644
--- a/src/imports/shapes/plugin.cpp
+++ b/src/imports/shapes/plugin.cpp
@@ -39,16 +39,7 @@
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
-
-#include "qquickshape_p.h"
-
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Shapes);
-#endif
- Q_INIT_RESOURCE(qtquickshapesplugin);
-}
+#include <QtQuickShapes/private/qquickshape_p.h>
QT_BEGIN_NAMESPACE
@@ -58,7 +49,11 @@ class QmlShapesPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QmlShapesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QmlShapesPlugin(QObject *parent = nullptr)
+ : QQmlExtensionPlugin(parent)
+ {
+ }
+
void registerTypes(const char *uri) override
{
Q_ASSERT(QByteArray(uri) == QByteArray("QtQuick.Shapes"));
diff --git a/src/imports/shapes/shapes.pro b/src/imports/shapes/shapes.pro
index 4d6e9508af..71bb456866 100644
--- a/src/imports/shapes/shapes.pro
+++ b/src/imports/shapes/shapes.pro
@@ -3,31 +3,9 @@ TARGET = qmlshapesplugin
TARGETPATH = QtQuick/Shapes
IMPORT_VERSION = 1.11
-QT = core gui-private qml quick-private
-
-HEADERS += \
- qquickshape_p.h \
- qquickshape_p_p.h \
- qquickshapegenericrenderer_p.h \
- qquickshapesoftwarerenderer_p.h
+QT = core gui-private qml quick-private quickshapes-private
SOURCES += \
plugin.cpp \
- qquickshape.cpp \
- qquickshapegenericrenderer.cpp \
- qquickshapesoftwarerenderer.cpp
-
-qtConfig(opengl) {
- HEADERS += \
- qquicknvprfunctions_p.h \
- qquicknvprfunctions_p_p.h \
- qquickshapenvprrenderer_p.h
-
- SOURCES += \
- qquicknvprfunctions.cpp \
- qquickshapenvprrenderer.cpp
-}
-
-RESOURCES += qtquickshapesplugin.qrc
load(qml_plugin)
diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp
index 93ced6e280..bf7499b31a 100644
--- a/src/imports/statemachine/plugin.cpp
+++ b/src/imports/statemachine/plugin.cpp
@@ -47,13 +47,6 @@
#include <QQmlExtensionPlugin>
#include <qqml.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQml_StateMachine);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QtQmlStateMachinePlugin : public QQmlExtensionPlugin
@@ -62,7 +55,7 @@ class QtQmlStateMachinePlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQmlStateMachinePlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQmlStateMachinePlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
qmlRegisterType<State>(uri, 1, 0, "State");
diff --git a/src/imports/tableview/plugin.cpp b/src/imports/tableview/plugin.cpp
new file mode 100644
index 0000000000..3bd9b72a8d
--- /dev/null
+++ b/src/imports/tableview/plugin.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQuick/private/qquicktableview_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//![class decl]
+class QtQuickTableViewPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QtQuickTableViewPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent)
+ {}
+
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.tableview"));
+ qmlRegisterType<QQuickTableView>(uri, 1, 0, "TableView");
+ }
+};
+//![class decl]
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/tableview/plugins.qmltypes b/src/imports/tableview/plugins.qmltypes
new file mode 100644
index 0000000000..8510b698a9
--- /dev/null
+++ b/src/imports/tableview/plugins.qmltypes
@@ -0,0 +1,33 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable Qt.labs.tableview 1.0'
+
+Module {
+ dependencies: ["QtQuick 2.8"]
+ Component {
+ name: "QQuickTableView"
+ defaultProperty: "flickableData"
+ prototype: "QQuickFlickable"
+ exports: ["Qt.labs.tableview/TableView 1.0"]
+ exportMetaObjectRevisions: [0]
+ attachedType: "QQuickTableViewAttached"
+ Property { name: "rows"; type: "int"; isReadonly: true }
+ Property { name: "columns"; type: "int"; isReadonly: true }
+ Property { name: "rowSpacing"; type: "double" }
+ Property { name: "columnSpacing"; type: "double" }
+ Property { name: "cacheBuffer"; type: "int" }
+ Property { name: "model"; type: "QVariant" }
+ Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
+ }
+ Component {
+ name: "QQuickTableViewAttached"
+ prototype: "QObject"
+ Property { name: "tableView"; type: "QQuickTableView"; isReadonly: true; isPointer: true }
+ Property { name: "row"; type: "int"; isReadonly: true }
+ Property { name: "column"; type: "int"; isReadonly: true }
+ }
+}
diff --git a/src/imports/tableview/qmldir b/src/imports/tableview/qmldir
new file mode 100644
index 0000000000..dac976794a
--- /dev/null
+++ b/src/imports/tableview/qmldir
@@ -0,0 +1,5 @@
+module Qt.labs.tableview
+plugin tableviewplugin
+classname QtQuickTableViewPlugin
+typeinfo plugins.qmltypes
+
diff --git a/src/imports/tableview/tableview.pro b/src/imports/tableview/tableview.pro
new file mode 100644
index 0000000000..97ced65e6b
--- /dev/null
+++ b/src/imports/tableview/tableview.pro
@@ -0,0 +1,10 @@
+CXX_MODULE = qml
+TARGET = tableviewplugin
+TARGETPATH = Qt/labs/tableview
+IMPORT_VERSION = 1.0
+
+SOURCES += $$PWD/plugin.cpp
+
+QT += quick-private qml-private
+
+load(qml_plugin)
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 77b644d3f2..535e29ee70 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -1084,6 +1084,24 @@ Item {
does not occur, then the test will fail. Similar to
\c{QTest::ignoreMessage(QtWarningMsg, message)} in C++.
+ Since Qt 5.12, \a message can be either a string, or a regular
+ expression providing a pattern of messages to ignore.
+
+ For example, the following snippet will ignore a string warning message:
+ \qml
+ ignoreWarning("Something sort of bad happened")
+ \endqml
+
+ And the following snippet will ignore a regular expression matching a
+ number of possible warning messages:
+ \qml
+ ignoreWarning(new RegExp("[0-9]+ bad things happened"))
+ \endqml
+
+ \note Despite being a JavaScript RegExp object, it will not be
+ interpreted as such; instead, the pattern will be passed to
+ \l QRegularExpression.
+
\sa warn()
*/
function ignoreWarning(msg) {
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index 443229bee9..af15a44012 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -54,13 +54,6 @@ QML_DECLARE_TYPE(QuickTestEvent)
#include <QtDebug>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtTest);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QuickTestUtil : public QObject
@@ -150,7 +143,7 @@ class QTestQmlModule : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QTestQmlModule(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QTestQmlModule(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest"));
diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp
index 907eecb060..3e45730bb1 100644
--- a/src/imports/window/plugin.cpp
+++ b/src/imports/window/plugin.cpp
@@ -41,13 +41,6 @@
#include <private/qquickwindowmodule_p.h>
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_Window_2);
-#endif
-}
-
QT_BEGIN_NAMESPACE
/*!
@@ -72,7 +65,7 @@ class QtQuick2WindowPlugin : public QQmlExtensionPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QtQuick2WindowPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { initResources(); }
+ QtQuick2WindowPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window"));
diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp
index 82e11eeeb3..c5356b8534 100644
--- a/src/imports/xmllistmodel/plugin.cpp
+++ b/src/imports/xmllistmodel/plugin.cpp
@@ -42,13 +42,6 @@
#include "qqmlxmllistmodel_p.h"
-static void initResources()
-{
-#ifdef QT_STATIC
- Q_INIT_RESOURCE(qmake_QtQuick_XmlListModel);
-#endif
-}
-
QT_BEGIN_NAMESPACE
class QmlXmlListModelPlugin : public QQmlExtensionPlugin
@@ -57,7 +50,7 @@ class QmlXmlListModelPlugin : public QQmlExtensionPlugin
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
- QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+ QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { }
void registerTypes(const char *uri) override
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.XmlListModel"));
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
index 773d9747f0..df0881092b 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp
@@ -54,8 +54,10 @@
#include <QXmlResultItems>
#include <QXmlNodeModelIndex>
#include <QBuffer>
+#if QT_CONFIG(qml_network)
#include <QNetworkRequest>
#include <QNetworkReply>
+#endif
#include <QTimer>
#include <QMutex>
@@ -542,7 +544,10 @@ class QQuickXmlListModelPrivate : public QAbstractItemModelPrivate
public:
QQuickXmlListModelPrivate()
: isComponentComplete(true), size(0), highestRole(Qt::UserRole)
- , reply(0), status(QQuickXmlListModel::Null), progress(0.0)
+#if QT_CONFIG(qml_network)
+ , reply(0)
+#endif
+ , status(QQuickXmlListModel::Null), progress(0.0)
, queryId(-1), roleObjects(), redirectCount(0) {}
@@ -555,6 +560,7 @@ public:
emit q->statusChanged(status);
}
+#if QT_CONFIG(qml_network)
void deleteReply() {
Q_Q(QQuickXmlListModel);
if (reply) {
@@ -563,6 +569,7 @@ public:
reply = 0;
}
}
+#endif
bool isComponentComplete;
QUrl src;
@@ -574,7 +581,9 @@ public:
QStringList roleNames;
int highestRole;
+#if QT_CONFIG(qml_network)
QNetworkReply *reply;
+#endif
QQuickXmlListModel::Status status;
QString errorString;
qreal progress;
@@ -1036,10 +1045,12 @@ void QQuickXmlListModel::reload()
if (d->size < 0)
d->size = 0;
+#if QT_CONFIG(qml_network)
if (d->reply) {
d->reply->abort();
d->deleteReply();
}
+#endif
if (!d->xml.isEmpty()) {
d->queryId = QQuickXmlQueryEngine::instance(qmlEngine(this))->doQuery(d->query, d->namespaces, d->xml.toUtf8(), &d->roleObjects, d->keyRoleResultsCache);
@@ -1050,7 +1061,19 @@ void QQuickXmlListModel::reload()
d->notifyQueryStarted(false);
QTimer::singleShot(0, this, SLOT(dataCleared()));
+ } else if (QQmlFile::isLocalFile(d->src)) {
+ QFile file(QQmlFile::urlToLocalFileOrQrc(d->src));
+ QByteArray data = file.open(QIODevice::ReadOnly) ? file.readAll() : QByteArray();
+ d->notifyQueryStarted(false);
+ if (data.isEmpty()) {
+ d->queryId = XMLLISTMODEL_CLEAR_ID;
+ QTimer::singleShot(0, this, SLOT(dataCleared()));
+ } else {
+ d->queryId = QQuickXmlQueryEngine::instance(qmlEngine(this))->doQuery(
+ d->query, d->namespaces, data, &d->roleObjects, d->keyRoleResultsCache);
+ }
} else {
+#if QT_CONFIG(qml_network)
d->notifyQueryStarted(true);
QNetworkRequest req(d->src);
req.setRawHeader("Accept", "application/xml,*/*");
@@ -1058,11 +1081,17 @@ void QQuickXmlListModel::reload()
QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished()));
QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
+#else
+ d->queryId = XMLLISTMODEL_CLEAR_ID;
+ d->notifyQueryStarted(false);
+ QTimer::singleShot(0, this, SLOT(dataCleared()));
+#endif
}
}
#define XMLLISTMODEL_MAX_REDIRECT 16
+#if QT_CONFIG(qml_network)
void QQuickXmlListModel::requestFinished()
{
Q_D(QQuickXmlListModel);
@@ -1108,6 +1137,7 @@ void QQuickXmlListModel::requestFinished()
emit progressChanged(d->progress);
}
}
+#endif
void QQuickXmlListModel::requestProgress(qint64 received, qint64 total)
{
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
index e6a0898bb9..65f1299324 100644
--- a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
+++ b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h
@@ -144,7 +144,9 @@ public Q_SLOTS:
void reload();
private Q_SLOTS:
+#if QT_CONFIG(qml_network)
void requestFinished();
+#endif
void requestProgress(qint64,qint64);
void dataCleared();
void queryCompleted(const QQuickXmlQueryResult &);
diff --git a/src/imports/xmllistmodel/xmllistmodel.pro b/src/imports/xmllistmodel/xmllistmodel.pro
index b5f559fc93..8ee9ea311f 100644
--- a/src/imports/xmllistmodel/xmllistmodel.pro
+++ b/src/imports/xmllistmodel/xmllistmodel.pro
@@ -3,7 +3,8 @@ TARGET = qmlxmllistmodelplugin
TARGETPATH = QtQuick/XmlListModel
IMPORT_VERSION = 2.$$QT_MINOR_VERSION
-QT = network xmlpatterns qml-private core-private
+QT = xmlpatterns qml-private core-private
+qtConfig(qml-network): QT += network
SOURCES += qqmlxmllistmodel.cpp plugin.cpp
HEADERS += qqmlxmllistmodel_p.h
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index eb9d2288d6..fe0c92bf06 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -518,7 +518,7 @@ QQuickV4ParticleData::QQuickV4ParticleData(QV4::ExecutionEngine* v4, QQuickParti
QV4::Scope scope(v4);
QV4ParticleDataDeletable *d = particleV4Data(scope.engine);
- QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QV4ParticleData>(datum, system));
+ QV4::ScopedObject o(scope, v4->memoryManager->allocate<QV4ParticleData>(datum, system));
QV4::ScopedObject p(scope, d->proto.value());
o->setPrototype(p);
m_v4Value = o;
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
index e1d6263e36..c256501301 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
@@ -106,6 +106,9 @@ class QPacketProtocolPrivate : public QObjectPrivate
public:
QPacketProtocolPrivate(QIODevice *dev);
+ bool writeToDevice(const char *bytes, qint64 size);
+ bool readFromDevice(char *buffer, qint64 size);
+
QList<qint32> sendingPackets;
QList<QByteArray> packets;
QByteArray inProgress;
@@ -143,18 +146,18 @@ void QPacketProtocol::send(const QByteArray &data)
return; // We don't send empty packets
if (data.size() > maxSize) {
- emit invalidPacket();
+ emit error();
return;
}
- qint32 sendSize = data.size() + sizeof(qint32);
+ const qint32 sendSize = data.size() + static_cast<qint32>(sizeof(qint32));
d->sendingPackets.append(sendSize);
+
qint32 sendSizeLE = qToLittleEndian(sendSize);
- qint64 writeBytes = d->dev->write((char *)&sendSizeLE, sizeof(qint32));
- Q_UNUSED(writeBytes);
- Q_ASSERT(writeBytes == sizeof(qint32));
- writeBytes = d->dev->write(data);
- Q_ASSERT(writeBytes == data.size());
+ if (!d->writeToDevice((const char *)&sendSizeLE, sizeof(qint32))
+ || !d->writeToDevice(data.data(), data.size())) {
+ emit error();
+ }
}
/*!
@@ -240,28 +243,41 @@ void QPacketProtocol::readyToRead()
// Need to get trailing data
if (-1 == d->inProgressSize) {
// We need a size header of sizeof(qint32)
- if (sizeof(qint32) > (uint)d->dev->bytesAvailable())
+ if (static_cast<qint64>(sizeof(qint32)) > d->dev->bytesAvailable())
return;
// Read size header
qint32 inProgressSizeLE;
- const qint64 read = d->dev->read((char *)&inProgressSizeLE, sizeof(qint32));
+ if (!d->readFromDevice((char *)&inProgressSizeLE, sizeof(qint32))) {
+ emit error();
+ return;
+ }
d->inProgressSize = qFromLittleEndian(inProgressSizeLE);
// Check sizing constraints
- if (read != sizeof(qint32) || d->inProgressSize < read) {
+ if (d->inProgressSize < qint32(sizeof(qint32))) {
disconnect(d->dev, &QIODevice::readyRead, this, &QPacketProtocol::readyToRead);
disconnect(d->dev, &QIODevice::aboutToClose, this, &QPacketProtocol::aboutToClose);
disconnect(d->dev, &QIODevice::bytesWritten, this, &QPacketProtocol::bytesWritten);
d->dev = nullptr;
- emit invalidPacket();
+ emit error();
return;
}
- d->inProgressSize -= read;
+ d->inProgressSize -= sizeof(qint32);
} else {
- d->inProgress.append(d->dev->read(d->inProgressSize - d->inProgress.size()));
+ const int bytesToRead = static_cast<int>(
+ qMin(d->dev->bytesAvailable(),
+ static_cast<qint64>(d->inProgressSize - d->inProgress.size())));
+
+ QByteArray toRead(bytesToRead, Qt::Uninitialized);
+ if (!d->readFromDevice(toRead.data(), toRead.length())) {
+ emit error();
+ return;
+ }
+
+ d->inProgress.append(toRead);
if (d->inProgressSize == d->inProgress.size()) {
// Packet has arrived!
d->packets.append(d->inProgress);
@@ -281,6 +297,30 @@ QPacketProtocolPrivate::QPacketProtocolPrivate(QIODevice *dev) :
{
}
+bool QPacketProtocolPrivate::writeToDevice(const char *bytes, qint64 size)
+{
+ qint64 totalWritten = 0;
+ while (totalWritten < size) {
+ const qint64 chunkSize = dev->write(bytes + totalWritten, size - totalWritten);
+ if (chunkSize < 0)
+ return false;
+ totalWritten += chunkSize;
+ }
+ return totalWritten == size;
+}
+
+bool QPacketProtocolPrivate::readFromDevice(char *buffer, qint64 size)
+{
+ qint64 totalRead = 0;
+ while (totalRead < size) {
+ const qint64 chunkSize = dev->read(buffer + totalRead, size - totalRead);
+ if (chunkSize < 0)
+ return false;
+ totalRead += chunkSize;
+ }
+ return totalRead == size;
+}
+
/*!
\fn void QPacketProtocol::readyRead()
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
index 35edb568aa..a478fc9996 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h
@@ -72,7 +72,7 @@ public:
Q_SIGNALS:
void readyRead();
- void invalidPacket();
+ void error();
private:
void aboutToClose();
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index 95e6d5704c..0993390483 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -46,6 +46,7 @@
#include <private/qv4objectiterator_p.h>
#include <private/qv4identifier_p.h>
#include <private/qv4runtime_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qqmlengine_p.h>
@@ -96,18 +97,17 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s
{
switch (scopeType) {
case QV4::Heap::ExecutionContext::Type_GlobalContext:
- return 0;
- case QV4::Heap::ExecutionContext::Type_CatchContext:
- return 4;
+ break;
case QV4::Heap::ExecutionContext::Type_WithContext:
return 2;
case QV4::Heap::ExecutionContext::Type_CallContext:
return 1;
case QV4::Heap::ExecutionContext::Type_QmlContext:
return 3;
- default:
- return -1;
+ case QV4::Heap::ExecutionContext::Type_BlockContext:
+ return 4;
}
+ return 0;
}
QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine)
@@ -268,9 +268,9 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
Refs collectedRefs;
QV4::ScopedValue v(scope);
- QV4::InternalClass *ic = ctxt->internalClass();
+ QV4::Heap::InternalClass *ic = ctxt->internalClass();
for (uint i = 0; i < ic->size; ++i) {
- QString name = ic->nameMap[i]->string;
+ QString name = ic->nameMap[i].toQString();
names.append(name);
v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i];
collectedRefs.append(collect(v));
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index 7950d21612..70f71de6ca 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -65,7 +65,7 @@ void JavaScriptJob::run()
QV4::Scope scope(engine);
QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext()
- : engine->rootContext());
+ : engine->scriptContext());
QObject scopeObject;
QV4::CppStackFrame *frame = engine->currentStackFrame;
@@ -103,7 +103,7 @@ void JavaScriptJob::run()
}
}
- QV4::Script script(ctx, QV4::Compiler::EvalCode, this->script);
+ QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, this->script);
if (const QV4::Function *function = frame ? frame->v4Function : engine->globalCode)
script.strictMode = function->isStrict();
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
index b19115aa60..36390a3ea5 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
@@ -51,6 +51,7 @@
#include <private/qv4runtime_p.h>
#include <private/qversionedpacket_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qv4identifiertable_p.h>
#include <QtQml/qjsengine.h>
#include <QtCore/qjsonarray.h>
@@ -252,9 +253,9 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(const QString &expression)
m_runningJob = true;
QV4::ExecutionContext *ctx = m_engine->currentStackFrame ? m_engine->currentContext()
- : m_engine->rootContext();
+ : m_engine->scriptContext();
- QV4::Script script(ctx, QV4::Compiler::EvalCode, expression);
+ QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, expression);
if (const QV4::Function *function = m_engine->currentStackFrame
? m_engine->currentStackFrame->v4Function : m_engine->globalCode)
script.strictMode = function->isStrict();
@@ -493,10 +494,10 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
collector.collect(&output, QString(), QStringLiteral("this"), thisObject);
QV4::Scoped<QV4::CallContext> callContext(scope, frame->callContext());
if (callContext) {
- QV4::InternalClass *ic = callContext->internalClass();
+ QV4::Heap::InternalClass *ic = callContext->internalClass();
QV4::ScopedValue v(scope);
for (uint i = 0; i < ic->size; ++i) {
- QString name = ic->nameMap[i]->string;
+ QString name = ic->nameMap[i].toQString();
v = callContext->d()->locals[i];
collector.collect(&output, QString(), name, v);
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 19104927f2..a688e98b3f 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -80,8 +80,7 @@ void QQmlProfilerAdapter::init(QQmlProfilerService *service, QQmlProfiler *profi
// convert to QByteArrays that can be sent to the debug client
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
QQmlProfiler::LocationHash &locations,
- QList<QByteArray> &messages,
- bool trackLocations)
+ QList<QByteArray> &messages)
{
QQmlDebugPacket ds;
Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO,
@@ -96,7 +95,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd
|| decodedMessageType == QQmlProfilerDefinitions::RangeStart) {
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
- if (trackLocations && d.locationId != 0)
+ if (d.locationId != 0)
ds << static_cast<qint64>(d.locationId);
} else {
auto i = locations.find(d.locationId);
@@ -107,8 +106,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
<< static_cast<qint32>(i->location.column);
if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) {
// Send both, location and data ...
- if (trackLocations)
- ds << static_cast<qint64>(d.locationId);
+ ds << static_cast<qint64>(d.locationId);
messages.append(ds.squeezedData());
ds.clear();
ds << d.time << int(QQmlProfilerDefinitions::RangeData)
@@ -116,10 +114,8 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
<< (i->location.sourceFile.isEmpty() ? i->url.toString() :
i->location.sourceFile);
}
- if (trackLocations) {
- ds << static_cast<qint64>(d.locationId);
- locations.erase(i); // ... so that we can erase here without missing anything.
- }
+ ds << static_cast<qint64>(d.locationId);
+ locations.erase(i); // ... so that we can erase here without missing anything.
} else {
// Skip RangeData and RangeLocation: We've already sent them
continue;
@@ -130,14 +126,13 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
}
}
-qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
- bool trackLocations)
+qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
while (next != data.length()) {
const QQmlProfilerData &nextData = data.at(next);
if (nextData.time > until || messages.length() > s_numMessagesPerBatch)
return nextData.time;
- qQmlProfilerDataToByteArrays(nextData, locations, messages, trackLocations);
+ qQmlProfilerDataToByteArrays(nextData, locations, messages);
++next;
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
index b14b72d254..12544a19c2 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
@@ -61,8 +61,7 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
public:
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine);
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader);
- qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
- bool trackLocations) override;
+ qint64 sendMessages(qint64 until, QList<QByteArray> &messages) override;
void receiveData(const QVector<QQmlProfilerData> &new_data,
const QQmlProfiler::LocationHash &locations);
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
index 21a5663f59..462401a093 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
@@ -58,7 +58,7 @@ Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) :
QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
- m_waitingForStop(false), m_useMessageTypes(false), m_globalEnabled(false), m_globalFeatures(0)
+ m_waitingForStop(false), m_globalEnabled(false), m_globalFeatures(0)
{
m_timer.start();
QQmlAbstractProfilerAdapter *quickAdapter =
@@ -332,7 +332,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
m_waitingForStop = true;
for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting))
- profiler->reportData(m_useMessageTypes);
+ profiler->reportData();
for (QQmlAbstractProfilerAdapter *profiler : qAsConst(stopping))
profiler->stopProfiling();
@@ -367,8 +367,7 @@ void QQmlProfilerServiceImpl::sendMessages()
m_startTimes.erase(m_startTimes.begin());
qint64 next = first->sendMessages(m_startTimes.isEmpty() ?
std::numeric_limits<qint64>::max() :
- m_startTimes.begin().key(), messages,
- m_useMessageTypes);
+ m_startTimes.begin().key(), messages);
if (next != -1)
m_startTimes.insert(next, first);
@@ -454,13 +453,15 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
&m_flushTimer, &QTimer::stop);
}
}
+
+ bool useMessageTypes = false;
if (!stream.atEnd())
- stream >> m_useMessageTypes;
+ stream >> useMessageTypes;
// If engineId == -1 objectForId() and then the cast will return 0.
- if (enabled)
+ if (enabled && useMessageTypes) // If the client doesn't support message types don't profile.
startProfiling(qobject_cast<QJSEngine *>(objectForId(engineId)), features);
- else
+ else if (!enabled) // On stopProfiling the client doesn't repeat useMessageTypes.
stopProfiling(qobject_cast<QJSEngine *>(objectForId(engineId)));
stopWaiting();
@@ -486,7 +487,7 @@ void QQmlProfilerServiceImpl::flush()
}
for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting))
- profiler->reportData(m_useMessageTypes);
+ profiler->reportData();
}
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
index 2b92a478c1..3791ab29ae 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h
@@ -117,7 +117,6 @@ private:
QElapsedTimer m_timer;
QTimer m_flushTimer;
bool m_waitingForStop;
- bool m_useMessageTypes;
bool m_globalEnabled;
quint64 m_globalFeatures;
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
index f1ac8ef998..e4f2f556fc 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
@@ -104,8 +104,7 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes
return callNext == -1 ? memoryNext : qMin(callNext, memoryNext);
}
-qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
- bool trackLocations)
+qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
QQmlDebugPacket d;
@@ -134,24 +133,17 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
appendMemoryEvents(props.start, messages, d);
auto location = m_functionLocations.find(props.id);
- d << props.start << int(RangeStart) << int(Javascript);
- if (trackLocations)
- d << static_cast<qint64>(props.id);
+ d << props.start << int(RangeStart) << int(Javascript) << static_cast<qint64>(props.id);
if (location != m_functionLocations.end()) {
messages.push_back(d.squeezedData());
d.clear();
d << props.start << int(RangeLocation) << int(Javascript) << location->file << location->line
- << location->column;
- if (trackLocations)
- d << static_cast<qint64>(props.id);
+ << location->column << static_cast<qint64>(props.id);
messages.push_back(d.squeezedData());
d.clear();
- d << props.start << int(RangeData) << int(Javascript) << location->name;
-
- if (trackLocations) {
- d << static_cast<qint64>(props.id);
- m_functionLocations.erase(location);
- }
+ d << props.start << int(RangeData) << int(Javascript) << location->name
+ << static_cast<qint64>(props.id);
+ m_functionLocations.erase(location);
}
messages.push_back(d.squeezedData());
d.clear();
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
index 2211c82fc5..c4ca38d9b0 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h
@@ -68,8 +68,7 @@ class QV4ProfilerAdapter : public QQmlAbstractProfilerAdapter {
public:
QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine);
- virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
- bool trackLocations) override;
+ virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) override;
void receiveData(const QV4::Profiling::FunctionLocationHash &,
const QVector<QV4::Profiling::FunctionCallProperties> &,
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index 2c152e4cd5..79a1c82411 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -152,10 +152,8 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
}
}
-qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
- bool trackLocations)
+qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
- Q_UNUSED(trackLocations);
while (next < m_data.size()) {
if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch)
qQuickProfilerDataToByteArrays(m_data[next++], messages);
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
index 1ad020afd6..1f3467c1d0 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h
@@ -61,7 +61,7 @@ class QQuickProfilerAdapter : public QQmlAbstractProfilerAdapter {
public:
QQuickProfilerAdapter(QObject *parent = 0);
~QQuickProfilerAdapter();
- qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) override;
+ qint64 sendMessages(qint64 until, QList<QByteArray> &messages) override;
void receiveData(const QVector<QQuickProfilerData> &new_data);
private:
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
index c1e86f0b3c..8293e88038 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
@@ -177,14 +177,13 @@ private:
void changeServiceState(const QString &serviceName, QQmlDebugService::State state);
void removeThread();
void receiveMessage();
- void invalidPacket();
+ void protocolError();
QQmlDebugServerConnection *m_connection;
QHash<QString, QQmlDebugService *> m_plugins;
QStringList m_clientPlugins;
bool m_gotHello;
bool m_blockingMode;
- bool m_clientSupportsMultiPackets;
QHash<QJSEngine *, EngineCondition> m_engineConditions;
@@ -277,8 +276,7 @@ static void cleanupOnShutdown()
QQmlDebugServerImpl::QQmlDebugServerImpl() :
m_connection(nullptr),
m_gotHello(false),
- m_blockingMode(false),
- m_clientSupportsMultiPackets(false)
+ m_blockingMode(false)
{
static bool postRoutineAdded = false;
if (!postRoutineAdded) {
@@ -464,10 +462,9 @@ void QQmlDebugServerImpl::receiveMessage()
s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion;
}
+ bool clientSupportsMultiPackets = false;
if (!in.atEnd())
- in >> m_clientSupportsMultiPackets;
- else
- m_clientSupportsMultiPackets = false;
+ in >> clientSupportsMultiPackets;
// Send the hello answer immediately, since it needs to arrive before
// the plugins below start sending messages.
@@ -475,13 +472,15 @@ void QQmlDebugServerImpl::receiveMessage()
QQmlDebugPacket out;
QStringList pluginNames;
QList<float> pluginVersions;
- const int count = m_plugins.count();
- pluginNames.reserve(count);
- pluginVersions.reserve(count);
- for (QHash<QString, QQmlDebugService *>::ConstIterator i = m_plugins.constBegin();
- i != m_plugins.constEnd(); ++i) {
- pluginNames << i.key();
- pluginVersions << i.value()->version();
+ if (clientSupportsMultiPackets) { // otherwise, disable all plugins
+ const int count = m_plugins.count();
+ pluginNames.reserve(count);
+ pluginVersions.reserve(count);
+ for (QHash<QString, QQmlDebugService *>::ConstIterator i = m_plugins.constBegin();
+ i != m_plugins.constEnd(); ++i) {
+ pluginNames << i.key();
+ pluginVersions << i.value()->version();
+ }
}
out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion
@@ -523,7 +522,7 @@ void QQmlDebugServerImpl::receiveMessage()
} else {
qWarning("QML Debugger: Invalid control message %d.", op);
- invalidPacket();
+ protocolError();
return;
}
@@ -701,16 +700,11 @@ void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &mes
void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages)
{
if (canSendMessage(name)) {
- if (m_clientSupportsMultiPackets) {
- QQmlDebugPacket out;
- out << name;
- for (const QByteArray &message : messages)
- out << message;
- m_protocol->send(out.data());
- } else {
- for (const QByteArray &message : messages)
- doSendMessage(name, message);
- }
+ QQmlDebugPacket out;
+ out << name;
+ for (const QByteArray &message : messages)
+ out << message;
+ m_protocol->send(out.data());
m_connection->flush();
}
}
@@ -743,16 +737,16 @@ void QQmlDebugServerImpl::setDevice(QIODevice *socket)
m_protocol = new QPacketProtocol(socket, this);
QObject::connect(m_protocol, &QPacketProtocol::readyRead,
this, &QQmlDebugServerImpl::receiveMessage);
- QObject::connect(m_protocol, &QPacketProtocol::invalidPacket,
- this, &QQmlDebugServerImpl::invalidPacket);
+ QObject::connect(m_protocol, &QPacketProtocol::error,
+ this, &QQmlDebugServerImpl::protocolError);
if (blockingMode())
m_protocol->waitForReadyRead(-1);
}
-void QQmlDebugServerImpl::invalidPacket()
+void QQmlDebugServerImpl::protocolError()
{
- qWarning("QML Debugger: Received a corrupted packet! Giving up ...");
+ qWarning("QML Debugger: A protocol error has occurred! Giving up ...");
m_connection->disconnect();
// protocol might still be processing packages at this point
m_protocol->deleteLater();
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
index 0bd51cbf46..d728686248 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
@@ -176,6 +176,12 @@ void QSGOpenVGInternalRectangleNode::setGradientStops(const QGradientStops &stop
m_fillDirty = true;
}
+void QSGOpenVGInternalRectangleNode::setGradientVertical(bool vertical)
+{
+ m_vertical = vertical;
+ m_fillDirty = true;
+}
+
void QSGOpenVGInternalRectangleNode::setRadius(qreal radius)
{
m_radius = radius;
@@ -242,13 +248,13 @@ void QSGOpenVGInternalRectangleNode::render()
} else {
// Linear Gradient
vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
- const VGfloat verticalLinearGradient[] = {
- 0.0f,
+ const VGfloat linearGradient[] = {
0.0f,
0.0f,
- static_cast<VGfloat>(m_rect.height())
+ m_vertical ? 0.0f : static_cast<VGfloat>(m_rect.width()),
+ m_vertical ? static_cast<VGfloat>(m_rect.height()) : 0.0f
};
- vgSetParameterfv(m_rectanglePaint, VG_PAINT_LINEAR_GRADIENT, 4, verticalLinearGradient);
+ vgSetParameterfv(m_rectanglePaint, VG_PAINT_LINEAR_GRADIENT, 4, linearGradient);
vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, false);
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
index e8d25c94f8..86d2c3318c 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
@@ -59,6 +59,7 @@ public:
void setPenColor(const QColor &color) override;
void setPenWidth(qreal width) override;
void setGradientStops(const QGradientStops &stops) override;
+ void setGradientVertical(bool vertical) override;
void setRadius(qreal radius) override;
void setAligned(bool aligned) override;
void update() override;
@@ -85,6 +86,7 @@ private:
qreal m_penWidth = 0.0;
qreal m_radius = 0.0;
bool m_aligned = false;
+ bool m_vertical = true;
QGradientStops m_gradientStops;
VGPath m_rectanglePath;
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 3f33e7e81b..4e82c7a062 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -78,7 +78,7 @@ QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create)
inst = animationTimer() ? animationTimer()->localData() : 0;
}
#else
- static QAnimationTimer unifiedTimer;
+ static QQmlAnimationTimer unifiedTimer;
inst = &unifiedTimer;
#endif
return inst;
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 63fd4b0dac..0be6ca96ea 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -56,6 +56,8 @@
#include <QtCore/private/qabstractanimation_p.h>
#include <vector>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QAnimationGroupJob;
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index fb567dc019..b01b2f3b36 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -54,6 +54,8 @@
#include "private/qabstractanimationjob_p.h"
#include <QtCore/qdebug.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
index 0bb9e83b2d..e3d6fe9178 100644
--- a/src/qml/animations/qanimationjobutil_p.h
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+QT_REQUIRE_CONFIG(qml_animation);
+
#define RETURN_IF_DELETED(func) \
{ \
bool *prevWasDeleted = m_wasDeleted; \
diff --git a/src/qml/animations/qcontinuinganimationgroupjob_p.h b/src/qml/animations/qcontinuinganimationgroupjob_p.h
index baf4ff1ae5..c67b8d39ad 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob_p.h
+++ b/src/qml/animations/qcontinuinganimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include "private/qanimationgroupjob_p.h"
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QContinuingAnimationGroupJob : public QAnimationGroupJob
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
index 67ba626247..0265fe3274 100644
--- a/src/qml/animations/qparallelanimationgroupjob_p.h
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include "private/qanimationgroupjob_p.h"
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
index d0e8d57fc7..6c9bbf0dab 100644
--- a/src/qml/animations/qpauseanimationjob_p.h
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -53,6 +53,8 @@
#include <private/qanimationgroupjob_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 800f0c3b90..13f9806be1 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -53,6 +53,8 @@
#include <private/qanimationgroupjob_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QPauseAnimationJob;
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 95096db51d..da3c173545 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -11,7 +11,8 @@ HEADERS += \
$$PWD/qv4codegen_p.h \
$$PWD/qqmlirbuilder_p.h \
$$PWD/qqmltypecompiler_p.h \
- $$PWD/qv4instr_moth_p.h
+ $$PWD/qv4instr_moth_p.h \
+ $$PWD/qv4bytecodehandler_p.h
SOURCES += \
$$PWD/qv4bytecodegenerator.cpp \
@@ -21,7 +22,8 @@ SOURCES += \
$$PWD/qv4compilerscanfunctions.cpp \
$$PWD/qv4codegen.cpp \
$$PWD/qqmlirbuilder.cpp \
- $$PWD/qv4instr_moth.cpp
+ $$PWD/qv4instr_moth.cpp \
+ $$PWD/qv4bytecodehandler.cpp
!qmldevtools_build {
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 8a1b3744ee..820f127331 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -96,23 +96,24 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
declarationsOverride = nullptr;
}
-QString Object::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
+QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
{
QSet<int> functionNames;
- for (Function *f = functions->first; f; f = f->next) {
- QQmlJS::AST::FunctionDeclaration *function = f->functionDeclaration;
- Q_ASSERT(function);
- *errorLocation = function->identifierToken;
+ for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) {
+ Function *f = functionit.ptr;
+ errorLocation->startLine = f->location.line;
+ errorLocation->startColumn = f->location.column;
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
- for (QmlIR::Signal *s = qmlSignals->first; s; s = s->next) {
+ for (auto signalit = obj->signalsBegin(); signalit != obj->signalsEnd(); ++signalit) {
+ QmlIR::Signal *s = signalit.ptr;
if (s->nameIndex == f->nameIndex)
return tr("Duplicate method name");
}
- const QString name = function->name.toString();
+ const QString name = stringAt(f->nameIndex);
if (name.at(0).isUpper())
return tr("Method names cannot begin with an upper case letter");
if (illegalNames.contains(name))
@@ -497,7 +498,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiObjectBinding *node)
bool IRBuilder::visit(QQmlJS::AST::UiScriptBinding *node)
{
- appendBinding(node->qualifiedId, node->statement);
+ appendBinding(node->qualifiedId, node->statement, node);
return false;
}
@@ -601,7 +602,7 @@ bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qu
return false;
QQmlJS::AST::SourceLocation loc;
- QString error = obj->sanityCheckFunctionNames(illegalNames, &loc);
+ QString error = sanityCheckFunctionNames(obj, illegalNames, &loc);
if (!error.isEmpty()) {
recordError(loc, error);
return false;
@@ -957,7 +958,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
QQmlJS::AST::Node::accept(node->binding, this);
} else if (node->statement) {
if (!isRedundantNullInitializerForPropertyDeclaration(_propertyDeclaration, node->statement))
- appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+ appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement, node);
}
qSwap(_propertyDeclaration, property);
}
@@ -971,26 +972,27 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
if (QQmlJS::AST::FunctionDeclaration *funDecl = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration *>(node->sourceElement)) {
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
foe->node = funDecl;
+ foe->parentNode = funDecl;
foe->nameIndex = registerString(funDecl->name.toString());
foe->disableAcceleratedLookups = false;
const int index = _object->functionsAndExpressions->append(foe);
Function *f = New<Function>();
- f->functionDeclaration = funDecl;
QQmlJS::AST::SourceLocation loc = funDecl->identifierToken;
f->location.line = loc.startLine;
f->location.column = loc.startColumn;
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
- int formalsCount = 0;
- for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next)
- ++formalsCount;
+ const QStringList formals = funDecl->formals ? funDecl->formals->formals() : QStringList();
+ int formalsCount = formals.size();
f->formals.allocate(pool, formalsCount);
int i = 0;
- for (QQmlJS::AST::FormalParameterList *it = funDecl->formals; it; it = it->next, ++i)
- f->formals[i] = registerString(it->name.toString());
+ for (const QString &arg : formals) {
+ f->formals[i] = registerString(arg);
+ ++i;
+ }
_object->appendFunction(f);
} else {
@@ -1044,7 +1046,7 @@ QStringRef IRBuilder::textRefAt(const QQmlJS::AST::SourceLocation &first, const
return QStringRef(&sourceCode, first.offset, last.offset + last.length - first.offset);
}
-void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement)
+void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
{
QQmlJS::AST::SourceLocation loc = statement->firstSourceLocation();
binding->valueLocation.line = loc.startLine;
@@ -1090,6 +1092,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
expr->node = statement;
+ expr->parentNode = parentNode;
expr->nameIndex = registerString(QLatin1String("expression for ")
+ stringAt(binding->propertyNameIndex));
expr->disableAcceleratedLookups = false;
@@ -1216,7 +1219,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg
}
}
-void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value)
+void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode)
{
const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken;
Object *object = nullptr;
@@ -1227,7 +1230,7 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Sta
return;
}
qSwap(_object, object);
- appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value);
+ appendBinding(qualifiedNameLocation, name->identifierToken, registerString(name->name.toString()), value, parentNode);
qSwap(_object, object);
}
@@ -1242,7 +1245,8 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex,
qSwap(_object, object);
}
-void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value)
+void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+ QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode)
{
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
@@ -1250,7 +1254,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
binding->flags = 0;
- setBindingValue(binding, value);
+ setBindingValue(binding, value, parentNode);
QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
if (!error.isEmpty()) {
recordError(qualifiedNameLocation, error);
@@ -1806,24 +1810,36 @@ void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject)
QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions)
{
+ auto qmlName = [&](const CompiledFunctionOrExpression &c) {
+ if (c.nameIndex != 0)
+ return stringPool->stringForIndex(c.nameIndex);
+ else
+ return QStringLiteral("%qml-expression-entry");
+ };
QVector<int> runtimeFunctionIndices(functions.size());
- QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::GlobalCode);
- scan.enterGlobalEnvironment(QV4::Compiler::QmlBinding);
+ QV4::Compiler::ScanFunctions scan(this, sourceCode, 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);
- if (function)
+ if (function) {
scan.enterQmlFunction(function);
- else
- scan.enterEnvironment(f.node, QV4::Compiler::QmlBinding);
+ } else {
+ Q_ASSERT(f.node != f.parentNode);
+ scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f));
+ }
scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
scan.leaveEnvironment();
+ if (hasError)
+ return QVector<int>();
+
_context = nullptr;
for (int i = 0; i < functions.count(); ++i) {
@@ -1836,15 +1852,13 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QString name;
if (function)
name = function->name.toString();
- else if (qmlFunction.nameIndex != 0)
- name = stringPool->stringForIndex(qmlFunction.nameIndex);
else
- name = QStringLiteral("%qml-expression-entry");
+ name = qmlName(qmlFunction);
- QQmlJS::AST::SourceElements *body;
- if (function)
- body = function->body ? function->body->elements : nullptr;
- else {
+ QQmlJS::AST::StatementList *body;
+ if (function) {
+ body = function->body;
+ } else {
// Synthesize source elements.
QQmlJS::MemoryPool *pool = jsEngine->pool();
@@ -1854,13 +1868,12 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QQmlJS::AST::ExpressionNode *expr = node->expressionCast();
stmt = new (pool) QQmlJS::AST::ExpressionStatement(expr);
}
- QQmlJS::AST::SourceElement *element = new (pool) QQmlJS::AST::StatementSourceElement(stmt);
- body = new (pool) QQmlJS::AST::SourceElements(element);
+ body = new (pool) QQmlJS::AST::StatementList(stmt);
body = body->finish();
}
_disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups;
- int idx = defineFunction(name, node,
+ int idx = defineFunction(name, function ? function : qmlFunction.parentNode,
function ? function->formals : nullptr,
body);
runtimeFunctionIndices[i] = idx;
@@ -1869,7 +1882,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-int JSCodeGen::defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals, AST::SourceElements *body)
+int JSCodeGen::defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals, AST::StatementList *body)
{
int qmlContextTemp = -1;
int importedScriptsTemp = -1;
@@ -2190,7 +2203,7 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n
// Look for IDs first.
for (const IdMapping &mapping : qAsConst(_idObjects)) {
if (name == mapping.name) {
- if (_context->compilationMode == QV4::Compiler::QmlBinding)
+ if (_context->contextType == QV4::Compiler::ContextType::Binding)
_context->idObjectDependencies.insert(mapping.idIndex);
Instruction::LoadIdObject load;
@@ -2446,8 +2459,6 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
}
}
- QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
-
const quint32_le *functionIdx = serializedObject->functionOffsetTable();
for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
QmlIR::Function *f = pool->New<QmlIR::Function>();
@@ -2458,26 +2469,10 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
f->location = compiledFunction->location;
f->nameIndex = compiledFunction->nameIndex;
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- const quint32_le *formalNameIdx = compiledFunction->formalsTable();
- for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) {
- const QString formal = unit->stringAt(*formalNameIdx);
- QStringRef paramNameRef = jsParserEngine->newStringRef(formal);
-
- if (paramList)
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef);
- else
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef);
- }
-
- if (paramList)
- paramList = paramList->finish();
-
const QString name = unit->stringAt(compiledFunction->nameIndex);
- f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/nullptr);
f->formals.allocate(pool, int(compiledFunction->nFormals));
- formalNameIdx = compiledFunction->formalsTable();
+ const quint32_le *formalNameIdx = compiledFunction->formalsTable();
for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx)
f->formals[i] = *formalNameIdx;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 689b232b1c..f8d481e14f 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -57,7 +57,6 @@
#include <private/qqmljsmemorypool_p.h>
#include <private/qv4codegen_p.h>
#include <private/qv4compiler_p.h>
-#include <private/qqmljslexer_p.h>
#include <QTextStream>
#include <QCoreApplication>
@@ -325,7 +324,6 @@ struct Alias : public QV4::CompiledData::Alias
struct Function
{
- QQmlJS::AST::FunctionDeclaration *functionDeclaration;
QV4::CompiledData::Location location;
int nameIndex;
quint32 index; // index in parsedQML::functions
@@ -342,12 +340,9 @@ struct Function
struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
-
{}
- CompiledFunctionOrExpression(QQmlJS::AST::Node *n)
- : node(n)
- {}
+ QQmlJS::AST::Node *parentNode = nullptr; // FunctionDeclaration, Statement or Expression
QQmlJS::AST::Node *node = nullptr; // FunctionDeclaration, Statement or Expression
quint32 nameIndex = 0;
bool disableAcceleratedLookups = false;
@@ -400,8 +395,6 @@ public:
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
- QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
-
QString appendEnum(Enum *enumeration);
QString appendSignal(Signal *signal);
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
@@ -520,12 +513,12 @@ public:
QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
const QQmlJS::AST::SourceLocation &last) const;
- void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement);
+ void setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, 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);
+ void appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, 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);
+ 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);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
@@ -548,6 +541,8 @@ public:
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement);
+ QString sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
+
QList<QQmlJS::DiagnosticMessage> errors;
QSet<QString> illegalNames;
@@ -578,7 +573,7 @@ private:
#ifndef V4_BOOTSTRAP
struct Q_QML_EXPORT PropertyResolver
{
- PropertyResolver(const QQmlPropertyCache *cache)
+ PropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
: cache(cache)
{}
@@ -597,7 +592,7 @@ struct Q_QML_EXPORT PropertyResolver
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
- const QQmlPropertyCache *cache;
+ QQmlRefPointer<QQmlPropertyCache> cache;
};
#endif
@@ -623,7 +618,7 @@ struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
int defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
- AST::SourceElements *body) override;
+ AST::StatementList *body) override;
protected:
void beginFunctionBodyHook() override;
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index 8bbc8291b4..02517ea6bb 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -99,8 +99,8 @@ public:
protected:
QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlPropertyCache *propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
- QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache);
+ QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const;
+ QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
QString stringAt(int index) const { return objectContainer->stringAt(index); }
@@ -152,7 +152,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
if (error.isSet())
return error;
@@ -166,7 +166,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
}
}
- QQmlPropertyCache *baseTypeCache;
+ QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
{
QQmlCompileError error;
baseTypeCache = propertyCacheForObject(obj, context, &error);
@@ -209,7 +209,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
}
template <typename ObjectContainer>
-inline 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, QQmlCompileError *error) const
{
if (context.instantiatingProperty) {
return context.instantiatingPropertyCache(enginePrivate);
@@ -241,14 +241,12 @@ inline QQmlPropertyCache *QQmlPropertyCacheCreator<ObjectContainer>::propertyCac
QString propertyName = stringAt(context.instantiatingBinding->propertyNameIndex);
if (imports->resolveType(propertyName, &qmltype, nullptr, nullptr, nullptr)) {
if (qmltype.isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
auto compilationUnit = tdata->compilationUnit();
qmltype = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
-
- tdata->release();
}
}
}
@@ -264,7 +262,7 @@ inline QQmlPropertyCache *QQmlPropertyCacheCreator<ObjectContainer>::propertyCac
}
template <typename ObjectContainer>
-inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, QQmlPropertyCache *baseTypeCache)
+inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
{
QQmlRefPointer<QQmlPropertyCache> cache;
cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
@@ -314,7 +312,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
}
}
if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache).className();
+ newClassName = QQmlMetaObject(baseTypeCache.data()).className();
newClassName.append("_QML_");
newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
}
@@ -354,7 +352,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
// and throw an error if there is a signal/method defined as an override.
QSet<QString> seenSignals;
seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache;
+ QQmlPropertyCache *parentCache = cache.data();
while ((parentCache = parentCache->parent())) {
if (int pSigCount = parentCache->signalCount()) {
int pSigOffset = parentCache->signalOffset();
@@ -440,15 +438,13 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
if (qmltype.isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
auto compilationUnit = tdata->compilationUnit();
paramTypes[i + 1] = compilationUnit->metaTypeId;
-
- tdata->release();
} else {
paramTypes[i + 1] = qmltype.typeId();
}
@@ -523,7 +519,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
Q_ASSERT(qmltype.isValid());
if (qmltype.isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
@@ -534,8 +530,6 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
} else {
propertyType = compilationUnit->listMetaTypeId;
}
-
- tdata->release();
} else {
if (p->type == QV4::CompiledData::Property::Custom) {
propertyType = qmltype.typeId();
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index ffd3b5975a..8ebd2da1c9 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -45,8 +45,9 @@
QT_BEGIN_NAMESPACE
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
+ , compilationUnit(compilationUnit)
, imports(imports)
, qmlUnit(compilationUnit->data)
, resolvedTypes(compilationUnit->resolvedTypes)
@@ -629,7 +630,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex);
if (auto *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex)) {
- QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
+ QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
const QMetaObject *mo = cache->firstCppMetaObject();
QQmlType qmlType;
while (mo && !qmlType.isValid()) {
@@ -670,7 +671,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
} else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- return QQmlCompileError(binding->location, tr("Unexpected object assignment"));
+ return QQmlCompileError(binding->location, tr("Unexpected object assignment for property \"%1\"").arg(propertyName));
} else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else {
@@ -680,7 +681,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
// Using -1 for the minor version ensures that we get the raw metaObject.
QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
- // Will be true if the assgned type inherits propertyMetaObject
+ // Will be true if the assigned type inherits propertyMetaObject
bool isAssignable = false;
// Determine isAssignable value
if (propertyMetaObject) {
diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h
index e37b8141f4..a8f75a0a7e 100644
--- a/src/qml/compiler/qqmlpropertyvalidator_p.h
+++ b/src/qml/compiler/qqmlpropertyvalidator_p.h
@@ -58,7 +58,7 @@ class QQmlPropertyValidator
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit);
+ QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
QVector<QQmlCompileError> validate();
@@ -74,6 +74,7 @@ private:
QString stringAt(int index) const { return qmlUnit->stringAt(index); }
QQmlEnginePrivate *enginePrivate;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
const QQmlImports &imports;
const QV4::CompiledData::Unit *qmlUnit;
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes;
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index a896745b3f..76245ced1d 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -67,7 +67,7 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *type
{
}
-QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
{
// Build property caches and VME meta object data
@@ -147,7 +147,7 @@ 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, typeNameCache, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
+ document->program, typeNameCache.data(), &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
v4CodeGenerator.setUseFastLookups(false);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
@@ -165,7 +165,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
// The js unit owns the data and will free the qml unit.
document->javaScriptCompilationUnit->data = qmlUnit;
- QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = document->javaScriptCompilationUnit;
compilationUnit = document->javaScriptCompilationUnit;
compilationUnit->typeNameCache = typeNameCache;
compilationUnit->resolvedTypes = resolvedTypes;
@@ -339,14 +339,12 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (!type.isValid()) {
if (imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr)) {
if (type.isComposite()) {
- QQmlTypeData *tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
+ QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(type.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
auto compilationUnit = tdata->compilationUnit();
type = QQmlMetaType::qmlType(compilationUnit->metaTypeId);
-
- tdata->release();
}
}
}
@@ -466,10 +464,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
for (const QString &param : qAsConst(parameters)) {
QStringRef paramNameRef = compiler->newStringRef(param);
- if (paramList)
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef);
- else
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef);
+ QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
}
if (paramList)
@@ -490,11 +486,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
}
if (!functionDeclaration) {
QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::SourceElement *sourceElement = new (pool) QQmlJS::AST::StatementSourceElement(statement);
- QQmlJS::AST::SourceElements *elements = new (pool) QQmlJS::AST::SourceElements(sourceElement);
- elements = elements->finish();
-
- QQmlJS::AST::FunctionBody *body = new (pool) QQmlJS::AST::FunctionBody(elements);
+ QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
+ body = body->finish();
functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
functionDeclaration->lbraceToken = functionDeclaration->functionToken
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index b8eddcb9b2..537f87ab4c 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -92,7 +92,7 @@ public:
QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypes;
// ---
- QV4::CompiledData::CompilationUnit *compile();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile();
QList<QQmlError> compilationErrors() const { return errors; }
void recordError(QQmlError error);
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index 4d50654d27..1d1e98ea58 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -185,6 +185,25 @@ void BytecodeGenerator::finalize(Compiler::Context *context)
}
int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, int offsetOfOffset) {
+ if (lastInstrType == int(Instr::Type::StoreReg)) {
+ if (type == Instr::Type::LoadReg) {
+ if (i.LoadReg.reg == lastInstr.StoreReg.reg) {
+ // value is already in the accumulator
+ return -1;
+ }
+ }
+ if (type == Instr::Type::MoveReg) {
+ if (i.MoveReg.srcReg == lastInstr.StoreReg.reg) {
+ Instruction::StoreReg store;
+ store.reg = i.MoveReg.destReg;
+ addInstruction(store);
+ return -1;
+ }
+ }
+ }
+ lastInstrType = int(type);
+ lastInstr = i;
+
#if QT_CONFIG(qml_debug)
if (debugMode && type != Instr::Type::Debug) {
QT_WARNING_PUSH
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index e69f2cd310..78ce3624ea 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -77,22 +77,18 @@ public:
Label(BytecodeGenerator *generator, LinkMode mode = LinkNow)
: generator(generator),
index(generator->labels.size()) {
- generator->labels.append(mode == LinkNow ? generator->instructions.size() : -1);
- }
- static Label returnLabel() {
- Label l;
- l.index = INT_MAX;
- return l;
- }
- bool isReturn() const {
- return index == INT_MAX;
+ generator->labels.append(-1);
+ if (mode == LinkNow)
+ link();
}
void link() {
Q_ASSERT(index >= 0);
Q_ASSERT(generator->labels[index] == -1);
generator->labels[index] = generator->instructions.size();
+ generator->clearLastInstruction();
}
+ bool isValid() const { return generator != nullptr; }
BytecodeGenerator *generator = nullptr;
int index = -1;
@@ -133,14 +129,16 @@ public:
};
struct ExceptionHandler : public Label {
+ ExceptionHandler() = default;
ExceptionHandler(BytecodeGenerator *generator)
: Label(generator, LinkLater)
{
}
~ExceptionHandler()
{
- Q_ASSERT(generator->currentExceptionHandler != this);
+ Q_ASSERT(!generator || generator->currentExceptionHandler != this);
}
+ bool isValid() const { return generator != nullptr; }
};
Label label() {
@@ -181,6 +179,18 @@ public:
return addJumpInstruction(data);
}
+ Q_REQUIRED_RESULT Jump jumpNotUndefined()
+ {
+ Instruction::JumpNotUndefined data;
+ return addJumpInstruction(data);
+ }
+
+ Q_REQUIRED_RESULT Jump jumpNoException()
+ {
+ Instruction::JumpNoException data;
+ return addJumpInstruction(data);
+ }
+
void jumpStrictEqual(const StackSlot &lhs, const Label &target)
{
Instruction::CmpStrictEqual cmp;
@@ -197,26 +207,10 @@ public:
addJumpInstruction(Instruction::JumpTrue()).link(target);
}
- Q_REQUIRED_RESULT Jump jumpStrictEqualStackSlotInt(const StackSlot &lhs, int rhs)
- {
- Instruction::JumpStrictEqualStackSlotInt data;
- data.lhs = lhs;
- data.rhs = rhs;
- return addJumpInstruction(data);
- }
-
- Q_REQUIRED_RESULT Jump jumpStrictNotEqualStackSlotInt(const StackSlot &lhs, int rhs)
- {
- Instruction::JumpStrictNotEqualStackSlotInt data;
- data.lhs = lhs;
- data.rhs = rhs;
- return addJumpInstruction(data);
- }
-
- void setExceptionHandler(ExceptionHandler *handler)
+ void setUnwindHandler(ExceptionHandler *handler)
{
currentExceptionHandler = handler;
- Instruction::SetExceptionHandler data;
+ Instruction::SetUnwindHandler data;
data.offset = 0;
if (!handler)
addInstruction(data);
@@ -224,6 +218,19 @@ public:
addJumpInstruction(data).link(*handler);
}
+ void unwindToLabel(int level, const Label &target)
+ {
+ if (level) {
+ Instruction::UnwindToLabel unwind;
+ unwind.level = level;
+ addJumpInstruction(unwind).link(target);
+ } else {
+ jump().link(target);
+ }
+ }
+
+
+
void setLocation(const QQmlJS::AST::SourceLocation &loc);
ExceptionHandler *exceptionHandler() const {
@@ -233,6 +240,7 @@ public:
int newRegister();
int newRegisterArray(int n);
int registerCount() const { return regCount; }
+ int currentRegister() const { return currentReg; }
void finalize(Compiler::Context *context);
@@ -252,6 +260,11 @@ public:
addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
+ void clearLastInstruction()
+ {
+ lastInstrType = -1;
+ }
+
private:
friend struct Jump;
friend struct Label;
@@ -275,7 +288,7 @@ private:
QVector<I> instructions;
QVector<int> labels;
- ExceptionHandler *currentExceptionHandler;
+ ExceptionHandler *currentExceptionHandler = nullptr;
int regCount = 0;
public:
int currentReg = 0;
@@ -283,6 +296,9 @@ private:
int startLine = 0;
int currentLine = 0;
bool debugMode = false;
+
+ int lastInstrType = -1;
+ Moth::Instr lastInstr;
};
}
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
new file mode 100644
index 0000000000..8d1ac0bfd9
--- /dev/null
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** 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 <private/qv4bytecodehandler_p.h>
+
+QT_USE_NAMESPACE
+using namespace QV4;
+using namespace Moth;
+
+ByteCodeHandler::~ByteCodeHandler()
+{
+}
+
+#define DISPATCH_INSTRUCTION(name, nargs, ...) \
+ generate_##name( \
+ __VA_ARGS__ \
+ );
+
+#define DECODE_AND_DISPATCH(instr) \
+ { \
+ INSTR_##instr(MOTH_DECODE_WITH_BASE) \
+ Q_UNUSED(base_ptr); \
+ startInstruction(Instr::Type::instr); \
+ _offset = code - start; \
+ INSTR_##instr(DISPATCH) \
+ endInstruction(Instr::Type::instr); \
+ continue; \
+ }
+
+void ByteCodeHandler::decode(const char *code, uint len)
+{
+ MOTH_JUMP_TABLE;
+
+ const char *start = code;
+ const char *end = code + len;
+ while (code < end) {
+ MOTH_DISPATCH()
+
+ FOR_EACH_MOTH_INSTR(DECODE_AND_DISPATCH)
+ }
+}
+
+#undef DECODE_AND_DISPATCH
+#undef DISPATCH_INSTRUCTION
+
+#define MOTH_UNUSED_ARGS0()
+#define MOTH_UNUSED_ARGS1(arg) \
+ Q_UNUSED(arg);
+#define MOTH_UNUSED_ARGS2(arg1, arg2) \
+ Q_UNUSED(arg1); \
+ Q_UNUSED(arg2);
+#define MOTH_UNUSED_ARGS3(arg1, arg2, arg3) \
+ Q_UNUSED(arg1); \
+ Q_UNUSED(arg2); \
+ Q_UNUSED(arg3);
+#define MOTH_UNUSED_ARGS4(arg1, arg2, arg3, arg4) \
+ Q_UNUSED(arg1); \
+ Q_UNUSED(arg2); \
+ Q_UNUSED(arg3); \
+ Q_UNUSED(arg4);
+
+#define MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, ...) \
+ MOTH_EXPAND_FOR_MSVC(MOTH_UNUSED_ARGS##nargs(__VA_ARGS__))
+
+#define MOTH_MARK_ARGS_UNUSED_INSTRUCTION(name, nargs, ...) \
+ MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, __VA_ARGS__)
+
+#define COLLECTOR_BEGIN_INSTR(instr) \
+ { \
+ INSTR_##instr(MOTH_DECODE_WITH_BASE) \
+ INSTR_##instr(MOTH_MARK_ARGS_UNUSED) \
+ Q_UNUSED(base_ptr);
+
+#define COLLECTOR_END_INSTR(instr) \
+ continue; \
+ }
+
+std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint len)
+{
+ MOTH_JUMP_TABLE;
+
+ std::vector<int> labels;
+
+ const auto addLabel = [&labels,len](int offset) {
+ Q_ASSERT(offset >= 0 && offset < static_cast<int>(len));
+ labels.push_back(offset);
+ };
+
+ const char *start = code;
+ const char *end = code + len;
+ while (code < end) {
+ MOTH_DISPATCH()
+ Q_UNREACHABLE();
+
+ COLLECTOR_BEGIN_INSTR(LoadReg)
+ COLLECTOR_END_INSTR(LoadReg)
+
+ COLLECTOR_BEGIN_INSTR(StoreReg)
+ COLLECTOR_END_INSTR(StoreReg)
+
+ COLLECTOR_BEGIN_INSTR(MoveReg)
+ COLLECTOR_END_INSTR(MoveReg)
+
+ COLLECTOR_BEGIN_INSTR(LoadConst)
+ COLLECTOR_END_INSTR(LoadConst)
+
+ COLLECTOR_BEGIN_INSTR(LoadNull)
+ COLLECTOR_END_INSTR(LoadNull)
+
+ COLLECTOR_BEGIN_INSTR(LoadZero)
+ COLLECTOR_END_INSTR(LoadZero)
+
+ COLLECTOR_BEGIN_INSTR(LoadTrue)
+ COLLECTOR_END_INSTR(LoadTrue)
+
+ COLLECTOR_BEGIN_INSTR(LoadFalse)
+ COLLECTOR_END_INSTR(LoadFalse)
+
+ COLLECTOR_BEGIN_INSTR(LoadUndefined)
+ COLLECTOR_END_INSTR(LoadUndefined)
+
+ COLLECTOR_BEGIN_INSTR(LoadInt)
+ COLLECTOR_END_INSTR(LoadInt)
+
+ COLLECTOR_BEGIN_INSTR(MoveConst)
+ COLLECTOR_END_INSTR(MoveConst)
+
+ COLLECTOR_BEGIN_INSTR(LoadLocal)
+ COLLECTOR_END_INSTR(LoadLocal)
+
+ COLLECTOR_BEGIN_INSTR(StoreLocal)
+ COLLECTOR_END_INSTR(StoreLocal)
+
+ COLLECTOR_BEGIN_INSTR(LoadScopedLocal)
+ COLLECTOR_END_INSTR(LoadScopedLocal)
+
+ COLLECTOR_BEGIN_INSTR(StoreScopedLocal)
+ COLLECTOR_END_INSTR(StoreScopedLocal)
+
+ COLLECTOR_BEGIN_INSTR(LoadRuntimeString)
+ COLLECTOR_END_INSTR(LoadRuntimeString)
+
+ COLLECTOR_BEGIN_INSTR(MoveRegExp)
+ COLLECTOR_END_INSTR(MoveRegExp)
+
+ COLLECTOR_BEGIN_INSTR(LoadClosure)
+ COLLECTOR_END_INSTR(LoadClosure)
+
+ COLLECTOR_BEGIN_INSTR(LoadName)
+ COLLECTOR_END_INSTR(LoadName)
+
+ COLLECTOR_BEGIN_INSTR(LoadGlobalLookup)
+ COLLECTOR_END_INSTR(LoadGlobalLookup)
+
+ COLLECTOR_BEGIN_INSTR(StoreNameSloppy)
+ COLLECTOR_END_INSTR(StoreNameSloppy)
+
+ COLLECTOR_BEGIN_INSTR(StoreNameStrict)
+ COLLECTOR_END_INSTR(StoreNameStrict)
+
+ COLLECTOR_BEGIN_INSTR(LoadElement)
+ COLLECTOR_END_INSTR(LoadElement)
+
+ COLLECTOR_BEGIN_INSTR(StoreElement)
+ COLLECTOR_END_INSTR(StoreElement)
+
+ COLLECTOR_BEGIN_INSTR(LoadProperty)
+ COLLECTOR_END_INSTR(LoadProperty)
+
+ COLLECTOR_BEGIN_INSTR(GetLookup)
+ COLLECTOR_END_INSTR(GetLookup)
+
+ COLLECTOR_BEGIN_INSTR(GetLookupA)
+ COLLECTOR_END_INSTR(GetLookupA)
+
+ COLLECTOR_BEGIN_INSTR(StoreProperty)
+ COLLECTOR_END_INSTR(StoreProperty)
+
+ COLLECTOR_BEGIN_INSTR(SetLookup)
+ COLLECTOR_END_INSTR(SetLookup)
+
+ COLLECTOR_BEGIN_INSTR(StoreScopeObjectProperty)
+ COLLECTOR_END_INSTR(StoreScopeObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(LoadScopeObjectProperty)
+ COLLECTOR_END_INSTR(LoadScopeObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(StoreContextObjectProperty)
+ COLLECTOR_END_INSTR(StoreContextObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(LoadContextObjectProperty)
+ COLLECTOR_END_INSTR(LoadContextObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(LoadIdObject)
+ COLLECTOR_END_INSTR(LoadIdObject)
+
+ COLLECTOR_BEGIN_INSTR(Yield)
+ COLLECTOR_END_INSTR(Yield)
+
+ COLLECTOR_BEGIN_INSTR(Resume)
+ COLLECTOR_END_INSTR(Resume)
+
+ COLLECTOR_BEGIN_INSTR(CallValue)
+ COLLECTOR_END_INSTR(CallValue)
+
+ COLLECTOR_BEGIN_INSTR(CallProperty)
+ COLLECTOR_END_INSTR(CallProperty)
+
+ COLLECTOR_BEGIN_INSTR(CallPropertyLookup)
+ COLLECTOR_END_INSTR(CallPropertyLookup)
+
+ COLLECTOR_BEGIN_INSTR(CallElement)
+ COLLECTOR_END_INSTR(CallElement)
+
+ COLLECTOR_BEGIN_INSTR(CallName)
+ COLLECTOR_END_INSTR(CallName)
+
+ COLLECTOR_BEGIN_INSTR(CallPossiblyDirectEval)
+ COLLECTOR_END_INSTR(CallPossiblyDirectEval)
+
+ COLLECTOR_BEGIN_INSTR(CallGlobalLookup)
+ COLLECTOR_END_INSTR(CallGlobalLookup)
+
+ COLLECTOR_BEGIN_INSTR(CallScopeObjectProperty)
+ COLLECTOR_END_INSTR(CallScopeObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(CallContextObjectProperty)
+ COLLECTOR_END_INSTR(CallContextObjectProperty)
+
+ COLLECTOR_BEGIN_INSTR(CallWithSpread)
+ COLLECTOR_END_INSTR(CallWithSpread)
+
+ COLLECTOR_BEGIN_INSTR(Construct)
+ COLLECTOR_END_INSTR(Construct)
+
+ COLLECTOR_BEGIN_INSTR(ConstructWithSpread)
+ COLLECTOR_END_INSTR(ConstructWithSpread)
+
+ COLLECTOR_BEGIN_INSTR(SetUnwindHandler)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(SetUnwindHandler)
+
+ COLLECTOR_BEGIN_INSTR(UnwindDispatch)
+ COLLECTOR_END_INSTR(UnwindDispatch)
+
+ COLLECTOR_BEGIN_INSTR(UnwindToLabel)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(UnwindToLabel)
+
+ COLLECTOR_BEGIN_INSTR(ThrowException)
+ COLLECTOR_END_INSTR(ThrowException)
+
+ COLLECTOR_BEGIN_INSTR(GetException)
+ COLLECTOR_END_INSTR(HasException)
+
+ COLLECTOR_BEGIN_INSTR(SetException)
+ COLLECTOR_END_INSTR(SetExceptionFlag)
+
+ COLLECTOR_BEGIN_INSTR(CreateCallContext)
+ COLLECTOR_END_INSTR(CreateCallContext)
+
+ COLLECTOR_BEGIN_INSTR(PushCatchContext)
+ COLLECTOR_END_INSTR(PushCatchContext)
+
+ COLLECTOR_BEGIN_INSTR(PushWithContext)
+ COLLECTOR_END_INSTR(PushWithContext)
+
+ COLLECTOR_BEGIN_INSTR(PushBlockContext)
+ COLLECTOR_END_INSTR(PushBlockContext)
+
+ COLLECTOR_BEGIN_INSTR(CloneBlockContext)
+ COLLECTOR_END_INSTR(CloneBlockContext)
+
+ COLLECTOR_BEGIN_INSTR(PushScriptContext)
+ COLLECTOR_END_INSTR(PushScriptContext)
+
+ COLLECTOR_BEGIN_INSTR(PopScriptContext)
+ COLLECTOR_END_INSTR(PopScriptContext)
+
+ COLLECTOR_BEGIN_INSTR(PopContext)
+ COLLECTOR_END_INSTR(PopContext)
+
+ COLLECTOR_BEGIN_INSTR(GetIterator)
+ COLLECTOR_END_INSTR(GetIterator)
+
+ COLLECTOR_BEGIN_INSTR(IteratorNext)
+ COLLECTOR_END_INSTR(IteratorNext)
+
+ COLLECTOR_BEGIN_INSTR(IteratorClose)
+ COLLECTOR_END_INSTR(IteratorClose)
+
+ COLLECTOR_BEGIN_INSTR(DestructureRestElement)
+ COLLECTOR_END_INSTR(DestructureRestElement)
+
+ COLLECTOR_BEGIN_INSTR(DeleteProperty)
+ COLLECTOR_END_INSTR(DeleteProperty)
+
+ COLLECTOR_BEGIN_INSTR(DeleteName)
+ COLLECTOR_END_INSTR(DeleteName)
+
+ COLLECTOR_BEGIN_INSTR(TypeofName)
+ COLLECTOR_END_INSTR(TypeofName)
+
+ COLLECTOR_BEGIN_INSTR(TypeofValue)
+ COLLECTOR_END_INSTR(TypeofValue)
+
+ COLLECTOR_BEGIN_INSTR(DeclareVar)
+ COLLECTOR_END_INSTR(DeclareVar)
+
+ COLLECTOR_BEGIN_INSTR(DefineArray)
+ COLLECTOR_END_INSTR(DefineArray)
+
+ COLLECTOR_BEGIN_INSTR(DefineObjectLiteral)
+ COLLECTOR_END_INSTR(DefineObjectLiteral)
+
+ COLLECTOR_BEGIN_INSTR(CreateMappedArgumentsObject)
+ COLLECTOR_END_INSTR(CreateMappedArgumentsObject)
+
+ COLLECTOR_BEGIN_INSTR(CreateUnmappedArgumentsObject)
+ COLLECTOR_END_INSTR(CreateUnmappedArgumentsObject)
+
+ COLLECTOR_BEGIN_INSTR(CreateRestParameter)
+ COLLECTOR_END_INSTR(CreateRestParameter)
+
+ COLLECTOR_BEGIN_INSTR(ConvertThisToObject)
+ COLLECTOR_END_INSTR(ConvertThisToObject)
+
+ COLLECTOR_BEGIN_INSTR(ToObject)
+ COLLECTOR_END_INSTR(ToObject)
+
+ COLLECTOR_BEGIN_INSTR(Jump)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(Jump)
+
+ COLLECTOR_BEGIN_INSTR(JumpTrue)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(JumpTrue)
+
+ COLLECTOR_BEGIN_INSTR(JumpFalse)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(JumpFalse)
+
+ COLLECTOR_BEGIN_INSTR(JumpNoException)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(JumpNoException)
+
+ COLLECTOR_BEGIN_INSTR(JumpNotUndefined)
+ addLabel(code - start + offset);
+ COLLECTOR_END_INSTR(JumpNotUndefined)
+
+ COLLECTOR_BEGIN_INSTR(CmpEqNull)
+ COLLECTOR_END_INSTR(CmpEqNull)
+
+ COLLECTOR_BEGIN_INSTR(CmpNeNull)
+ COLLECTOR_END_INSTR(CmpNeNull)
+
+ COLLECTOR_BEGIN_INSTR(CmpEqInt)
+ COLLECTOR_END_INSTR(CmpEq)
+
+ COLLECTOR_BEGIN_INSTR(CmpNeInt)
+ COLLECTOR_END_INSTR(CmpNeInt)
+
+ COLLECTOR_BEGIN_INSTR(CmpEq)
+ COLLECTOR_END_INSTR(CmpEq)
+
+ COLLECTOR_BEGIN_INSTR(CmpNe)
+ COLLECTOR_END_INSTR(CmpNe)
+
+ COLLECTOR_BEGIN_INSTR(CmpGt)
+ COLLECTOR_END_INSTR(CmpGt)
+
+ COLLECTOR_BEGIN_INSTR(CmpGe)
+ COLLECTOR_END_INSTR(CmpGe)
+
+ COLLECTOR_BEGIN_INSTR(CmpLt)
+ COLLECTOR_END_INSTR(CmpLt)
+
+ COLLECTOR_BEGIN_INSTR(CmpLe)
+ COLLECTOR_END_INSTR(CmpLe)
+
+ COLLECTOR_BEGIN_INSTR(CmpStrictEqual)
+ COLLECTOR_END_INSTR(CmpStrictEqual)
+
+ COLLECTOR_BEGIN_INSTR(CmpStrictNotEqual)
+ COLLECTOR_END_INSTR(CmpStrictNotEqual)
+
+ COLLECTOR_BEGIN_INSTR(CmpIn)
+ COLLECTOR_END_INSTR(CmpIn)
+
+ COLLECTOR_BEGIN_INSTR(CmpInstanceOf)
+ COLLECTOR_END_INSTR(CmpInstanceOf)
+
+ COLLECTOR_BEGIN_INSTR(UNot)
+ COLLECTOR_END_INSTR(UNot)
+
+ COLLECTOR_BEGIN_INSTR(UPlus)
+ COLLECTOR_END_INSTR(UPlus)
+
+ COLLECTOR_BEGIN_INSTR(UMinus)
+ COLLECTOR_END_INSTR(UMinus)
+
+ COLLECTOR_BEGIN_INSTR(UCompl)
+ COLLECTOR_END_INSTR(UCompl)
+
+ COLLECTOR_BEGIN_INSTR(Increment)
+ COLLECTOR_END_INSTR(PreIncrement)
+
+ COLLECTOR_BEGIN_INSTR(Decrement)
+ COLLECTOR_END_INSTR(PreDecrement)
+
+ COLLECTOR_BEGIN_INSTR(Add)
+ COLLECTOR_END_INSTR(Add)
+
+ COLLECTOR_BEGIN_INSTR(BitAnd)
+ COLLECTOR_END_INSTR(BitAnd)
+
+ COLLECTOR_BEGIN_INSTR(BitOr)
+ COLLECTOR_END_INSTR(BitOr)
+
+ COLLECTOR_BEGIN_INSTR(BitXor)
+ COLLECTOR_END_INSTR(BitXor)
+
+ COLLECTOR_BEGIN_INSTR(UShr)
+ COLLECTOR_END_INSTR(UShr)
+
+ COLLECTOR_BEGIN_INSTR(Shr)
+ COLLECTOR_END_INSTR(Shr)
+
+ COLLECTOR_BEGIN_INSTR(Shl)
+ COLLECTOR_END_INSTR(Shl)
+
+ COLLECTOR_BEGIN_INSTR(BitAndConst)
+ COLLECTOR_END_INSTR(BitAndConst)
+
+ COLLECTOR_BEGIN_INSTR(BitOrConst)
+ COLLECTOR_END_INSTR(BitOr)
+
+ COLLECTOR_BEGIN_INSTR(BitXorConst)
+ COLLECTOR_END_INSTR(BitXor)
+
+ COLLECTOR_BEGIN_INSTR(UShrConst)
+ COLLECTOR_END_INSTR(UShrConst)
+
+ COLLECTOR_BEGIN_INSTR(ShrConst)
+ COLLECTOR_END_INSTR(ShrConst)
+
+ COLLECTOR_BEGIN_INSTR(ShlConst)
+ COLLECTOR_END_INSTR(ShlConst)
+
+ COLLECTOR_BEGIN_INSTR(Exp)
+ COLLECTOR_END_INSTR(Exp)
+
+ COLLECTOR_BEGIN_INSTR(Mul)
+ COLLECTOR_END_INSTR(Mul)
+
+ COLLECTOR_BEGIN_INSTR(Div)
+ COLLECTOR_END_INSTR(Div)
+
+ COLLECTOR_BEGIN_INSTR(Mod)
+ COLLECTOR_END_INSTR(Mod)
+
+ COLLECTOR_BEGIN_INSTR(Sub)
+ COLLECTOR_END_INSTR(Sub)
+
+ COLLECTOR_BEGIN_INSTR(Ret)
+ COLLECTOR_END_INSTR(Ret)
+
+#ifndef QT_NO_QML_DEBUGGER
+ COLLECTOR_BEGIN_INSTR(Debug)
+ COLLECTOR_END_INSTR(Debug)
+#endif // QT_NO_QML_DEBUGGER
+
+ COLLECTOR_BEGIN_INSTR(LoadQmlContext)
+ COLLECTOR_END_INSTR(LoadQmlContext)
+
+ COLLECTOR_BEGIN_INSTR(LoadQmlImportedScripts)
+ COLLECTOR_END_INSTR(LoadQmlImportedScripts)
+ }
+
+ return labels;
+}
+
+#undef COLLECTOR_BEGIN_INSTR
+#undef COLLECTOR_END_INSTR
diff --git a/src/qml/compiler/qv4bytecodehandler_p.h b/src/qml/compiler/qv4bytecodehandler_p.h
new file mode 100644
index 0000000000..5f1121306f
--- /dev/null
+++ b/src/qml/compiler/qv4bytecodehandler_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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 QV4BYTECODEHANDLER_P_H
+#define QV4BYTECODEHANDLER_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/qv4instr_moth_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace Moth {
+
+#define BYTECODE_HANDLER_DEFINE_ARGS(nargs, ...) \
+ MOTH_EXPAND_FOR_MSVC(BYTECODE_HANDLER_DEFINE_ARGS##nargs(__VA_ARGS__))
+
+#define BYTECODE_HANDLER_DEFINE_ARGS0()
+#define BYTECODE_HANDLER_DEFINE_ARGS1(arg) \
+ int arg
+#define BYTECODE_HANDLER_DEFINE_ARGS2(arg1, arg2) \
+ int arg1, \
+ int arg2
+#define BYTECODE_HANDLER_DEFINE_ARGS3(arg1, arg2, arg3) \
+ int arg1, \
+ int arg2, \
+ int arg3
+#define BYTECODE_HANDLER_DEFINE_ARGS4(arg1, arg2, arg3, arg4) \
+ int arg1, \
+ int arg2, \
+ int arg3, \
+ int arg4
+
+#define BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER_INSTRUCTION(name, nargs, ...) \
+ virtual void generate_##name( \
+ BYTECODE_HANDLER_DEFINE_ARGS(nargs, __VA_ARGS__) \
+ ) = 0;
+
+#define BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER(instr) \
+ INSTR_##instr(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
+
+class ByteCodeHandler
+{
+public:
+ virtual ~ByteCodeHandler();
+
+ void decode(const char *code, uint len);
+
+ int instructionOffset() const { return _offset; }
+
+ static std::vector<int> collectLabelsInBytecode(const char *code, uint len);
+
+protected:
+ FOR_EACH_MOTH_INSTR(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
+
+ virtual void startInstruction(Moth::Instr::Type instr) = 0;
+ virtual void endInstruction(Moth::Instr::Type instr) = 0;
+
+private:
+ int _offset = 0;
+};
+
+} // Moth namespace
+} // QV4 namespace
+
+QT_END_NAMESPACE
+
+#endif // QV4BYTECODEHANDLER_P_H
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index e831fd48f5..fc2fb86666 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -58,6 +58,8 @@
#include <cmath>
#include <iostream>
+static const bool disable_lookups = false;
+
#ifdef CONST
#undef CONST
#endif
@@ -77,8 +79,6 @@ static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGene
case Statement::Kind_ForEachStatement:
case Statement::Kind_ForStatement:
case Statement::Kind_IfStatement:
- case Statement::Kind_LocalForEachStatement:
- case Statement::Kind_LocalForStatement:
case Statement::Kind_WhileStatement:
bytecodeGenerator->setLocation(fallback);
break;
@@ -90,7 +90,7 @@ static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGene
Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
: _module(nullptr)
- , _returnAddress(0)
+ , _returnAddress(-1)
, _context(nullptr)
, _labelledStatement(nullptr)
, jsUnitGenerator(jsUnitGenerator)
@@ -106,7 +106,7 @@ void Codegen::generateFromProgram(const QString &fileName,
const QString &sourceCode,
Program *node,
Module *module,
- CompilationMode mode)
+ ContextType contextType)
{
Q_ASSERT(node);
@@ -117,10 +117,13 @@ void Codegen::generateFromProgram(const QString &fileName,
_module->fileName = fileName;
_module->finalUrl = finalUrl;
- ScanFunctions scan(this, sourceCode, mode);
+ ScanFunctions scan(this, sourceCode, contextType);
scan(node);
- defineFunction(QStringLiteral("%entry"), node, nullptr, node->elements);
+ if (hasError)
+ return;
+
+ defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements);
}
void Codegen::enterContext(Node *node)
@@ -132,12 +135,17 @@ void Codegen::enterContext(Node *node)
int Codegen::leaveContext()
{
Q_ASSERT(_context);
- Q_ASSERT(!_context->controlFlow);
int functionIndex = _context->functionIndex;
_context = _context->parent;
return functionIndex;
}
+Context *Codegen::enterBlock(Node *node)
+{
+ enterContext(node);
+ return _context;
+}
+
Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
{
if (hasError)
@@ -267,9 +275,9 @@ void Codegen::statement(Statement *ast)
bytecodeGenerator->setLocation(ast->firstSourceLocation());
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
- qSwap(_volataleMemoryLocations, vLocs);
+ qSwap(_volatileMemoryLocations, vLocs);
accept(ast);
- qSwap(_volataleMemoryLocations, vLocs);
+ qSwap(_volatileMemoryLocations, vLocs);
}
void Codegen::statement(ExpressionNode *ast)
@@ -282,11 +290,11 @@ void Codegen::statement(ExpressionNode *ast)
Result r(nx);
qSwap(_expr, r);
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
- qSwap(_volataleMemoryLocations, vLocs);
+ qSwap(_volatileMemoryLocations, vLocs);
accept(ast);
- qSwap(_volataleMemoryLocations, vLocs);
+ qSwap(_volatileMemoryLocations, vLocs);
qSwap(_expr, r);
if (hasError)
@@ -337,60 +345,103 @@ Codegen::Reference Codegen::expression(ExpressionNode *ast)
return r.result();
}
-Codegen::Result Codegen::sourceElement(SourceElement *ast)
+void Codegen::program(Program *ast)
{
- Result r(nx);
if (ast) {
- qSwap(_expr, r);
- accept(ast);
- qSwap(_expr, r);
+ statementList(ast->statements);
}
- return r;
}
-void Codegen::functionBody(FunctionBody *ast)
-{
- if (ast)
- sourceElements(ast->elements);
-}
+enum class CompletionState {
+ Empty,
+ EmptyAbrupt,
+ NonEmpty
+};
-void Codegen::program(Program *ast)
-{
- if (ast) {
- sourceElements(ast->elements);
+static CompletionState completionState(StatementList *list)
+{
+ for (StatementList *it = list; it; it = it->next) {
+ if (it->statement->kind == Statement::Kind_BreakStatement ||
+ it->statement->kind == Statement::Kind_ContinueStatement)
+ return CompletionState::EmptyAbrupt;
+ if (it->statement->kind == Statement::Kind_EmptyStatement ||
+ it->statement->kind == Statement::Kind_VariableDeclaration ||
+ it->statement->kind == Statement::Kind_FunctionDeclaration)
+ continue;
+ if (it->statement->kind == Statement::Kind_Block) {
+ CompletionState subState = completionState(static_cast<Block *>(it->statement)->statements);
+ if (subState != CompletionState::Empty)
+ return subState;
+ continue;
+ }
+ return CompletionState::NonEmpty;
}
+ return CompletionState::Empty;
}
-void Codegen::sourceElements(SourceElements *ast)
+static Node *completionStatement(StatementList *list)
{
- bool _requiresReturnValue = false;
- qSwap(_requiresReturnValue, requiresReturnValue);
- for (SourceElements *it = ast; it; it = it->next) {
- if (!it->next)
- qSwap(_requiresReturnValue, requiresReturnValue);
- sourceElement(it->element);
- if (hasError)
- return;
- if (StatementSourceElement *sse = AST::cast<StatementSourceElement *>(it->element)) {
- if (AST::cast<ThrowStatement *>(sse->statement) ||
- AST::cast<ReturnStatement *>(sse->statement))
- return;
+ Node *completionStatement = nullptr;
+ for (StatementList *it = list; it; it = it->next) {
+ if (it->statement->kind == Statement::Kind_BreakStatement ||
+ it->statement->kind == Statement::Kind_ContinueStatement)
+ return completionStatement;
+ if (it->statement->kind == Statement::Kind_ThrowStatement ||
+ it->statement->kind == Statement::Kind_ReturnStatement)
+ return it->statement;
+ if (it->statement->kind == Statement::Kind_EmptyStatement ||
+ it->statement->kind == Statement::Kind_VariableStatement ||
+ it->statement->kind == Statement::Kind_FunctionDeclaration)
+ continue;
+ if (it->statement->kind == Statement::Kind_Block) {
+ CompletionState state = completionState(static_cast<Block *>(it->statement)->statements);
+ switch (state) {
+ case CompletionState::Empty:
+ continue;
+ case CompletionState::EmptyAbrupt:
+ return it->statement;
+ case CompletionState::NonEmpty:
+ break;
+ }
}
+ completionStatement = it->statement;
}
+ return completionStatement;
}
void Codegen::statementList(StatementList *ast)
{
+ if (!ast)
+ return;
+
bool _requiresReturnValue = requiresReturnValue;
- requiresReturnValue = false;
- for (StatementList *it = ast; it; it = it->next) {
- if (!it->next ||
- it->next->statement->kind == Statement::Kind_BreakStatement ||
- it->next->statement->kind == Statement::Kind_ContinueStatement ||
- it->next->statement->kind == Statement::Kind_ReturnStatement)
- requiresReturnValue = _requiresReturnValue;
- statement(it->statement);
+ // ### the next line is pessimizing a bit too much, as there are many cases, where the complietion from the break
+ // statement will not be used, but it's at least spec compliant
+ if (!controlFlow || !controlFlow->hasLoop())
requiresReturnValue = false;
+
+ Node *needsCompletion = nullptr;
+
+ if (_requiresReturnValue && !requiresReturnValue)
+ needsCompletion = completionStatement(ast);
+
+ if (requiresReturnValue && !needsCompletion && !insideSwitch) {
+ // break or continue is the first real statement, set the return value to undefined
+ Reference::fromConst(this, Encode::undefined()).storeOnStack(_returnAddress);
+ }
+
+ bool _insideSwitch = insideSwitch;
+ insideSwitch = false;
+
+ for (StatementList *it = ast; it; it = it->next) {
+ if (it->statement == needsCompletion)
+ requiresReturnValue = true;
+ if (Statement *s = it->statement->statementCast())
+ statement(s);
+ else
+ statement(static_cast<ExpressionNode *>(it->statement));
+ if (it->statement == needsCompletion)
+ requiresReturnValue = false;
if (it->statement->kind == Statement::Kind_ThrowStatement ||
it->statement->kind == Statement::Kind_BreakStatement ||
it->statement->kind == Statement::Kind_ContinueStatement ||
@@ -399,22 +450,16 @@ void Codegen::statementList(StatementList *ast)
break;
}
requiresReturnValue = _requiresReturnValue;
+ insideSwitch = _insideSwitch;
}
-void Codegen::variableDeclaration(VariableDeclaration *ast)
+void Codegen::variableDeclaration(PatternElement *ast)
{
RegisterScope scope(this);
- if (!ast->expression)
+ if (!ast->initializer)
return;
- Reference rhs = expression(ast->expression);
- if (hasError)
- return;
-
- Reference lhs = referenceForName(ast->name.toString(), true);
- //### if lhs is a temp, this won't generate a temp-to-temp move. Same for when rhs is a const
- rhs.loadInAccumulator();
- lhs.storeConsumeAccumulator();
+ initializeAndDestructureBindingElement(ast, Reference());
}
void Codegen::variableDeclarationList(VariableDeclarationList *ast)
@@ -424,6 +469,190 @@ void Codegen::variableDeclarationList(VariableDeclarationList *ast)
}
}
+Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p)
+{
+ if (!p->bindingIdentifier.isNull())
+ return referenceForName(p->bindingIdentifier, true);
+ if (!p->bindingTarget || p->destructuringPattern())
+ return Codegen::Reference::fromStackSlot(this);
+ Reference lhs = expression(p->bindingTarget);
+ if (hasError)
+ return lhs;
+ lhs = lhs.asLValue();
+ return lhs;
+}
+
+void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, const Reference &base)
+{
+ Q_ASSERT(e->type == AST::PatternElement::Binding || e->type == AST::PatternElement::RestElement);
+ RegisterScope scope(this);
+ Reference baseRef = (base.isAccumulator()) ? base.storeOnStack() : base;
+ Reference varToStore = targetForPatternElement(e);
+ if (hasError)
+ return;
+
+ if (e->initializer) {
+ if (!baseRef.isValid()) {
+ // assignment
+ Reference expr = expression(e->initializer);
+ if (hasError)
+ return;
+ expr.loadInAccumulator();
+ varToStore.storeConsumeAccumulator();
+ } else if (baseRef == varToStore) {
+ baseRef.loadInAccumulator();
+ BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
+ Reference expr = expression(e->initializer);
+ if (hasError) {
+ jump.link();
+ return;
+ }
+ expr.loadInAccumulator();
+ varToStore.storeConsumeAccumulator();
+ jump.link();
+ } else {
+ baseRef.loadInAccumulator();
+ BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined();
+ Reference expr = expression(e->initializer);
+ if (hasError) {
+ jump.link();
+ return;
+ }
+ expr.loadInAccumulator();
+ jump.link();
+ varToStore.storeConsumeAccumulator();
+ }
+ } else if (baseRef != varToStore && baseRef.isValid()) {
+ baseRef.loadInAccumulator();
+ varToStore.storeConsumeAccumulator();
+ }
+ Pattern *p = e->destructuringPattern();
+ if (!p)
+ return;
+
+ if (!varToStore.isStackSlot())
+ varToStore = varToStore.storeOnStack();
+ if (PatternElementList *l = e->elementList()) {
+ destructureElementList(varToStore, l);
+ } else if (PatternPropertyList *p = e->propertyList()) {
+ destructurePropertyList(varToStore, p);
+ } else if (e->bindingTarget) {
+ // empty binding pattern. For spec compatibility, try to coerce the argument to an object
+ varToStore.loadInAccumulator();
+ Instruction::ToObject toObject;
+ bytecodeGenerator->addInstruction(toObject);
+ return;
+ }
+}
+
+void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternPropertyList *bindingList)
+{
+ RegisterScope scope(this);
+
+ for (PatternPropertyList *it = bindingList; it; it = it->next) {
+ PatternProperty *p = it->property;
+ RegisterScope scope(this);
+ AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
+ Reference property;
+ if (cname) {
+ Reference computedName = expression(cname->expression);
+ if (hasError)
+ return;
+ computedName = computedName.storeOnStack();
+ property = Reference::fromSubscript(object, computedName).asLValue();
+ } else {
+ QString propertyName = p->name->asString();
+ property = Reference::fromMember(object, propertyName);
+ }
+ initializeAndDestructureBindingElement(p, property);
+ if (hasError)
+ return;
+ }
+}
+
+void Codegen::destructureElementList(const Codegen::Reference &array, PatternElementList *bindingList)
+{
+ RegisterScope scope(this);
+
+ Reference iterator = Reference::fromStackSlot(this);
+ Reference iteratorValue = Reference::fromStackSlot(this);
+ Reference iteratorDone = Reference::fromStackSlot(this);
+
+ array.loadInAccumulator();
+ Instruction::GetIterator iteratorObjInstr;
+ iteratorObjInstr.iterator = 1; // ForEachType::Of
+ bytecodeGenerator->addInstruction(iteratorObjInstr);
+ iterator.storeConsumeAccumulator();
+
+ bool hadNext = false;
+ bool hasRest = false;
+
+ BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+
+ for (PatternElementList *p = bindingList; p; p = p->next) {
+ PatternElement *e = p->element;
+ for (Elision *elision = p->elision; elision; elision = elision->next) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ next.value = iteratorValue.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ hadNext = true;
+ bool last = !elision->next && !e && !p->next;
+ if (last)
+ iteratorDone.storeConsumeAccumulator();
+ }
+
+ if (!e)
+ continue;
+
+ hadNext = true;
+ RegisterScope scope(this);
+ iterator.loadInAccumulator();
+
+ if (e->type == PatternElement::RestElement) {
+ bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
+ initializeAndDestructureBindingElement(e, Reference::fromAccumulator(this));
+ hasRest = true;
+ } else {
+ Instruction::IteratorNext next;
+ next.value = iteratorValue.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ bool last = !p->next || (!p->next->elision && !p->next->element);
+ if (last)
+ iteratorDone.storeConsumeAccumulator();
+ initializeAndDestructureBindingElement(e, iteratorValue);
+ if (hasError) {
+ end.link();
+ return;
+ }
+ }
+ }
+
+ if (!hadNext) {
+ Reference::storeConstOnStack(this, Encode(false), iteratorDone.stackSlot());
+ }
+
+ if (!hasRest) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorClose close;
+ close.done = iteratorDone.stackSlot();
+ bytecodeGenerator->addInstruction(close);
+ }
+
+ end.link();
+}
+
+void Codegen::destructurePattern(Pattern *p, const Reference &rhs)
+{
+ RegisterScope scope(this);
+ if (auto *o = AST::cast<ObjectPattern *>(p))
+ destructurePropertyList(rhs, o->properties);
+ else if (auto *a = AST::cast<ArrayPattern *>(p))
+ destructureElementList(rhs, a->elements);
+ else
+ Q_UNREACHABLE();
+}
+
bool Codegen::visit(ArgumentList *)
{
@@ -461,12 +690,6 @@ bool Codegen::visit(DefaultClause *)
return false;
}
-bool Codegen::visit(ElementList *)
-{
- Q_UNREACHABLE();
- return false;
-}
-
bool Codegen::visit(Elision *)
{
Q_UNREACHABLE();
@@ -485,37 +708,31 @@ bool Codegen::visit(FormalParameterList *)
return false;
}
-bool Codegen::visit(FunctionBody *)
-{
- Q_UNREACHABLE();
- return false;
-}
-
bool Codegen::visit(Program *)
{
Q_UNREACHABLE();
return false;
}
-bool Codegen::visit(PropertyAssignmentList *)
+bool Codegen::visit(PatternElement *)
{
Q_UNREACHABLE();
return false;
}
-bool Codegen::visit(PropertyNameAndValue *)
+bool Codegen::visit(PatternElementList *)
{
Q_UNREACHABLE();
return false;
}
-bool Codegen::visit(PropertyGetterSetter *)
+bool Codegen::visit(PatternProperty *)
{
Q_UNREACHABLE();
return false;
}
-bool Codegen::visit(SourceElements *)
+bool Codegen::visit(PatternPropertyList *)
{
Q_UNREACHABLE();
return false;
@@ -587,15 +804,15 @@ bool Codegen::visit(UiQualifiedPragmaId *)
return false;
}
-bool Codegen::visit(VariableDeclaration *)
+bool Codegen::visit(VariableDeclarationList *)
{
Q_UNREACHABLE();
return false;
}
-bool Codegen::visit(VariableDeclarationList *)
+bool Codegen::visit(ClassExpression *ast)
{
- Q_UNREACHABLE();
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Support for 'class' is unimplemented."));
return false;
}
@@ -609,50 +826,160 @@ bool Codegen::visit(Expression *ast)
return false;
}
-bool Codegen::visit(ArrayLiteral *ast)
+bool Codegen::visit(ArrayPattern *ast)
{
if (hasError)
return false;
- RegisterScope scope(this);
+ PatternElementList *it = ast->elements;
int argc = 0;
- int args = -1;
- auto push = [this, &argc, &args](AST::ExpressionNode *arg) {
- int temp = bytecodeGenerator->newRegister();
- if (args == -1)
- args = temp;
- if (!arg) {
- auto c = Reference::fromConst(this, Primitive::emptyValue().asReturnedValue());
- (void) c.storeOnStack(temp);
- } else {
- RegisterScope scope(this);
- (void) expression(arg).storeOnStack(temp);
+ {
+ RegisterScope scope(this);
+
+ int args = -1;
+ auto push = [this, &argc, &args](AST::ExpressionNode *arg) {
+ int temp = bytecodeGenerator->newRegister();
+ if (args == -1)
+ args = temp;
+ if (!arg) {
+ auto c = Reference::fromConst(this, Primitive::emptyValue().asReturnedValue());
+ (void) c.storeOnStack(temp);
+ } else {
+ RegisterScope scope(this);
+ Reference r = expression(arg);
+ if (hasError)
+ return;
+ (void) r.storeOnStack(temp);
+ }
+ ++argc;
+ };
+
+ for (; it; it = it->next) {
+ PatternElement *e = it->element;
+ if (e && e->type == PatternElement::SpreadElement)
+ break;
+ for (Elision *elision = it->elision; elision; elision = elision->next)
+ push(nullptr);
+
+ if (!e)
+ continue;
+
+ push(e->initializer);
+ if (hasError)
+ return false;
}
- ++argc;
- };
- for (ElementList *it = ast->elements; it; it = it->next) {
+ if (args == -1) {
+ Q_ASSERT(argc == 0);
+ args = 0;
+ }
- for (Elision *elision = it->elision; elision; elision = elision->next)
- push(nullptr);
+ Instruction::DefineArray call;
+ call.argc = argc;
+ call.args = Moth::StackSlot::createRegister(args);
+ bytecodeGenerator->addInstruction(call);
+ }
- push(it->expression);
- if (hasError)
- return false;
+ if (!it) {
+ _expr.setResult(Reference::fromAccumulator(this));
+ return false;
}
- for (Elision *elision = ast->elision; elision; elision = elision->next)
- push(nullptr);
+ Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
- if (args == -1) {
- Q_ASSERT(argc == 0);
- args = 0;
+ RegisterScope scope(this);
+ Reference array = Reference::fromStackSlot(this);
+ array.storeConsumeAccumulator();
+ Reference index = Reference::storeConstOnStack(this, Encode(argc));
+
+ auto pushAccumulator = [&]() {
+ Reference slot = Reference::fromSubscript(array, index);
+ slot.storeConsumeAccumulator();
+
+ index.loadInAccumulator();
+ Instruction::Increment inc;
+ bytecodeGenerator->addInstruction(inc);
+ index.storeConsumeAccumulator();
+ };
+
+ while (it) {
+ for (Elision *elision = it->elision; elision; elision = elision->next) {
+ Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()).loadInAccumulator();
+ pushAccumulator();
+ }
+
+ if (!it->element) {
+ it = it->next;
+ continue;
+ }
+
+ // handle spread element
+ if (it->element->type == PatternElement::SpreadElement) {
+ RegisterScope scope(this);
+
+ Reference iterator = Reference::fromStackSlot(this);
+ Reference lhsValue = Reference::fromStackSlot(this);
+
+ // There should be a temporal block, so that variables declared in lhs shadow outside vars.
+ // This block should define a temporal dead zone for those variables, which is not yet implemented.
+ {
+ RegisterScope innerScope(this);
+ Reference expr = expression(it->element->initializer);
+ if (hasError)
+ return false;
+
+ expr.loadInAccumulator();
+ Instruction::GetIterator iteratorObjInstr;
+ iteratorObjInstr.iterator = /*ForEachType::Of*/ 1;
+ bytecodeGenerator->addInstruction(iteratorObjInstr);
+ iterator.storeConsumeAccumulator();
+ }
+
+ BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
+
+ {
+ ControlFlowLoop flow(this, &end, &in, /*requiresUnwind*/ true);
+ bytecodeGenerator->jump().link(in);
+
+ BytecodeGenerator::Label body = bytecodeGenerator->label();
+
+ lhsValue.loadInAccumulator();
+ pushAccumulator();
+
+ in.link();
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ next.value = lhsValue.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpFalse()).link(body);
+ bytecodeGenerator->jump().link(done);
+ }
+
+ end.link();
+
+ Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
+ iterator.loadInAccumulator();
+ Instruction::IteratorClose close;
+ close.done = iteratorDone.stackSlot();
+ bytecodeGenerator->addInstruction(close);
+
+ done.link();
+ } else {
+ RegisterScope innerScope(this);
+ Reference expr = expression(it->element->initializer);
+ if (hasError)
+ return false;
+
+ expr.loadInAccumulator();
+ pushAccumulator();
+ }
+
+ it = it->next;
}
- Instruction::DefineArray call;
- call.argc = argc;
- call.args = Moth::StackSlot::createRegister(args);
- bytecodeGenerator->addInstruction(call);
+ array.loadInAccumulator();
_expr.setResult(Reference::fromAccumulator(this));
return false;
@@ -692,6 +1019,7 @@ static QSOperator::Op baseOp(int op)
case QSOperator::InplaceAdd: return QSOperator::Add;
case QSOperator::InplaceLeftShift: return QSOperator::LShift;
case QSOperator::InplaceMod: return QSOperator::Mod;
+ case QSOperator::InplaceExp: return QSOperator::Exp;
case QSOperator::InplaceMul: return QSOperator::Mul;
case QSOperator::InplaceOr: return QSOperator::BitOr;
case QSOperator::InplaceRightShift: return QSOperator::RShift;
@@ -764,19 +1092,21 @@ bool Codegen::visit(BinaryExpression *ast)
_expr.setResult(Reference::fromAccumulator(this));
}
return false;
- }
-
- Reference left = expression(ast->left);
- if (hasError)
- return false;
-
- switch (ast->op) {
- case QSOperator::Or:
- case QSOperator::And:
- Q_UNREACHABLE(); // handled separately above
- break;
+ } else if (ast->op == QSOperator::Assign) {
+ if (AST::Pattern *p = ast->left->patternCast()) {
+ RegisterScope scope(this);
+ Reference right = expression(ast->right).storeOnStack();
+ destructurePattern(p, right);
+ if (!_expr.accept(nx)) {
+ right.loadInAccumulator();
+ _expr.setResult(Reference::fromAccumulator(this));
+ }
+ return false;
+ }
+ Reference left = expression(ast->left);
+ if (hasError)
+ return false;
- case QSOperator::Assign: {
if (!left.isLValue()) {
throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue"));
return false;
@@ -792,15 +1122,27 @@ bool Codegen::visit(BinaryExpression *ast)
_expr.setResult(left.storeConsumeAccumulator());
else
_expr.setResult(left.storeRetainAccumulator());
- break;
+ return false;
}
+ Reference left = expression(ast->left);
+ if (hasError)
+ return false;
+
+ switch (ast->op) {
+ case QSOperator::Or:
+ case QSOperator::And:
+ case QSOperator::Assign:
+ Q_UNREACHABLE(); // handled separately above
+ break;
+
case QSOperator::InplaceAnd:
case QSOperator::InplaceSub:
case QSOperator::InplaceDiv:
case QSOperator::InplaceAdd:
case QSOperator::InplaceLeftShift:
case QSOperator::InplaceMod:
+ case QSOperator::InplaceExp:
case QSOperator::InplaceMul:
case QSOperator::InplaceOr:
case QSOperator::InplaceRightShift:
@@ -850,6 +1192,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::StrictNotEqual:
case QSOperator::Add:
case QSOperator::Div:
+ case QSOperator::Exp:
case QSOperator::Mod:
case QSOperator::Mul:
case QSOperator::Sub:
@@ -902,6 +1245,14 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
}
break;
}
+ case QSOperator::Exp: {
+ left = left.storeOnStack();
+ right.loadInAccumulator();
+ Instruction::Exp exp;
+ exp.lhs = left.stackSlot();
+ bytecodeGenerator->addInstruction(exp);
+ break;
+ }
case QSOperator::Mul: {
left = left.storeOnStack();
right.loadInAccumulator();
@@ -1259,6 +1610,7 @@ bool Codegen::visit(CallExpression *ast)
RegisterScope scope(this);
Reference base = expression(ast->base);
+
if (hasError)
return false;
switch (base.type) {
@@ -1275,10 +1627,42 @@ bool Codegen::visit(CallExpression *ast)
break;
}
+ int thisObject = bytecodeGenerator->newRegister();
+ int functionObject = bytecodeGenerator->newRegister();
+
auto calldata = pushArgs(ast->arguments);
if (hasError)
return false;
+ if (calldata.hasSpread) {
+ Reference baseObject = base.baseObject();
+ if (!baseObject.isStackSlot()) {
+ baseObject.storeOnStack(thisObject);
+ baseObject = Reference::fromStackSlot(this, thisObject);
+ }
+ if (!base.isStackSlot()) {
+ base.storeOnStack(functionObject);
+ base = Reference::fromStackSlot(this, functionObject);
+ }
+
+ Instruction::CallWithSpread call;
+ call.func = base.stackSlot();
+ call.thisObject = baseObject.stackSlot();
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(call);
+
+ _expr.setResult(Reference::fromAccumulator(this));
+ return false;
+
+ }
+
+ handleCall(base, calldata);
+ return false;
+}
+
+void Codegen::handleCall(Reference &base, Arguments calldata)
+{
//### Do we really need all these call instructions? can's we load the callee in a temp?
if (base.type == Reference::QmlScopeObject) {
Instruction::CallScopeObjectProperty call;
@@ -1295,7 +1679,7 @@ bool Codegen::visit(CallExpression *ast)
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Member) {
- if (useFastLookups) {
+ if (!disable_lookups && useFastLookups) {
Instruction::CallPropertyLookup call;
call.base = base.propertyBase.stackSlot();
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
@@ -1323,7 +1707,7 @@ bool Codegen::visit(CallExpression *ast)
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
- } else if (useFastLookups && base.global) {
+ } else if (!disable_lookups && useFastLookups && base.global) {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
@@ -1346,36 +1730,69 @@ bool Codegen::visit(CallExpression *ast)
}
_expr.setResult(Reference::fromAccumulator(this));
- return false;
}
Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
{
+ bool hasSpread = false;
int argc = 0;
- for (ArgumentList *it = args; it; it = it->next)
+ for (ArgumentList *it = args; it; it = it->next) {
+ if (it->isSpreadElement) {
+ hasSpread = true;
+ ++argc;
+ }
++argc;
+ }
if (!argc)
- return { 0, 0 };
+ return { 0, 0, false };
int calldata = bytecodeGenerator->newRegisterArray(argc);
argc = 0;
for (ArgumentList *it = args; it; it = it->next) {
+ if (it->isSpreadElement) {
+ Reference::fromConst(this, Primitive::emptyValue().asReturnedValue()).storeOnStack(calldata + argc);
+ ++argc;
+ }
RegisterScope scope(this);
Reference e = expression(it->expression);
if (hasError)
break;
- if (!argc && !it->next) {
+ if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
if (e.isStackSlot())
- return { 1, e.stackSlot() };
+ return { 1, e.stackSlot(), hasSpread };
}
(void) e.storeOnStack(calldata + argc);
++argc;
}
- return { argc, calldata };
+ return { argc, calldata, hasSpread };
+}
+
+Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args)
+{
+ int argc = 0;
+ for (TemplateLiteral *it = args; it; it = it->next)
+ ++argc;
+
+ if (!argc)
+ return { 0, 0, false };
+
+ int calldata = bytecodeGenerator->newRegisterArray(argc);
+
+ argc = 0;
+ for (TemplateLiteral *it = args; it && it->expression; it = it->next) {
+ RegisterScope scope(this);
+ Reference e = expression(it->expression);
+ if (hasError)
+ break;
+ (void) e.storeOnStack(calldata + argc);
+ ++argc;
+ }
+
+ return { argc, calldata, false };
}
bool Codegen::visit(ConditionalExpression *ast)
@@ -1413,6 +1830,7 @@ bool Codegen::visit(DeleteExpression *ast)
if (hasError)
return false;
+ RegisterScope scope(this);
Reference expr = expression(ast->expression);
if (hasError)
return false;
@@ -1444,9 +1862,14 @@ bool Codegen::visit(DeleteExpression *ast)
case Reference::Member: {
//### maybe add a variant where the base can be in the accumulator?
expr = expr.asLValue();
- Instruction::DeleteMember del;
+ Instruction::LoadRuntimeString instr;
+ instr.stringId = expr.propertyNameIndex;
+ bytecodeGenerator->addInstruction(instr);
+ Reference index = Reference::fromStackSlot(this);
+ index.storeConsumeAccumulator();
+ Instruction::DeleteProperty del;
del.base = expr.propertyBase.stackSlot();
- del.member = expr.propertyNameIndex;
+ del.index = index.stackSlot();
bytecodeGenerator->addInstruction(del);
_expr.setResult(Reference::fromAccumulator(this));
return false;
@@ -1454,7 +1877,7 @@ bool Codegen::visit(DeleteExpression *ast)
case Reference::Subscript: {
//### maybe add a variant where the index can be in the accumulator?
expr = expr.asLValue();
- Instruction::DeleteSubscript del;
+ Instruction::DeleteProperty del;
del.base = expr.elementBase;
del.index = expr.elementSubscript.stackSlot();
bytecodeGenerator->addInstruction(del);
@@ -1478,11 +1901,31 @@ bool Codegen::visit(FalseLiteral *)
return false;
}
+bool Codegen::visit(SuperLiteral *ast)
+{
+ if (hasError)
+ return false;
+
+ throwSyntaxError(ast->superToken, QLatin1String("Support for 'super' keyword not implemented"));
+ return false;
+}
+
bool Codegen::visit(FieldMemberExpression *ast)
{
if (hasError)
return false;
+ if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
+ if (id->name == QLatin1String("new")) {
+ // new.target
+ if (ast->name != QLatin1String("target")) {
+ throwSyntaxError(ast->identifierToken, QLatin1String("Expected 'target' after 'new.'."));
+ return false;
+ }
+ throwSyntaxError(ast->identifierToken, QLatin1String("Support for 'new.target' unimplemented."));
+ }
+ }
+
Reference base = expression(ast->base);
if (hasError)
return false;
@@ -1490,97 +1933,126 @@ bool Codegen::visit(FieldMemberExpression *ast)
return false;
}
-bool Codegen::visit(FunctionExpression *ast)
+bool Codegen::visit(TaggedTemplate *ast)
{
if (hasError)
return false;
RegisterScope scope(this);
- int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : nullptr);
- loadClosure(function);
- _expr.setResult(Reference::fromAccumulator(this));
+ Reference base = expression(ast->base);
+ if (hasError)
+ return false;
+ switch (base.type) {
+ case Reference::Member:
+ case Reference::Subscript:
+ base = base.asLValue();
+ break;
+ case Reference::Name:
+ break;
+ default:
+ base = base.storeOnStack();
+ break;
+ }
+
+ int arrayTemp = createTemplateArray(ast->templateLiteral);
+ Q_UNUSED(arrayTemp);
+ auto calldata = pushTemplateArgs(ast->templateLiteral);
+ if (hasError)
+ return false;
+ ++calldata.argc;
+ Q_ASSERT(calldata.argv == arrayTemp + 1);
+ --calldata.argv;
+
+ handleCall(base, calldata);
+ return false;
+
+
return false;
}
-Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs)
+int Codegen::createTemplateArray(TemplateLiteral *t)
{
- int scope = 0;
- Context *c = _context;
-
- // skip the innermost context if it's simple (as the runtime won't
- // create a context for it
- if (c->canUseSimpleCall()) {
- Context::Member m = c->findMember(name);
- if (m.type != Context::UndefinedMember) {
- Q_ASSERT((!m.canEscape));
- Reference r = Reference::fromStackSlot(this, m.index, true /*isLocal*/);
- if (name == QLatin1String("arguments") || name == QLatin1String("eval")) {
- r.isArgOrEval = true;
- if (isLhs && c->isStrict)
- // ### add correct source location
- throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- }
- return r;
- }
- const int argIdx = c->findArgument(name);
- if (argIdx != -1) {
- Q_ASSERT(!c->argumentsCanEscape && (c->usesArgumentsObject != Context::ArgumentsObjectUsed || c->isStrict));
- return Reference::fromArgument(this, argIdx, _volataleMemoryLocations.isVolatile(name));
- }
- c = c->parent;
- }
+ int arrayTemp = bytecodeGenerator->newRegister();
- while (c->parent) {
- if (c->forceLookupByName())
- goto loadByName;
+ RegisterScope scope(this);
- Context::Member m = c->findMember(name);
- if (m.type != Context::UndefinedMember) {
- Reference r = m.canEscape ? Reference::fromScopedLocal(this, m.index, scope)
- : Reference::fromStackSlot(this, m.index, true /*isLocal*/);
- if (name == QLatin1String("arguments") || name == QLatin1String("eval")) {
- r.isArgOrEval = true;
- if (isLhs && c->isStrict)
- // ### add correct source location
- throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- }
- return r;
- }
- const int argIdx = c->findArgument(name);
- if (argIdx != -1) {
- if (c->argumentsCanEscape || c->usesArgumentsObject == Context::ArgumentsObjectUsed) {
- int idx = argIdx + c->locals.size();
- return Reference::fromScopedLocal(this, idx, scope);
- } else {
- Q_ASSERT(scope == 0);
- return Reference::fromArgument(this, argIdx, _volataleMemoryLocations.isVolatile(name));
- }
- }
+ int argc = 0;
+ int args = -1;
+ auto push = [this, &argc, &args](const QStringRef &arg) {
+ int temp = bytecodeGenerator->newRegister();
+ if (args == -1)
+ args = temp;
+ Instruction::LoadRuntimeString instr;
+ instr.stringId = registerString(arg.toString());
+ bytecodeGenerator->addInstruction(instr);
+ Instruction::StoreReg store;
+ store.reg = temp;
+ bytecodeGenerator->addInstruction(store);
- if (!c->isStrict && c->hasDirectEval)
- goto loadByName;
+ ++argc;
+ };
- ++scope;
- c = c->parent;
- }
+ for (TemplateLiteral *it = t; it; it = it->next)
+ push(it->value);
- {
- // This hook allows implementing QML lookup semantics
- Reference fallback = fallbackNameLookup(name);
- if (fallback.type != Reference::Invalid)
- return fallback;
+ if (args == -1) {
+ Q_ASSERT(argc == 0);
+ args = 0;
}
- if (!c->parent && !c->forceLookupByName() && _context->compilationMode != EvalCode && c->compilationMode != QmlBinding) {
- Reference r = Reference::fromName(this, name);
- r.global = true;
+ Instruction::DefineArray call;
+ call.argc = argc;
+ call.args = Moth::StackSlot::createRegister(args);
+ bytecodeGenerator->addInstruction(call);
+
+ Instruction::StoreReg store;
+ store.reg = arrayTemp;
+ bytecodeGenerator->addInstruction(store);
+
+ return arrayTemp;
+}
+
+bool Codegen::visit(FunctionExpression *ast)
+{
+ if (hasError)
+ return false;
+
+ RegisterScope scope(this);
+
+ int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
+ if (hasError)
+ return false;
+ loadClosure(function);
+ _expr.setResult(Reference::fromAccumulator(this));
+ return false;
+}
+
+Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs)
+{
+ Context::ResolvedName resolved = _context->resolveName(name);
+
+ if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack) {
+ if (resolved.isArgOrEval && isLhs)
+ // ### add correct source location
+ throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode"));
+ Reference r = (resolved.type == Context::ResolvedName::Local) ?
+ Reference::fromScopedLocal(this, resolved.index, resolved.scope) :
+ Reference::fromStackSlot(this, resolved.index, true /*isLocal*/);
+ if (r.isStackSlot() && _volatileMemoryLocations.isVolatile(name))
+ r.isVolatile = true;
+ r.isArgOrEval = resolved.isArgOrEval;
return r;
}
- // global context or with. Lookup by name
- loadByName:
- return Reference::fromName(this, name);
+ // This hook allows implementing QML lookup semantics
+ Reference fallback = fallbackNameLookup(name);
+ if (fallback.type != Reference::Invalid)
+ return fallback;
+
+ Reference r = Reference::fromName(this, name);
+ r.global = (resolved.type == Context::ResolvedName::Global);
+ return r;
}
void Codegen::loadClosure(int closureId)
@@ -1656,11 +2128,19 @@ bool Codegen::visit(NewMemberExpression *ast)
if (hasError)
return false;
- Instruction::Construct create;
- create.func = base.stackSlot();
- create.argc = calldata.argc;
- create.argv = calldata.argv;
- bytecodeGenerator->addInstruction(create);
+ if (calldata.hasSpread) {
+ Instruction::ConstructWithSpread create;
+ create.func = base.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ } else {
+ Instruction::Construct create;
+ create.func = base.stackSlot();
+ create.argc = calldata.argc;
+ create.argv = calldata.argv;
+ bytecodeGenerator->addInstruction(create);
+ }
_expr.setResult(Reference::fromAccumulator(this));
return false;
}
@@ -1696,133 +2176,105 @@ bool Codegen::visit(NumericLiteral *ast)
return false;
}
-bool Codegen::visit(ObjectLiteral *ast)
+bool Codegen::visit(ObjectPattern *ast)
{
if (hasError)
return false;
+ QVector<QPair<Reference, ObjectPropertyValue>> computedProperties;
QMap<QString, ObjectPropertyValue> valueMap;
RegisterScope scope(this);
- for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
- QString name = it->assignment->name->asString();
- if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
- Reference value = expression(nv->value);
- if (hasError)
- return false;
-
- ObjectPropertyValue &v = valueMap[name];
- if (v.hasGetter() || v.hasSetter() || (_context->isStrict && v.rvalue.isValid())) {
- throwSyntaxError(nv->lastSourceLocation(),
- QStringLiteral("Illegal duplicate key '%1' in object literal").arg(name));
- return false;
- }
-
- v.rvalue = value.storeOnStack();
- } else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
- const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : nullptr);
- ObjectPropertyValue &v = valueMap[name];
- if (v.rvalue.isValid() ||
- (gs->type == PropertyGetterSetter::Getter && v.hasGetter()) ||
- (gs->type == PropertyGetterSetter::Setter && v.hasSetter())) {
- throwSyntaxError(gs->lastSourceLocation(),
- QStringLiteral("Illegal duplicate key '%1' in object literal").arg(name));
- return false;
- }
- if (gs->type == PropertyGetterSetter::Getter)
- v.getter = function;
- else
- v.setter = function;
- } else {
- Q_UNREACHABLE();
- }
- }
-
- QVector<QString> nonArrayKey, arrayKeyWithValue, arrayKeyWithGetterSetter;
- bool needSparseArray = false; // set to true if any array index is bigger than 16
-
- for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(), eit = valueMap.end();
- it != eit; ++it) {
- QString name = it.key();
- uint keyAsIndex = QV4::String::toArrayIndex(name);
- if (keyAsIndex != std::numeric_limits<uint>::max()) {
- it->keyAsIndex = keyAsIndex;
- if (keyAsIndex > 16)
- needSparseArray = true;
- if (it->hasSetter() || it->hasGetter())
- arrayKeyWithGetterSetter.append(name);
- else
- arrayKeyWithValue.append(name);
- } else {
- nonArrayKey.append(name);
- }
- }
+ QStringList members;
- int args = -1;
- auto push = [this, &args](const Reference &arg) {
+ int argc = 0;
+ int args = 0;
+ auto push = [this, &args, &argc](const Reference &arg) {
int temp = bytecodeGenerator->newRegister();
- if (args == -1)
+ if (argc == 0)
args = temp;
(void) arg.storeOnStack(temp);
+ ++argc;
};
- QVector<QV4::Compiler::JSUnitGenerator::MemberInfo> members;
+ PatternPropertyList *it = ast->properties;
+ for (; it; it = it->next) {
+ PatternProperty *p = it->property;
+ AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
+ if (cname || p->type == PatternProperty::Getter || p->type == PatternProperty::Setter)
+ break;
+ QString name = p->name->asString();
+ uint arrayIndex = QV4::String::toArrayIndex(name);
+ if (arrayIndex != UINT_MAX)
+ break;
+ if (members.contains(name))
+ break;
+ members.append(name);
- Reference acc = Reference::fromAccumulator(this);
- // generate the key/value pairs
- for (const QString &key : qAsConst(nonArrayKey)) {
- const ObjectPropertyValue &prop = valueMap[key];
-
- if (prop.hasGetter() || prop.hasSetter()) {
- Q_ASSERT(!prop.rvalue.isValid());
- loadClosure(prop.getter);
- push(acc);
- loadClosure(prop.setter);
- push(acc);
- members.append({ key, true });
- } else {
- Q_ASSERT(prop.rvalue.isValid());
- push(prop.rvalue);
- members.append({ key, false });
+ {
+ RegisterScope innerScope(this);
+ Reference value = expression(p->initializer);
+ if (hasError)
+ return false;
+ value.loadInAccumulator();
}
- }
-
- // generate array entries with values
- for (const QString &key : qAsConst(arrayKeyWithValue)) {
- const ObjectPropertyValue &prop = valueMap[key];
- Q_ASSERT(!prop.hasGetter() && !prop.hasSetter());
- push(Reference::fromConst(this, Encode(prop.keyAsIndex)));
- push(prop.rvalue);
- }
-
- // generate array entries with both a value and a setter
- for (const QString &key : qAsConst(arrayKeyWithGetterSetter)) {
- const ObjectPropertyValue &prop = valueMap[key];
- Q_ASSERT(!prop.rvalue.isValid());
- push(Reference::fromConst(this, Encode(prop.keyAsIndex)));
- loadClosure(prop.getter);
- push(acc);
- loadClosure(prop.setter);
- push(acc);
+ push(Reference::fromAccumulator(this));
}
int classId = jsUnitGenerator->registerJSClass(members);
- uint arrayGetterSetterCountAndFlags = arrayKeyWithGetterSetter.size();
- arrayGetterSetterCountAndFlags |= needSparseArray << 30;
-
- if (args == -1)
- args = 0;
+ // handle complex property setters
+ for (; it; it = it->next) {
+ PatternProperty *p = it->property;
+ AST::ComputedPropertyName *cname = AST::cast<AST::ComputedPropertyName *>(p->name);
+ ObjectLiteralArgument argType = ObjectLiteralArgument::Value;
+ if (p->type == PatternProperty::Getter)
+ argType = ObjectLiteralArgument::Getter;
+ else if (p->type == PatternProperty::Setter)
+ argType = ObjectLiteralArgument::Setter;
+
+ Reference::fromConst(this, Encode(int(argType))).loadInAccumulator();
+ push(Reference::fromAccumulator(this));
+
+ if (cname) {
+ RegisterScope innerScope(this);
+ Reference name = expression(cname->expression);
+ if (hasError)
+ return false;
+ name.loadInAccumulator();
+ } else {
+ QString name = p->name->asString();
+#if 0
+ uint arrayIndex = QV4::String::toArrayIndex(name);
+ if (arrayIndex != UINT_MAX) {
+ Reference::fromConst(this, Encode(arrayIndex)).loadInAccumulator();
+ } else
+#endif
+ {
+ Instruction::LoadRuntimeString instr;
+ instr.stringId = registerString(name);
+ bytecodeGenerator->addInstruction(instr);
+ }
+ }
+ push(Reference::fromAccumulator(this));
+ {
+ RegisterScope innerScope(this);
+ Reference value = expression(p->initializer);
+ if (hasError)
+ return false;
+ value.loadInAccumulator();
+ }
+ push(Reference::fromAccumulator(this));
+ }
Instruction::DefineObjectLiteral call;
call.internalClassId = classId;
- call.arrayValueCount = arrayKeyWithValue.size();
- call.arrayGetterSetterCountAndFlags = arrayGetterSetterCountAndFlags;
+ call.argc = argc;
call.args = Moth::StackSlot::createRegister(args);
bytecodeGenerator->addInstruction(call);
-
- _expr.setResult(Reference::fromAccumulator(this));
+ Reference result = Reference::fromAccumulator(this);
+ _expr.setResult(result);
return false;
}
@@ -1933,6 +2385,49 @@ bool Codegen::visit(StringLiteral *ast)
return false;
}
+bool Codegen::visit(TemplateLiteral *ast)
+{
+ if (hasError)
+ return false;
+
+ Instruction::LoadRuntimeString instr;
+ instr.stringId = registerString(ast->value.toString());
+ bytecodeGenerator->addInstruction(instr);
+
+ if (ast->expression) {
+ RegisterScope scope(this);
+ int temp = bytecodeGenerator->newRegister();
+ Instruction::StoreReg store;
+ store.reg = temp;
+ bytecodeGenerator->addInstruction(store);
+
+ Reference expr = expression(ast->expression);
+
+ if (ast->next) {
+ int temp2 = bytecodeGenerator->newRegister();
+ expr.storeOnStack(temp2);
+ visit(ast->next);
+
+ Instruction::Add instr;
+ instr.lhs = temp2;
+ bytecodeGenerator->addInstruction(instr);
+ } else {
+ expr.loadInAccumulator();
+ }
+
+ Instruction::Add instr;
+ instr.lhs = temp;
+ bytecodeGenerator->addInstruction(instr);
+ }
+
+ auto r = Reference::fromAccumulator(this);
+ r.isReadonly = true;
+
+ _expr.setResult(r);
+ return false;
+
+}
+
bool Codegen::visit(ThisExpression *)
{
if (hasError)
@@ -2023,13 +2518,40 @@ bool Codegen::visit(FunctionDeclaration * ast)
RegisterScope scope(this);
- if (_context->compilationMode == QmlBinding)
- Reference::fromName(this, ast->name.toString()).loadInAccumulator();
+ if (_functionContext->contextType == ContextType::Binding)
+ referenceForName(ast->name.toString(), true).loadInAccumulator();
_expr.accept(nx);
return false;
}
-static bool endsWithReturn(Node *node)
+bool Codegen::visit(YieldExpression *ast)
+{
+ if (ast->isYieldStar) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("yield* is not currently supported"));
+ return false;
+ }
+ if (inFormalParameterList) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("yield is not allowed inside parameter lists"));
+ return false;
+ }
+
+
+ Reference result = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
+ if (hasError)
+ return false;
+ result.loadInAccumulator();
+ Instruction::Yield yield;
+ bytecodeGenerator->addInstruction(yield);
+ Instruction::Resume resume;
+ BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
+ Reference acc = Reference::fromAccumulator(this);
+ emitReturn(acc);
+ jump.link();
+ _expr.setResult(acc);
+ return false;
+}
+
+static bool endsWithReturn(Module *module, Node *node)
{
if (!node)
return false;
@@ -2038,32 +2560,29 @@ static bool endsWithReturn(Node *node)
if (AST::cast<ThrowStatement *>(node))
return true;
if (Program *p = AST::cast<Program *>(node))
- return endsWithReturn(p->elements);
- if (SourceElements *se = AST::cast<SourceElements *>(node)) {
- while (se->next)
- se = se->next;
- return endsWithReturn(se->element);
- }
- if (StatementSourceElement *sse = AST::cast<StatementSourceElement *>(node))
- return endsWithReturn(sse->statement);
+ return endsWithReturn(module, p->statements);
if (StatementList *sl = AST::cast<StatementList *>(node)) {
while (sl->next)
sl = sl->next;
- return endsWithReturn(sl->statement);
+ return endsWithReturn(module, sl->statement);
+ }
+ if (Block *b = AST::cast<Block *>(node)) {
+ Context *blockContext = module->contextMap.value(node);
+ if (blockContext->requiresExecutionContext)
+ // we need to emit a return statement here, because of the
+ // unwind handler
+ return false;
+ return endsWithReturn(module, b->statements);
}
- if (Block *b = AST::cast<Block *>(node))
- return endsWithReturn(b->statements);
if (IfStatement *is = AST::cast<IfStatement *>(node))
- return is->ko && endsWithReturn(is->ok) && endsWithReturn(is->ko);
+ return is->ko && endsWithReturn(module, is->ok) && endsWithReturn(module, is->ko);
return false;
}
int Codegen::defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
- AST::SourceElements *body)
+ AST::StatementList *body)
{
- Q_UNUSED(formals);
-
enterContext(ast);
if (_context->functionIndex >= 0)
@@ -2074,7 +2593,15 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_module->functions.append(_context);
_context->functionIndex = _module->functions.count() - 1;
- _context->hasDirectEval |= (_context->compilationMode == EvalCode || _context->compilationMode == GlobalCode || _module->debugMode); // Conditional breakpoints are like eval in the function
+ Context *savedFunctionContext = _functionContext;
+ _functionContext = _context;
+ ControlFlow *savedControlFlow = controlFlow;
+ controlFlow = nullptr;
+
+ if (_context->contextType == ContextType::Global) {
+ _module->blocks.append(_context);
+ _context->blockIndex = _module->blocks.count() - 1;
+ }
if (_module->debugMode) // allow the debugger to see overwritten arguments
_context->argumentsCanEscape = true;
@@ -2084,132 +2611,104 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// at all, because if the onSignal is a signal handler, the user is actually making it explicit
// that the binding is a function, so we should execute that. However, we don't know that during
// AOT compilation, so mark the surrounding function as only-returning-a-closure.
- _context->returnsClosure = cast<ExpressionStatement *>(ast) && cast<FunctionExpression *>(cast<ExpressionStatement *>(ast)->expression);
+ _context->returnsClosure = body && body->statement && cast<ExpressionStatement *>(body->statement) && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
BytecodeGenerator bytecode(_context->line, _module->debugMode);
BytecodeGenerator *savedBytecodeGenerator;
savedBytecodeGenerator = bytecodeGenerator;
bytecodeGenerator = &bytecode;
bytecodeGenerator->setLocation(ast->firstSourceLocation());
+ BytecodeGenerator::Label *savedReturnLabel = _returnLabel;
+ _returnLabel = nullptr;
+
+ bool savedFunctionEndsWithReturn = functionEndsWithReturn;
+ functionEndsWithReturn = endsWithReturn(_module, body);
// reserve the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
+ bool _inFormalParameterList = false;
+ qSwap(_inFormalParameterList, inFormalParameterList);
+
int returnAddress = -1;
- bool _requiresReturnValue = (_context->compilationMode == QmlBinding || _context->compilationMode == EvalCode || _context->compilationMode == GlobalCode);
+ bool _requiresReturnValue = _context->requiresImplicitReturnValue();
qSwap(requiresReturnValue, _requiresReturnValue);
- if (requiresReturnValue)
- returnAddress = bytecodeGenerator->newRegister();
- if (!_context->parent || _context->usesArgumentsObject == Context::ArgumentsObjectUnknown)
- _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
- if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed)
- _context->addLocalVar(QStringLiteral("arguments"), Context::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
-
- bool allVarsEscape = _context->hasWith || _context->hasTry || _context->hasDirectEval;
- bool needsCallContext = false;
- const QLatin1String exprForOn("expression for on");
- if (!_context->canUseSimpleCall() && _context->compilationMode != GlobalCode && (_context->compilationMode != EvalCode || _context->isStrict))
- needsCallContext = true;
- else if (_context->compilationMode == QmlBinding && name.length() > exprForOn.size() && name.startsWith(exprForOn) && name.at(exprForOn.size()).isUpper())
- // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not.
- needsCallContext = true;
- if (needsCallContext) {
- Instruction::CreateCallContext createContext;
- bytecodeGenerator->addInstruction(createContext);
- }
-
- // variables in global code are properties of the global context object, not locals as with other functions.
- if (_context->compilationMode == FunctionCode || _context->compilationMode == QmlBinding) {
- for (Context::MemberMap::iterator it = _context->members.begin(), end = _context->members.end(); it != end; ++it) {
- const QString &local = it.key();
- if (allVarsEscape)
- it->canEscape = true;
- if (it->canEscape) {
- it->index = _context->locals.size();
- _context->locals.append(local);
- if (it->type == Context::ThisFunctionName) {
- // move the name from the stack to the call context
- Instruction::LoadReg load;
- load.reg = CallData::Function;
- bytecodeGenerator->addInstruction(load);
- Instruction::StoreLocal store;
- store.index = it->index;
- bytecodeGenerator->addInstruction(store);
- }
- } else {
- if (it->type == Context::ThisFunctionName)
- it->index = CallData::Function;
- else
- it->index = bytecodeGenerator->newRegister();
- }
- }
- } else {
- for (Context::MemberMap::const_iterator it = _context->members.constBegin(), cend = _context->members.constEnd(); it != cend; ++it) {
- const QString &local = it.key();
+ returnAddress = bytecodeGenerator->newRegister();
+ qSwap(_returnAddress, returnAddress);
- Instruction::DeclareVar declareVar;
- declareVar.isDeletable = false;
- declareVar.varName = registerString(local);
- bytecodeGenerator->addInstruction(declareVar);
- }
+ // register the lexical scope for global code
+ if (!_context->parent && _context->requiresExecutionContext) {
+ _module->blocks.append(_context);
+ _context->blockIndex = _module->blocks.count() - 1;
}
- qSwap(_returnAddress, returnAddress);
- for (const Context::Member &member : qAsConst(_context->members)) {
- if (member.function) {
- const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
- member.function->body ? member.function->body->elements : nullptr);
- loadClosure(function);
- if (! _context->parent) {
- Reference::fromName(this, member.function->name.toString()).storeConsumeAccumulator();
- } else {
- Q_ASSERT(member.index >= 0);
- Reference local = member.canEscape ? Reference::fromScopedLocal(this, member.index, 0)
- : Reference::fromStackSlot(this, member.index, true);
- local.storeConsumeAccumulator();
- }
+ RegisterScope registerScope(this);
+ _context->emitBlockHeader(this);
+
+ inFormalParameterList = true;
+ int argc = 0;
+ while (formals) {
+ PatternElement *e = formals->element;
+ if (!e) {
+ if (!formals->next)
+ // trailing comma
+ break;
+ Q_UNREACHABLE();
}
- }
- if (_context->usesArgumentsObject == Context::ArgumentsObjectUsed) {
- if (_context->isStrict) {
- Instruction::CreateUnmappedArgumentsObject setup;
- bytecodeGenerator->addInstruction(setup);
+
+ Reference arg = referenceForName(e->bindingIdentifier, true);
+ if (e->type == PatternElement::RestElement) {
+ Q_ASSERT(!formals->next);
+ Instruction::CreateRestParameter rest;
+ rest.argIndex = argc;
+ bytecodeGenerator->addInstruction(rest);
+ arg.storeConsumeAccumulator();
} else {
- Instruction::CreateMappedArgumentsObject setup;
- bytecodeGenerator->addInstruction(setup);
+ if (e->bindingTarget || e->initializer) {
+ initializeAndDestructureBindingElement(e, arg);
+ if (hasError)
+ break;
+ }
}
- referenceForName(QStringLiteral("arguments"), false).storeConsumeAccumulator();
+ formals = formals->next;
+ ++argc;
}
- if (_context->usesThis && !_context->isStrict) {
- // make sure we convert this to an object
- Instruction::ConvertThisToObject convert;
- bytecodeGenerator->addInstruction(convert);
+ inFormalParameterList = false;
+
+ if (_context->isGenerator) {
+ Instruction::Yield yield;
+ bytecodeGenerator->addInstruction(yield);
}
beginFunctionBodyHook();
- sourceElements(body);
+ statementList(body);
- if (hasError || !endsWithReturn(body)) {
- bytecodeGenerator->setLocation(ast->lastSourceLocation());
- if (requiresReturnValue) {
- if (_returnAddress >= 0) {
- Instruction::LoadReg load;
- load.reg = Moth::StackSlot::createRegister(_returnAddress);
- bytecodeGenerator->addInstruction(load);
- }
+ bytecodeGenerator->setLocation(ast->lastSourceLocation());
+ _context->emitBlockFooter(this);
+
+ if (_returnLabel || hasError || !functionEndsWithReturn) {
+ if (_returnLabel)
+ _returnLabel->link();
+
+ if (_returnLabel || requiresReturnValue) {
+ Instruction::LoadReg load;
+ load.reg = Moth::StackSlot::createRegister(_returnAddress);
+ bytecodeGenerator->addInstruction(load);
} else {
Reference::fromConst(this, Encode::undefined()).loadInAccumulator();
}
+
bytecodeGenerator->addInstruction(Instruction::Ret());
}
+ Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
- _context->registerCount = bytecodeGenerator->registerCount();
+ _context->registerCountInFunction = bytecodeGenerator->registerCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
- << "register count" << _context->registerCount;
+ << "register count" << _context->registerCountInFunction << "implicit return" << requiresReturnValue;
QV4::Moth::dumpBytecode(_context->code, _context->locals.size(), _context->arguments.size(),
_context->line, _context->lineNumberMapping);
qDebug();
@@ -2217,29 +2716,17 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
qSwap(_returnAddress, returnAddress);
qSwap(requiresReturnValue, _requiresReturnValue);
+ qSwap(_inFormalParameterList, inFormalParameterList);
bytecodeGenerator = savedBytecodeGenerator;
+ delete _returnLabel;
+ _returnLabel = savedReturnLabel;
+ controlFlow = savedControlFlow;
+ functionEndsWithReturn = savedFunctionEndsWithReturn;
+ _functionContext = savedFunctionContext;
return leaveContext();
}
-bool Codegen::visit(FunctionSourceElement *ast)
-{
- if (hasError)
- return false;
-
- statement(ast->declaration);
- return false;
-}
-
-bool Codegen::visit(StatementSourceElement *ast)
-{
- if (hasError)
- return false;
-
- statement(ast->statement);
- return false;
-}
-
bool Codegen::visit(Block *ast)
{
if (hasError)
@@ -2247,6 +2734,7 @@ bool Codegen::visit(Block *ast)
RegisterScope scope(this);
+ ControlFlowBlock controlFlow(this, ast);
statementList(ast->statements);
return false;
}
@@ -2256,13 +2744,13 @@ bool Codegen::visit(BreakStatement *ast)
if (hasError)
return false;
- if (!_context->controlFlow) {
+ if (!controlFlow) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
return false;
}
- ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Break, ast->label.toString());
- if (h.type == ControlFlow::Invalid) {
+ ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Break, ast->label.toString());
+ if (!target.linkLabel.isValid()) {
if (ast->label.isEmpty())
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
else
@@ -2270,7 +2758,7 @@ bool Codegen::visit(BreakStatement *ast)
return false;
}
- _context->controlFlow->jumpToHandler(h);
+ bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
return false;
}
@@ -2282,13 +2770,13 @@ bool Codegen::visit(ContinueStatement *ast)
RegisterScope scope(this);
- if (!_context->controlFlow) {
+ if (!controlFlow) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Continue outside of loop"));
return false;
}
- ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Continue, ast->label.toString());
- if (h.type == ControlFlow::Invalid) {
+ ControlFlow::UnwindTarget target = controlFlow->unwindTarget(ControlFlow::Continue, ast->label.toString());
+ if (!target.linkLabel.isValid()) {
if (ast->label.isEmpty())
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Undefined label '%1'").arg(ast->label.toString()));
else
@@ -2296,7 +2784,7 @@ bool Codegen::visit(ContinueStatement *ast)
return false;
}
- _context->controlFlow->jumpToHandler(h);
+ bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
return false;
}
@@ -2370,45 +2858,86 @@ bool Codegen::visit(ForEachStatement *ast)
RegisterScope scope(this);
- Reference nextIterObj = Reference::fromStackSlot(this);
- Reference iterObj = Reference::fromStackSlot(this);
- Reference expr = expression(ast->expression);
- if (hasError)
- return true;
+ Reference iterator = Reference::fromStackSlot(this);
+ Reference lhsValue = Reference::fromStackSlot(this);
- expr.loadInAccumulator();
- Instruction::ForeachIteratorObject iteratorObjInstr;
- bytecodeGenerator->addInstruction(iteratorObjInstr);
- iterObj.storeConsumeAccumulator();
+ // There should be a temporal block, so that variables declared in lhs shadow outside vars.
+ // This block should define a temporal dead zone for those variables, which is not yet implemented.
+ {
+ RegisterScope innerScope(this);
+ ControlFlowBlock controlFlow(this, ast);
+ Reference expr = expression(ast->expression);
+ if (hasError)
+ return true;
- Reference lhs = expression(ast->initialiser).asLValue();
+ expr.loadInAccumulator();
+ Instruction::GetIterator iteratorObjInstr;
+ iteratorObjInstr.iterator = (ast->type == ForEachType::Of) ? 1 : 0;
+ bytecodeGenerator->addInstruction(iteratorObjInstr);
+ iterator.storeConsumeAccumulator();
+ }
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
- bytecodeGenerator->jump().link(in);
-
- ControlFlowLoop flow(this, &end, &in);
-
- BytecodeGenerator::Label body = bytecodeGenerator->label();
+ {
+ ControlFlowLoop flow(this, &end, &in, /*requiresUnwind*/ true);
+ bytecodeGenerator->jump().link(in);
+
+ BytecodeGenerator::Label body = bytecodeGenerator->label();
+
+ // each iteration gets it's own context, as per spec
+ {
+ RegisterScope innerScope(this);
+ ControlFlowBlock controlFlow(this, ast);
+
+ if (ExpressionNode *e = ast->lhs->expressionCast()) {
+ if (AST::Pattern *p = e->patternCast()) {
+ RegisterScope scope(this);
+ destructurePattern(p, lhsValue);
+ } else {
+ Reference lhs = expression(e);
+ if (hasError)
+ goto error;
+ lhs = lhs.asLValue();
+ lhsValue.loadInAccumulator();
+ lhs.storeConsumeAccumulator();
+ }
+ } else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
+ initializeAndDestructureBindingElement(p, lhsValue);
+ if (hasError)
+ goto error;
+ } else {
+ Q_UNREACHABLE();
+ }
- nextIterObj.loadInAccumulator();
- lhs.storeConsumeAccumulator();
+ statement(ast->statement);
+ setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
- statement(ast->statement);
- setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
+ }
- in.link();
+ error:
+ in.link();
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ next.value = lhsValue.stackSlot();
+ bytecodeGenerator->addInstruction(next);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpFalse()).link(body);
+ bytecodeGenerator->jump().link(done);
+ }
- iterObj.loadInAccumulator();
- Instruction::ForeachNextPropertyName nextPropInstr;
- bytecodeGenerator->addInstruction(nextPropInstr);
- nextIterObj.storeConsumeAccumulator();
+ end.link();
- Reference::fromConst(this, QV4::Encode::null()).loadInAccumulator();
- bytecodeGenerator->jumpStrictNotEqual(nextIterObj.stackSlot(), body);
+ if (ast->type == ForEachType::Of) {
+ Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
+ iterator.loadInAccumulator();
+ Instruction::IteratorClose close;
+ close.done = iteratorDone.stackSlot();
+ bytecodeGenerator->addInstruction(close);
+ }
- end.link();
+ done.link();
return false;
}
@@ -2420,7 +2949,12 @@ bool Codegen::visit(ForStatement *ast)
RegisterScope scope(this);
- statement(ast->initialiser);
+ ControlFlowBlock controlFlow(this, ast);
+
+ if (ast->initialiser)
+ statement(ast->initialiser);
+ else if (ast->declarations)
+ variableDeclarationList(ast->declarations);
BytecodeGenerator::Label cond = bytecodeGenerator->label();
BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
@@ -2436,6 +2970,10 @@ bool Codegen::visit(ForStatement *ast)
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
step.link();
+ if (_context->requiresExecutionContext) {
+ Instruction::CloneBlockContext clone;
+ bytecodeGenerator->addInstruction(clone);
+ }
statement(ast->expression);
bytecodeGenerator->jump().link(cond);
@@ -2458,7 +2996,7 @@ bool Codegen::visit(IfStatement *ast)
trueLabel.link();
statement(ast->ok);
if (ast->ko) {
- if (endsWithReturn(ast)) {
+ if (endsWithReturn(_module, ast)) {
falseLabel.link();
statement(ast->ko);
} else {
@@ -2482,7 +3020,7 @@ bool Codegen::visit(LabelledStatement *ast)
RegisterScope scope(this);
// check that no outer loop contains the label
- ControlFlow *l = _context->controlFlow;
+ ControlFlow *l = controlFlow;
while (l) {
if (l->label() == ast->label) {
QString error = QString(QStringLiteral("Label '%1' has already been declared")).arg(ast->label.toString());
@@ -2497,9 +3035,7 @@ bool Codegen::visit(LabelledStatement *ast)
AST::cast<AST::WhileStatement *>(ast->statement) ||
AST::cast<AST::DoWhileStatement *>(ast->statement) ||
AST::cast<AST::ForStatement *>(ast->statement) ||
- AST::cast<AST::ForEachStatement *>(ast->statement) ||
- AST::cast<AST::LocalForStatement *>(ast->statement) ||
- AST::cast<AST::LocalForEachStatement *>(ast->statement)) {
+ AST::cast<AST::ForEachStatement *>(ast->statement)) {
statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop.
} else {
BytecodeGenerator::Label breakLabel = bytecodeGenerator->newLabel();
@@ -2511,85 +3047,17 @@ bool Codegen::visit(LabelledStatement *ast)
return false;
}
-bool Codegen::visit(LocalForEachStatement *ast)
-{
- if (hasError)
- return true;
-
- RegisterScope scope(this);
-
- Reference nextIterObj = Reference::fromStackSlot(this);
- Reference iterObj = Reference::fromStackSlot(this);
- Reference expr = expression(ast->expression);
- if (hasError)
- return true;
-
- variableDeclaration(ast->declaration);
-
- expr.loadInAccumulator();
- Instruction::ForeachIteratorObject iteratorObjInstr;
- bytecodeGenerator->addInstruction(iteratorObjInstr);
- iterObj.storeConsumeAccumulator();
-
- BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
- BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
-
- bytecodeGenerator->jump().link(in);
- ControlFlowLoop flow(this, &end, &in);
-
- BytecodeGenerator::Label body = bytecodeGenerator->label();
-
- Reference it = referenceForName(ast->declaration->name.toString(), true).asLValue();
-
- nextIterObj.loadInAccumulator();
- it.storeConsumeAccumulator();
-
- statement(ast->statement);
- setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
-
- in.link();
-
- iterObj.loadInAccumulator();
- Instruction::ForeachNextPropertyName nextPropInstr;
- bytecodeGenerator->addInstruction(nextPropInstr);
- nextIterObj.storeConsumeAccumulator();
-
- Reference::fromConst(this, QV4::Encode::null()).loadInAccumulator();
- bytecodeGenerator->jumpStrictNotEqual(nextIterObj.stackSlot(), body);
-
- end.link();
-
- return false;
-}
-
-bool Codegen::visit(LocalForStatement *ast)
+void Codegen::emitReturn(const Reference &expr)
{
- if (hasError)
- return true;
-
- RegisterScope scope(this);
-
- variableDeclarationList(ast->declarations);
-
- BytecodeGenerator::Label cond = bytecodeGenerator->label();
- BytecodeGenerator::Label body = bytecodeGenerator->newLabel();
- BytecodeGenerator::Label step = bytecodeGenerator->newLabel();
- BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
-
- ControlFlowLoop flow(this, &end, &step);
-
- condition(ast->condition, &body, &end, true);
-
- body.link();
- statement(ast->statement);
- setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
-
- step.link();
- statement(ast->expression);
- bytecodeGenerator->jump().link(cond);
- end.link();
-
- return false;
+ ControlFlow::UnwindTarget target = controlFlow ? controlFlow->unwindTarget(ControlFlow::Return) : ControlFlow::UnwindTarget();
+ if (target.linkLabel.isValid() && target.unwindLevel) {
+ Q_ASSERT(_returnAddress >= 0);
+ (void) expr.storeOnStack(_returnAddress);
+ bytecodeGenerator->unwindToLabel(target.unwindLevel, target.linkLabel);
+ } else {
+ expr.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::Ret());
+ }
}
bool Codegen::visit(ReturnStatement *ast)
@@ -2597,7 +3065,7 @@ bool Codegen::visit(ReturnStatement *ast)
if (hasError)
return true;
- if (_context->compilationMode != FunctionCode && _context->compilationMode != QmlBinding) {
+ if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) {
throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
return false;
}
@@ -2610,17 +3078,8 @@ bool Codegen::visit(ReturnStatement *ast)
expr = Reference::fromConst(this, Encode::undefined());
}
- if (_context->controlFlow && _context->controlFlow->returnRequiresUnwind()) {
- if (_returnAddress >= 0)
- (void) expr.storeOnStack(_returnAddress);
- else
- expr.loadInAccumulator();
- ControlFlow::Handler h = _context->controlFlow->getHandler(ControlFlow::Return);
- _context->controlFlow->jumpToHandler(h);
- } else {
- expr.loadInAccumulator();
- bytecodeGenerator->addInstruction(Instruction::Ret());
- }
+ emitReturn(expr);
+
return false;
}
@@ -2629,9 +3088,14 @@ bool Codegen::visit(SwitchStatement *ast)
if (hasError)
return true;
+ if (requiresReturnValue)
+ Reference::fromConst(this, Encode::undefined()).storeOnStack(_returnAddress);
+
RegisterScope scope(this);
if (ast->block) {
+ ControlFlowBlock controlFlow(this, ast->block);
+
BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel();
Reference lhs = expression(ast->expression);
@@ -2674,6 +3138,7 @@ bool Codegen::visit(SwitchStatement *ast)
ControlFlowLoop flow(this, &switchEnd);
+ insideSwitch = true;
for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
CaseClause *clause = it->clause;
blockMap[clause].link();
@@ -2694,6 +3159,7 @@ bool Codegen::visit(SwitchStatement *ast)
statementList(clause->statements);
}
+ insideSwitch = false;
switchEnd.link();
@@ -2713,25 +3179,15 @@ bool Codegen::visit(ThrowStatement *ast)
if (hasError)
return false;
- if (_context->controlFlow) {
- _context->controlFlow->handleThrow(expr);
- } else {
- expr.loadInAccumulator();
- Instruction::ThrowException instr;
- bytecodeGenerator->addInstruction(instr);
- }
+ expr.loadInAccumulator();
+ Instruction::ThrowException instr;
+ bytecodeGenerator->addInstruction(instr);
return false;
}
void Codegen::handleTryCatch(TryStatement *ast)
{
Q_ASSERT(ast);
- if (_context->isStrict &&
- (ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments"))) {
- throwSyntaxError(ast->catchExpression->identifierToken, QStringLiteral("Catch variable name may not be eval or arguments in strict mode"));
- return;
- }
-
RegisterScope scope(this);
BytecodeGenerator::Label noException = bytecodeGenerator->newLabel();
{
@@ -2761,8 +3217,6 @@ bool Codegen::visit(TryStatement *ast)
if (hasError)
return true;
- Q_ASSERT(_context->hasTry);
-
RegisterScope scope(this);
if (ast->finallyExpression && ast->finallyExpression->statement) {
@@ -2817,17 +3271,18 @@ bool Codegen::visit(WithStatement *ast)
RegisterScope scope(this);
- _context->hasWith = true;
-
Reference src = expression(ast->expression);
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();
- ControlFlowWith flow(this);
-
- statement(ast->statement);
+ enterContext(ast);
+ {
+ ControlFlowWith flow(this);
+ statement(ast->statement);
+ }
+ leaveContext();
return false;
}
@@ -3080,6 +3535,22 @@ Codegen::RValue Codegen::RValue::storeOnStack() const
}
}
+void Codegen::RValue::loadInAccumulator() const
+{
+ switch (type) {
+ case Accumulator:
+ // nothing to do
+ return;
+ case StackSlot:
+ return Reference::fromStackSlot(codegen, theStackSlot).loadInAccumulator();
+ case Const:
+ return Reference::fromConst(codegen, constant).loadInAccumulator();
+ default:
+ Q_UNREACHABLE();
+ }
+
+}
+
Codegen::Reference::Reference(const Codegen::Reference &other)
{
*this = other;
@@ -3209,6 +3680,28 @@ Codegen::Reference Codegen::Reference::storeConsumeAccumulator() const
return Reference();
}
+Codegen::Reference Codegen::Reference::baseObject() const
+{
+ if (type == Reference::QmlScopeObject || type == Reference::QmlContextObject) {
+ return Reference::fromStackSlot(codegen, qmlBase.stackSlot());
+ } else if (type == Reference::Member) {
+ RValue rval = propertyBase;
+ if (!rval.isValid())
+ return Reference::fromConst(codegen, Encode::undefined());
+ if (rval.isAccumulator())
+ return Reference::fromAccumulator(codegen);
+ if (rval.isStackSlot())
+ Reference::fromStackSlot(codegen, rval.stackSlot());
+ if (rval.isConst())
+ return Reference::fromConst(codegen, rval.constantValue());
+ Q_UNREACHABLE();
+ } else if (type == Reference::Subscript) {
+ return Reference::fromStackSlot(codegen, elementBase.stackSlot());
+ } else {
+ return Reference::fromConst(codegen, Encode::undefined());
+ }
+}
+
Codegen::Reference Codegen::Reference::storeOnStack() const
{ return doStoreOnStack(-1); }
@@ -3313,7 +3806,7 @@ void Codegen::Reference::storeAccumulator() const
}
} return;
case Member:
- if (codegen->useFastLookups) {
+ if (!disable_lookups && codegen->useFastLookups) {
Instruction::SetLookup store;
store.base = propertyBase.stackSlot();
store.index = codegen->registerSetterLookup(propertyNameIndex);
@@ -3429,7 +3922,7 @@ QT_WARNING_POP
return;
}
}
- if (codegen->useFastLookups && global) {
+ if (!disable_lookups && codegen->useFastLookups && global) {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
codegen->bytecodeGenerator->addInstruction(load);
@@ -3440,7 +3933,7 @@ QT_WARNING_POP
}
return;
case Member:
- if (codegen->useFastLookups) {
+ if (!disable_lookups && codegen->useFastLookups) {
if (propertyBase.isAccumulator()) {
Instruction::GetLookupA load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
@@ -3452,34 +3945,17 @@ QT_WARNING_POP
codegen->bytecodeGenerator->addInstruction(load);
}
} else {
- if (propertyBase.isAccumulator()) {
- Instruction::LoadPropertyA load;
- load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addInstruction(load);
- } else {
- Instruction::LoadProperty load;
- load.base = propertyBase.storeOnStack().stackSlot();
- load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addInstruction(load);
- }
+ propertyBase.loadInAccumulator();
+ Instruction::LoadProperty load;
+ load.name = propertyNameIndex;
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Subscript: {
- if (elementSubscript.isAccumulator()) {
- Instruction::LoadElementA load;
- load.base = elementBase;
- codegen->bytecodeGenerator->addInstruction(load);
- } else if (elementSubscript.isConst()) {
- Reference::fromConst(codegen, elementSubscript.constantValue()).loadInAccumulator();
- Instruction::LoadElementA load;
- load.base = elementBase;
- codegen->bytecodeGenerator->addInstruction(load);
- } else {
- Instruction::LoadElement load;
- load.base = elementBase;
- load.index = elementSubscript.storeOnStack().stackSlot();
- codegen->bytecodeGenerator->addInstruction(load);
- }
+ elementSubscript.loadInAccumulator();
+ Instruction::LoadElement load;
+ load.base = elementBase;
+ codegen->bytecodeGenerator->addInstruction(load);
} return;
case QmlScopeObject: {
Instruction::LoadScopeObjectProperty load;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index d51dc29517..83b8731179 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -101,7 +101,7 @@ public:
const QString &sourceCode,
AST::Program *ast,
Module *module,
- CompilationMode mode = GlobalCode);
+ ContextType contextType = ContextType::Global);
public:
class VolatileMemoryLocationScanner;
@@ -172,6 +172,7 @@ public:
}
Q_REQUIRED_RESULT RValue storeOnStack() const;
+ void loadInAccumulator() const;
};
struct Reference {
enum Type {
@@ -197,6 +198,8 @@ public:
Reference &operator =(const Reference &other);
bool operator==(const Reference &other) const;
+ bool operator!=(const Reference &other) const
+ { return !(*this == other); }
bool isValid() const { return type != Invalid; }
bool loadTriggersSideEffect() const {
@@ -322,6 +325,8 @@ public:
Q_REQUIRED_RESULT Reference storeRetainAccumulator() const;
Reference storeConsumeAccumulator() const;
+ Q_REQUIRED_RESULT Reference baseObject() const;
+
bool storeWipesAccumulator() const;
void loadInAccumulator() const;
@@ -464,7 +469,10 @@ protected:
void enterContext(AST::Node *node);
int leaveContext();
-
+public:
+ Context *enterBlock(AST::Node *node);
+ int leaveBlock() { return leaveContext(); }
+protected:
void leaveLoop();
enum UnaryOperation {
@@ -482,6 +490,7 @@ protected:
void addCJump();
+public:
int registerString(const QString &name) {
return jsUnitGenerator->registerString(name);
}
@@ -493,33 +502,35 @@ protected:
// Returns index in _module->functions
virtual int defineFunction(const QString &name, AST::Node *ast,
AST::FormalParameterList *formals,
- AST::SourceElements *body);
+ AST::StatementList *body);
+protected:
void statement(AST::Statement *ast);
void statement(AST::ExpressionNode *ast);
void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
Reference expression(AST::ExpressionNode *ast);
- Result sourceElement(AST::SourceElement *ast);
void accept(AST::Node *node);
- void functionBody(AST::FunctionBody *ast);
void program(AST::Program *ast);
- void sourceElements(AST::SourceElements *ast);
void statementList(AST::StatementList *ast);
- void variableDeclaration(AST::VariableDeclaration *ast);
+ void variableDeclaration(AST::PatternElement *ast);
void variableDeclarationList(AST::VariableDeclarationList *ast);
- Reference referenceForName(const QString &name, bool lhs);
-
- void loadClosure(int index);
+ Reference targetForPatternElement(AST::PatternElement *p);
+ void initializeAndDestructureBindingElement(AST::PatternElement *e, const Reference &baseRef = Reference());
+ void destructurePropertyList(const Reference &object, AST::PatternPropertyList *bindingList);
+ void destructureElementList(const Reference &array, AST::PatternElementList *bindingList);
+ void destructurePattern(AST::Pattern *p, const Reference &rhs);
// Hook provided to implement QML lookup semantics
virtual Reference fallbackNameLookup(const QString &name);
virtual void beginFunctionBodyHook() {}
+ void emitReturn(const Reference &expr);
+
// nodes
bool visit(AST::ArgumentList *ast) override;
bool visit(AST::CaseBlock *ast) override;
@@ -527,16 +538,10 @@ protected:
bool visit(AST::CaseClauses *ast) override;
bool visit(AST::Catch *ast) override;
bool visit(AST::DefaultClause *ast) override;
- bool visit(AST::ElementList *ast) override;
bool visit(AST::Elision *ast) override;
bool visit(AST::Finally *ast) override;
bool visit(AST::FormalParameterList *ast) override;
- bool visit(AST::FunctionBody *ast) override;
bool visit(AST::Program *ast) override;
- bool visit(AST::PropertyNameAndValue *ast) override;
- bool visit(AST::PropertyAssignmentList *ast) override;
- bool visit(AST::PropertyGetterSetter *ast) override;
- bool visit(AST::SourceElements *ast) override;
bool visit(AST::StatementList *ast) override;
bool visit(AST::UiArrayMemberList *ast) override;
bool visit(AST::UiImport *ast) override;
@@ -548,19 +553,25 @@ protected:
bool visit(AST::UiProgram *ast) override;
bool visit(AST::UiQualifiedId *ast) override;
bool visit(AST::UiQualifiedPragmaId *ast) override;
- bool visit(AST::VariableDeclaration *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;
+
// expressions
bool visit(AST::Expression *ast) override;
- bool visit(AST::ArrayLiteral *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;
@@ -569,13 +580,14 @@ protected:
bool visit(AST::NotExpression *ast) override;
bool visit(AST::NullExpression *ast) override;
bool visit(AST::NumericLiteral *ast) override;
- bool visit(AST::ObjectLiteral *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;
@@ -584,10 +596,8 @@ protected:
bool visit(AST::UnaryPlusExpression *ast) override;
bool visit(AST::VoidExpression *ast) override;
bool visit(AST::FunctionDeclaration *ast) override;
-
- // source elements
- bool visit(AST::FunctionSourceElement *ast) override;
- bool visit(AST::StatementSourceElement *ast) override;
+ bool visit(AST::YieldExpression *ast) override;
+ bool visit(AST::ClassExpression *ast) override;
// statements
bool visit(AST::Block *ast) override;
@@ -601,8 +611,6 @@ protected:
bool visit(AST::ForStatement *ast) override;
bool visit(AST::IfStatement *ast) override;
bool visit(AST::LabelledStatement *ast) override;
- bool visit(AST::LocalForEachStatement *ast) override;
- bool visit(AST::LocalForStatement *ast) override;
bool visit(AST::ReturnStatement *ast) override;
bool visit(AST::SwitchStatement *ast) override;
bool visit(AST::ThrowStatement *ast) override;
@@ -631,18 +639,36 @@ public:
Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right);
- struct Arguments { int argc; int argv; };
+ struct Arguments { int argc; int argv; bool hasSpread; };
Arguments pushArgs(AST::ArgumentList *args);
+ void handleCall(Reference &base, Arguments calldata);
+
+ Arguments pushTemplateArgs(AST::TemplateLiteral *args);
+ int createTemplateArray(AST::TemplateLiteral *t);
void setUseFastLookups(bool b) { useFastLookups = b; }
void handleTryCatch(AST::TryStatement *ast);
void handleTryFinally(AST::TryStatement *ast);
+
+ Reference referenceForName(const QString &name, bool lhs);
+
QQmlRefPointer<QV4::CompiledData::CompilationUnit> generateCompilationUnit(bool generateUnitData = true);
static QQmlRefPointer<QV4::CompiledData::CompilationUnit> createUnitForLoading();
Context *currentContext() const { return _context; }
+ BytecodeGenerator *generator() const { return bytecodeGenerator; }
+
+ void loadClosure(int index);
+
+ Module *module() const { return _module; }
+
+ BytecodeGenerator::Label returnLabel() {
+ if (!_returnLabel)
+ _returnLabel = new BytecodeGenerator::Label(bytecodeGenerator->newLabel());
+ return *_returnLabel;
+ }
protected:
friend class ScanFunctions;
@@ -650,16 +676,22 @@ protected:
friend struct ControlFlowCatch;
friend struct ControlFlowFinally;
Result _expr;
- VolatileMemoryLocations _volataleMemoryLocations;
+ VolatileMemoryLocations _volatileMemoryLocations;
Module *_module;
int _returnAddress;
Context *_context;
+ Context *_functionContext = nullptr;
AST::LabelledStatement *_labelledStatement;
QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
BytecodeGenerator *bytecodeGenerator = nullptr;
+ Moth::BytecodeGenerator::Label *_returnLabel = nullptr;
bool _strictMode;
bool useFastLookups = true;
bool requiresReturnValue = false;
+ bool insideSwitch = false;
+ bool inFormalParameterList = false;
+ bool functionEndsWithReturn = false;
+ ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
bool hasError;
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
index 8348613888..1fef4d38f4 100644
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
@@ -92,8 +92,16 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
void CompilationUnitMapper::close()
{
- if (dataPtr != nullptr)
- munmap(dataPtr, length);
+ // Do not unmap the data here.
+ if (dataPtr != nullptr) {
+ // Do not unmap cache files that are built with the StaticData flag. That's the majority of
+ // them and it's necessary to benefit from the QString literal optimization. There might
+ // still be QString instances around that point into that memory area. The memory is backed
+ // on the disk, so the kernel is free to release the pages and all that remains is the
+ // address space allocation.
+ if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
+ munmap(dataPtr, length);
+ }
dataPtr = nullptr;
}
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
index 8b000021f8..3e44d045fc 100644
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp
@@ -90,14 +90,9 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
- const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
- ? PAGE_EXECUTE_READ : PAGE_READONLY;
- const uint viewFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
- ? (FILE_MAP_READ | FILE_MAP_EXECUTE) : FILE_MAP_READ;
-
// Data structure and qt version matched, so now we can access the rest of the file safely.
- HANDLE fileMappingHandle = CreateFileMapping(handle, 0, mappingFlags, 0, 0, 0);
+ HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0);
if (!fileMappingHandle) {
*errorString = qt_error_string(GetLastError());
return nullptr;
@@ -107,7 +102,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
CloseHandle(fileMappingHandle);
});
- dataPtr = MapViewOfFile(fileMappingHandle, viewFlags, 0, 0, 0);
+ dataPtr = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0);
if (!dataPtr) {
*errorString = qt_error_string(GetLastError());
return nullptr;
@@ -118,8 +113,15 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
void CompilationUnitMapper::close()
{
- if (dataPtr != nullptr)
- UnmapViewOfFile(dataPtr);
+ if (dataPtr != nullptr) {
+ // Do not unmap cache files that are built with the StaticData flag. That's the majority of
+ // them and it's necessary to benefit from the QString literal optimization. There might
+ // still be QString instances around that point into that memory area. The memory is backed
+ // on the disk, so the kernel is free to release the pages and all that remains is the
+ // address space allocation.
+ if (!(reinterpret_cast<CompiledData::Unit*>(dataPtr)->flags & CompiledData::Unit::StaticData))
+ UnmapViewOfFile(dataPtr);
+ }
dataPtr = nullptr;
}
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 8dcc068a06..c809d497fd 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -78,26 +78,10 @@ namespace CompiledData {
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");
-#if !defined(V4_BOOTSTRAP)
-static QString cacheFilePath(const QUrl &url)
+CompilationUnit::CompilationUnit(const Unit *unitData)
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString localCachePath = localSourcePath + QLatin1Char('c');
-#ifndef Q_OS_ANDROID
- if (QFile::exists(localCachePath) || QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
- return localCachePath;
-#endif
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+ data = unitData;
}
-#endif
-
-CompilationUnit::CompilationUnit(const Unit *unitData)
- : data(unitData)
-{}
#ifndef V4_BOOTSTRAP
CompilationUnit::~CompilationUnit()
@@ -108,6 +92,17 @@ CompilationUnit::~CompilationUnit()
data = nullptr;
}
+QString CompilationUnit::localCacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
+}
+
QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
{
this->engine = engine;
@@ -157,15 +152,15 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
}
if (data->jsClassTableSize) {
- runtimeClasses = (QV4::InternalClass**)malloc(data->jsClassTableSize * sizeof(QV4::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 *));
for (uint i = 0; i < data->jsClassTableSize; ++i) {
int memberCount = 0;
const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount);
- QV4::InternalClass *klass = engine->internalClasses[QV4::ExecutionEngine::Class_Object];
+ runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object);
for (int j = 0; j < memberCount; ++j, ++member)
- klass = klass->addMember(engine->identifierTable->identifier(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
-
- runtimeClasses[i] = klass;
+ runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->identifier(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data);
}
}
@@ -215,8 +210,6 @@ void CompilationUnit::unlink()
propertyCaches.clear();
- for (int ii = 0; ii < dependentScripts.count(); ++ii)
- dependentScripts.at(ii)->release();
dependentScripts.clear();
typeNameCache = nullptr;
@@ -244,13 +237,31 @@ void CompilationUnit::unlink()
void CompilationUnit::markObjects(QV4::MarkStack *markStack)
{
- for (uint i = 0; i < data->stringTableSize; ++i)
- if (runtimeStrings[i])
- runtimeStrings[i]->mark(markStack);
+ if (runtimeStrings) {
+ for (uint i = 0; i < data->stringTableSize; ++i)
+ if (runtimeStrings[i])
+ runtimeStrings[i]->mark(markStack);
+ }
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
runtimeRegularExpressions[i].mark(markStack);
}
+ if (runtimeClasses) {
+ for (uint i = 0; i < data->jsClassTableSize; ++i)
+ if (runtimeClasses[i])
+ runtimeClasses[i]->mark(markStack);
+ }
+ for (QV4::Function *f : qAsConst(runtimeFunctions))
+ if (f && f->internalClass)
+ f->internalClass->mark(markStack);
+ for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks))
+ if (c)
+ c->mark(markStack);
+
+ if (runtimeLookups) {
+ for (uint i = 0; i < data->lookupTableSize; ++i)
+ runtimeLookups[i].markObjects(markStack);
+ }
}
IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
@@ -344,7 +355,11 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeS
const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourceTimeStamp, errorString);
+ QString cachePath = sourcePath + QLatin1Char('c');
+ if (!QFile::exists(cachePath))
+ cachePath = localCacheFilePath(url);
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString);
if (!mappedUnit)
return false;
@@ -367,7 +382,22 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
runtimeFunctions.resize(data->functionTableSize);
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
- runtimeFunctions[i] = new QV4::Function(engine, this, compiledFunction, &Moth::VME::exec);
+ runtimeFunctions[i] = new QV4::Function(engine, this, compiledFunction);
+ }
+
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope);
+
+ runtimeBlocks.resize(data->blockTableSize);
+ for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
+ const QV4::CompiledData::Block *compiledBlock = data->blockAt(i);
+ ic = engine->internalClasses(EngineBase::Class_CallContext);
+
+ // first locals
+ const quint32_le *localsIndices = compiledBlock->localsTable();
+ for (quint32 i = 0; i < compiledBlock->nLocals; ++i)
+ ic = ic->addMember(engine->identifierTable->identifier(runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
+ runtimeBlocks[i] = ic->d();
}
}
@@ -391,7 +421,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
- const QString outputFileName = cacheFilePath(unitUrl);
+ const QString outputFileName = localCacheFilePath(unitUrl);
#endif
#if QT_CONFIG(temporaryfile)
@@ -476,8 +506,11 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals;
changedSignalParameters << parameters;
- for (; parameters; parameters = parameters->next)
- stringTable.registerString(parameters->name.toString());
+ if (parameters) {
+ const QStringList formals = parameters->formals();
+ for (const QString &arg : formals)
+ stringTable.registerString(arg);
+ }
}
}
@@ -500,14 +533,14 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex];
- for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i);
- parameters; parameters = parameters->next) {
- signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString()));
- function->nFormals = function->nFormals + 1;
- }
+ if (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i)) {
+ const QStringList formals = parameters->formals();
+ for (const QString &arg : formals)
+ signalParameterNameTable.append(stringTable.getStringId(arg));
- // Hack to ensure an activation is created.
- function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval;
+ function->nFormals = formals.size();
+ }
+ function->length = function->nFormals;
signalParameterNameTableOffset += function->nFormals * sizeof(quint32);
}
@@ -626,7 +659,7 @@ QString Binding::valueAsScriptString(const Unit *unit) const
/*!
Returns the property cache, if one alread exists. The cache is not referenced.
*/
-QQmlPropertyCache *ResolvedTypeReference::propertyCache() const
+QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const
{
if (type.isValid())
return typePropertyCache;
@@ -637,7 +670,7 @@ QQmlPropertyCache *ResolvedTypeReference::propertyCache() const
/*!
Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
*/
-QQmlPropertyCache *ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
+QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
{
if (typePropertyCache) {
return typePropertyCache;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 1df9d6794f..08170e1c3b 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -186,32 +186,72 @@ struct JSClass
};
static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+// This data structure is intended to be binary compatible with QStringData/QStaticStringData on
+// 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped
+// from a file must be castable to a QStringData regardless of the pointer size. With the first
+// few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a
+// ptrdiff_t and thus variable in size.
+// On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while
+// on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain
+// the same value.
struct String
{
+ qint32_le refcount; // -1
qint32_le size;
+ quint32_le allocAndCapacityReservedFlag; // 0
+ quint32_le offsetOn32Bit;
+ quint64_le offsetOn64Bit;
// uint16 strdata[]
static int calculateSize(const QString &str) {
- return (sizeof(String) + str.length() * sizeof(quint16) + 7) & ~0x7;
+ return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
}
};
-static_assert(sizeof(String) == 4, "String 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(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
+// Ensure compatibility with QString
+static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
+static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
+static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
+static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
+#if QT_POINTER_SIZE == 8
+static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
+#else
+static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
+#endif
struct CodeOffsetToLine {
quint32_le codeOffset;
quint32_le line;
};
+struct Block
+{
+ quint32_le nLocals;
+ quint32_le localsOffset;
+
+ const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
+
+ static int calculateSize(int nLocals) {
+ int trailingData = nLocals*sizeof (quint32);
+ size_t size = align(align(sizeof(Block)) + size_t(trailingData));
+ Q_ASSERT(size < INT_MAX);
+ return int(size);
+ }
+
+ static size_t align(size_t a) {
+ return (a + 7) & ~size_t(7);
+ }
+};
+
// 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
{
enum Flags : unsigned int {
IsStrict = 0x1,
- HasDirectEval = 0x2,
- UsesArgumentsObject = 0x4,
-// Unused = 0x8,
- HasCatchOrWith = 0x10
+ IsArrowFunction = 0x2,
+ IsGenerator = 0x4
};
// Absolute offset into file where the code for this function is located.
@@ -219,6 +259,7 @@ struct Function
quint32_le codeSize;
quint32_le nameIndex;
+ quint32_le length;
quint32_le nFormals;
quint32_le formalsOffset;
quint32_le nLocals;
@@ -238,16 +279,14 @@ struct Function
quint32_le dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End
-// quint32 formalsIndex[nFormals]
-// quint32 localsIndex[nLocals]
-// quint32 offsetForInnerFunctions[nInnerFunctions]
-// Function[nInnerFunctions]
-
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
quint16_le padding2;
+ // quint32 formalsIndex[nFormals]
+ // quint32 localsIndex[nLocals]
+
const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(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); }
@@ -260,7 +299,7 @@ struct Function
const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
// ---
- const uchar *code() const { return reinterpret_cast<const uchar *>(this) + codeOffset; }
+ const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@@ -276,7 +315,7 @@ struct Function
return (a + 7) & ~size_t(7);
}
};
-static_assert(sizeof(Function) == 76, "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) == 80, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
// Qml data structures
@@ -701,14 +740,15 @@ struct Unit
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10, // .pragma shared?
- ContainsMachineCode = 0x20, // used to determine if we need to mmap with execute permissions
- PendingTypeCompilation = 0x40 // the QML data structures present are incomplete and require type compilation
+ PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
};
quint32_le flags;
quint32_le stringTableSize;
quint32_le offsetToStringTable;
quint32_le functionTableSize;
quint32_le offsetToFunctionTable;
+ quint32_le blockTableSize;
+ quint32_le offsetToBlockTable;
quint32_le lookupTableSize;
quint32_le offsetToLookupTable;
quint32_le regexpTableSize;
@@ -753,11 +793,11 @@ struct Unit
if (str->size == 0)
return QString();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ if (flags & StaticData) {
+ const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) };
+ return QString(holder);
+ }
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
- // Too risky to do this while we unmap disk backed compilation but keep pointers to string
- // data in the identifier tables.
- // if (flags & StaticData)
- // return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
#else
const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
@@ -770,6 +810,7 @@ struct Unit
}
const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+ const quint32_le *blockOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToBlockTable); }
const Function *functionAt(int idx) const {
const quint32_le *offsetTable = functionOffsetTable();
@@ -777,6 +818,12 @@ struct Unit
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
+ const Block *blockAt(int idx) const {
+ const quint32_le *offsetTable = blockOffsetTable();
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Block *>(reinterpret_cast<const char *>(this) + offset);
+ }
+
const Lookup *lookupTable() const { return reinterpret_cast<const Lookup*>(reinterpret_cast<const char *>(this) + offsetToLookupTable); }
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
@@ -795,7 +842,7 @@ struct Unit
}
};
-static_assert(sizeof(Unit) == 192, "Unit 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(Unit) == 200, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct TypeReference
{
@@ -832,9 +879,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
if (prop->type >= QV4::CompiledData::Property::Custom) {
- // ### FIXME: We could report the more accurate location here by using prop->location, but the old
- // compiler can't and the tests expect it to be the object location right now.
- TypeReference &r = this->add(prop->customTypeNameIndex, obj->location);
+ TypeReference &r = this->add(prop->customTypeNameIndex, prop->location);
r.errorWhenNotFound = true;
}
}
@@ -881,6 +926,8 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase
QV4::Heap::String **runtimeStrings = nullptr; // Array
const Value* constants = nullptr;
QV4::Value *runtimeRegularExpressions = nullptr;
+ const Unit *data = nullptr;
+ QV4::Heap::InternalClass **runtimeClasses = nullptr;
};
Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
@@ -915,8 +962,6 @@ public:
return refCount.load();
}
- const Unit *data = nullptr;
-
// Called only when building QML, when we build the header for JS first and append QML data
QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
@@ -943,14 +988,14 @@ public:
}
QV4::Lookup *runtimeLookups = nullptr;
- QV4::InternalClass **runtimeClasses = nullptr;
QVector<QV4::Function *> runtimeFunctions;
+ QVector<QV4::Heap::InternalClass *> runtimeBlocks;
mutable QQmlNullableValue<QUrl> m_url;
mutable QQmlNullableValue<QUrl> m_finalUrl;
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
- QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
+ QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
@@ -970,7 +1015,7 @@ public:
int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
int totalObjectCount = 0; // Number of objects explicitly instantiated
- QVector<QQmlScriptData *> dependentScripts;
+ QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
ResolvedTypeReferenceMap resolvedTypes;
bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const;
@@ -1010,6 +1055,8 @@ public:
bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
+ static QString localCacheFilePath(const QUrl &url);
+
protected:
void linkBackendToEngine(QV4::ExecutionEngine *engine);
#endif // V4_BOOTSTRAP
@@ -1046,8 +1093,8 @@ struct ResolvedTypeReference
// therefore cannot have a property cache installed when instantiated.
bool isFullyDynamicType;
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+ QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
+ QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
void doDynamicTypeCheck();
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index c9e535c93f..d5a02a3ac8 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -90,7 +90,11 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
const QString &qstr = strings.at(i);
QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
+ s->refcount = -1;
s->size = qstr.length();
+ s->allocAndCapacityReservedFlag = 0;
+ s->offsetOn32Bit = sizeof(QV4::CompiledData::String);
+ s->offsetOn64Bit = sizeof(QV4::CompiledData::String);
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
memcpy(s + 1, qstr.constData(), qstr.length()*sizeof(ushort));
#else
@@ -98,6 +102,7 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
for (int i = 0; i < qstr.length(); ++i)
uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
#endif
+ reinterpret_cast<ushort *>(s + 1)[s->size] = 0;
stringData += QV4::CompiledData::String::calculateSize(qstr);
}
@@ -183,7 +188,7 @@ QV4::ReturnedValue QV4::Compiler::JSUnitGenerator::constant(int idx)
return constants.at(idx);
}
-int QV4::Compiler::JSUnitGenerator::registerJSClass(const QVector<MemberInfo> &members)
+int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members)
{
// ### re-use existing class definitions.
@@ -197,31 +202,15 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(const QVector<MemberInfo> &m
jsClass->nMembers = members.size();
CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
- for (const MemberInfo &memberInfo : members) {
- member->nameOffset = registerString(memberInfo.name);
- member->isAccessor = memberInfo.isAccessor;
+ for (const auto &name : members) {
+ member->nameOffset = registerString(name);
+ member->isAccessor = false;
++member;
}
return jsClassOffsets.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, CompiledData::JSClassMember *members)
-{
- const int size = CompiledData::JSClass::calculateSize(count);
- jsClassOffsets.append(jsClassData.size());
- const int oldSize = jsClassData.size();
- jsClassData.resize(jsClassData.size() + size);
- memset(jsClassData.data() + oldSize, 0, size);
-
- CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
- jsClass->nMembers = count;
- CompiledData::JSClassMember *jsClassMembers = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
- memcpy(jsClassMembers, members, sizeof(CompiledData::JSClassMember)*count);
-
- return jsClassOffsets.size() - 1;
-}
-
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
registerString(module->fileName);
@@ -233,28 +222,39 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
for (int i = 0; i < f->locals.size(); ++i)
registerString(f->locals.at(i));
}
+ for (Context *c : qAsConst(module->blocks)) {
+ for (int i = 0; i < c->locals.size(); ++i)
+ registerString(c->locals.at(i));
+ }
- Q_ALLOCA_VAR(quint32_le, functionOffsets, module->functions.size() * sizeof(quint32_le));
+ Q_ALLOCA_VAR(quint32_le, blockAndFunctionOffsets, (module->functions.size() + module->blocks.size()) * sizeof(quint32_le));
uint jsClassDataOffset = 0;
char *dataPtr;
CompiledData::Unit *unit;
{
- QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset);
+ QV4::CompiledData::Unit tempHeader = generateHeader(option, blockAndFunctionOffsets, &jsClassDataOffset);
dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
memset(dataPtr, 0, tempHeader.unitSize);
memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
memcpy(unit, &tempHeader, sizeof(tempHeader));
}
- memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(quint32_le));
+ memcpy(dataPtr + unit->offsetToFunctionTable, blockAndFunctionOffsets, unit->functionTableSize * sizeof(quint32_le));
+ memcpy(dataPtr + unit->offsetToBlockTable, blockAndFunctionOffsets + unit->functionTableSize, unit->blockTableSize * sizeof(quint32_le));
for (int i = 0; i < module->functions.size(); ++i) {
Context *function = module->functions.at(i);
if (function == module->rootContext)
unit->indexOfRootFunction = i;
- writeFunction(dataPtr + functionOffsets[i], function);
+ writeFunction(dataPtr + blockAndFunctionOffsets[i], function);
+ }
+
+ for (int i = 0; i < module->blocks.size(); ++i) {
+ Context *block = module->blocks.at(i);
+
+ writeBlock(dataPtr + blockAndFunctionOffsets[i + module->functions.size()], block);
}
CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
@@ -300,17 +300,16 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
- if (irFunction->hasDirectEval)
- function->flags |= CompiledData::Function::HasDirectEval;
- if (irFunction->usesArgumentsObject)
- function->flags |= CompiledData::Function::UsesArgumentsObject;
if (irFunction->isStrict)
function->flags |= CompiledData::Function::IsStrict;
- if (irFunction->hasTry || irFunction->hasWith)
- function->flags |= CompiledData::Function::HasCatchOrWith;
+ if (irFunction->isArrowFunction)
+ function->flags |= CompiledData::Function::IsArrowFunction;
+ if (irFunction->isGenerator)
+ function->flags |= CompiledData::Function::IsGenerator;
function->nestedFunctionIndex =
irFunction->returnsClosure ? quint32(module->functions.indexOf(irFunction->nestedContexts.first()))
: std::numeric_limits<uint32_t>::max();
+ function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -324,7 +323,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nRegisters = irFunction->registerCount;
+ function->nRegisters = irFunction->registerCountInFunction;
function->nDependingIdObjects = 0;
function->nDependingContextProperties = 0;
@@ -390,7 +389,32 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size());
}
-QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, quint32_le *functionOffsets, uint *jsClassDataOffset)
+void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context *irBlock) const
+{
+ QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
+
+ quint32 currentOffset = sizeof(QV4::CompiledData::Block);
+ currentOffset = (currentOffset + 7) & ~quint32(0x7);
+
+ block->nLocals = irBlock->locals.size();
+ block->localsOffset = currentOffset;
+ currentOffset += block->nLocals * sizeof(quint32);
+
+ // write locals
+ quint32_le *locals = (quint32_le *)(b + block->localsOffset);
+ for (int i = 0; i < irBlock->locals.size(); ++i)
+ locals[i] = getStringId(irBlock->locals.at(i));
+
+ static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
+ if (showCode) {
+ qDebug() << "=== Variables for block" << irBlock->blockIndex;
+ for (int i = 0; i < irBlock->locals.size(); ++i)
+ qDebug() << " " << i << ":" << locals[i];
+ qDebug();
+ }
+}
+
+QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, quint32_le *blockAndFunctionOffsets, uint *jsClassDataOffset)
{
CompiledData::Unit unit;
memset(&unit, 0, sizeof(unit));
@@ -409,6 +433,10 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.offsetToFunctionTable = nextOffset;
nextOffset += unit.functionTableSize * sizeof(uint);
+ unit.blockTableSize = module->blocks.size();
+ unit.offsetToBlockTable = nextOffset;
+ nextOffset += unit.blockTableSize * sizeof(uint);
+
unit.lookupTableSize = lookups.count();
unit.offsetToLookupTable = nextOffset;
nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
@@ -435,13 +463,21 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
for (int i = 0; i < module->functions.size(); ++i) {
Context *f = module->functions.at(i);
- functionOffsets[i] = nextOffset;
+ blockAndFunctionOffsets[i] = nextOffset;
const int qmlIdDepsCount = f->idObjectDependencies.count();
const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
nextOffset += QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(),
qmlIdDepsCount, qmlPropertyDepsCount, f->code.size());
}
+ blockAndFunctionOffsets += module->functions.size();
+
+ for (int i = 0; i < module->blocks.size(); ++i) {
+ Context *c = module->blocks.at(i);
+ blockAndFunctionOffsets[i] = nextOffset;
+
+ nextOffset += QV4::CompiledData::Block::calculateSize(c->locals.size());
+ }
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 360af6540f..c40d49213a 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -116,8 +116,7 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
int registerConstant(ReturnedValue v);
ReturnedValue constant(int idx);
- int registerJSClass(const QVector<MemberInfo> &members);
- int registerJSClass(int count, CompiledData::JSClassMember *members);
+ int registerJSClass(const QStringList &members);
enum GeneratorOption {
GenerateWithStringTable,
@@ -125,8 +124,8 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
};
QV4::CompiledData::Unit *generateUnit(GeneratorOption option = GenerateWithStringTable);
- // Returns bytes written
void writeFunction(char *f, Context *irFunction) const;
+ void writeBlock(char *f, Context *irBlock) const;
StringTableGenerator stringTable;
QString codeGeneratorName;
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 0a9d3d8efe..bd9d19f491 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -39,6 +39,7 @@
#include "qv4compilercontext_p.h"
#include "qv4compilercontrolflow_p.h"
+#include "qv4bytecodegenerator_p.h"
QT_USE_NAMESPACE
using namespace QV4;
@@ -47,11 +48,11 @@ using namespace QQmlJS::AST;
QT_BEGIN_NAMESPACE
-Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode)
+Context *Module::newContext(Node *node, Context *parent, ContextType contextType)
{
Q_ASSERT(!contextMap.contains(node));
- Context *c = new Context(parent, compilationMode);
+ Context *c = new Context(parent, contextType);
if (node) {
SourceLocation loc = node->firstSourceLocation();
c->line = loc.startLine;
@@ -70,15 +71,249 @@ Context *Module::newContext(Node *node, Context *parent, CompilationMode compila
return c;
}
-bool Context::forceLookupByName()
+bool Context::addLocalVar(const QString &name, Context::MemberType type, VariableScope scope, FunctionExpression *function)
{
- ControlFlow *flow = controlFlow;
- while (flow) {
- if (flow->needsLookupByName)
+ // ### can this happen?
+ if (name.isEmpty())
+ return true;
+
+ if (type != FunctionDefinition) {
+ if (formals && formals->containsName(name))
+ return (scope == VariableScope::Var);
+ }
+ if (!isCatchBlock || name != caughtVariable) {
+ MemberMap::iterator it = members.find(name);
+ if (it != members.end()) {
+ if (scope != VariableScope::Var || (*it).scope != VariableScope::Var)
+ return false;
+ if ((*it).type <= type) {
+ (*it).type = type;
+ (*it).function = function;
+ }
return true;
- flow = flow->parent;
+ }
+ }
+
+ // hoist var declarations to the function level
+ if (contextType == ContextType::Block && (scope == VariableScope::Var && type != MemberType::FunctionDefinition))
+ return parent->addLocalVar(name, type, scope, function);
+
+ Member m;
+ m.type = type;
+ m.function = function;
+ m.scope = scope;
+ members.insert(name, m);
+ return true;
+}
+
+Context::ResolvedName Context::resolveName(const QString &name)
+{
+ int scope = 0;
+ Context *c = this;
+
+ ResolvedName result;
+
+ while (c) {
+ if (c->isWithBlock)
+ return result;
+
+ Context::Member m = c->findMember(name);
+ if (!c->parent && m.index < 0)
+ break;
+
+ if (m.type != Context::UndefinedMember) {
+ result.type = m.canEscape ? ResolvedName::Local : ResolvedName::Stack;
+ result.scope = scope;
+ result.index = m.index;
+ if (c->isStrict && (name == QLatin1String("arguments") || name == QLatin1String("eval")))
+ result.isArgOrEval = true;
+ return result;
+ }
+ const int argIdx = c->findArgument(name);
+ if (argIdx != -1) {
+ if (c->argumentsCanEscape) {
+ result.index = argIdx + c->locals.size();
+ result.scope = scope;
+ result.type = ResolvedName::Local;
+ return result;
+ } else {
+ result.index = argIdx + sizeof(CallData)/sizeof(Value) - 1;
+ result.scope = 0;
+ result.type = ResolvedName::Stack;
+ return result;
+ }
+ }
+ if (c->hasDirectEval) {
+ Q_ASSERT(!c->isStrict && c->contextType != ContextType::Block);
+ return result;
+ }
+
+ if (c->requiresExecutionContext)
+ ++scope;
+ c = c->parent;
+ }
+
+ // ### can we relax the restrictions here?
+ if (contextType == ContextType::Eval || c->contextType == ContextType::Binding)
+ return result;
+
+ result.type = ResolvedName::Global;
+ return result;
+}
+
+void Context::emitBlockHeader(Codegen *codegen)
+{
+ using Instruction = Moth::Instruction;
+ Moth::BytecodeGenerator *bytecodeGenerator = codegen->generator();
+
+ setupFunctionIndices(bytecodeGenerator);
+
+ if (requiresExecutionContext) {
+ if (blockIndex < 0) {
+ codegen->module()->blocks.append(this);
+ blockIndex = codegen->module()->blocks.count() - 1;
+ }
+
+ if (contextType == ContextType::Global) {
+ Instruction::PushScriptContext scriptContext;
+ scriptContext.index = blockIndex;
+ bytecodeGenerator->addInstruction(scriptContext);
+ } else if (contextType == ContextType::Block || (contextType == ContextType::Eval && !isStrict)) {
+ if (isCatchBlock) {
+ Instruction::PushCatchContext catchContext;
+ catchContext.index = blockIndex;
+ catchContext.name = codegen->registerString(caughtVariable);
+ bytecodeGenerator->addInstruction(catchContext);
+ } else {
+ Instruction::PushBlockContext blockContext;
+ blockContext.index = blockIndex;
+ bytecodeGenerator->addInstruction(blockContext);
+ }
+ } else {
+ Instruction::CreateCallContext createContext;
+ bytecodeGenerator->addInstruction(createContext);
+ }
+ }
+
+ if (usesThis) {
+ Q_ASSERT(!isStrict);
+ // make sure we convert this to an object
+ Instruction::ConvertThisToObject convert;
+ bytecodeGenerator->addInstruction(convert);
+ }
+
+ if (contextType == ContextType::Global || (contextType == ContextType::Eval && !isStrict)) {
+ // variables in global code are properties of the global context object, not locals as with other functions.
+ for (Context::MemberMap::const_iterator it = members.constBegin(), cend = members.constEnd(); it != cend; ++it) {
+ if (it->isLexicallyScoped())
+ continue;
+ const QString &local = it.key();
+
+ Instruction::DeclareVar declareVar;
+ declareVar.isDeletable = (contextType == ContextType::Eval);
+ declareVar.varName = codegen->registerString(local);
+ bytecodeGenerator->addInstruction(declareVar);
+ }
+ }
+
+ if (contextType == ContextType::Function || contextType == ContextType::Binding) {
+ for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) {
+ if (it->canEscape && it->type == Context::ThisFunctionName) {
+ // move the function from the stack to the call context
+ Instruction::LoadReg load;
+ load.reg = CallData::Function;
+ bytecodeGenerator->addInstruction(load);
+ Instruction::StoreLocal store;
+ store.index = it->index;
+ bytecodeGenerator->addInstruction(store);
+ }
+ }
+ }
+
+ if (usesArgumentsObject == Context::ArgumentsObjectUsed) {
+ Q_ASSERT(contextType != ContextType::Block);
+ if (isStrict || (formals && !formals->isSimpleParameterList())) {
+ Instruction::CreateUnmappedArgumentsObject setup;
+ bytecodeGenerator->addInstruction(setup);
+ } else {
+ Instruction::CreateMappedArgumentsObject setup;
+ bytecodeGenerator->addInstruction(setup);
+ }
+ codegen->referenceForName(QStringLiteral("arguments"), false).storeConsumeAccumulator();
+ }
+
+ for (const Context::Member &member : qAsConst(members)) {
+ if (member.function) {
+ const int function = codegen->defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body);
+ codegen->loadClosure(function);
+ Codegen::Reference r = codegen->referenceForName(member.function->name.toString(), true);
+ r.storeConsumeAccumulator();
+ }
+ }
+}
+
+void Context::emitBlockFooter(Codegen *codegen)
+{
+ using Instruction = Moth::Instruction;
+ Moth::BytecodeGenerator *bytecodeGenerator = codegen->generator();
+
+ if (!requiresExecutionContext)
+ return;
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty structs.
+ if (contextType == ContextType::Global)
+ bytecodeGenerator->addInstruction(Instruction::PopScriptContext());
+ else
+ bytecodeGenerator->addInstruction(Instruction::PopContext());
+QT_WARNING_POP
+}
+
+void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
+{
+ if (registerOffset != -1) {
+ // already computed, check for consistency
+ Q_ASSERT(registerOffset == bytecodeGenerator->currentRegister());
+ bytecodeGenerator->newRegisterArray(nRegisters);
+ return;
+ }
+ Q_ASSERT(locals.size() == 0);
+ Q_ASSERT(nRegisters == 0);
+ registerOffset = bytecodeGenerator->currentRegister();
+
+ switch (contextType) {
+ case ContextType::Block:
+ case ContextType::Function:
+ case ContextType::Binding: {
+ for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) {
+ const QString &local = it.key();
+ if (it->canEscape) {
+ it->index = locals.size();
+ locals.append(local);
+ } else {
+ if (it->type == Context::ThisFunctionName)
+ it->index = CallData::Function;
+ else
+ it->index = bytecodeGenerator->newRegister();
+ }
+ }
+ break;
+ }
+ case ContextType::Global:
+ case ContextType::Eval:
+ for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) {
+ if (!it->isLexicallyScoped() && (contextType == ContextType::Global || !isStrict))
+ continue;
+ if (it->canEscape) {
+ it->index = locals.size();
+ locals.append(it.key());
+ } else {
+ it->index = bytecodeGenerator->newRegister();
+ }
+ }
+ break;
}
- return false;
+ nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 455a76c729..070be7573a 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -66,14 +66,15 @@ namespace Compiler {
struct ControlFlow;
-enum CompilationMode {
- GlobalCode,
- EvalCode,
- FunctionCode,
- QmlBinding // This is almost the same as EvalCode, except:
+enum class ContextType {
+ Global,
+ Function,
+ Eval,
+ Binding, // This is almost the same as Eval, except:
// * function declarations are moved to the return address when encountered
// * return statements are allowed everywhere (like in FunctionCode)
// * variable declarations are treated as true locals (like in FunctionCode)
+ Block
};
struct Context;
@@ -86,10 +87,11 @@ struct Module {
qDeleteAll(contextMap);
}
- Context *newContext(QQmlJS::AST::Node *node, Context *parent, CompilationMode compilationMode);
+ Context *newContext(QQmlJS::AST::Node *node, Context *parent, ContextType compilationMode);
QHash<QQmlJS::AST::Node *, Context *> contextMap;
QList<Context *> functions;
+ QList<Context *> blocks;
Context *rootContext;
QString fileName;
QString finalUrl;
@@ -104,8 +106,9 @@ struct Context {
QString name;
int line = 0;
int column = 0;
- int registerCount = 0;
+ int registerCountInFunction = 0;
int functionIndex = -1;
+ int blockIndex = -1;
enum MemberType {
UndefinedMember,
@@ -118,11 +121,11 @@ struct Context {
struct Member {
MemberType type = UndefinedMember;
int index = -1;
- QQmlJS::AST::VariableDeclaration::VariableScope scope = QQmlJS::AST::VariableDeclaration::FunctionScope;
+ QQmlJS::AST::VariableScope scope = QQmlJS::AST::VariableScope::Var;
mutable bool canEscape = false;
QQmlJS::AST::FunctionExpression *function = nullptr;
- bool isLexicallyScoped() const { return this->scope != QQmlJS::AST::VariableDeclaration::FunctionScope; }
+ bool isLexicallyScoped() const { return this->scope != QQmlJS::AST::VariableScope::Var; }
};
typedef QMap<QString, Member> MemberMap;
@@ -137,15 +140,22 @@ struct Context {
QByteArray code;
QVector<CompiledData::CodeOffsetToLine> lineNumberMapping;
- int maxNumberOfArguments = 0;
+ int nRegisters = 0;
+ int registerOffset = -1;
bool hasDirectEval = false;
+ bool allVarsEscape = false;
bool hasNestedFunctions = false;
bool isStrict = false;
+ bool isArrowFunction = false;
+ bool isGenerator = false;
bool usesThis = false;
bool hasTry = false;
- bool hasWith = false;
bool returnsClosure = false;
mutable bool argumentsCanEscape = false;
+ bool requiresExecutionContext = false;
+ bool isWithBlock = false;
+ bool isCatchBlock = false;
+ QString caughtVariable;
enum UsesArgumentsObject {
ArgumentsObjectUnknown,
@@ -155,7 +165,7 @@ struct Context {
UsesArgumentsObject usesArgumentsObject = ArgumentsObjectUnknown;
- CompilationMode compilationMode;
+ ContextType contextType;
template <typename T>
class SmallSet: public QVarLengthArray<T, 8>
@@ -204,24 +214,14 @@ struct Context {
PropertyDependencyMap contextObjectPropertyDependencies;
PropertyDependencyMap scopeObjectPropertyDependencies;
- Context(Context *parent, CompilationMode mode)
+ Context(Context *parent, ContextType type)
: parent(parent)
- , compilationMode(mode)
+ , contextType(type)
{
if (parent && parent->isStrict)
isStrict = true;
}
- bool forceLookupByName();
-
-
- bool canUseSimpleCall() const {
- return nestedContexts.isEmpty() &&
- locals.isEmpty() &&
- !hasTry && !hasWith &&
- (usesArgumentsObject == ArgumentsObjectNotUsed || isStrict) && !hasDirectEval;
- }
-
int findArgument(const QString &name)
{
// search backwards to handle duplicate argument names correctly
@@ -253,37 +253,36 @@ struct Context {
return true;
}
+ bool requiresImplicitReturnValue() const {
+ return contextType == ContextType::Binding ||
+ contextType == ContextType::Eval ||
+ contextType == ContextType::Global;
+ }
+
void addUsedVariable(const QString &name) {
usedVariables.insert(name);
}
- bool addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr)
- {
- if (name.isEmpty())
- return true;
+ bool addLocalVar(const QString &name, MemberType contextType, QQmlJS::AST::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr);
+
+ struct ResolvedName {
+ enum Type {
+ Unresolved,
+ Global,
+ Local,
+ Stack
+ };
+ Type type = Unresolved;
+ bool isArgOrEval = false;
+ int scope = -1;
+ int index = -1;
+ bool isValid() const { return type != Unresolved; }
+ };
+ ResolvedName resolveName(const QString &name);
+ void emitBlockHeader(Compiler::Codegen *codegen);
+ void emitBlockFooter(Compiler::Codegen *codegen);
- if (type != FunctionDefinition) {
- for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next)
- if (it->name == name)
- return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope);
- }
- MemberMap::iterator it = members.find(name);
- if (it != members.end()) {
- if (scope != QQmlJS::AST::VariableDeclaration::FunctionScope || (*it).scope != QQmlJS::AST::VariableDeclaration::FunctionScope)
- return false;
- if ((*it).type <= type) {
- (*it).type = type;
- (*it).function = function;
- }
- return true;
- }
- Member m;
- m.type = type;
- m.function = function;
- m.scope = scope;
- members.insert(name, m);
- return true;
- }
+ void setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator);
};
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 9bda20905a..1ef290ea56 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -53,6 +53,7 @@
#include <private/qv4global_p.h>
#include <private/qv4codegen_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qv4bytecodegenerator_p.h>
QT_BEGIN_NAMESPACE
@@ -68,117 +69,84 @@ struct ControlFlow {
enum Type {
Loop,
With,
+ Block,
Finally,
Catch
};
- enum HandlerType {
- Invalid,
+ enum UnwindType {
Break,
Continue,
- Return,
- Throw
+ Return
};
- struct Handler {
- HandlerType type;
- QString label;
+ struct UnwindTarget {
BytecodeGenerator::Label linkLabel;
- int tempIndex;
- int value;
+ int unwindLevel;
};
Codegen *cg;
ControlFlow *parent;
Type type;
- bool needsLookupByName = false;
ControlFlow(Codegen *cg, Type type)
- : cg(cg), parent(cg->_context->controlFlow), type(type)
+ : cg(cg), parent(cg->controlFlow), type(type)
{
- cg->_context->controlFlow = this;
+ cg->controlFlow = this;
}
virtual ~ControlFlow() {
- cg->_context->controlFlow = parent;
+ cg->controlFlow = parent;
}
- void emitReturnStatement() const {
- if (cg->_returnAddress >= 0) {
- Instruction::LoadReg load;
- load.reg = Moth::StackSlot::createRegister(cg->_returnAddress);
- generator()->addInstruction(load);
+ UnwindTarget unwindTarget(UnwindType type, const QString &label = QString())
+ {
+ Q_ASSERT(type == Break || type == Continue || type == Return);
+ ControlFlow *flow = this;
+ int level = 0;
+ while (flow) {
+ BytecodeGenerator::Label l = flow->getUnwindTarget(type, label);
+ if (l.isValid())
+ return UnwindTarget{l, level};
+ if (flow->requiresUnwind())
+ ++level;
+ flow = flow->parent;
}
- Instruction::Ret ret;
- cg->bytecodeGenerator->addInstruction(ret);
+ if (type == Return)
+ return UnwindTarget{ cg->returnLabel(), level };
+ return UnwindTarget();
}
- void jumpToHandler(const Handler &h) {
- if (h.linkLabel.isReturn()) {
- emitReturnStatement();
- } else {
- if (h.tempIndex >= 0)
- Reference::storeConstOnStack(cg, QV4::Encode(h.value), h.tempIndex);
- cg->bytecodeGenerator->jump().link(h.linkLabel);
- }
- }
+ virtual QString label() const { return QString(); }
- bool returnRequiresUnwind() const {
- const ControlFlow *f = this;
- while (f) {
- if (f->type == Finally)
+ bool hasLoop() const {
+ const ControlFlow *flow = this;
+ while (flow) {
+ if (flow->type == Loop)
return true;
- f = f->parent;
+ flow = flow->parent;
}
return false;
}
- virtual QString label() const { return QString(); }
-
- bool isSimple() const {
- return type == Loop;
+protected:
+ virtual BytecodeGenerator::Label getUnwindTarget(UnwindType, const QString & = QString()) {
+ return BytecodeGenerator::Label();
}
-
- Handler getParentHandler(HandlerType type, const QString &label = QString()) {
- if (parent)
- return parent->getHandler(type, label);
- switch (type) {
- case Break:
- case Continue:
- return { Invalid, QString(), {}, -1, 0 };
- case Return:
- case Throw:
- return { type, QString(), BytecodeGenerator::Label::returnLabel(), -1, 0 };
- case Invalid:
- break;
- }
- Q_ASSERT(false);
- Q_UNREACHABLE();
+ virtual bool requiresUnwind() {
+ return false;
}
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) = 0;
-
- BytecodeGenerator::ExceptionHandler *parentExceptionHandler() {
- return parent ? parent->exceptionHandler() : nullptr;
+public:
+ BytecodeGenerator::ExceptionHandler *parentUnwindHandler() {
+ return parent ? parent->unwindHandler() : nullptr;
}
- virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
- return parentExceptionHandler();
+ virtual BytecodeGenerator::ExceptionHandler *unwindHandler() {
+ return parentUnwindHandler();
}
- virtual void handleThrow(const Reference &expr) {
- Reference e = expr;
- Handler h = getHandler(ControlFlow::Throw);
- if (h.tempIndex >= 0) {
- e = e.storeOnStack();
- Reference::storeConstOnStack(cg, QV4::Encode(h.value), h.tempIndex);
- }
- e.loadInAccumulator();
- Instruction::ThrowException instr;
- generator()->addInstruction(instr);
- }
-
protected:
QString loopLabel() const {
QString label;
@@ -193,136 +161,145 @@ protected:
}
};
-struct ControlFlowLoop : public ControlFlow
+struct ControlFlowUnwind : public ControlFlow
{
- QString loopLabel;
- BytecodeGenerator::Label *breakLabel = nullptr;
- BytecodeGenerator::Label *continueLabel = nullptr;
+ BytecodeGenerator::ExceptionHandler unwindLabel;
- ControlFlowLoop(Codegen *cg, BytecodeGenerator::Label *breakLabel, BytecodeGenerator::Label *continueLabel = nullptr)
- : ControlFlow(cg, Loop), loopLabel(ControlFlow::loopLabel()), breakLabel(breakLabel), continueLabel(continueLabel)
+ ControlFlowUnwind(Codegen *cg, Type type)
+ : ControlFlow(cg, type)
{
}
- virtual QString label() const { return loopLabel; }
+ void setupUnwindHandler()
+ {
+ unwindLabel = generator()->newExceptionHandler();
+ }
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) {
- switch (type) {
- case Break:
- if (breakLabel && (label.isEmpty() || label == loopLabel))
- return { type, loopLabel, *breakLabel, -1, 0 };
- break;
- case Continue:
- if (continueLabel && (label.isEmpty() || label == loopLabel))
- return { type, loopLabel, *continueLabel, -1, 0 };
- break;
- case Return:
- case Throw:
- break;
- case Invalid:
- Q_ASSERT(false);
- Q_UNREACHABLE();
- }
- return getParentHandler(type, label);
+ void emitUnwindHandler()
+ {
+ Q_ASSERT(requiresUnwind());
+
+ Instruction::UnwindDispatch dispatch;
+ generator()->addInstruction(dispatch);
}
+ virtual BytecodeGenerator::ExceptionHandler *unwindHandler() override {
+ return unwindLabel.isValid() ? &unwindLabel : parentUnwindHandler();
+ }
};
-struct ControlFlowUnwind : public ControlFlow
+struct ControlFlowLoop : public ControlFlowUnwind
{
- BytecodeGenerator::ExceptionHandler unwindLabel;
- int controlFlowTemp;
- QVector<Handler> handlers;
+ QString loopLabel;
+ BytecodeGenerator::Label *breakLabel = nullptr;
+ BytecodeGenerator::Label *continueLabel = nullptr;
+ bool _requiresUnwind;
- ControlFlowUnwind(Codegen *cg, Type type)
- : ControlFlow(cg, type), unwindLabel(generator()->newExceptionHandler())
+ ControlFlowLoop(Codegen *cg, BytecodeGenerator::Label *breakLabel, BytecodeGenerator::Label *continueLabel = nullptr, bool requiresUnwind = false)
+ : ControlFlowUnwind(cg, Loop), loopLabel(ControlFlow::loopLabel()), breakLabel(breakLabel), continueLabel(continueLabel), _requiresUnwind(requiresUnwind)
{
- Q_ASSERT(type != Loop);
- controlFlowTemp = static_cast<int>(generator()->newRegister());
- Reference::storeConstOnStack(cg, QV4::Encode::undefined(), controlFlowTemp);
- // we'll need at least a handler for throw
- getHandler(Throw);
+ if (_requiresUnwind) {
+ setupUnwindHandler();
+ generator()->setUnwindHandler(&unwindLabel);
+ }
}
- void emitUnwindHandler()
- {
- Q_ASSERT(!isSimple());
-
- Reference temp = Reference::fromStackSlot(cg, controlFlowTemp);
- for (const auto &h : qAsConst(handlers)) {
- Handler parentHandler = getParentHandler(h.type, h.label);
-
- if (h.type == Throw || parentHandler.tempIndex >= 0) {
- BytecodeGenerator::Label skip = generator()->newLabel();
- generator()->jumpStrictNotEqualStackSlotInt(temp.stackSlot(), h.value).link(skip);
- if (h.type == Throw)
- emitForThrowHandling();
- jumpToHandler(parentHandler);
- skip.link();
- } else {
- if (parentHandler.linkLabel.isReturn()) {
- BytecodeGenerator::Label skip = generator()->newLabel();
- generator()->jumpStrictNotEqualStackSlotInt(temp.stackSlot(), h.value).link(skip);
- emitReturnStatement();
- skip.link();
- } else {
- generator()->jumpStrictEqualStackSlotInt(temp.stackSlot(), h.value).link(parentHandler.linkLabel);
- }
- }
+ ~ControlFlowLoop() {
+ if (_requiresUnwind) {
+ unwindLabel.link();
+ generator()->setUnwindHandler(parentUnwindHandler());
+ emitUnwindHandler();
}
}
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) {
- for (const auto &h : qAsConst(handlers)) {
- if (h.type == type && h.label == label)
- return h;
- }
- Handler h = {
- type,
- label,
- unwindLabel,
- controlFlowTemp,
- handlers.size()
- };
- handlers.append(h);
- return h;
+ bool requiresUnwind() override {
+ return _requiresUnwind;
}
- virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
- return &unwindLabel;
+ BytecodeGenerator::Label getUnwindTarget(UnwindType type, const QString &label) override {
+ switch (type) {
+ case Break:
+ if (breakLabel && (label.isEmpty() || label == loopLabel))
+ return *breakLabel;
+ break;
+ case Continue:
+ if (continueLabel && (label.isEmpty() || label == loopLabel))
+ return *continueLabel;
+ break;
+ default:
+ break;
+ }
+ return BytecodeGenerator::Label();
}
- virtual void emitForThrowHandling() { }
+ QString label() const override { return loopLabel; }
};
+
struct ControlFlowWith : public ControlFlowUnwind
{
ControlFlowWith(Codegen *cg)
: ControlFlowUnwind(cg, With)
{
- needsLookupByName = true;
-
- savedContextRegister = Moth::StackSlot::createRegister(generator()->newRegister());
+ setupUnwindHandler();
// assumes the with object is in the accumulator
Instruction::PushWithContext pushScope;
- pushScope.reg = savedContextRegister;
generator()->addInstruction(pushScope);
- generator()->setExceptionHandler(&unwindLabel);
+ generator()->setUnwindHandler(&unwindLabel);
}
- virtual ~ControlFlowWith() {
+ ~ControlFlowWith() {
// emit code for unwinding
unwindLabel.link();
- generator()->setExceptionHandler(parentExceptionHandler());
+ generator()->setUnwindHandler(parentUnwindHandler());
Instruction::PopContext pop;
- pop.reg = savedContextRegister;
generator()->addInstruction(pop);
emitUnwindHandler();
}
- Moth::StackSlot savedContextRegister;
+
+ bool requiresUnwind() override {
+ return true;
+ }
+
+
+};
+
+struct ControlFlowBlock : public ControlFlowUnwind
+{
+ ControlFlowBlock(Codegen *cg, AST::Node *ast)
+ : ControlFlowUnwind(cg, Block)
+ {
+ block = cg->enterBlock(ast);
+ block->emitBlockHeader(cg);
+
+ if (block->requiresExecutionContext) {
+ setupUnwindHandler();
+ generator()->setUnwindHandler(&unwindLabel);
+ }
+ }
+
+ virtual ~ControlFlowBlock() {
+ // emit code for unwinding
+ if (block->requiresExecutionContext) {
+ unwindLabel.link();
+ generator()->setUnwindHandler(parentUnwindHandler());
+ }
+
+ block->emitBlockFooter(cg);
+
+ if (block->requiresExecutionContext )
+ emitUnwindHandler();
+ cg->leaveBlock();
+ }
+
+ virtual bool requiresUnwind() override {
+ return block->requiresExecutionContext;
+ }
+
+ Context *block;
};
struct ControlFlowCatch : public ControlFlowUnwind
@@ -330,71 +307,57 @@ struct ControlFlowCatch : public ControlFlowUnwind
AST::Catch *catchExpression;
bool insideCatch = false;
BytecodeGenerator::ExceptionHandler exceptionLabel;
- BytecodeGenerator::ExceptionHandler catchUnwindLabel;
+ bool oldLookupByName;
ControlFlowCatch(Codegen *cg, AST::Catch *catchExpression)
: ControlFlowUnwind(cg, Catch), catchExpression(catchExpression),
- exceptionLabel(generator()->newExceptionHandler()),
- catchUnwindLabel(generator()->newExceptionHandler())
+ exceptionLabel(generator()->newExceptionHandler())
{
- generator()->setExceptionHandler(&exceptionLabel);
+ generator()->setUnwindHandler(&exceptionLabel);
}
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) {
- Handler h = getParentHandler(type, label);
- if (h.type == Invalid)
- return h;
- h = ControlFlowUnwind::getHandler(type, label);
- if (insideCatch)
- // if we're inside the catch block, we need to jump to the pop scope
- // instruction at the end of the catch block, not the unwind handler
- h.linkLabel = catchUnwindLabel;
- else if (type == Throw)
- // if we're inside the try block, we need to jump to the catch block,
- // not the unwind handler
- h.linkLabel = exceptionLabel;
- return h;
+ virtual bool requiresUnwind() override {
+ return true;
}
- virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
- return insideCatch ? &catchUnwindLabel : &exceptionLabel;
+ BytecodeGenerator::ExceptionHandler *unwindHandler() override {
+ return insideCatch ? &unwindLabel : &exceptionLabel;
}
~ControlFlowCatch() {
// emit code for unwinding
-
- needsLookupByName = true;
insideCatch = true;
+ setupUnwindHandler();
Codegen::RegisterScope scope(cg);
// exceptions inside the try block go here
exceptionLabel.link();
- Moth::StackSlot savedContextReg = Moth::StackSlot::createRegister(generator()->newRegister());
- Instruction::PushCatchContext pushCatch;
- pushCatch.name = cg->registerString(catchExpression->name.toString());
- pushCatch.reg = savedContextReg;
- generator()->addInstruction(pushCatch);
- // clear the unwind temp for exceptions, we want to resume normal code flow afterwards
- Reference::storeConstOnStack(cg, QV4::Encode::undefined(), controlFlowTemp);
- generator()->setExceptionHandler(&catchUnwindLabel);
+ BytecodeGenerator::Jump noException = generator()->jumpNoException();
- cg->statement(catchExpression->statement);
+ Context *block = cg->enterBlock(catchExpression);
- insideCatch = false;
- needsLookupByName = false;
+ block->emitBlockHeader(cg);
- // exceptions inside catch and break/return statements go here
- catchUnwindLabel.link();
- Instruction::PopContext pop;
- pop.reg = savedContextReg;
- generator()->addInstruction(pop);
+ generator()->setUnwindHandler(&unwindLabel);
+
+ if (catchExpression->patternElement->bindingIdentifier.isEmpty())
+ // destructuring pattern
+ cg->initializeAndDestructureBindingElement(catchExpression->patternElement, Reference::fromName(cg, QStringLiteral("@caught")));
+ // skip the additional block
+ cg->statementList(catchExpression->statement->statements);
- // break/continue/return statements in try go here
+ // exceptions inside catch and break/return statements go here
unwindLabel.link();
- generator()->setExceptionHandler(parentExceptionHandler());
+ block->emitBlockFooter(cg);
+
+ cg->leaveBlock();
+
+ noException.link();
+ generator()->setUnwindHandler(parentUnwindHandler());
emitUnwindHandler();
+ insideCatch = false;
}
};
@@ -402,25 +365,21 @@ struct ControlFlowFinally : public ControlFlowUnwind
{
AST::Finally *finally;
bool insideFinally = false;
- int exceptionTemp = -1;
ControlFlowFinally(Codegen *cg, AST::Finally *finally)
: ControlFlowUnwind(cg, Finally), finally(finally)
{
Q_ASSERT(finally != nullptr);
- generator()->setExceptionHandler(&unwindLabel);
+ setupUnwindHandler();
+ generator()->setUnwindHandler(&unwindLabel);
}
- virtual Handler getHandler(HandlerType type, const QString &label = QString()) {
- // if we're inside the finally block, any exceptions etc. should
- // go directly to the parent handler
- if (insideFinally)
- return getParentHandler(type, label);
- return ControlFlowUnwind::getHandler(type, label);
+ virtual bool requiresUnwind() override {
+ return !insideFinally;
}
- virtual BytecodeGenerator::ExceptionHandler *exceptionHandler() {
- return insideFinally ? parentExceptionHandler() : ControlFlowUnwind::exceptionHandler();
+ BytecodeGenerator::ExceptionHandler *unwindHandler() override {
+ return insideFinally ? parentUnwindHandler() : ControlFlowUnwind::unwindHandler();
}
~ControlFlowFinally() {
@@ -429,34 +388,35 @@ struct ControlFlowFinally : public ControlFlowUnwind
Codegen::RegisterScope scope(cg);
- Moth::StackSlot retVal = Moth::StackSlot::createRegister(generator()->newRegister());
- Instruction::StoreReg storeRetVal;
- storeRetVal.reg = retVal;
- generator()->addInstruction(storeRetVal);
-
insideFinally = true;
- exceptionTemp = generator()->newRegister();
+ int returnValueTemp = -1;
+ if (cg->requiresReturnValue) {
+ returnValueTemp = generator()->newRegister();
+ Instruction::MoveReg move;
+ move.srcReg = cg->_returnAddress;
+ move.destReg = returnValueTemp;
+ generator()->addInstruction(move);
+ }
+ int exceptionTemp = generator()->newRegister();
Instruction::GetException instr;
generator()->addInstruction(instr);
Reference::fromStackSlot(cg, exceptionTemp).storeConsumeAccumulator();
- generator()->setExceptionHandler(parentExceptionHandler());
+ generator()->setUnwindHandler(parentUnwindHandler());
cg->statement(finally->statement);
insideFinally = false;
- Instruction::LoadReg loadRetVal;
- loadRetVal.reg = retVal;
- generator()->addInstruction(loadRetVal);
-
- emitUnwindHandler();
- }
-
- virtual void emitForThrowHandling() {
- // reset the exception flag, that got cleared before executing the statements in finally
+ if (cg->requiresReturnValue) {
+ Instruction::MoveReg move;
+ move.srcReg = returnValueTemp;
+ move.destReg = cg->_returnAddress;
+ generator()->addInstruction(move);
+ }
Reference::fromStackSlot(cg, exceptionTemp).loadInAccumulator();
Instruction::SetException setException;
- Q_ASSERT(exceptionTemp != -1);
generator()->addInstruction(setException);
+
+ emitUnwindHandler();
}
};
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 84ee452332..7506b238f8 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -56,12 +56,12 @@ using namespace QV4;
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
-ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
+ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType)
: _cg(cg)
, _sourceCode(sourceCode)
, _context(nullptr)
, _allowFuncDecls(true)
- , defaultProgramMode(defaultProgramMode)
+ , defaultProgramType(defaultProgramType)
{
}
@@ -73,18 +73,19 @@ void ScanFunctions::operator()(Node *node)
calcEscapingVariables();
}
-void ScanFunctions::enterGlobalEnvironment(CompilationMode compilationMode)
+void ScanFunctions::enterGlobalEnvironment(ContextType compilationMode)
{
- enterEnvironment(astNodeForGlobalEnvironment, compilationMode);
+ enterEnvironment(astNodeForGlobalEnvironment, compilationMode, QStringLiteral("%GlobalCode"));
}
-void ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
+void ScanFunctions::enterEnvironment(Node *node, ContextType compilationMode, const QString &name)
{
Context *c = _cg->_module->contextMap.value(node);
if (!c)
c = _cg->_module->newContext(node, _context, compilationMode);
if (!c->isStrict)
c->isStrict = _cg->_strictMode;
+ c->name = name;
_contextStack.append(c);
_context = c;
}
@@ -92,28 +93,26 @@ void ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode
void ScanFunctions::leaveEnvironment()
{
_contextStack.pop();
- _context = _contextStack.isEmpty() ? 0 : _contextStack.top();
-}
-
-void ScanFunctions::checkDirectivePrologue(SourceElements *ast)
-{
- for (SourceElements *it = ast; it; it = it->next) {
- if (StatementSourceElement *stmt = cast<StatementSourceElement *>(it->element)) {
- if (ExpressionStatement *expr = cast<ExpressionStatement *>(stmt->statement)) {
- if (StringLiteral *strLit = cast<StringLiteral *>(expr->expression)) {
- // Use the source code, because the StringLiteral's
- // value might have escape sequences in it, which is not
- // allowed.
- if (strLit->literalToken.length < 2)
- continue;
- QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
- if (str == QLatin1String("use strict")) {
- _context->isStrict = true;
- } else {
- // TODO: give a warning.
- }
+ _context = _contextStack.isEmpty() ? nullptr : _contextStack.top();
+}
+
+void ScanFunctions::checkDirectivePrologue(StatementList *ast)
+{
+ for (StatementList *it = ast; it; it = it->next) {
+ if (ExpressionStatement *expr = cast<ExpressionStatement *>(it->statement)) {
+ if (StringLiteral *strLit = cast<StringLiteral *>(expr->expression)) {
+ // Use the source code, because the StringLiteral's
+ // value might have escape sequences in it, which is not
+ // allowed.
+ if (strLit->literalToken.length < 2)
continue;
+ QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
+ if (str == QLatin1String("use strict")) {
+ _context->isStrict = true;
+ } else {
+ // TODO: give a warning.
}
+ continue;
}
}
@@ -138,20 +137,10 @@ void ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc)
}
}
-bool ScanFunctions::formalsContainName(AST::FormalParameterList *parameters, const QString &name)
-{
- while (parameters) {
- if (parameters->name == name)
- return true;
- parameters = parameters->next;
- }
- return false;
-}
-
bool ScanFunctions::visit(Program *ast)
{
- enterEnvironment(ast, defaultProgramMode);
- checkDirectivePrologue(ast->elements);
+ enterEnvironment(ast, defaultProgramType, QStringLiteral("%ProgramCode"));
+ checkDirectivePrologue(ast->statements);
return true;
}
@@ -162,7 +151,7 @@ void ScanFunctions::endVisit(Program *)
bool ScanFunctions::visit(CallExpression *ast)
{
- if (! _context->hasDirectEval) {
+ if (!_context->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
if (_context->usesArgumentsObject == Context::ArgumentsObjectUnknown)
@@ -171,53 +160,31 @@ bool ScanFunctions::visit(CallExpression *ast)
}
}
}
- int argc = 0;
- for (ArgumentList *it = ast->arguments; it; it = it->next)
- ++argc;
- _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, argc);
return true;
}
-bool ScanFunctions::visit(NewMemberExpression *ast)
+bool ScanFunctions::visit(PatternElement *ast)
{
- int argc = 0;
- for (ArgumentList *it = ast->arguments; it; it = it->next)
- ++argc;
- _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, argc);
- return true;
-}
+ if (!ast->isVariableDeclaration())
+ return true;
-bool ScanFunctions::visit(ArrayLiteral *ast)
-{
- int index = 0;
- for (ElementList *it = ast->elements; it; it = it->next) {
- for (Elision *elision = it->elision; elision; elision = elision->next)
- ++index;
- ++index;
- }
- if (ast->elision) {
- for (Elision *elision = ast->elision->next; elision; elision = elision->next)
- ++index;
- }
- _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, index);
- return true;
-}
+ QStringList names;
+ ast->boundNames(&names);
-bool ScanFunctions::visit(VariableDeclaration *ast)
-{
- if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
- checkName(ast->name, ast->identifierToken);
- if (ast->name == QLatin1String("arguments"))
- _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
- if (ast->scope == AST::VariableDeclaration::VariableScope::ReadOnlyBlockScope && !ast->expression) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
- return false;
- }
- QString name = ast->name.toString();
- if (!_context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope)) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
- return false;
+ for (const QString &name : qAsConst(names)) {
+ if (_context->isStrict && (name == QLatin1String("eval") || name == 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"))
+ _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ if (ast->scope == VariableScope::Const && !ast->initializer && !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)) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
+ }
}
return true;
}
@@ -237,7 +204,8 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
if (!_allowFuncDecls)
_cg->throwSyntaxError(expr->functionToken, QStringLiteral("conditional function or closure declaration"));
- enterFunction(expr, /*enterName*/ true);
+ if (!enterFunction(expr, /*enterName*/ true))
+ return false;
Node::accept(expr->formals, this);
Node::accept(expr->body, this);
leaveEnvironment();
@@ -253,15 +221,25 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
bool ScanFunctions::visit(FunctionExpression *ast)
{
- enterFunction(ast, /*enterName*/ false);
+ return enterFunction(ast, /*enterName*/ false);
+}
+
+bool ScanFunctions::visit(TemplateLiteral *ast)
+{
+ while (ast) {
+ if (ast->expression)
+ Node::accept(ast->expression, this);
+ ast = ast->next;
+ }
return true;
+
}
-void ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName)
+bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName)
{
if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
- enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : nullptr);
+ return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName);
}
void ScanFunctions::endVisit(FunctionExpression *)
@@ -269,40 +247,34 @@ void ScanFunctions::endVisit(FunctionExpression *)
leaveEnvironment();
}
-bool ScanFunctions::visit(ObjectLiteral *ast)
+bool ScanFunctions::visit(ObjectPattern *ast)
{
- int argc = 0;
- for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
- QString key = it->assignment->name->asString();
- if (QV4::String::toArrayIndex(key) != UINT_MAX)
- ++argc;
- ++argc;
- if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
- ++argc;
- }
- _context->maxNumberOfArguments = qMax(_context->maxNumberOfArguments, argc);
-
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
Node::accept(ast->properties, this);
return false;
}
-bool ScanFunctions::visit(PropertyGetterSetter *ast)
+bool ScanFunctions::visit(PatternProperty *ast)
{
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
- enterFunction(ast, QString(), ast->formals, ast->functionBody, /*FunctionExpression*/nullptr);
+ Q_UNUSED(ast);
+ // ### Shouldn't be required anymore
+// if (ast->type == PatternProperty::Getter || ast->type == PatternProperty::Setter) {
+// TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
+// return enterFunction(ast, QString(), ast->formals, ast->functionBody, /*enterName */ false);
+// }
return true;
}
-void ScanFunctions::endVisit(PropertyGetterSetter *)
+void ScanFunctions::endVisit(PatternProperty *)
{
- leaveEnvironment();
+ // ###
+// if (ast->type == PatternProperty::Getter || ast->type == PatternProperty::Setter)
+// leaveEnvironment();
}
bool ScanFunctions::visit(FunctionDeclaration *ast)
{
- enterFunction(ast, /*enterName*/ true);
- return true;
+ return enterFunction(ast, /*enterName*/ true);
}
void ScanFunctions::endVisit(FunctionDeclaration *)
@@ -310,24 +282,6 @@ void ScanFunctions::endVisit(FunctionDeclaration *)
leaveEnvironment();
}
-bool ScanFunctions::visit(TryStatement *)
-{
- // ### should limit to catch(), as try{} finally{} should be ok without
- _context->hasTry = true;
- return true;
-}
-
-bool ScanFunctions::visit(WithStatement *ast)
-{
- if (_context->isStrict) {
- _cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
- return false;
- }
-
- _context->hasWith = true;
- return true;
-}
-
bool ScanFunctions::visit(DoWhileStatement *ast) {
{
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_context->isStrict);
@@ -338,7 +292,9 @@ bool ScanFunctions::visit(DoWhileStatement *ast) {
}
bool ScanFunctions::visit(ForStatement *ast) {
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%For"));
Node::accept(ast->initialiser, this);
+ Node::accept(ast->declarations, this);
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
@@ -348,9 +304,14 @@ bool ScanFunctions::visit(ForStatement *ast) {
return false;
}
-bool ScanFunctions::visit(LocalForStatement *ast) {
- Node::accept(ast->declarations, this);
- Node::accept(ast->condition, this);
+void ScanFunctions::endVisit(ForStatement *)
+{
+ leaveEnvironment();
+}
+
+bool ScanFunctions::visit(ForEachStatement *ast) {
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%Foreach"));
+ Node::accept(ast->lhs, this);
Node::accept(ast->expression, this);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_context->isStrict);
@@ -359,90 +320,154 @@ bool ScanFunctions::visit(LocalForStatement *ast) {
return false;
}
-bool ScanFunctions::visit(ForEachStatement *ast) {
- Node::accept(ast->initialiser, this);
- Node::accept(ast->expression, this);
+void ScanFunctions::endVisit(ForEachStatement *)
+{
+ leaveEnvironment();
+}
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_context->isStrict);
- Node::accept(ast->statement, this);
+bool ScanFunctions::visit(ThisExpression *)
+{
+ _context->usesThis = true;
+ return false;
+}
+bool ScanFunctions::visit(Block *ast)
+{
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ? false : _allowFuncDecls);
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%Block"));
+ Node::accept(ast->statements, this);
return false;
}
-bool ScanFunctions::visit(LocalForEachStatement *ast) {
- Node::accept(ast->declaration, this);
- Node::accept(ast->expression, this);
+void ScanFunctions::endVisit(Block *)
+{
+ leaveEnvironment();
+}
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_context->isStrict);
- Node::accept(ast->statement, this);
+bool ScanFunctions::visit(CaseBlock *ast)
+{
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%CaseBlock"));
+ return true;
+}
- return false;
+void ScanFunctions::endVisit(CaseBlock *)
+{
+ leaveEnvironment();
}
-bool ScanFunctions::visit(ThisExpression *)
+bool ScanFunctions::visit(Catch *ast)
{
- _context->usesThis = true;
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ? false : _allowFuncDecls);
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%CatchBlock"));
+ _context->isCatchBlock = true;
+ QString caughtVar = ast->patternElement->bindingIdentifier;
+ if (caughtVar.isEmpty())
+ caughtVar = QStringLiteral("@caught");
+ _context->addLocalVar(caughtVar, Context::MemberType::VariableDefinition, VariableScope::Let);
+
+ _context->caughtVariable = caughtVar;
+ if (_context->isStrict &&
+ (caughtVar == QLatin1String("eval") || caughtVar == QLatin1String("arguments"))) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Catch variable name may not be eval or arguments in strict mode"));
+ return false;
+ }
+ Node::accept(ast->patternElement, this);
+ // skip the block statement
+ Node::accept(ast->statement->statements, this);
return false;
}
-bool ScanFunctions::visit(Block *ast) {
+void ScanFunctions::endVisit(Catch *)
+{
+ leaveEnvironment();
+}
+
+bool ScanFunctions::visit(WithStatement *ast)
+{
+ Node::accept(ast->expression, this);
+
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ? false : _allowFuncDecls);
- Node::accept(ast->statements, this);
+ enterEnvironment(ast, ContextType::Block, QStringLiteral("%WithBlock"));
+ _context->isWithBlock = true;
+
+ if (_context->isStrict) {
+ _cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
+ return false;
+ }
+ Node::accept(ast->statement, this);
+
return false;
}
-void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr)
+void ScanFunctions::endVisit(WithStatement *)
+{
+ leaveEnvironment();
+}
+
+bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, bool enterName)
{
Context *outerContext = _context;
- enterEnvironment(ast, FunctionCode);
+ enterEnvironment(ast, ContextType::Function, name);
+ FunctionExpression *expr = AST::cast<FunctionExpression *>(ast);
+ if (!expr)
+ expr = AST::cast<FunctionDeclaration *>(ast);
if (outerContext) {
outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (expr) {
- if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr)) {
+ if (enterName) {
+ if (!outerContext->addLocalVar(name, Context::FunctionDefinition, VariableScope::Var, expr)) {
_cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
- return;
+ return false;
}
+ outerContext->addLocalVar(name, Context::FunctionDefinition, VariableScope::Var, expr);
}
if (name == QLatin1String("arguments"))
outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
}
- if (formalsContainName(formals, QStringLiteral("arguments")))
+ _context->name = name;
+ if (formals && formals->containsName(QStringLiteral("arguments")))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ if (expr) {
+ if (expr->isArrowFunction)
+ _context->isArrowFunction = true;
+ else if (expr->isGenerator)
+ _context->isGenerator = true;
+ }
- if (!name.isEmpty() && !formalsContainName(formals, name))
- _context->addLocalVar(name, Context::ThisFunctionName, QQmlJS::AST::VariableDeclaration::FunctionScope);
+ if (!name.isEmpty() && (!formals || !formals->containsName(name)))
+ _context->addLocalVar(name, Context::ThisFunctionName, VariableScope::Var);
_context->formals = formals;
if (body && !_context->isStrict)
- checkDirectivePrologue(body->elements);
-
- for (FormalParameterList *it = formals; it; it = it->next) {
- QString arg = it->name.toString();
- int duplicateIndex = _context->arguments.indexOf(arg);
- if (duplicateIndex != -1) {
- if (_context->isStrict) {
- _cg->throwSyntaxError(it->identifierToken, QStringLiteral("Duplicate parameter name '%1' is not allowed in strict mode").arg(arg));
- return;
- } else {
- // change the name of the earlier argument to enforce the specified lookup semantics
- QString modified = arg;
- while (_context->arguments.contains(modified))
- modified += QString(0xfffe);
- _context->arguments[duplicateIndex] = modified;
+ checkDirectivePrologue(body);
+
+ bool isSimpleParameterList = formals && formals->isSimpleParameterList();
+
+ _context->arguments = formals ? formals->formals() : QStringList();
+
+ const QStringList boundNames = formals ? formals->boundNames() : QStringList();
+ for (int i = 0; i < boundNames.size(); ++i) {
+ const QString &arg = boundNames.at(i);
+ if (_context->isStrict || !isSimpleParameterList) {
+ bool duplicate = (boundNames.indexOf(arg, i + 1) != -1);
+ if (duplicate) {
+ _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("Duplicate parameter name '%1' is not allowed.").arg(arg));
+ return false;
}
}
if (_context->isStrict) {
if (arg == QLatin1String("eval") || arg == QLatin1String("arguments")) {
- _cg->throwSyntaxError(it->identifierToken, QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg));
- return;
+ _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg));
+ return false;
}
}
- _context->arguments += arg;
+ if (!_context->arguments.contains(arg))
+ _context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var);
}
+ return true;
}
void ScanFunctions::calcEscapingVariables()
@@ -450,27 +475,114 @@ void ScanFunctions::calcEscapingVariables()
Module *m = _cg->_module;
for (Context *inner : qAsConst(m->contextMap)) {
+ if (inner->contextType == ContextType::Block && inner->usesArgumentsObject == Context::ArgumentsObjectUsed) {
+ Context *c = inner->parent;
+ while (c->contextType == ContextType::Block)
+ c = c->parent;
+ c->usesArgumentsObject = Context::ArgumentsObjectUsed;
+ inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ }
+ }
+ for (Context *inner : qAsConst(m->contextMap)) {
+ if (!inner->parent || inner->usesArgumentsObject == Context::ArgumentsObjectUnknown)
+ inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ if (inner->usesArgumentsObject == Context::ArgumentsObjectUsed) {
+ QString arguments = QStringLiteral("arguments");
+ inner->addLocalVar(arguments, Context::VariableDeclaration, AST::VariableScope::Var);
+ if (!inner->isStrict) {
+ inner->argumentsCanEscape = true;
+ inner->requiresExecutionContext = true;
+ }
+ }
+ }
+
+ for (Context *inner : qAsConst(m->contextMap)) {
for (const QString &var : qAsConst(inner->usedVariables)) {
Context *c = inner;
while (c) {
+ Context *current = c;
+ c = c->parent;
+ if (current->isWithBlock || current->contextType != ContextType::Block)
+ break;
+ }
+ Q_ASSERT(c != inner);
+ while (c) {
Context::MemberMap::const_iterator it = c->members.find(var);
if (it != c->members.end()) {
- if (c != inner)
+ if (c->parent || it->isLexicallyScoped()) {
it->canEscape = true;
+ c->requiresExecutionContext = true;
+ }
break;
}
if (c->findArgument(var) != -1) {
- if (c != inner)
- c->argumentsCanEscape = true;
+ c->argumentsCanEscape = true;
+ c->requiresExecutionContext = true;
break;
}
c = c->parent;
}
}
- Context *c = inner->parent;
- while (c) {
- c->hasDirectEval |= inner->hasDirectEval;
- c = c->parent;
+ if (inner->hasDirectEval) {
+ inner->hasDirectEval = false;
+ if (!inner->isStrict) {
+ Context *c = inner;
+ while (c->contextType == ContextType::Block) {
+ c = c->parent;
+ }
+ Q_ASSERT(c);
+ c->hasDirectEval = true;
+ }
+ Context *c = inner;
+ while (c) {
+ c->allVarsEscape = true;
+ c = c->parent;
+ }
+ }
+ if (inner->usesThis) {
+ inner->usesThis = false;
+ if (!inner->isStrict) {
+ Context *c = inner;
+ while (c->contextType == ContextType::Block) {
+ c = c->parent;
+ }
+ Q_ASSERT(c);
+ c->usesThis = true;
+ }
+ }
+ }
+ for (Context *c : qAsConst(m->contextMap)) {
+ if (c->allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty())
+ c->allVarsEscape = false;
+ if (c->contextType == ContextType::Global || (!c->isStrict && c->contextType == ContextType::Eval) || m->debugMode)
+ c->allVarsEscape = true;
+ if (c->allVarsEscape) {
+ if (c->parent) {
+ c->requiresExecutionContext = true;
+ c->argumentsCanEscape = true;
+ } else {
+ for (const auto &m : qAsConst(c->members)) {
+ if (m.isLexicallyScoped()) {
+ c->requiresExecutionContext = true;
+ break;
+ }
+ }
+ }
+ }
+ if (c->contextType == ContextType::Block && c->isCatchBlock) {
+ c->requiresExecutionContext = true;
+ auto m = c->members.find(c->caughtVariable);
+ m->canEscape = true;
+ }
+ const QLatin1String exprForOn("expression for on");
+ if (c->contextType == ContextType::Binding && c->name.length() > exprForOn.size() &&
+ c->name.startsWith(exprForOn) && c->name.at(exprForOn.size()).isUpper())
+ // we don't really need this for bindings, but we do for signal handlers, and in this case,
+ // we don't know if the code is a signal handler or not.
+ c->requiresExecutionContext = true;
+ if (c->allVarsEscape) {
+ for (auto &m : c->members)
+ m.canEscape = true;
}
}
@@ -478,10 +590,12 @@ void ScanFunctions::calcEscapingVariables()
if (showEscapingVars) {
qDebug() << "==== escaping variables ====";
for (Context *c : qAsConst(m->contextMap)) {
- qDebug() << "Context" << c->name << ":";
- qDebug() << " Arguments escape" << c->argumentsCanEscape;
+ qDebug() << "Context" << c << c->name << "requiresExecutionContext" << c->requiresExecutionContext;
+ qDebug() << " parent:" << c->parent;
+ if (c->argumentsCanEscape)
+ qDebug() << " Arguments escape";
for (auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
- qDebug() << " " << it.key() << it.value().canEscape;
+ qDebug() << " " << it.key() << it.value().canEscape << "isLexicallyScoped:" << it.value().isLexicallyScoped();
}
}
}
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 87b7210879..3120ce917c 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -81,11 +81,11 @@ class ScanFunctions: protected QQmlJS::AST::Visitor
{
typedef QV4::TemporaryAssignment<bool> TemporaryBoolAssignment;
public:
- ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode);
+ ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
void operator()(AST::Node *node);
- void enterGlobalEnvironment(CompilationMode compilationMode);
- void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
+ void enterGlobalEnvironment(ContextType compilationMode);
+ void enterEnvironment(AST::Node *node, ContextType compilationMode, const QString &name);
void leaveEnvironment();
void enterQmlFunction(AST::FunctionDeclaration *ast)
@@ -95,48 +95,54 @@ protected:
using Visitor::visit;
using Visitor::endVisit;
- void checkDirectivePrologue(AST::SourceElements *ast);
+ void checkDirectivePrologue(AST::StatementList *ast);
void checkName(const QStringRef &name, const AST::SourceLocation &loc);
- bool formalsContainName(AST::FormalParameterList *parameters, const QString &name);
bool visit(AST::Program *ast) override;
void endVisit(AST::Program *) override;
bool visit(AST::CallExpression *ast) override;
- bool visit(AST::NewMemberExpression *ast) override;
- bool visit(AST::ArrayLiteral *ast) override;
- bool visit(AST::VariableDeclaration *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;
- void enterFunction(AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(AST::FunctionExpression *ast, bool enterName);
void endVisit(AST::FunctionExpression *) override;
- bool visit(AST::ObjectLiteral *ast) override;
+ bool visit(AST::ObjectPattern *ast) override;
- bool visit(AST::PropertyGetterSetter *ast) override;
- void endVisit(AST::PropertyGetterSetter *) override;
+ bool visit(AST::PatternProperty *ast) override;
+ void endVisit(AST::PatternProperty *) override;
bool visit(AST::FunctionDeclaration *ast) override;
void endVisit(AST::FunctionDeclaration *) override;
- bool visit(AST::TryStatement *ast) override;
- bool visit(AST::WithStatement *ast) override;
-
bool visit(AST::DoWhileStatement *ast) override;
bool visit(AST::ForStatement *ast) override;
- bool visit(AST::LocalForStatement *ast) override;
+ void endVisit(AST::ForStatement *) override;
bool visit(AST::ForEachStatement *ast) override;
- bool visit(AST::LocalForEachStatement *ast) override;
+ void endVisit(AST::ForEachStatement *) override;
+
bool visit(AST::ThisExpression *ast) override;
bool visit(AST::Block *ast) override;
+ void endVisit(AST::Block *ast) override;
+
+ bool visit(AST::CaseBlock *ast) override;
+ void endVisit(AST::CaseBlock *ast) override;
+
+ bool visit(AST::Catch *ast) override;
+ void endVisit(AST::Catch *ast) override;
+
+ bool visit(AST::WithStatement *ast) override;
+ void endVisit(AST::WithStatement *ast) override;
protected:
- void enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::FunctionBody *body, AST::FunctionExpression *expr);
+ bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
void calcEscapingVariables();
// fields:
@@ -146,7 +152,7 @@ protected:
QStack<Context *> _contextStack;
bool _allowFuncDecls;
- CompilationMode defaultProgramMode;
+ ContextType defaultProgramType;
private:
static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 450fa50528..df5dd5610c 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -286,10 +286,6 @@ 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) << "[" << dumpRegister(index, nFormals) << "]";
- MOTH_END_INSTR(LoadElement)
-
- MOTH_BEGIN_INSTR(LoadElementA)
d << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
@@ -298,12 +294,8 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << dumpRegister(base, nFormals) << "[" << name << "]";
- MOTH_END_INSTR(LoadProperty)
-
- MOTH_BEGIN_INSTR(LoadPropertyA)
d << "acc[" << name << "]";
- MOTH_END_INSTR(LoadElementA)
+ MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
d << dumpRegister(base, nFormals) << "(" << index << ")";
@@ -341,6 +333,13 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(base, nFormals) << "[" << index << "]";
MOTH_END_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(Yield)
+ MOTH_END_INSTR(Yield)
+
+ MOTH_BEGIN_INSTR(Resume)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(Resume)
+
MOTH_BEGIN_INSTR(CallValue)
d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
@@ -377,12 +376,31 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallContextObjectProperty)
- MOTH_BEGIN_INSTR(SetExceptionHandler)
+ MOTH_BEGIN_INSTR(CallWithSpread)
+ d << "new" << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(CallWithSpread)
+
+ MOTH_BEGIN_INSTR(Construct)
+ d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(Construct)
+
+ MOTH_BEGIN_INSTR(ConstructWithSpread)
+ d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ MOTH_END_INSTR(ConstructWithSpread)
+
+ MOTH_BEGIN_INSTR(SetUnwindHandler)
if (offset)
d << ABSOLUTE_OFFSET();
else
d << "<null>";
- MOTH_END_INSTR(SetExceptionHandler)
+ MOTH_END_INSTR(SetUnwindHandler)
+
+ MOTH_BEGIN_INSTR(UnwindDispatch)
+ MOTH_END_INSTR(UnwindDispatch)
+
+ MOTH_BEGIN_INSTR(UnwindToLabel)
+ d << "(" << level << ") " << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(UnwindToLabel)
MOTH_BEGIN_INSTR(ThrowException)
MOTH_END_INSTR(ThrowException)
@@ -397,30 +415,47 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(CreateCallContext)
MOTH_BEGIN_INSTR(PushCatchContext)
- d << dumpRegister(reg, nFormals) << ", " << name;
+ d << index << ", " << name;
MOTH_END_INSTR(PushCatchContext)
MOTH_BEGIN_INSTR(PushWithContext)
- d << dumpRegister(reg, nFormals);
MOTH_END_INSTR(PushWithContext)
+ MOTH_BEGIN_INSTR(PushBlockContext)
+ d << index;
+ MOTH_END_INSTR(PushBlockContext)
+
+ MOTH_BEGIN_INSTR(CloneBlockContext)
+ MOTH_END_INSTR(CloneBlockContext)
+
+ MOTH_BEGIN_INSTR(PushScriptContext)
+ d << index;
+ MOTH_END_INSTR(PushScriptContext)
+
+ MOTH_BEGIN_INSTR(PopScriptContext)
+ MOTH_END_INSTR(PopScriptContext)
+
MOTH_BEGIN_INSTR(PopContext)
- d << dumpRegister(reg, nFormals);
MOTH_END_INSTR(PopContext)
- MOTH_BEGIN_INSTR(ForeachIteratorObject)
- MOTH_END_INSTR(ForeachIteratorObject)
+ MOTH_BEGIN_INSTR(GetIterator)
+ d << iterator;
+ MOTH_END_INSTR(GetIterator)
+
+ MOTH_BEGIN_INSTR(IteratorNext)
+ d << dumpRegister(value, nFormals);
+ MOTH_END_INSTR(IteratorNext)
- MOTH_BEGIN_INSTR(ForeachNextPropertyName)
- MOTH_END_INSTR(ForeachNextPropertyName)
+ MOTH_BEGIN_INSTR(IteratorClose)
+ d << dumpRegister(done, nFormals);
+ MOTH_END_INSTR(IteratorClose)
- MOTH_BEGIN_INSTR(DeleteMember)
- d << dumpRegister(base, nFormals) << "[" << member << "]";
- MOTH_END_INSTR(DeleteMember)
+ MOTH_BEGIN_INSTR(DestructureRestElement)
+ MOTH_END_INSTR(DestructureRestElement)
- MOTH_BEGIN_INSTR(DeleteSubscript)
+ MOTH_BEGIN_INSTR(DeleteProperty)
d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
- MOTH_END_INSTR(DeleteSubscript)
+ MOTH_END_INSTR(DeleteProperty)
MOTH_BEGIN_INSTR(DeleteName)
d << name;
@@ -442,10 +477,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(DefineArray)
MOTH_BEGIN_INSTR(DefineObjectLiteral)
- d << dumpRegister(args, nFormals)
- << ", " << internalClassId
- << ", " << arrayValueCount
- << ", " << arrayGetterSetterCountAndFlags;
+ d << internalClassId
+ << ", " << argc
+ << ", " << dumpRegister(args, nFormals);
MOTH_END_INSTR(DefineObjectLiteral)
MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
@@ -454,12 +488,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
MOTH_END_INSTR(CreateUnmappedArgumentsObject)
+ MOTH_BEGIN_INSTR(CreateRestParameter)
+ d << argIndex;
+ MOTH_END_INSTR(CreateRestParameter)
+
MOTH_BEGIN_INSTR(ConvertThisToObject)
MOTH_END_INSTR(ConvertThisToObject)
- MOTH_BEGIN_INSTR(Construct)
- d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
- MOTH_END_INSTR(Construct)
+ MOTH_BEGIN_INSTR(ToObject)
+ MOTH_END_INSTR(ToObject)
MOTH_BEGIN_INSTR(Jump)
d << ABSOLUTE_OFFSET();
@@ -473,6 +510,14 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
+ MOTH_BEGIN_INSTR(JumpNotUndefined)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(JumpNotUndefined)
+
+ MOTH_BEGIN_INSTR(JumpNoException)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(JumpNoException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
@@ -519,14 +564,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpStrictNotEqual)
- MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
- d << dumpRegister(lhs, nFormals) << ", " << rhs << " " << ABSOLUTE_OFFSET();
- MOTH_END_INSTR(JumpStrictEqualStackSlotInt)
-
- MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
- d << dumpRegister(lhs, nFormals) << ", " << rhs << " " << ABSOLUTE_OFFSET();
- MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
-
MOTH_BEGIN_INSTR(UNot)
MOTH_END_INSTR(UNot)
@@ -597,6 +634,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << "acc, " << rhs;
MOTH_END_INSTR(ShlConst)
+ MOTH_BEGIN_INSTR(Exp)
+ d << dumpRegister(lhs, nFormals) << ", acc";
+ MOTH_END_INSTR(Exp)
+
MOTH_BEGIN_INSTR(Mul)
d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 7dd639c94c..85b30507a1 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -53,6 +53,8 @@
#include <private/qv4global_p.h>
#include <private/qv4value_p.h>
#include <private/qv4runtime_p.h>
+#include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper
+#include <qendian.h>
QT_BEGIN_NAMESPACE
@@ -84,19 +86,19 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 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, base)
-#define INSTR_LoadPropertyA(op) INSTRUCTION(op, LoadPropertyA, 1, name)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, base)
#define INSTR_GetLookupA(op) INSTRUCTION(op, GetLookupA, 1, index)
#define INSTR_LoadScopeObjectProperty(op) INSTRUCTION(op, LoadScopeObjectProperty, 3, propertyIndex, base, captureRequired)
#define INSTR_LoadContextObjectProperty(op) INSTRUCTION(op, LoadContextObjectProperty, 3, propertyIndex, base, captureRequired)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
+#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
+#define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset)
#define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base)
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_StoreScopeObjectProperty(op) INSTRUCTION(op, StoreScopeObjectProperty, 2, base, propertyIndex)
#define INSTR_StoreContextObjectProperty(op) INSTRUCTION(op, StoreContextObjectProperty, 2, base, propertyIndex)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, index)
-#define INSTR_LoadElementA(op) INSTRUCTION(op, LoadElementA, 1, base)
+#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_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
@@ -107,32 +109,44 @@ QT_BEGIN_NAMESPACE
#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
#define INSTR_CallScopeObjectProperty(op) INSTRUCTION(op, CallScopeObjectProperty, 4, name, base, argc, argv)
#define INSTR_CallContextObjectProperty(op) INSTRUCTION(op, CallContextObjectProperty, 4, name, base, argc, argv)
-#define INSTR_SetExceptionHandler(op) INSTRUCTION(op, SetExceptionHandler, 1, offset)
+#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)
+#define INSTR_UnwindDispatch(op) INSTRUCTION(op, UnwindDispatch, 0)
+#define INSTR_UnwindToLabel(op) INSTRUCTION(op, UnwindToLabel, 2, level, offset)
#define INSTR_ThrowException(op) INSTRUCTION(op, ThrowException, 0)
#define INSTR_GetException(op) INSTRUCTION(op, GetException, 0)
#define INSTR_SetException(op) INSTRUCTION(op, SetException, 0)
#define INSTR_CreateCallContext(op) INSTRUCTION(op, CreateCallContext, 0)
-#define INSTR_PushCatchContext(op) INSTRUCTION(op, PushCatchContext, 2, name, reg)
-#define INSTR_PushWithContext(op) INSTRUCTION(op, PushWithContext, 1, reg)
-#define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 1, reg)
-#define INSTR_ForeachIteratorObject(op) INSTRUCTION(op, ForeachIteratorObject, 0)
-#define INSTR_ForeachNextPropertyName(op) INSTRUCTION(op, ForeachNextPropertyName, 0)
-#define INSTR_DeleteMember(op) INSTRUCTION(op, DeleteMember, 2, member, base)
-#define INSTR_DeleteSubscript(op) INSTRUCTION(op, DeleteSubscript, 2, base, index)
+#define INSTR_PushCatchContext(op) INSTRUCTION(op, PushCatchContext, 2, index, name)
+#define INSTR_PushWithContext(op) INSTRUCTION(op, PushWithContext, 0)
+#define INSTR_PushBlockContext(op) INSTRUCTION(op, PushBlockContext, 1, index)
+#define INSTR_CloneBlockContext(op) INSTRUCTION(op, CloneBlockContext, 0)
+#define INSTR_PushScriptContext(op) INSTRUCTION(op, PushScriptContext, 1, index)
+#define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0)
+#define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 0)
+#define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator)
+#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 1, value)
+#define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 1, done)
+#define INSTR_DestructureRestElement(op) INSTRUCTION(op, DestructureRestElement, 0)
+#define INSTR_DeleteProperty(op) INSTRUCTION(op, DeleteProperty, 2, base, index)
#define INSTR_DeleteName(op) INSTRUCTION(op, DeleteName, 1, name)
#define INSTR_TypeofName(op) INSTRUCTION(op, TypeofName, 1, name)
#define INSTR_TypeofValue(op) INSTRUCTION(op, TypeofValue, 0)
#define INSTR_DeclareVar(op) INSTRUCTION(op, DeclareVar, 2, varName, isDeletable)
#define INSTR_DefineArray(op) INSTRUCTION(op, DefineArray, 2, argc, args)
-// arrayGetterSetterCountAndFlags contains 30 bits for count, 1 bit for needsSparseArray boolean
-#define INSTR_DefineObjectLiteral(op) INSTRUCTION(op, DefineObjectLiteral, 4, internalClassId, arrayValueCount, arrayGetterSetterCountAndFlags, args)
+#define INSTR_DefineObjectLiteral(op) INSTRUCTION(op, DefineObjectLiteral, 3, internalClassId, argc, args)
#define INSTR_CreateMappedArgumentsObject(op) INSTRUCTION(op, CreateMappedArgumentsObject, 0)
#define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0)
+#define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex)
#define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0)
-#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
+#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, 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_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -147,8 +161,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpStrictNotEqual(op) INSTRUCTION(op, CmpStrictNotEqual, 1, lhs)
#define INSTR_CmpIn(op) INSTRUCTION(op, CmpIn, 1, lhs)
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
-#define INSTR_JumpStrictEqualStackSlotInt(op) INSTRUCTION(op, JumpStrictEqualStackSlotInt, 3, lhs, rhs, offset)
-#define INSTR_JumpStrictNotEqualStackSlotInt(op) INSTRUCTION(op, JumpStrictNotEqualStackSlotInt, 3, lhs, rhs, offset)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
@@ -168,6 +180,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_UShrConst(op) INSTRUCTION(op, UShrConst, 1, rhs)
#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, 1, lhs)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
@@ -202,10 +215,8 @@ QT_BEGIN_NAMESPACE
F(StoreNameSloppy) \
F(StoreNameStrict) \
F(LoadElement) \
- F(LoadElementA) \
F(StoreElement) \
F(LoadProperty) \
- F(LoadPropertyA) \
F(GetLookup) \
F(GetLookupA) \
F(StoreProperty) \
@@ -215,6 +226,8 @@ QT_BEGIN_NAMESPACE
F(LoadScopeObjectProperty) \
F(LoadContextObjectProperty) \
F(LoadIdObject) \
+ F(Yield) \
+ F(Resume) \
F(CallValue) \
F(CallProperty) \
F(CallPropertyLookup) \
@@ -224,18 +237,28 @@ QT_BEGIN_NAMESPACE
F(CallGlobalLookup) \
F(CallScopeObjectProperty) \
F(CallContextObjectProperty) \
- F(SetExceptionHandler) \
+ F(CallWithSpread) \
+ F(Construct) \
+ F(ConstructWithSpread) \
+ F(SetUnwindHandler) \
+ F(UnwindDispatch) \
+ F(UnwindToLabel) \
F(ThrowException) \
F(GetException) \
F(SetException) \
F(CreateCallContext) \
F(PushCatchContext) \
F(PushWithContext) \
+ F(PushBlockContext) \
+ F(CloneBlockContext) \
+ F(PushScriptContext) \
+ F(PopScriptContext) \
F(PopContext) \
- F(ForeachIteratorObject) \
- F(ForeachNextPropertyName) \
- F(DeleteMember) \
- F(DeleteSubscript) \
+ F(GetIterator) \
+ F(IteratorNext) \
+ F(IteratorClose) \
+ F(DestructureRestElement) \
+ F(DeleteProperty) \
F(DeleteName) \
F(TypeofName) \
F(TypeofValue) \
@@ -244,11 +267,14 @@ QT_BEGIN_NAMESPACE
F(DefineObjectLiteral) \
F(CreateMappedArgumentsObject) \
F(CreateUnmappedArgumentsObject) \
+ F(CreateRestParameter) \
F(ConvertThisToObject) \
- F(Construct) \
+ F(ToObject) \
F(Jump) \
F(JumpTrue) \
F(JumpFalse) \
+ F(JumpNoException) \
+ F(JumpNotUndefined) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
@@ -263,8 +289,6 @@ QT_BEGIN_NAMESPACE
F(CmpStrictNotEqual) \
F(CmpIn) \
F(CmpInstanceOf) \
- F(JumpStrictEqualStackSlotInt) \
- F(JumpStrictNotEqualStackSlotInt) \
F(UNot) \
F(UPlus) \
F(UMinus) \
@@ -284,6 +308,7 @@ QT_BEGIN_NAMESPACE
F(UShrConst) \
F(ShrConst) \
F(ShlConst) \
+ F(Exp) \
F(Mul) \
F(Div) \
F(Mod) \
@@ -347,7 +372,9 @@ QT_BEGIN_NAMESPACE
nargs,
#define MOTH_DECODE_ARG(arg, type, nargs, offset) \
- arg = qFromLittleEndian<type>(reinterpret_cast<const type *>(code)[-nargs + offset]);
+ arg = qFromLittleEndian<type>( \
+ static_cast<const void *>( \
+ &reinterpret_cast<const type *>(code)[-nargs + offset]));
#define MOTH_ADJUST_CODE(type, nargs) \
code += static_cast<quintptr>(nargs*sizeof(type) + 1)
diff --git a/src/qml/configure.json b/src/qml/configure.json
index 681cecea99..7d67db8b2c 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -40,6 +40,47 @@
],
"output": [ "privateFeature" ]
},
+ "qml-devtools": {
+ "label": "QML Development Tools",
+ "purpose": "Provides the QmlDevtools library and various utilities.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-sequence-object": {
+ "label": "QML sequence object",
+ "purpose": "Supports mapping sequence types into QML.",
+ "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.",
+ "section": "QML",
+ "condition": [
+ "features.xmlstreamreader",
+ "features.qml-network"
+ ],
+ "output": [ "privateFeature" ]
+ },
+ "qml-locale": {
+ "label": "QML Locale",
+ "purpose": "Provides support for locales in QML.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-animation": {
+ "label": "QML Animations",
+ "purpose": "Provides support for animations and timers in QML.",
+ "section": "QML",
+ "condition": "features.animation",
+ "output": [ "privateFeature" ]
+ },
"qml-delegate-model": {
"label": "QML delegate model",
"purpose": "Provides the DelegateModel QML type.",
@@ -54,6 +95,10 @@
"entries": [
"qml-network",
"qml-debug",
+ "qml-sequence-object",
+ "qml-list-model",
+ "qml-xml-http-request",
+ "qml-locale",
"qml-delegate-model"
]
}
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index c63e694c7e..f39f8fccd2 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -73,13 +73,13 @@ public:
~QQmlAbstractProfilerAdapter() override {}
void setService(QQmlProfilerService *new_service) { service = new_service; }
- virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) = 0;
+ virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0;
void startProfiling(quint64 features);
void stopProfiling();
- void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
+ void reportData() { emit dataRequested(); }
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
@@ -96,7 +96,7 @@ signals:
void profilingDisabled();
void profilingDisabledWhileWaiting();
- void dataRequested(bool trackLocations);
+ void dataRequested();
void referenceTimeKnown(const QElapsedTimer &timer);
protected:
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index d9f51ce09f..0ef40d6911 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -82,7 +82,7 @@ Q_GLOBAL_STATIC(QQmlDebugConnectorParams, qmlDebugConnectorParams)
void QQmlDebugConnector::setPluginKey(const QString &key)
{
QQmlDebugConnectorParams *params = qmlDebugConnectorParams();
- if (params) {
+ if (params && params->pluginKey != key) {
if (params->instance)
qWarning() << "QML debugger: Cannot set plugin key after loading the plugin.";
else
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index 8c0bd73822..da0b14dd85 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -59,19 +59,18 @@ void QQmlProfiler::startProfiling(quint64 features)
void QQmlProfiler::stopProfiling()
{
featuresEnabled = false;
- reportData(true);
+ reportData();
m_locations.clear();
}
-void QQmlProfiler::reportData(bool trackLocations)
+void QQmlProfiler::reportData()
{
LocationHash resolved;
resolved.reserve(m_locations.size());
for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
- if (!trackLocations || !it->sent) {
+ if (!it->sent) {
resolved.insert(it.key(), it.value());
- if (trackLocations)
- it->sent = true;
+ it->sent = true;
}
}
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 287c53ea05..d01e2bc429 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -383,7 +383,7 @@ public:
void startProfiling(quint64 features);
void stopProfiling();
- void reportData(bool trackLocations);
+ void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 9b2771c18e..9d1a03a399 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -262,8 +262,8 @@ local timezone will be used ignoring any DST complications it may have.
\section2 Sequence Type to JavaScript Array
-Certain C++ sequence types are supported transparently in QML as JavaScript
-\c Array types.
+Certain C++ sequence types are supported transparently in QML to behave like
+JavaScript \c Array types.
In particular, QML currently supports:
\list
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 55ca040af6..62c0f5d81b 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -538,30 +538,6 @@
}
\endqml
- Since singleton types do not have an associated QQmlContext object, then within the functions of a QObject-derived
- type that is registered as a singleton type implementation the QML context and engine information is not available.
- The QQmlEngine::contextForObject() function returns NULL when supplied with a pointer to an QObject that
- implements a singleton type.
-
- Extending the above example:
-
- \code
- class SingletonTypeExample : public QObject
- {
- ...
-
- Q_INVOKABLE void doSomethingElse()
- {
- // QML Engine/Context information is not accessible here:
- Q_ASSERT(QQmlEngine::contextForObject(this) == 0);
- Q_ASSERT(qmlContext(this) == 0);
- Q_ASSERT(qmlEngine(this) == 0);
- }
-
- ...
- }
- \endcode
-
\sa {Choosing the Correct Integration Method Between C++ and QML}
*/
@@ -662,3 +638,25 @@
are registered for that version. This is particularly useful for keeping the
versions of related modules in sync.
*/
+
+/*!
+ \since 5.12
+ \fn int qmlTypeId(const char* uri, int versionMajor, int versionMinor, const char *qmlName);
+ \relates QQmlEngine
+
+ Returns the QML type id of a type that was registered with the
+ name \a qmlName in a particular \a uri and a version specified in \a
+ versionMajor and \a versionMinor.
+
+ This function returns the same value as the QML type registration functions
+ such as qmlRegisterType() and qmlRegisterSingletonType().
+
+ If \a qmlName, \a uri and \a versionMajor match a registered type, but the
+ specified minor version in \a versionMinor is higher, then the id of the type
+ with the closest minor version is returned.
+
+ Returns -1 if no matching type was found or one of the given parameters
+ was invalid.
+
+ \sa qmlRegisterType(), qmlRegisterSingletonType()
+*/
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index 2080844d93..2b6b2e7c3c 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -2,9 +2,9 @@ INCLUDEPATH += $$PWD
INCLUDEPATH += $$OUT_PWD
SOURCES += \
- $$PWD/qv4jit.cpp \
+ $$PWD/qv4baselinejit.cpp \
$$PWD/qv4assembler.cpp
HEADERS += \
- $$PWD/qv4jit_p.h \
+ $$PWD/qv4baselinejit_p.h \
$$PWD/qv4assembler_p.h
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 9786293e4c..be6c03ab8f 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -680,6 +680,12 @@ struct PlatformAssembler64 : PlatformAssemblerCommon
store64(AccumulatorRegister, addr);
}
+ void moveReg(Address sourceRegAddress, Address destRegAddress)
+ {
+ load64(sourceRegAddress, ScratchRegister);
+ store64(ScratchRegister, destRegAddress);
+ }
+
void loadString(int stringId)
{
loadAccumulator(loadStringAddress(stringId));
@@ -700,6 +706,17 @@ struct PlatformAssembler64 : PlatformAssemblerCommon
PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();});
}
+ void jumpNotUndefined(int offset)
+ {
+ auto jump = branch64(NotEqual, AccumulatorRegister, TrustedImm64(0));
+ patches.push_back({ jump, offset });
+ }
+
+ Jump jumpEmpty()
+ {
+ return branch64(Equal, AccumulatorRegister, TrustedImm64(Primitive::emptyValue().asReturnedValue()));
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
@@ -803,26 +820,6 @@ struct PlatformAssembler64 : PlatformAssemblerCommon
return branch32(Equal, TrustedImm32(3), ScratchRegister);
}
- void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
- {
- Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value)));
- load64(lhsAddr, ScratchRegister);
- Jump isUndef = branch64(Equal, ScratchRegister, TrustedImm64(0));
- Jump equal = branch32(Equal, TrustedImm32(rhs), ScratchRegister);
- patches.push_back({ equal, offset });
- isUndef.link(this);
- }
-
- void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset)
- {
- Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value)));
- load64(lhsAddr, ScratchRegister);
- Jump isUndef = branch64(Equal, ScratchRegister, TrustedImm64(0));
- patches.push_back({ isUndef, offset });
- Jump notEqual = branch32(NotEqual, TrustedImm32(rhs), ScratchRegister);
- patches.push_back({ notEqual, offset });
- }
-
void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister)
{
if (sourceReg == NoRegister)
@@ -960,6 +957,16 @@ struct PlatformAssembler32 : PlatformAssemblerCommon
store32(AccumulatorRegisterTag, addr);
}
+ void moveReg(Address sourceRegAddress, Address destRegAddress)
+ {
+ load32(sourceRegAddress, ReturnValueRegisterValue);
+ sourceRegAddress.offset += 4;
+ load32(sourceRegAddress, ReturnValueRegisterTag);
+ store32(ReturnValueRegisterValue, destRegAddress);
+ destRegAddress.offset += 4;
+ store32(ReturnValueRegisterTag, destRegAddress);
+ }
+
void loadString(int stringId)
{
load32(loadStringAddress(stringId), AccumulatorRegisterValue);
@@ -1135,6 +1142,19 @@ struct PlatformAssembler32 : PlatformAssemblerCommon
push(TrustedImm32(v));
}
+ void jumpNotUndefined(int offset)
+ {
+ move(AccumulatorRegisterTag, ScratchRegister);
+ or32(AccumulatorRegisterValue, ScratchRegister);
+ auto jump = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ patches.push_back({ jump, offset });
+ }
+
+ Jump jumpEmpty()
+ {
+ return branch32(Equal, AccumulatorRegisterTag, TrustedImm32(Primitive::emptyValue().asReturnedValue() >> 32));
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32),
@@ -1174,34 +1194,6 @@ struct PlatformAssembler32 : PlatformAssemblerCommon
done.link(this);
}
- void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
- {
- Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value)));
- load32(lhsAddr, ScratchRegister);
- Jump notEqInt = branch32(NotEqual, ScratchRegister, TrustedImm32(rhs));
- Jump notEqUndefVal = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
- patches.push_back({ notEqUndefVal, offset });
- lhsAddr.offset += 4;
- load32(lhsAddr, ScratchRegister);
- Jump notEqUndefTag = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
- patches.push_back({ notEqUndefTag, offset });
- notEqInt.link(this);
- }
-
- void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset)
- {
- Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value)));
- load32(lhsAddr, ScratchRegister);
- Jump notEqual = branch32(NotEqual, TrustedImm32(rhs), ScratchRegister);
- patches.push_back({ notEqual, offset });
- Jump notUndefValue = branch32(NotEqual, TrustedImm32(0), ScratchRegister);
- lhsAddr.offset += 4;
- load32(lhsAddr, ScratchRegister);
- Jump equalUndef = branch32(Equal, TrustedImm32(0), ScratchRegister);
- patches.push_back({ equalUndef, offset });
- notUndefValue.link(this);
- }
-
void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister)
{
if (sourceReg != NoRegister)
@@ -1415,7 +1407,6 @@ void Assembler::link(Function *function)
function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
-#if defined(Q_OS_LINUX)
// This implements writing of JIT'd addresses so that perf can find the
// symbol names.
//
@@ -1423,7 +1414,7 @@ void Assembler::link(Function *function)
// content, for more information, see:
// https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
- if (doProfile) {
+ if (Q_UNLIKELY(doProfile)) {
static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
.arg(QCoreApplication::applicationPid()));
static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
@@ -1441,7 +1432,6 @@ void Assembler::link(Function *function)
perfMapFile.flush();
}
}
-#endif
}
void Assembler::addLabel(int offset)
@@ -1469,6 +1459,11 @@ void Assembler::loadReg(int reg)
pasm()->loadAccumulator(regAddr(reg));
}
+void JIT::Assembler::moveReg(int sourceReg, int destReg)
+{
+ pasm()->moveReg(regAddr(sourceReg), regAddr(destReg));
+}
+
void Assembler::storeReg(int reg)
{
pasm()->storeAccumulator(regAddr(reg));
@@ -1981,14 +1976,19 @@ void Assembler::jumpFalse(int offset)
});
}
-void Assembler::jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
+void Assembler::jumpNoException(int offset)
{
- pasm()->jumpStrictEqualStackSlotInt(lhs, rhs, offset);
+ auto jump = pasm()->branch32(
+ PlatformAssembler::Equal,
+ PlatformAssembler::Address(PlatformAssembler::EngineRegister,
+ offsetof(EngineBase, hasException)),
+ TrustedImm32(0));
+ pasm()->patches.push_back({ jump, offset });
}
-void Assembler::jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset)
+void Assembler::jumpNotUndefined(int offset)
{
- pasm()->jumpStrictNotEqualStackSlotInt(lhs, rhs, offset);
+ pasm()->jumpNotUndefined(offset);
}
void Assembler::prepareCallWithArgCount(int argc)
@@ -2182,39 +2182,70 @@ void Assembler::getException()
void Assembler::setException()
{
+ auto noException = pasm()->jumpEmpty();
Address addr(PlatformAssembler::EngineRegister, offsetof(EngineBase, exceptionValue));
pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister));
addr.offset = offsetof(EngineBase, hasException);
Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1);
pasm()->store8(TrustedImm32(1), addr);
+ noException.link(pasm());
}
-void Assembler::setExceptionHandler(int offset)
+void Assembler::setUnwindHandler(int offset)
{
auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress());
pasm()->ehTargets.push_back({ l, offset });
}
-void Assembler::clearExceptionHandler()
+void Assembler::clearUnwindHandler()
{
pasm()->storePtr(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress());
}
-void Assembler::pushCatchContext(int name, int reg)
+void JIT::Assembler::unwindDispatch()
{
- pasm()->copyReg(pasm()->contextAddress(), regAddr(reg));
- prepareCallWithArgCount(2);
- passInt32AsArg(name, 1);
+ checkException();
+ pasm()->load32(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)), PlatformAssembler::ScratchRegister);
+ auto noUnwind = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
+ pasm()->sub32(TrustedImm32(1), PlatformAssembler::ScratchRegister);
+ pasm()->store32(PlatformAssembler::ScratchRegister, Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
+ auto jump = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
+ gotoCatchException();
+ jump.link(pasm());
+
+ pasm()->loadPtr(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)), PlatformAssembler::ScratchRegister);
+ pasm()->jump(PlatformAssembler::ScratchRegister);
+
+ noUnwind.link(pasm());
+}
+
+void JIT::Assembler::unwindToLabel(int level, int offset)
+{
+ auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)));
+ pasm()->ehTargets.push_back({ l, offset });
+ pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
+ gotoCatchException();
+}
+
+void Assembler::pushCatchContext(int index, int name)
+{
+ prepareCallWithArgCount(3);
+ passInt32AsArg(name, 2);
+ passInt32AsArg(index, 1);
passRegAsArg(CallData::Context, 0);
IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_createCatchContext, ResultInAccumulator);
pasm()->storeAccumulator(pasm()->contextAddress());
}
-void Assembler::popContext(int reg)
+void Assembler::popContext()
{
- pasm()->copyReg(regAddr(reg), pasm()->contextAddress());
+ Heap::CallContext ctx;
+ Q_UNUSED(ctx)
+ pasm()->loadPointerFromValue(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
+ pasm()->loadAccumulator(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset));
+ pasm()->storeAccumulator(regAddr(CallData::Context));
}
void Assembler::ret()
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 37d4232a17..2cf59f53ee 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -90,6 +90,7 @@ public:
void loadConst(int constIndex);
void copyConst(int constIndex, int destReg);
void loadReg(int reg);
+ void moveReg(int sourceReg, int destReg);
void storeReg(int reg);
void loadLocal(int index, int level = 0);
void storeLocal(int index, int level = 0);
@@ -140,8 +141,8 @@ public:
void jump(int offset);
void jumpTrue(int offset);
void jumpFalse(int offset);
- void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset);
- void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset);
+ void jumpNoException(int offset);
+ void jumpNotUndefined(int offset);
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
@@ -160,10 +161,12 @@ public:
void gotoCatchException();
void getException();
void setException();
- void setExceptionHandler(int offset);
- void clearExceptionHandler();
- void pushCatchContext(int name, int reg);
- void popContext(int reg);
+ void setUnwindHandler(int offset);
+ void clearUnwindHandler();
+ void unwindDispatch();
+ void unwindToLabel(int level, int offset);
+ void pushCatchContext(int index, int name);
+ void popContext();
// other stuff
void ret();
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4baselinejit.cpp
index bc46c0ca1d..3e8991122f 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -37,9 +37,10 @@
**
****************************************************************************/
-#include "qv4jit_p.h"
+#include "qv4baselinejit_p.h"
#include "qv4assembler_p.h"
#include <private/qv4lookup_p.h>
+#include <private/qv4generatorobject_p.h>
#ifdef V4_ENABLE_JIT
@@ -48,42 +49,6 @@ using namespace QV4;
using namespace QV4::JIT;
using namespace QV4::Moth;
-ByteCodeHandler::~ByteCodeHandler()
-{
-}
-
-#define DISPATCH_INSTRUCTION(name, nargs, ...) \
- generate_##name( \
- __VA_ARGS__ \
- );
-
-#define DECODE_AND_DISPATCH(instr) \
- { \
- INSTR_##instr(MOTH_DECODE_WITH_BASE) \
- Q_UNUSED(base_ptr); \
- startInstruction(Instr::Type::instr); \
- _offset = code - start; \
- INSTR_##instr(DISPATCH) \
- endInstruction(Instr::Type::instr); \
- continue; \
- }
-
-void ByteCodeHandler::decode(const char *code, uint len)
-{
- MOTH_JUMP_TABLE;
-
- const char *start = code;
- const char *end = code + len;
- while (code < end) {
- MOTH_DISPATCH()
-
- FOR_EACH_MOTH_INSTR(DECODE_AND_DISPATCH)
- }
-}
-
-#undef DECODE_AND_DISPATCH
-#undef DISPATCH_INSTRUCTION
-
BaselineJIT::BaselineJIT(Function *function)
: function(function)
, as(new Assembler(function->compilationUnit->constants))
@@ -95,10 +60,12 @@ BaselineJIT::~BaselineJIT()
void BaselineJIT::generate()
{
// qDebug()<<"jitting" << function->name()->toQString();
- collectLabelsInBytecode();
+ const char *code = function->codeData;
+ uint len = function->compiledFunction->codeSize;
+ labels = collectLabelsInBytecode(code, len);
as->generatePrologue();
- decode(reinterpret_cast<const char *>(function->codeData), function->compiledFunction->codeSize);
+ decode(code, len);
as->generateEpilogue();
as->link(function);
@@ -168,8 +135,8 @@ void BaselineJIT::generate_StoreReg(int reg)
void BaselineJIT::generate_MoveReg(int srcReg, int destReg)
{
- as->loadReg(srcReg);
- as->storeReg(destReg);
+ // Don't clobber the accumulator.
+ as->moveReg(srcReg, destReg);
}
void BaselineJIT::generate_LoadLocal(int index)
@@ -266,18 +233,7 @@ void BaselineJIT::generate_StoreNameStrict(int name)
as->checkException();
}
-void BaselineJIT::generate_LoadElement(int base, int index)
-{
- STORE_IP();
- as->prepareCallWithArgCount(3);
- as->passRegAsArg(index, 2);
- as->passRegAsArg(base, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_loadElement, Assembler::ResultInAccumulator);
- as->checkException();
-}
-
-void BaselineJIT::generate_LoadElementA(int base)
+void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
@@ -309,17 +265,7 @@ void BaselineJIT::generate_StoreElement(int base, int index)
as->checkException();
}
-void BaselineJIT::generate_LoadProperty(int name, int base)
-{
- STORE_IP();
- as->prepareCallWithArgCount(3);
- as->passInt32AsArg(name, 2);
- as->passRegAsArg(base, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_loadProperty, Assembler::ResultInAccumulator);
- as->checkException();
-}
-void BaselineJIT::generate_LoadPropertyA(int name)
+void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
@@ -462,6 +408,18 @@ void BaselineJIT::generate_LoadIdObject(int index, int base)
as->checkException();
}
+void BaselineJIT::generate_Yield()
+{
+ // #####
+ Q_UNREACHABLE();
+}
+
+void BaselineJIT::generate_Resume(int)
+{
+ // #####
+ Q_UNREACHABLE();
+}
+
void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
@@ -574,14 +532,64 @@ void BaselineJIT::generate_CallContextObjectProperty(int propIdx, int base, int
as->checkException();
}
-void BaselineJIT::generate_SetExceptionHandler(int offset)
+
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(5);
+ as->passInt32AsArg(argc, 4);
+ as->passRegAsArg(argv, 3);
+ as->passRegAsArg(thisObject, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_callWithSpread, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+
+void BaselineJIT::generate_Construct(int func, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(4);
+ as->passInt32AsArg(argc, 3);
+ as->passRegAsArg(argv, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_construct, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
+{
+ STORE_IP();
+ as->prepareCallWithArgCount(4);
+ as->passInt32AsArg(argc, 3);
+ as->passRegAsArg(argv, 2);
+ as->passRegAsArg(func, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_constructWithSpread, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+void BaselineJIT::generate_SetUnwindHandler(int offset)
{
if (offset)
- as->setExceptionHandler(instructionOffset() + offset);
+ as->setUnwindHandler(instructionOffset() + offset);
else
- as->clearExceptionHandler();
+ as->clearUnwindHandler();
}
+void BaselineJIT::generate_UnwindDispatch()
+{
+ as->unwindDispatch();
+}
+
+void BaselineJIT::generate_UnwindToLabel(int level, int offset)
+{
+ as->unwindToLabel(level, instructionOffset() + offset);
+}
+
+
void BaselineJIT::generate_ThrowException()
{
STORE_IP();
@@ -604,80 +612,126 @@ void BaselineJIT::generate_CreateCallContext()
as->storeHeapObject(CallData::Context);
}
-void BaselineJIT::generate_PushCatchContext(int name, int reg) { as->pushCatchContext(name, reg); }
+void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
-static void pushWithContextHelper(ExecutionEngine *engine, QV4::Value *stack, int reg)
+void BaselineJIT::generate_PushWithContext()
+{
+ STORE_IP();
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(2);
+ as->passRegAsArg(0, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_createWithContext, Assembler::IgnoreResult); // keeps result in return value register
+ as->checkException();
+ as->storeHeapObject(CallData::Context);
+}
+
+static void pushBlockContextHelper(QV4::Value *stack, int index)
{
- QV4::Value &accumulator = stack[CallData::Accumulator];
- accumulator = accumulator.toObject(engine);
- if (engine->hasException)
- return;
- stack[reg] = stack[CallData::Context];
ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- stack[CallData::Context] = Runtime::method_createWithContext(c, accumulator);
+ stack[CallData::Context] = Runtime::method_createBlockContext(c, index);
}
-void BaselineJIT::generate_PushWithContext(int reg)
+void BaselineJIT::generate_PushBlockContext(int index)
+{
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(2);
+ as->passInt32AsArg(index, 1);
+ as->passRegAsArg(0, 0);
+ JIT_GENERATE_RUNTIME_CALL(pushBlockContextHelper, Assembler::IgnoreResult);
+}
+
+static void cloneBlockContextHelper(QV4::Value *contextSlot)
+{
+ *contextSlot = Runtime::method_cloneBlockContext(static_cast<QV4::ExecutionContext *>(contextSlot));
+}
+
+void BaselineJIT::generate_CloneBlockContext()
+{
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(1);
+ as->passRegAsArg(CallData::Context, 0);
+ JIT_GENERATE_RUNTIME_CALL(cloneBlockContextHelper, Assembler::IgnoreResult);
+}
+
+static void pushScriptContextHelper(QV4::Value *stack, ExecutionEngine *engine, int index)
+{
+ stack[CallData::Context] = Runtime::method_createScriptContext(engine, index);
+}
+
+void BaselineJIT::generate_PushScriptContext(int index)
{
- STORE_IP();
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(3);
- as->passInt32AsArg(reg, 2);
- as->passRegAsArg(0, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(pushWithContextHelper, Assembler::IgnoreResult);
- as->checkException();
+ as->passInt32AsArg(index, 2);
+ as->passEngineAsArg(1);
+ as->passRegAsArg(0, 0);
+ JIT_GENERATE_RUNTIME_CALL(pushScriptContextHelper, Assembler::IgnoreResult);
}
-void BaselineJIT::generate_PopContext(int reg) { as->popContext(reg); }
+static void popScriptContextHelper(QV4::Value *stack, ExecutionEngine *engine)
+{
+ stack[CallData::Context] = Runtime::method_popScriptContext(engine);
+}
-void BaselineJIT::generate_ForeachIteratorObject()
+void BaselineJIT::generate_PopScriptContext()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
+ as->passEngineAsArg(1);
+ as->passRegAsArg(0, 0);
+ JIT_GENERATE_RUNTIME_CALL(popScriptContextHelper, Assembler::IgnoreResult);
+}
+
+void BaselineJIT::generate_PopContext() { as->popContext(); }
+
+void BaselineJIT::generate_GetIterator(int iterator)
+{
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(3);
+ as->passInt32AsArg(iterator, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_foreachIterator, Assembler::ResultInAccumulator);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_getIterator, Assembler::ResultInAccumulator);
as->checkException();
}
-void BaselineJIT::generate_ForeachNextPropertyName()
+void BaselineJIT::generate_IteratorNext(int value)
{
as->saveAccumulatorInFrame();
- as->prepareCallWithArgCount(1);
- as->passAccumulatorAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_foreachNextPropertyName,
- Assembler::ResultInAccumulator);
+ as->prepareCallWithArgCount(3);
+ as->passRegAsArg(value, 2);
+ as->passAccumulatorAsArg(1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorNext, Assembler::ResultInAccumulator);
as->checkException();
}
-static ReturnedValue deleteMemberHelper(QV4::Function *function, const QV4::Value &base, int member)
+void BaselineJIT::generate_IteratorClose(int done)
{
- auto engine = function->internalClass->engine;
- if (!Runtime::method_deleteMember(engine, base, member)) {
- if (function->isStrict())
- engine->throwTypeError();
- return Encode(false);
- } else {
- return Encode(true);
- }
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(3);
+ as->passRegAsArg(done, 2);
+ as->passAccumulatorAsArg(1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorClose, Assembler::ResultInAccumulator);
+ as->checkException();
}
-void BaselineJIT::generate_DeleteMember(int member, int base)
+void BaselineJIT::generate_DestructureRestElement()
{
- STORE_IP();
- as->prepareCallWithArgCount(3);
- as->passInt32AsArg(member, 2);
- as->passRegAsArg(base, 1);
- as->passFunctionAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(deleteMemberHelper, Assembler::ResultInAccumulator);
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(2);
+ as->passAccumulatorAsArg(1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_destructureRestElement, Assembler::ResultInAccumulator);
as->checkException();
}
-static ReturnedValue deleteSubscriptHelper(QV4::Function *function, const QV4::Value &base, const QV4::Value &index)
+static ReturnedValue deletePropertyHelper(QV4::Function *function, const QV4::Value &base, const QV4::Value &index)
{
auto engine = function->internalClass->engine;
- if (!Runtime::method_deleteElement(engine, base, index)) {
+ if (!Runtime::method_deleteProperty(engine, base, index)) {
if (function->isStrict())
engine->throwTypeError();
return Encode(false);
@@ -686,14 +740,14 @@ static ReturnedValue deleteSubscriptHelper(QV4::Function *function, const QV4::V
}
}
-void BaselineJIT::generate_DeleteSubscript(int base, int index)
+void BaselineJIT::generate_DeleteProperty(int base, int index)
{
STORE_IP();
as->prepareCallWithArgCount(3);
as->passRegAsArg(index, 2);
as->passRegAsArg(base, 1);
as->passFunctionAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(deleteSubscriptHelper, Assembler::ResultInAccumulator);
+ JIT_GENERATE_RUNTIME_CALL(deletePropertyHelper, Assembler::ResultInAccumulator);
as->checkException();
}
@@ -754,14 +808,12 @@ void BaselineJIT::generate_DefineArray(int argc, int args)
JIT_GENERATE_RUNTIME_CALL(Runtime::method_arrayLiteral, Assembler::ResultInAccumulator);
}
-void BaselineJIT::generate_DefineObjectLiteral(int internalClassId, int arrayValueCount,
- int arrayGetterSetterCountAndFlags, int args)
+void BaselineJIT::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
{
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(arrayGetterSetterCountAndFlags, 4);
- as->passInt32AsArg(arrayValueCount, 3);
- as->passInt32AsArg(internalClassId, 2);
- as->passRegAsArg(args, 1);
+ as->prepareCallWithArgCount(4);
+ as->passRegAsArg(args, 3);
+ as->passInt32AsArg(argc, 2);
+ as->passInt32AsArg(internalClassId, 1);
as->passEngineAsArg(0);
JIT_GENERATE_RUNTIME_CALL(Runtime::method_objectLiteral, Assembler::ResultInAccumulator);
}
@@ -781,6 +833,14 @@ void BaselineJIT::generate_CreateUnmappedArgumentsObject()
Assembler::ResultInAccumulator);
}
+void BaselineJIT::generate_CreateRestParameter(int argIndex)
+{
+ as->prepareCallWithArgCount(2);
+ as->passInt32AsArg(argIndex, 1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_createRestParameter, Assembler::ResultInAccumulator);
+}
+
static void convertThisToObjectHelper(ExecutionEngine *engine, Value *t)
{
if (!t->isObject()) {
@@ -801,21 +861,30 @@ void BaselineJIT::generate_ConvertThisToObject()
as->checkException();
}
-void BaselineJIT::generate_Construct(int func, int argc, int argv)
+static ReturnedValue ToObjectHelper(ExecutionEngine *engine, const Value &obj)
{
- STORE_IP();
- as->prepareCallWithArgCount(4);
- as->passInt32AsArg(argc, 3);
- as->passRegAsArg(argv, 2);
- as->passRegAsArg(func, 1);
+ if (obj.isObject())
+ return obj.asReturnedValue();
+
+ return obj.toObject(engine)->asReturnedValue();
+}
+
+void BaselineJIT::generate_ToObject()
+{
+ STORE_ACC();
+ as->prepareCallWithArgCount(2);
+ as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_construct, Assembler::ResultInAccumulator);
+ JIT_GENERATE_RUNTIME_CALL(ToObjectHelper, Assembler::ResultInAccumulator);
as->checkException();
+
}
void BaselineJIT::generate_Jump(int offset) { as->jump(instructionOffset() + offset); }
void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(instructionOffset() + offset); }
void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(instructionOffset() + offset); }
+void BaselineJIT::generate_JumpNoException(int offset) { as->jumpNoException(instructionOffset() + offset); }
+void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(instructionOffset() + offset); }
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
@@ -852,16 +921,6 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
as->checkException();
}
-void BaselineJIT::generate_JumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
-{
- as->jumpStrictEqualStackSlotInt(lhs, rhs, instructionOffset() + offset);
-}
-
-void BaselineJIT::generate_JumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset)
-{
- as->jumpStrictNotEqualStackSlotInt(lhs, rhs, instructionOffset() + offset);
-}
-
void BaselineJIT::generate_UNot() { as->unot(); }
void BaselineJIT::generate_UPlus() { as->toNumber(); }
void BaselineJIT::generate_UMinus() { as->uminus(); }
@@ -884,6 +943,24 @@ void BaselineJIT::generate_UShrConst(int rhs) { as->ushrConst(rhs); }
void BaselineJIT::generate_ShrConst(int rhs) { as->shrConst(rhs); }
void BaselineJIT::generate_ShlConst(int rhs) { as->shlConst(rhs); }
+static ReturnedValue expHelper(const Value &base, const Value &exp)
+{
+ double b = base.toNumber();
+ double e = exp.toNumber();
+ if (qIsInf(e) && (b == 1 || b == -1))
+ return Encode(qSNaN());
+ return Encode(pow(b,e));
+}
+
+void BaselineJIT::generate_Exp(int lhs) {
+ STORE_IP();
+ STORE_ACC();
+ as->prepareCallWithArgCount(2);
+ as->passAccumulatorAsArg(1);
+ as->passRegAsArg(lhs, 0);
+ JIT_GENERATE_RUNTIME_CALL(expHelper, Assembler::ResultInAccumulator);
+ as->checkException();
+}
void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
@@ -928,401 +1005,4 @@ void BaselineJIT::endInstruction(Instr::Type instr)
Q_UNUSED(instr);
}
-#define MOTH_UNUSED_ARGS0()
-#define MOTH_UNUSED_ARGS1(arg) \
- Q_UNUSED(arg);
-#define MOTH_UNUSED_ARGS2(arg1, arg2) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2);
-#define MOTH_UNUSED_ARGS3(arg1, arg2, arg3) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2); \
- Q_UNUSED(arg3);
-#define MOTH_UNUSED_ARGS4(arg1, arg2, arg3, arg4) \
- Q_UNUSED(arg1); \
- Q_UNUSED(arg2); \
- Q_UNUSED(arg3); \
- Q_UNUSED(arg4);
-
-#define MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, ...) \
- MOTH_EXPAND_FOR_MSVC(MOTH_UNUSED_ARGS##nargs(__VA_ARGS__))
-
-#define MOTH_MARK_ARGS_UNUSED_INSTRUCTION(name, nargs, ...) \
- MOTH_MARK_ARGS_UNUSED_PLEASE(nargs, __VA_ARGS__)
-
-#define MOTH_BEGIN_INSTR(instr) \
- { \
- INSTR_##instr(MOTH_DECODE_WITH_BASE) \
- INSTR_##instr(MOTH_MARK_ARGS_UNUSED) \
- Q_UNUSED(base_ptr);
-
-#define MOTH_END_INSTR(instr) \
- continue; \
- }
-
-void BaselineJIT::collectLabelsInBytecode()
-{
- MOTH_JUMP_TABLE;
-
- const auto addLabel = [&](int offset) {
- Q_ASSERT(offset >= 0 && offset < static_cast<int>(function->compiledFunction->codeSize));
- labels.push_back(offset);
- };
-
- const char *code = reinterpret_cast<const char *>(function->codeData);
- const char *start = code;
- const char *end = code + function->compiledFunction->codeSize;
- while (code < end) {
- MOTH_DISPATCH()
- Q_UNREACHABLE();
-
- MOTH_BEGIN_INSTR(LoadReg)
- MOTH_END_INSTR(LoadReg)
-
- MOTH_BEGIN_INSTR(StoreReg)
- MOTH_END_INSTR(StoreReg)
-
- MOTH_BEGIN_INSTR(MoveReg)
- MOTH_END_INSTR(MoveReg)
-
- MOTH_BEGIN_INSTR(LoadConst)
- MOTH_END_INSTR(LoadConst)
-
- MOTH_BEGIN_INSTR(LoadNull)
- MOTH_END_INSTR(LoadNull)
-
- MOTH_BEGIN_INSTR(LoadZero)
- MOTH_END_INSTR(LoadZero)
-
- MOTH_BEGIN_INSTR(LoadTrue)
- MOTH_END_INSTR(LoadTrue)
-
- MOTH_BEGIN_INSTR(LoadFalse)
- MOTH_END_INSTR(LoadFalse)
-
- MOTH_BEGIN_INSTR(LoadUndefined)
- MOTH_END_INSTR(LoadUndefined)
-
- MOTH_BEGIN_INSTR(LoadInt)
- MOTH_END_INSTR(LoadInt)
-
- MOTH_BEGIN_INSTR(MoveConst)
- MOTH_END_INSTR(MoveConst)
-
- MOTH_BEGIN_INSTR(LoadLocal)
- MOTH_END_INSTR(LoadLocal)
-
- MOTH_BEGIN_INSTR(StoreLocal)
- MOTH_END_INSTR(StoreLocal)
-
- MOTH_BEGIN_INSTR(LoadScopedLocal)
- MOTH_END_INSTR(LoadScopedLocal)
-
- MOTH_BEGIN_INSTR(StoreScopedLocal)
- MOTH_END_INSTR(StoreScopedLocal)
-
- MOTH_BEGIN_INSTR(LoadRuntimeString)
- MOTH_END_INSTR(LoadRuntimeString)
-
- MOTH_BEGIN_INSTR(MoveRegExp)
- MOTH_END_INSTR(MoveRegExp)
-
- MOTH_BEGIN_INSTR(LoadClosure)
- MOTH_END_INSTR(LoadClosure)
-
- MOTH_BEGIN_INSTR(LoadName)
- MOTH_END_INSTR(LoadName)
-
- MOTH_BEGIN_INSTR(LoadGlobalLookup)
- MOTH_END_INSTR(LoadGlobalLookup)
-
- MOTH_BEGIN_INSTR(StoreNameSloppy)
- MOTH_END_INSTR(StoreNameSloppy)
-
- MOTH_BEGIN_INSTR(StoreNameStrict)
- MOTH_END_INSTR(StoreNameStrict)
-
- MOTH_BEGIN_INSTR(LoadElement)
- MOTH_END_INSTR(LoadElement)
-
- MOTH_BEGIN_INSTR(LoadElementA)
- MOTH_END_INSTR(LoadElement)
-
- MOTH_BEGIN_INSTR(StoreElement)
- MOTH_END_INSTR(StoreElement)
-
- MOTH_BEGIN_INSTR(LoadProperty)
- MOTH_END_INSTR(LoadProperty)
-
- MOTH_BEGIN_INSTR(LoadPropertyA)
- MOTH_END_INSTR(LoadElementA)
-
- MOTH_BEGIN_INSTR(GetLookup)
- MOTH_END_INSTR(GetLookup)
-
- MOTH_BEGIN_INSTR(GetLookupA)
- MOTH_END_INSTR(GetLookupA)
-
- MOTH_BEGIN_INSTR(StoreProperty)
- MOTH_END_INSTR(StoreProperty)
-
- MOTH_BEGIN_INSTR(SetLookup)
- MOTH_END_INSTR(SetLookup)
-
- MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- MOTH_END_INSTR(StoreScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- MOTH_END_INSTR(LoadScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- MOTH_END_INSTR(StoreContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- MOTH_END_INSTR(LoadContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadIdObject)
- MOTH_END_INSTR(LoadIdObject)
-
- MOTH_BEGIN_INSTR(CallValue)
- MOTH_END_INSTR(CallValue)
-
- MOTH_BEGIN_INSTR(CallProperty)
- MOTH_END_INSTR(CallProperty)
-
- MOTH_BEGIN_INSTR(CallPropertyLookup)
- MOTH_END_INSTR(CallPropertyLookup)
-
- MOTH_BEGIN_INSTR(CallElement)
- MOTH_END_INSTR(CallElement)
-
- MOTH_BEGIN_INSTR(CallName)
- MOTH_END_INSTR(CallName)
-
- MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- MOTH_END_INSTR(CallPossiblyDirectEval)
-
- MOTH_BEGIN_INSTR(CallGlobalLookup)
- MOTH_END_INSTR(CallGlobalLookup)
-
- MOTH_BEGIN_INSTR(CallScopeObjectProperty)
- MOTH_END_INSTR(CallScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(CallContextObjectProperty)
- MOTH_END_INSTR(CallContextObjectProperty)
-
- MOTH_BEGIN_INSTR(SetExceptionHandler)
- addLabel(code - start + offset);
- MOTH_END_INSTR(SetExceptionHandler)
-
- MOTH_BEGIN_INSTR(ThrowException)
- MOTH_END_INSTR(ThrowException)
-
- MOTH_BEGIN_INSTR(GetException)
- MOTH_END_INSTR(HasException)
-
- MOTH_BEGIN_INSTR(SetException)
- MOTH_END_INSTR(SetExceptionFlag)
-
- MOTH_BEGIN_INSTR(CreateCallContext)
- MOTH_END_INSTR(CreateCallContext)
-
- MOTH_BEGIN_INSTR(PushCatchContext)
- MOTH_END_INSTR(PushCatchContext)
-
- MOTH_BEGIN_INSTR(PushWithContext)
- MOTH_END_INSTR(PushWithContext)
-
- MOTH_BEGIN_INSTR(PopContext)
- MOTH_END_INSTR(PopContext)
-
- MOTH_BEGIN_INSTR(ForeachIteratorObject)
- MOTH_END_INSTR(ForeachIteratorObject)
-
- MOTH_BEGIN_INSTR(ForeachNextPropertyName)
- MOTH_END_INSTR(ForeachNextPropertyName)
-
- MOTH_BEGIN_INSTR(DeleteMember)
- MOTH_END_INSTR(DeleteMember)
-
- MOTH_BEGIN_INSTR(DeleteSubscript)
- MOTH_END_INSTR(DeleteSubscript)
-
- MOTH_BEGIN_INSTR(DeleteName)
- MOTH_END_INSTR(DeleteName)
-
- MOTH_BEGIN_INSTR(TypeofName)
- MOTH_END_INSTR(TypeofName)
-
- MOTH_BEGIN_INSTR(TypeofValue)
- MOTH_END_INSTR(TypeofValue)
-
- MOTH_BEGIN_INSTR(DeclareVar)
- MOTH_END_INSTR(DeclareVar)
-
- MOTH_BEGIN_INSTR(DefineArray)
- MOTH_END_INSTR(DefineArray)
-
- MOTH_BEGIN_INSTR(DefineObjectLiteral)
- MOTH_END_INSTR(DefineObjectLiteral)
-
- MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
- MOTH_END_INSTR(CreateMappedArgumentsObject)
-
- MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
- MOTH_END_INSTR(CreateUnmappedArgumentsObject)
-
- MOTH_BEGIN_INSTR(ConvertThisToObject)
- MOTH_END_INSTR(ConvertThisToObject)
-
- MOTH_BEGIN_INSTR(Construct)
- MOTH_END_INSTR(Construct)
-
- MOTH_BEGIN_INSTR(Jump)
- addLabel(code - start + offset);
- MOTH_END_INSTR(Jump)
-
- MOTH_BEGIN_INSTR(JumpTrue)
- addLabel(code - start + offset);
- MOTH_END_INSTR(JumpTrue)
-
- MOTH_BEGIN_INSTR(JumpFalse)
- addLabel(code - start + offset);
- MOTH_END_INSTR(JumpFalse)
-
- MOTH_BEGIN_INSTR(CmpEqNull)
- MOTH_END_INSTR(CmpEqNull)
-
- MOTH_BEGIN_INSTR(CmpNeNull)
- MOTH_END_INSTR(CmpNeNull)
-
- MOTH_BEGIN_INSTR(CmpEqInt)
- MOTH_END_INSTR(CmpEq)
-
- MOTH_BEGIN_INSTR(CmpNeInt)
- MOTH_END_INSTR(CmpNeInt)
-
- MOTH_BEGIN_INSTR(CmpEq)
- MOTH_END_INSTR(CmpEq)
-
- MOTH_BEGIN_INSTR(CmpNe)
- MOTH_END_INSTR(CmpNe)
-
- MOTH_BEGIN_INSTR(CmpGt)
- MOTH_END_INSTR(CmpGt)
-
- MOTH_BEGIN_INSTR(CmpGe)
- MOTH_END_INSTR(CmpGe)
-
- MOTH_BEGIN_INSTR(CmpLt)
- MOTH_END_INSTR(CmpLt)
-
- MOTH_BEGIN_INSTR(CmpLe)
- MOTH_END_INSTR(CmpLe)
-
- MOTH_BEGIN_INSTR(CmpStrictEqual)
- MOTH_END_INSTR(CmpStrictEqual)
-
- MOTH_BEGIN_INSTR(CmpStrictNotEqual)
- MOTH_END_INSTR(CmpStrictNotEqual)
-
- MOTH_BEGIN_INSTR(CmpIn)
- MOTH_END_INSTR(CmpIn)
-
- MOTH_BEGIN_INSTR(CmpInstanceOf)
- MOTH_END_INSTR(CmpInstanceOf)
-
- MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
- addLabel(code - start + offset);
- MOTH_END_INSTR(JumpStrictEqualStackSlotInt)
-
- MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
- addLabel(code - start + offset);
- MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
-
- MOTH_BEGIN_INSTR(UNot)
- MOTH_END_INSTR(UNot)
-
- MOTH_BEGIN_INSTR(UPlus)
- MOTH_END_INSTR(UPlus)
-
- MOTH_BEGIN_INSTR(UMinus)
- MOTH_END_INSTR(UMinus)
-
- MOTH_BEGIN_INSTR(UCompl)
- MOTH_END_INSTR(UCompl)
-
- MOTH_BEGIN_INSTR(Increment)
- MOTH_END_INSTR(PreIncrement)
-
- MOTH_BEGIN_INSTR(Decrement)
- MOTH_END_INSTR(PreDecrement)
-
- MOTH_BEGIN_INSTR(Add)
- MOTH_END_INSTR(Add)
-
- MOTH_BEGIN_INSTR(BitAnd)
- MOTH_END_INSTR(BitAnd)
-
- MOTH_BEGIN_INSTR(BitOr)
- MOTH_END_INSTR(BitOr)
-
- MOTH_BEGIN_INSTR(BitXor)
- MOTH_END_INSTR(BitXor)
-
- MOTH_BEGIN_INSTR(UShr)
- MOTH_END_INSTR(UShr)
-
- MOTH_BEGIN_INSTR(Shr)
- MOTH_END_INSTR(Shr)
-
- MOTH_BEGIN_INSTR(Shl)
- MOTH_END_INSTR(Shl)
-
- MOTH_BEGIN_INSTR(BitAndConst)
- MOTH_END_INSTR(BitAndConst)
-
- MOTH_BEGIN_INSTR(BitOrConst)
- MOTH_END_INSTR(BitOr)
-
- MOTH_BEGIN_INSTR(BitXorConst)
- MOTH_END_INSTR(BitXor)
-
- MOTH_BEGIN_INSTR(UShrConst)
- MOTH_END_INSTR(UShrConst)
-
- MOTH_BEGIN_INSTR(ShrConst)
- MOTH_END_INSTR(ShrConst)
-
- MOTH_BEGIN_INSTR(ShlConst)
- MOTH_END_INSTR(ShlConst)
-
- MOTH_BEGIN_INSTR(Mul)
- MOTH_END_INSTR(Mul)
-
- MOTH_BEGIN_INSTR(Div)
- MOTH_END_INSTR(Div)
-
- MOTH_BEGIN_INSTR(Mod)
- MOTH_END_INSTR(Mod)
-
- MOTH_BEGIN_INSTR(Sub)
- MOTH_END_INSTR(Sub)
-
- MOTH_BEGIN_INSTR(Ret)
- MOTH_END_INSTR(Ret)
-
- MOTH_BEGIN_INSTR(Debug)
- MOTH_END_INSTR(Debug)
-
- MOTH_BEGIN_INSTR(LoadQmlContext)
- MOTH_END_INSTR(LoadQmlContext)
-
- MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- MOTH_END_INSTR(LoadQmlImportedScripts)
- }
-}
-#undef MOTH_BEGIN_INSTR
-#undef MOTH_END_INSTR
-
#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 5aebf78a8d..11548219af 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -54,36 +54,10 @@
#include <private/qv4global_p.h>
#include <private/qv4function_p.h>
#include <private/qv4instr_moth_p.h>
+#include <private/qv4bytecodehandler_p.h>
//QT_REQUIRE_CONFIG(qml_jit);
-#define JIT_DEFINE_ARGS(nargs, ...) \
- MOTH_EXPAND_FOR_MSVC(JIT_DEFINE_ARGS##nargs(__VA_ARGS__))
-
-#define JIT_DEFINE_ARGS0()
-#define JIT_DEFINE_ARGS1(arg) \
- int arg
-#define JIT_DEFINE_ARGS2(arg1, arg2) \
- int arg1, \
- int arg2
-#define JIT_DEFINE_ARGS3(arg1, arg2, arg3) \
- int arg1, \
- int arg2, \
- int arg3
-#define JIT_DEFINE_ARGS4(arg1, arg2, arg3, arg4) \
- int arg1, \
- int arg2, \
- int arg3, \
- int arg4
-
-#define JIT_DEFINE_VIRTUAL_BYTECODE_HANDLER_INSTRUCTION(name, nargs, ...) \
- virtual void generate_##name( \
- JIT_DEFINE_ARGS(nargs, __VA_ARGS__) \
- ) = 0;
-
-#define JIT_DEFINE_VIRTUAL_BYTECODE_HANDLER(instr) \
- INSTR_##instr(JIT_DEFINE_VIRTUAL_BYTECODE_HANDLER)
-
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -91,31 +65,12 @@ namespace JIT {
class Assembler;
-class ByteCodeHandler
-{
-public:
- virtual ~ByteCodeHandler();
-
- void decode(const char *code, uint len);
-
- int instructionOffset() const { return _offset; }
-
-protected:
- FOR_EACH_MOTH_INSTR(JIT_DEFINE_VIRTUAL_BYTECODE_HANDLER)
-
- virtual void startInstruction(Moth::Instr::Type instr) = 0;
- virtual void endInstruction(Moth::Instr::Type instr) = 0;
-
-private:
- int _offset = 0;
-};
-
#ifdef V4_ENABLE_JIT
-class BaselineJIT final: public ByteCodeHandler
+class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
BaselineJIT(QV4::Function *);
- virtual ~BaselineJIT();
+ virtual ~BaselineJIT() Q_DECL_OVERRIDE;
void generate();
@@ -143,11 +98,9 @@ public:
void generate_LoadGlobalLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int index) override;
- void generate_LoadElementA(int base) override;
+ void generate_LoadElement(int base) override;
void generate_StoreElement(int base, int index) override;
- void generate_LoadProperty(int name, int base) override;
- void generate_LoadPropertyA(int name) override;
+ void generate_LoadProperty(int name) override;
void generate_GetLookup(int index, int base) override;
void generate_GetLookupA(int index) override;
void generate_StoreProperty(int name, int base) override;
@@ -161,6 +114,9 @@ public:
void generate_LoadContextObjectProperty(int propertyIndex, int base,
int captureRequired) override;
void generate_LoadIdObject(int index, int base) override;
+ void generate_Yield() override;
+ void generate_Resume(int) override;
+
void generate_CallValue(int name, 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;
@@ -170,33 +126,44 @@ public:
void generate_CallGlobalLookup(int index, int argc, int argv) override;
void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv) override;
void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv) override;
- void generate_SetExceptionHandler(int offset) override;
+ void generate_CallWithSpread(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;
+ void generate_SetUnwindHandler(int offset) override;
+ void generate_UnwindDispatch() override;
+ void generate_UnwindToLabel(int level, int offset) override;
void generate_ThrowException() override;
void generate_GetException() override;
void generate_SetException() override;
void generate_CreateCallContext() override;
- void generate_PushCatchContext(int name, int reg) override;
- void generate_PushWithContext(int reg) override;
- void generate_PopContext(int reg) override;
- void generate_ForeachIteratorObject() override;
- void generate_ForeachNextPropertyName() override;
- void generate_DeleteMember(int member, int base) override;
- void generate_DeleteSubscript(int base, int index) override;
+ void generate_PushCatchContext(int index, int name) override;
+ void generate_PushWithContext() override;
+ void generate_PushBlockContext(int index) override;
+ void generate_CloneBlockContext() override;
+ void generate_PushScriptContext(int index) override;
+ void generate_PopScriptContext() override;
+ void generate_PopContext() override;
+ void generate_GetIterator(int iterator) override;
+ void generate_IteratorNext(int value) override;
+ void generate_IteratorClose(int done) override;
+ void generate_DestructureRestElement() override;
+ void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;
void generate_TypeofName(int name) override;
void generate_TypeofValue() override;
void generate_DeclareVar(int varName, int isDeletable) override;
void generate_DefineArray(int argc, int args) override;
- void generate_DefineObjectLiteral(int internalClassId, int arrayValueCount,
- int arrayGetterSetterCountAndFlags,
- int args) override;
+ void generate_DefineObjectLiteral(int internalClassId, int argc, int args) override;
void generate_CreateMappedArgumentsObject() override;
void generate_CreateUnmappedArgumentsObject() override;
+ void generate_CreateRestParameter(int argIndex) override;
void generate_ConvertThisToObject() override;
- void generate_Construct(int func, int argc, int argv) override;
+ void generate_ToObject() override;
void generate_Jump(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_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
@@ -211,10 +178,6 @@ public:
void generate_CmpStrictNotEqual(int lhs) override;
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
- void generate_JumpStrictEqualStackSlotInt(int lhs, int rhs,
- int offset) override;
- void generate_JumpStrictNotEqualStackSlotInt(int lhs, int rhs,
- int offset) override;
void generate_UNot() override;
void generate_UPlus() override;
void generate_UMinus() override;
@@ -234,6 +197,7 @@ public:
void generate_UShrConst(int rhs) override;
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
+ void generate_Exp(int lhs) override;
void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
void generate_Mod(int lhs) override;
@@ -249,9 +213,6 @@ protected:
{ return std::find(labels.cbegin(), labels.cend(), instructionOffset()) != labels.cend(); }
private:
- void collectLabelsInBytecode();
-
-private:
QV4::Function *function;
QScopedPointer<Assembler> as;
std::vector<int> labels;
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index c483af638b..ebc35a8fd7 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -304,9 +304,9 @@ QJSEngine::QJSEngine()
QJSEngine::QJSEngine(QObject *parent)
: QObject(*new QJSEnginePrivate, parent)
- , m_v4Engine(new QV4::ExecutionEngine)
+ , m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(this, m_v4Engine);
+ m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
QJSEnginePrivate::addToDebugServer(this);
@@ -317,9 +317,9 @@ QJSEngine::QJSEngine(QObject *parent)
*/
QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
: QObject(dd, parent)
- , m_v4Engine(new QV4::ExecutionEngine)
+ , m_v4Engine(new QV4::ExecutionEngine(this))
{
- m_v4Engine->v8Engine = new QV8Engine(this, m_v4Engine);
+ m_v4Engine->v8Engine = new QV8Engine(m_v4Engine);
checkForApplicationInstance();
}
@@ -462,7 +462,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
QV4::Scope scope(v4);
QV4::ScopedValue result(scope);
- QV4::Script script(v4->rootContext(), QV4::Compiler::GlobalCode, program, fileName, lineNumber);
+ QV4::Script script(v4->rootContext(), QV4::Compiler::ContextType::Global, program, fileName, lineNumber);
script.strictMode = false;
if (v4->currentStackFrame)
script.strictMode = v4->currentStackFrame->v4Function->isStrict();
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index ce472ce7e5..222f63ed4a 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -57,7 +57,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
QV4::Scope scope(e);
QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&v));
- iterator.set(e, e->newForEachIteratorObject(o));
+ iterator.set(e, e->newForInIteratorObject(o));
}
@@ -102,7 +102,7 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object)
if (!v4)
return;
QV4::Scope scope(v4);
- QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
+ QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
it->d()->it().flags = QV4::ObjectIterator::NoFlags;
QV4::ScopedString nm(scope);
QV4::Property nextProperty;
@@ -153,7 +153,7 @@ bool QJSValueIterator::next()
if (!v4)
return false;
QV4::Scope scope(v4);
- QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
+ QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
QV4::ScopedString nm(scope);
QV4::Property nextProperty;
QV4::PropertyAttributes nextAttributes;
@@ -229,8 +229,8 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, QJSValuePrivate::getValue(&object));
- d_ptr->iterator.set(v4, v4->newForEachIteratorObject(o));
- QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
+ d_ptr->iterator.set(v4, v4->newForInIteratorObject(o));
+ QV4::Scoped<QV4::ForInIteratorObject> it(scope, d_ptr->iterator.value());
it->d()->it().flags = QV4::ObjectIterator::NoFlags;
QV4::ScopedString nm(scope);
QV4::Property nextProperty;
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 4bc877bd9d..a2408d7d2a 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -14,13 +14,16 @@ SOURCES += \
$$PWD/qv4sparsearray.cpp \
$$PWD/qv4arraydata.cpp \
$$PWD/qv4arrayobject.cpp \
+ $$PWD/qv4arrayiterator.cpp \
$$PWD/qv4argumentsobject.cpp \
$$PWD/qv4booleanobject.cpp \
$$PWD/qv4dateobject.cpp \
$$PWD/qv4errorobject.cpp \
$$PWD/qv4function.cpp \
$$PWD/qv4functionobject.cpp \
+ $$PWD/qv4generatorobject.cpp \
$$PWD/qv4globalobject.cpp \
+ $$PWD/qv4iterator.cpp \
$$PWD/qv4jsonobject.cpp \
$$PWD/qv4mathobject.cpp \
$$PWD/qv4memberdata.cpp \
@@ -28,7 +31,9 @@ SOURCES += \
$$PWD/qv4object.cpp \
$$PWD/qv4objectproto.cpp \
$$PWD/qv4qmlcontext.cpp \
+ $$PWD/qv4reflect.cpp \
$$PWD/qv4regexpobject.cpp \
+ $$PWD/qv4stringiterator.cpp \
$$PWD/qv4stringobject.cpp \
$$PWD/qv4variantobject.cpp \
$$PWD/qv4objectiterator.cpp \
@@ -36,13 +41,17 @@ SOURCES += \
$$PWD/qv4runtimecodegen.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4sequenceobject.cpp \
+ $$PWD/qv4symbol.cpp \
+ $$PWD/qv4setobject.cpp \
+ $$PWD/qv4setiterator.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4arraybuffer.cpp \
$$PWD/qv4typedarray.cpp \
$$PWD/qv4dataview.cpp \
- $$PWD/qv4vme_moth.cpp
+ $$PWD/qv4vme_moth.cpp \
+ $$PWD/qv4mapobject.cpp \
+ $$PWD/qv4mapiterator.cpp
qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp
@@ -64,13 +73,16 @@ HEADERS += \
$$PWD/qv4sparsearray_p.h \
$$PWD/qv4arraydata_p.h \
$$PWD/qv4arrayobject_p.h \
+ $$PWD/qv4arrayiterator_p.h \
$$PWD/qv4argumentsobject_p.h \
$$PWD/qv4booleanobject_p.h \
$$PWD/qv4dateobject_p.h \
$$PWD/qv4errorobject_p.h \
$$PWD/qv4function_p.h \
$$PWD/qv4functionobject_p.h \
+ $$PWD/qv4generatorobject_p.h \
$$PWD/qv4globalobject_p.h \
+ $$PWD/qv4iterator_p.h \
$$PWD/qv4jsonobject_p.h \
$$PWD/qv4mathobject_p.h \
$$PWD/qv4memberdata_p.h \
@@ -78,8 +90,10 @@ HEADERS += \
$$PWD/qv4object_p.h \
$$PWD/qv4objectproto_p.h \
$$PWD/qv4qmlcontext_p.h \
+ $$PWD/qv4reflect_p.h \
$$PWD/qv4regexpobject_p.h \
$$PWD/qv4runtimecodegen_p.h \
+ $$PWD/qv4stringiterator_p.h \
$$PWD/qv4stringobject_p.h \
$$PWD/qv4variantobject_p.h \
$$PWD/qv4property_p.h \
@@ -87,16 +101,28 @@ HEADERS += \
$$PWD/qv4regexp_p.h \
$$PWD/qv4serialize_p.h \
$$PWD/qv4script_p.h \
+ $$PWD/qv4symbol_p.h \
+ $$PWD/qv4setobject_p.h \
+ $$PWD/qv4setiterator_p.h \
$$PWD/qv4scopedvalue_p.h \
$$PWD/qv4executableallocator_p.h \
- $$PWD/qv4sequenceobject_p.h \
$$PWD/qv4include_p.h \
$$PWD/qv4qobjectwrapper_p.h \
$$PWD/qv4profiling_p.h \
$$PWD/qv4arraybuffer_p.h \
$$PWD/qv4typedarray_p.h \
$$PWD/qv4dataview_p.h \
- $$PWD/qv4vme_moth_p.h
+ $$PWD/qv4vme_moth_p.h \
+ $$PWD/qv4mapobject_p.h \
+ $$PWD/qv4mapiterator_p.h
+
+qtConfig(qml-sequence-object) {
+ HEADERS += \
+ $$PWD/qv4sequenceobject_p.h
+
+ SOURCES += \
+ $$PWD/qv4sequenceobject.cpp
+}
}
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 075e7afd8a..58951d043c 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -37,11 +37,13 @@
**
****************************************************************************/
#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>
using namespace QV4;
@@ -61,10 +63,12 @@ void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
- Q_ASSERT(CalleePropertyIndex == internalClass->find(v4->id_callee()));
+ Q_ASSERT(CalleePropertyIndex == internalClass->find(v4->id_callee()->identifier()));
setProperty(v4, CalleePropertyIndex, context->d()->function);
- Q_ASSERT(LengthPropertyIndex == internalClass->find(v4->id_length()));
+ Q_ASSERT(LengthPropertyIndex == internalClass->find(v4->id_length()->identifier()));
setProperty(v4, LengthPropertyIndex, Primitive::fromInt32(context->argc()));
+ Q_ASSERT(SymbolIteratorPropertyIndex == internalClass->find(v4->symbol_iterator()->identifier()));
+ setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
}
void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
@@ -74,19 +78,18 @@ void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
Object::init();
- Q_ASSERT(CalleePropertyIndex == internalClass->find(v4->id_callee()));
- Q_ASSERT(CallerPropertyIndex == internalClass->find(v4->id_caller()));
+ Q_ASSERT(CalleePropertyIndex == internalClass->find(v4->id_callee()->identifier()));
+ Q_ASSERT(SymbolIteratorPropertyIndex == internalClass->find(v4->symbol_iterator()->identifier()));
+ setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
setProperty(v4, CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
setProperty(v4, CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
- setProperty(v4, CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
- setProperty(v4, CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
Scope scope(v4);
Scoped<QV4::StrictArgumentsObject> args(scope, this);
args->arrayReserve(frame->originalArgumentsCount);
args->arrayPut(0, frame->originalArguments, frame->originalArgumentsCount);
- Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()));
+ Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()->identifier()));
setProperty(v4, LengthPropertyIndex, Primitive::fromInt32(frame->originalArgumentsCount));
}
@@ -136,7 +139,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
mapAttrs = arrayData()->attributes(index);
arrayData()->getProperty(index, map, &mapAttrs);
setArrayAttributes(index, Attr_Data);
- ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) };
+ PropertyIndex arrayIndex{ arrayData(), arrayData()->values.values + arrayData()->mappedIndex(index) };
arrayIndex.set(scope.engine, d()->mappedArguments->values[index]);
}
@@ -245,10 +248,8 @@ ReturnedValue ArgumentsSetterFunction::call(const FunctionObject *setter, const
return Encode::undefined();
}
-uint ArgumentsObject::getLength(const Managed *m)
+qint64 ArgumentsObject::getLength(const Managed *m)
{
const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
- if (a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->isInteger())
- return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->integerValue();
- return Primitive::toUInt32(a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->doubleValue());
+ return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->toLength();
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index ac281f555a..f246f66019 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -85,7 +85,8 @@ DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
DECLARE_MARKOBJECTS(ArgumentsObject);
enum {
LengthPropertyIndex = 0,
- CalleePropertyIndex = 1
+ SymbolIteratorPropertyIndex = 1,
+ CalleePropertyIndex = 2
};
void init(CppStackFrame *frame);
};
@@ -95,8 +96,8 @@ DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
DECLARE_HEAP_OBJECT(StrictArgumentsObject, Object) {
enum {
LengthPropertyIndex = 0,
- CalleePropertyIndex = 1,
- CallerPropertyIndex = 3
+ SymbolIteratorPropertyIndex = 1,
+ CalleePropertyIndex = 2
};
void init(CppStackFrame *frame);
};
@@ -142,7 +143,7 @@ struct ArgumentsObject: Object {
bool fullyCreated() const { return d()->fullyCreated; }
static bool isNonStrictArgumentsObject(Managed *m) {
- return m->d()->vtable() == staticVTable();
+ return m->vtable() == staticVTable();
}
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
@@ -150,7 +151,7 @@ struct ArgumentsObject: Object {
static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static uint getLength(const Managed *m);
+ static qint64 getLength(const Managed *m);
void fullyCreate();
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index 59a2b9d913..b0c2ba597a 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -41,6 +41,7 @@
#include "qv4dataview_p.h"
#include "qv4string_p.h"
#include "qv4jscall_p.h"
+#include "qv4symbol_p.h"
using namespace QV4;
@@ -94,7 +95,8 @@ ReturnedValue ArrayBufferCtor::method_isView(const FunctionObject *, const Value
void Heap::ArrayBuffer::init(size_t length)
{
Object::init();
- data = QTypedArrayData<char>::allocate(length + 1);
+ if (length < UINT_MAX)
+ data = QTypedArrayData<char>::allocate(length + 1);
if (!data) {
internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
return;
@@ -147,13 +149,17 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1);
+ ctor->addSymbolSpecies();
+
defineDefaultProperty(engine->id_constructor(), (o = ctor));
defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
+ ScopedString name(scope, engine->newString(QStringLiteral("ArrayBuffer")));
+ defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
}
ReturnedValue ArrayBufferPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 855407e6f7..ecc0b138c0 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -59,8 +59,9 @@ const QV4::VTable QV4::ArrayData::static_vtbl = {
QV4::ArrayData::IsFunctionObject,
QV4::ArrayData::IsErrorObject,
QV4::ArrayData::IsArrayData,
- 0,
+ QV4::ArrayData::IsStringOrSymbol,
QV4::ArrayData::MyType,
+ { 0, 0, 0, 0 },
"ArrayData",
Q_VTABLE_FUNCTION(QV4::ArrayData, destroy),
ArrayData::Data::markObjects,
@@ -104,13 +105,6 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF
Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SimpleArrayData));
Q_STATIC_ASSERT(sizeof(Heap::ArrayData) == sizeof(Heap::SparseArrayData));
-static Q_ALWAYS_INLINE void storeValue(ReturnedValue *target, uint value)
-{
- Value v;
- v.setEmpty(value);
- *target = v.asReturnedValue();
-}
-
void Heap::ArrayData::markObjects(Heap::Base *base, MarkStack *stack)
{
ArrayData *a = static_cast<ArrayData *>(base);
@@ -195,7 +189,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
Heap::SparseArrayData *sparse = static_cast<Heap::SparseArrayData *>(newData->d());
- ReturnedValue *lastFree;
+ Value *lastFree;
if (d && d->type() == Heap::ArrayData::Sparse) {
Heap::SparseArrayData *old = static_cast<Heap::SparseArrayData *>(d->d());
sparse->sparse = old->sparse;
@@ -204,29 +198,29 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
} else {
sparse->sparse = new SparseArray;
lastFree = &sparse->sparse->freeList;
- storeValue(lastFree, 0);
+ *lastFree = Encode(0);
for (uint i = 0; i < toCopy; ++i) {
if (!sparse->values[i].isEmpty()) {
SparseArrayNode *n = sparse->sparse->insert(i);
n->value = i;
} else {
- storeValue(lastFree, i);
+ *lastFree = Encode(i);
sparse->values.values[i].setEmpty();
- lastFree = &sparse->values.values[i].rawValueRef();
+ lastFree = &sparse->values.values[i];
}
}
}
if (toCopy < sparse->values.alloc) {
for (uint i = toCopy; i < sparse->values.alloc; ++i) {
- storeValue(lastFree, i);
+ *lastFree = Encode(i);
sparse->values.values[i].setEmpty();
- lastFree = &sparse->values.values[i].rawValueRef();
+ lastFree = &sparse->values.values[i];
}
}
- storeValue(lastFree, UINT_MAX);
+ *lastFree = Encode(-1);
- Q_ASSERT(Value::fromReturnedValue(sparse->sparse->freeList).isEmpty());
+ Q_ASSERT(sparse->sparse->freeList.isInteger());
// ### Could explicitly free the old data
}
@@ -368,12 +362,12 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx)
Value *v = d->values.values + idx;
if (d->attrs && d->attrs[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
- v[1].setEmpty(Value::fromReturnedValue(d->sparse->freeList).emptyValue());
- v[0].setEmpty(idx + 1);
+ v[1] = d->sparse->freeList;
+ v[0] = Encode(idx + 1);
} else {
- v->setEmpty(Value::fromReturnedValue(d->sparse->freeList).emptyValue());
+ *v = d->sparse->freeList;
}
- d->sparse->freeList = Primitive::emptyValue(idx).asReturnedValue();
+ d->sparse->freeList = Encode(idx);
if (d->attrs)
d->attrs[idx].clear();
}
@@ -390,36 +384,34 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Sparse);
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
if (doubleSlot) {
- ReturnedValue *last = &dd->sparse->freeList;
+ Value *last = &dd->sparse->freeList;
while (1) {
- if (Value::fromReturnedValue(*last).value() == UINT_MAX) {
+ if (last->int_32() == -1) {
reallocate(o, dd->values.alloc + 2, true);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
last = &dd->sparse->freeList;
- Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX);
+ Q_ASSERT(last->int_32() != -1);
}
- Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
- if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
+ Q_ASSERT(dd->values[static_cast<uint>(last->int_32())].int_32() != last->int_32());
+ if (dd->values[static_cast<uint>(last->int_32())].int_32() == last->int_32() + 1) {
// found two slots in a row
- uint idx = Value::fromReturnedValue(*last).emptyValue();
- Value lastV = Value::fromReturnedValue(*last);
- lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value());
- *last = lastV.rawValue();
+ uint idx = static_cast<uint>(last->int_32());
+ *last = Encode(dd->values[static_cast<uint>(last->int_32()) + 1].int_32());
dd->attrs[idx] = Attr_Accessor;
return idx;
}
- last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef();
+ last = &dd->values.values[last->int_32()];
}
} else {
- if (Value::fromReturnedValue(dd->sparse->freeList).value() == UINT_MAX) {
+ if (dd->sparse->freeList.int_32() == -1) {
reallocate(o, dd->values.alloc + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- uint idx = Value::fromReturnedValue(dd->sparse->freeList).value();
- Q_ASSERT(idx != UINT_MAX);
- dd->sparse->freeList = dd->values[idx].asReturnedValue();
- Q_ASSERT(Value::fromReturnedValue(dd->sparse->freeList).isEmpty());
+ Q_ASSERT(dd->sparse->freeList.int_32() != -1);
+ uint idx = static_cast<uint>(dd->sparse->freeList.int_32());
+ dd->sparse->freeList = dd->values[idx];
+ Q_ASSERT(dd->sparse->freeList.isInteger());
if (dd->attrs)
dd->attrs[idx] = Attr_Data;
return idx;
@@ -474,14 +466,14 @@ bool SparseArrayData::del(Object *o, uint index)
if (isAccessor) {
// free up both indices
- dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->sparse->freeList).emptyValue());
- dd->values.values[pidx].setEmpty(pidx + 1);
+ dd->values.values[pidx + 1] = dd->sparse->freeList;
+ dd->values.values[pidx] = Encode(pidx + 1);
} else {
Q_ASSERT(dd->type == Heap::ArrayData::Sparse);
- dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->sparse->freeList).emptyValue());
+ dd->values.values[pidx] = dd->sparse->freeList;
}
- dd->sparse->freeList = Primitive::emptyValue(pidx).asReturnedValue();
+ dd->sparse->freeList = Encode(pidx);
dd->sparse->erase(n);
return true;
}
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 7ec060f9c6..ac5b430356 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -103,28 +103,16 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) {
enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 };
- struct Index {
- Heap::ArrayData *arrayData;
- uint index;
-
- void set(EngineBase *e, Value newVal) {
- arrayData->values.set(e, index, newVal);
- }
- const Value *operator->() const { return &arrayData->values[index]; }
- const Value &operator*() const { return arrayData->values[index]; }
- bool isNull() const { return !arrayData; }
- };
-
bool isSparse() const { return type == Sparse; }
- const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); }
+ const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); }
inline ReturnedValue get(uint i) const {
return vtable()->get(this, i);
}
inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
inline void setProperty(EngineBase *e, uint index, const Property *p);
- inline Index getValueOrSetter(uint index, PropertyAttributes *attrs);
+ inline PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs);
inline PropertyAttributes attributes(uint i) const;
bool isEmpty(uint i) const {
@@ -187,8 +175,6 @@ struct Q_QML_EXPORT ArrayData : public Managed
IsArrayData = true
};
- typedef Heap::ArrayData::Index Index;
-
uint alloc() const { return d()->values.alloc; }
uint &alloc() { return d()->values.alloc; }
void setAlloc(uint a) { d()->values.alloc = a; }
@@ -303,9 +289,9 @@ bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
*attrs = attributes(index);
if (p) {
- p->value = *(Index{ this, mapped });
+ p->value = *(PropertyIndex{ this, values.values + mapped });
if (attrs->isAccessor())
- p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ p->set = *(PropertyIndex{ this, values.values + mapped + 1 /*Object::SetterOffset*/ });
}
return true;
}
@@ -326,16 +312,18 @@ inline PropertyAttributes ArrayData::attributes(uint i) const
return static_cast<const SimpleArrayData *>(this)->attributes(i);
}
-ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
+PropertyIndex ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
uint idx = mappedIndex(index);
if (idx == UINT_MAX) {
*attrs = Attr_Invalid;
- return { nullptr, 0 };
+ return { nullptr, nullptr };
}
*attrs = attributes(index);
- return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx };
+ if (attrs->isAccessor())
+ ++idx;
+ return { this, values.values + idx };
}
diff --git a/src/qml/jsruntime/qv4arrayiterator.cpp b/src/qml/jsruntime/qv4arrayiterator.cpp
new file mode 100644
index 0000000000..d6f787c01d
--- /dev/null
+++ b/src/qml/jsruntime/qv4arrayiterator.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
+** 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 <private/qv4iterator_p.h>
+#include <private/qv4arrayiterator_p.h>
+#include <private/qv4typedarray_p.h>
+#include <private/qv4symbol_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(ArrayIteratorObject);
+
+void ArrayIteratorPrototype::init(ExecutionEngine *e)
+{
+ defineDefaultProperty(QStringLiteral("next"), method_next, 0);
+
+ Scope scope(e);
+ ScopedString val(scope, e->newString(QLatin1String("Array Iterator")));
+ defineReadonlyConfigurableProperty(e->symbol_toStringTag(), val);
+}
+
+ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const Value *that, const Value *, int)
+{
+ Scope scope(b);
+ const ArrayIteratorObject *thisObject = that->as<ArrayIteratorObject>();
+ if (!thisObject)
+ return scope.engine->throwTypeError(QLatin1String("Not an Array Iterator instance"));
+
+ ScopedObject a(scope, thisObject->d()->iteratedObject);
+ if (!a) {
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ quint32 index = thisObject->d()->nextIndex;
+ IteratorKind itemKind = thisObject->d()->iterationKind;
+
+ Scoped<TypedArray> ta(scope, a->as<TypedArray>());
+ quint32 len = a->getLength();
+
+ if (index >= len) {
+ thisObject->d()->iteratedObject.set(scope.engine, nullptr);
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ thisObject->d()->nextIndex = index + 1;
+ if (itemKind == KeyIteratorKind) {
+ return IteratorPrototype::createIterResultObject(scope.engine, Primitive::fromInt32(index), false);
+ }
+
+ ReturnedValue elementValue = a->getIndexed(index);
+ CHECK_EXCEPTION();
+
+ if (itemKind == ValueIteratorKind) {
+ return IteratorPrototype::createIterResultObject(scope.engine, Value::fromReturnedValue(elementValue), false);
+ } else {
+ Q_ASSERT(itemKind == KeyValueIteratorKind);
+
+ ScopedArrayObject resultArray(scope, scope.engine->newArrayObject());
+ resultArray->arrayReserve(2);
+ resultArray->arrayPut(0, Primitive::fromInt32(index));
+ resultArray->arrayPut(1, Value::fromReturnedValue(elementValue));
+ resultArray->setArrayLengthUnchecked(2);
+
+ return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false);
+ }
+}
+
diff --git a/src/qml/jsruntime/qv4arrayiterator_p.h b/src/qml/jsruntime/qv4arrayiterator_p.h
new file mode 100644
index 0000000000..6d6bb466f1
--- /dev/null
+++ b/src/qml/jsruntime/qv4arrayiterator_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
+** 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 QV4ARRAYITERATOR_P_H
+#define QV4ARRAYITERATOR_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 "qv4object_p.h"
+#include "qv4iterator_p.h"
+#include "qv4arraydata_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace QV4 {
+
+namespace Heap {
+
+#define ArrayIteratorObjectMembers(class, Member) \
+ Member(class, Pointer, Object *, iteratedObject) \
+ Member(class, NoMark, IteratorKind, iterationKind) \
+ Member(class, NoMark, quint32, nextIndex)
+
+DECLARE_HEAP_OBJECT(ArrayIteratorObject, Object) {
+ DECLARE_MARKOBJECTS(ArrayIteratorObject);
+ void init(Object *obj, QV4::ExecutionEngine *engine)
+ {
+ Object::init();
+ this->iteratedObject.set(engine, obj);
+ this->nextIndex = 0;
+ }
+};
+
+}
+
+struct ArrayIteratorPrototype : Object
+{
+ V4_PROTOTYPE(iteratorPrototype)
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct ArrayIteratorObject : Object
+{
+ V4_OBJECT2(ArrayIteratorObject, Object)
+ Q_MANAGED_TYPE(ArrayIteratorObject)
+ V4_PROTOTYPE(arrayIteratorPrototype)
+
+ void init(ExecutionEngine *engine);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ARRAYITERATOR_P_H
+
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index bd019d3bcb..434f6781a8 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -38,12 +39,15 @@
****************************************************************************/
#include "qv4arrayobject_p.h"
+#include "qv4objectiterator_p.h"
+#include "qv4arrayiterator_p.h"
#include "qv4sparsearray_p.h"
#include "qv4objectproto_p.h"
#include "qv4jscall_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4runtime_p.h"
#include "qv4string_p.h"
+#include "qv4symbol_p.h"
#include <QtCore/qscopedvaluerollback.h>
using namespace QV4;
@@ -89,13 +93,19 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
ctor->defineDefaultProperty(QStringLiteral("isArray"), method_isArray, 1);
+ ctor->defineDefaultProperty(QStringLiteral("of"), method_of, 0);
+ ctor->defineDefaultProperty(QStringLiteral("from"), method_from, 1);
+ ctor->addSymbolSpecies();
+
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0);
defineDefaultProperty(QStringLiteral("concat"), method_concat, 1);
+ defineDefaultProperty(QStringLiteral("copyWithin"), method_copyWithin, 2);
+ defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
defineDefaultProperty(QStringLiteral("find"), method_find, 1);
defineDefaultProperty(QStringLiteral("findIndex"), method_findIndex, 1);
defineDefaultProperty(QStringLiteral("join"), method_join, 1);
@@ -107,15 +117,23 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(QStringLiteral("splice"), method_splice, 2);
defineDefaultProperty(QStringLiteral("unshift"), method_unshift, 1);
+ defineDefaultProperty(QStringLiteral("includes"), method_includes, 1);
defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("every"), method_every, 1);
+ defineDefaultProperty(QStringLiteral("fill"), method_fill, 1);
defineDefaultProperty(QStringLiteral("some"), method_some, 1);
defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
defineDefaultProperty(QStringLiteral("map"), method_map, 1);
defineDefaultProperty(QStringLiteral("filter"), method_filter, 1);
defineDefaultProperty(QStringLiteral("reduce"), method_reduce, 1);
defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
+ ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral("values")));
+ ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0));
+ engine->jsObjects[ExecutionEngine::ArrayProtoValues] = values;
+ defineDefaultProperty(QStringLiteral("values"), values);
+ defineDefaultProperty(engine->symbol_iterator(), values);
}
ReturnedValue ArrayPrototype::method_isArray(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -124,6 +142,200 @@ ReturnedValue ArrayPrototype::method_isArray(const FunctionObject *, const Value
return Encode(isArray);
}
+ScopedObject createObjectFromCtorOrArray(Scope &scope, ScopedFunctionObject ctor, bool useLen, int len)
+{
+ ScopedObject a(scope, Primitive::undefinedValue());
+
+ if (ctor) {
+ // ### the spec says that we should only call constructors if
+ // IsConstructor(that), but we have no way of knowing if a builtin is a
+ // constructor. so for the time being, just try call it, and silence any
+ // exceptions-- this is not ideal, as the spec also says that we should
+ // return on exception.
+ //
+ // this also 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) : Primitive::undefinedValue());
+ a = ctor->callAsConstructor(argument, useLen ? 1 : 0);
+ if (scope.engine->hasException)
+ scope.engine->catchException(); // probably not a constructor, then.
+ }
+
+ if (!a) {
+ a = scope.engine->newArrayObject(len);
+ }
+
+ return a;
+}
+
+ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(builtin);
+ ScopedFunctionObject thatCtor(scope, thisObject);
+ ScopedObject itemsObject(scope, argv[0]);
+ bool usingIterator = false;
+
+ if (itemsObject) {
+ // If the object claims to support iterators, then let's try use them.
+ ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
+ if (!it->isNullOrUndefined()) {
+ ScopedFunctionObject itfunc(scope, it);
+ if (!itfunc)
+ return scope.engine->throwTypeError();
+ usingIterator = true;
+ }
+ }
+
+ ScopedFunctionObject mapfn(scope, Primitive::undefinedValue());
+ Value *mapArguments = nullptr;
+ if (argc > 1) {
+ mapfn = ScopedFunctionObject(scope, argv[1]);
+ if (!mapfn)
+ return scope.engine->throwTypeError(QString::fromLatin1("%1 is not a function").arg(argv[1].toQStringNoThrow()));
+ mapArguments = scope.alloc(2);
+ }
+
+ ScopedValue thisArg(scope);
+ if (argc > 2)
+ thisArg = argv[2];
+
+ if (usingIterator) {
+ // 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));
+ CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
+ if (!iterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ qint64 k = 0;
+ ScopedValue mappedValue(scope);
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+
+ // The loop below pulls out all the properties using the iterator, and
+ // sets them into the created array.
+ forever {
+ 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);
+ }
+
+ // Retrieve the next value. If the iteration ends, we're done here.
+ done = Value::fromReturnedValue(Runtime::method_iteratorNext(scope.engine, iterator, nextValue));
+ CHECK_EXCEPTION();
+ if (done->toBoolean()) {
+ if (ArrayObject *ao = a->as<ArrayObject>()) {
+ ao->setArrayLengthUnchecked(k);
+ } else {
+ a->set(scope.engine->id_length(), Primitive::fromDouble(k), QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ return a.asReturnedValue();
+ }
+
+ if (mapfn) {
+ mapArguments[0] = *nextValue;
+ mapArguments[1] = Primitive::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ if (scope.engine->hasException)
+ return Runtime::method_iteratorClose(scope.engine, iterator, Primitive::fromBoolean(false));
+ } else {
+ mappedValue = *nextValue;
+ }
+
+ if (!a->hasOwnProperty(k)) {
+ a->arraySet(k, mappedValue);
+ } else {
+ // Don't return: we need to close the iterator.
+ scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k));
+ }
+
+ if (scope.engine->hasException) {
+ ScopedValue falsey(scope, Encode(false));
+ return Runtime::method_iteratorClose(scope.engine, iterator, falsey);
+ }
+
+ k++;
+ }
+
+ // the return is hidden up in the loop above, when iteration finishes.
+ } else {
+ // Array-like fallback. We request properties by index, and set them on
+ // the return object.
+ ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
+ if (!arrayLike)
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
+ qint64 len = arrayLike->getLength();
+ ScopedObject a(createObjectFromCtorOrArray(scope, thatCtor, true, len));
+ CHECK_EXCEPTION();
+
+ qint64 k = 0;
+ ScopedValue mappedValue(scope, Primitive::undefinedValue());
+ ScopedValue kValue(scope);
+ while (k < len) {
+ kValue = arrayLike->getIndexed(k);
+ CHECK_EXCEPTION();
+
+ if (mapfn) {
+ mapArguments[0] = kValue;
+ mapArguments[1] = Primitive::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ CHECK_EXCEPTION();
+ } else {
+ mappedValue = kValue;
+ }
+
+ if (a->hasOwnProperty(k))
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k));
+
+ a->arraySet(k, mappedValue);
+ CHECK_EXCEPTION();
+
+ k++;
+ }
+
+ if (ArrayObject *ao = a->as<ArrayObject>()) {
+ ao->setArrayLengthUnchecked(k);
+ } else {
+ a->set(scope.engine->id_length(), Primitive::fromDouble(k), QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ return a.asReturnedValue();
+ }
+
+}
+
+ReturnedValue ArrayPrototype::method_of(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(builtin);
+ ScopedFunctionObject that(scope, thisObject);
+ ScopedObject a(createObjectFromCtorOrArray(scope, that, true, argc));
+ CHECK_EXCEPTION();
+
+ int k = 0;
+ while (k < argc) {
+ if (a->hasOwnProperty(k)) {
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k));
+ }
+ a->arraySet(k, argv[k]);
+ CHECK_EXCEPTION();
+
+ k++;
+ }
+
+ // ArrayObject updates its own length, and will throw if we try touch it.
+ if (!a->as<ArrayObject>()) {
+ a->set(scope.engine->id_length(), Primitive::fromDouble(argc), QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+
+ return a.asReturnedValue();
+}
+
ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(builtin);
@@ -183,6 +395,88 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value
return result.asReturnedValue();
}
+ReturnedValue ArrayPrototype::method_copyWithin(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ double len = instance->getLength();
+ double target = argv[0].toInteger();
+ double start = argv[1].toInteger();
+ double end = len;
+
+ if (argc > 2 && !argv[2].isUndefined()) {
+ end = argv[2].toInteger();
+ }
+
+ double relativeTarget = target;
+ double relativeStart = start;
+ double relativeEnd = end;
+ double from = 0;
+ double to = 0;
+
+ if (relativeTarget < 0) {
+ to = std::max(len+relativeTarget, 0.0);
+ } else {
+ to = std::min(relativeTarget, len);
+ }
+ if (relativeStart < 0) {
+ from = std::max(len+relativeStart, 0.0);
+ } else {
+ from = std::min(relativeStart, len);
+ }
+
+ double fin = 0;
+ if (relativeEnd < 0) {
+ fin = std::max(len+relativeEnd, 0.0);
+ } else {
+ fin = std::min(relativeEnd, len);
+ }
+ double count = std::min(fin-from, len-to);
+ double direction = 1;
+ if (from < to && to < from+count) {
+ direction = -1;
+ from = from + count - 1;
+ to = to + count - 1;
+ }
+
+ while (count > 0) {
+ bool fromPresent = false;
+ ScopedValue fromVal(scope, instance->getIndexed(from, &fromPresent));
+
+ if (fromPresent) {
+ instance->setIndexed(to, fromVal, QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ } else {
+ bool didDelete = instance->deleteIndexedProperty(to);
+ CHECK_EXCEPTION();
+ if (!didDelete) {
+ return scope.engine->throwTypeError();
+ }
+ }
+
+ from = from + direction;
+ to = to + direction;
+ count = count - 1;
+ }
+
+ return instance.asReturnedValue();
+}
+
+ReturnedValue ArrayPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject O(scope, thisObject->toObject(scope.engine));
+ if (!O)
+ RETURN_UNDEFINED();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
ReturnedValue ArrayPrototype::method_find(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
@@ -352,9 +646,9 @@ ReturnedValue ArrayPrototype::method_push(const FunctionObject *b, const Value *
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
- uint len = instance->getLength();
+ qint64 len = instance->getLength();
- if (len + argc < len) {
+ if (len + quint64(argc) >= UINT_MAX) {
// ughh... this goes beyond UINT_MAX
double l = len;
ScopedString s(scope);
@@ -393,7 +687,7 @@ ReturnedValue ArrayPrototype::method_push(const FunctionObject *b, const Value *
return scope.engine->throwTypeError();
}
- return Encode(len);
+ return Encode(uint(len));
}
ReturnedValue ArrayPrototype::method_reverse(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -403,7 +697,10 @@ ReturnedValue ArrayPrototype::method_reverse(const FunctionObject *b, const Valu
if (!instance)
RETURN_UNDEFINED();
- uint length = instance->getLength();
+ qint64 length = instance->getLength();
+ // ### FIXME
+ if (length >= UINT_MAX)
+ return scope.engine->throwRangeError(QLatin1String("Array.prototype.reverse: Length out of range."));
int lo = 0, hi = length - 1;
@@ -548,19 +845,31 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value
if (!instance)
RETURN_UNDEFINED();
- uint len = instance->getLength();
-
- ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
+ qint64 len = instance->getLength();
double rs = (argc ? argv[0] : Primitive::undefinedValue()).toInteger();
- uint start;
+ qint64 start;
if (rs < 0)
- start = (uint) qMax(0., len + rs);
+ start = static_cast<qint64>(qMax(0., len + rs));
else
- start = (uint) qMin(rs, (double)len);
+ start = static_cast<qint64>(qMin(rs, static_cast<double>(len)));
+
+ qint64 deleteCount = 0;
+ qint64 itemCount = 0;
+ if (argc == 1) {
+ deleteCount = len - start;
+ } else if (argc > 1){
+ itemCount = argc - 2;
+ double dc = argv[1].toInteger();
+ deleteCount = static_cast<qint64>(qMin(qMax(dc, 0.), double(len - start)));
+ }
- uint deleteCount = (uint)qMin(qMax((argc > 1 ? argv[1] : Primitive::undefinedValue()).toInteger(), 0.), (double)(len - start));
+ if (len + itemCount - deleteCount > /*(static_cast<qint64>(1) << 53) - 1*/ UINT_MAX - 1)
+ return scope.engine->throwTypeError();
+ if (deleteCount > /*(static_cast<qint64>(1) << 53) - 1*/ UINT_MAX - 1)
+ return scope.engine->throwRangeError(QString::fromLatin1("Array length out of range."));
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
newArray->arrayReserve(deleteCount);
ScopedValue v(scope);
for (uint i = 0; i < deleteCount; ++i) {
@@ -572,7 +881,6 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = argc < 2 ? 0 : argc - 2;
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
@@ -663,6 +971,44 @@ ReturnedValue ArrayPrototype::method_unshift(const FunctionObject *b, const Valu
return Encode(newLen);
}
+ReturnedValue ArrayPrototype::method_includes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ qint64 len = instance->getLength();
+ if (len == 0) {
+ return Encode(false);
+ }
+
+ double n = 0;
+ if (argc > 1 && !argv[1].isUndefined()) {
+ n = argv[1].toInteger();
+ }
+
+ double k = 0;
+ if (n >= 0) {
+ k = n;
+ } else {
+ k = len + n;
+ if (k < 0) {
+ k = 0;
+ }
+ }
+
+ while (k < len) {
+ ScopedValue val(scope, instance->getIndexed(k));
+ if (val->sameValueZero(argv[0])) {
+ return Encode(true);
+ }
+ k++;
+ }
+
+ return Encode(false);
+}
+
ReturnedValue ArrayPrototype::method_indexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
@@ -729,6 +1075,18 @@ ReturnedValue ArrayPrototype::method_indexOf(const FunctionObject *b, const Valu
return Encode(-1);
}
+ReturnedValue ArrayPrototype::method_keys(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ ScopedObject O(scope, thisObject->toObject(scope.engine));
+ if (!O)
+ RETURN_UNDEFINED();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::KeyIteratorKind;
+ return ao->asReturnedValue();
+}
+
ReturnedValue ArrayPrototype::method_lastIndexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
@@ -805,6 +1163,42 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value
return Encode(ok);
}
+ReturnedValue ArrayPrototype::method_fill(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ uint len = instance->getLength();
+ int relativeStart = argc > 1 ? argv[1].toInteger() : 0;
+ int relativeEnd = len;
+ if (argc > 2 && !argv[2].isUndefined()) {
+ relativeEnd = argv[2].toInteger();
+ }
+ uint k = 0;
+ uint fin = 0;
+
+ if (relativeStart < 0) {
+ k = std::max(len+relativeStart, uint(0));
+ } else {
+ k = std::min(uint(relativeStart), len);
+ }
+
+ if (relativeEnd < 0) {
+ fin = std::max(len + relativeEnd, uint(0));
+ } else {
+ fin = std::min(uint(relativeEnd), len);
+ }
+
+ while (k < fin) {
+ instance->setIndexed(k, argv[0], QV4::Object::DoThrowOnRejection);
+ k++;
+ }
+
+ return instance.asReturnedValue();
+}
+
ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
@@ -873,12 +1267,15 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t
if (!instance)
RETURN_UNDEFINED();
- uint len = instance->getLength();
+ qint64 len = instance->getLength();
if (!argc || !argv->isFunctionObject())
THROW_TYPE_ERROR();
const FunctionObject *callback = static_cast<const FunctionObject *>(argv);
+ if (len > UINT_MAX - 1)
+ return scope.engine->throwRangeError(QString::fromLatin1("Array length out of range."));
+
ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
@@ -1041,3 +1438,20 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const
return acc->asReturnedValue();
}
+ReturnedValue ArrayPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject O(scope, thisObject->toObject(scope.engine));
+ if (!O)
+ RETURN_UNDEFINED();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue ArrayPrototype::method_get_species(const FunctionObject *, const Value *thisObject, const Value *, int)
+{
+ return thisObject->asReturnedValue();
+}
+
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index 3825a600a2..f1acfed7e7 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -79,9 +79,13 @@ struct ArrayPrototype: ArrayObject
void init(ExecutionEngine *engine, Object *ctor);
static ReturnedValue method_isArray(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toLocaleString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_concat(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_copyWithin(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_find(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_findIndex(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_join(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -93,15 +97,23 @@ struct ArrayPrototype: ArrayObject
static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_splice(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_unshift(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_includes(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_indexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_every(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_fill(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_some(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_map(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_filter(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_reduce(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_reduceRight(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+ // while this function is implemented here, it's the same for many other JS classes, so the corresponding JS function
+ // is instantiated in the engine, and it can be added to any JS object through Object::addSymbolSpecies()
+ static ReturnedValue method_get_species(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 020e519e74..78cca8d525 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -53,7 +53,42 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
DEFINE_MANAGED_VTABLE(CallContext);
-DEFINE_MANAGED_VTABLE(CatchContext);
+
+Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int blockIndex)
+{
+ Function *function = frame->v4Function;
+
+ Heap::InternalClass *ic = function->compilationUnit->runtimeBlocks.at(blockIndex);
+ uint nLocals = ic->size;
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals;
+
+ ExecutionEngine *v4 = function->internalClass->engine;
+ Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory, ic);
+ c->init();
+ c->type = Heap::ExecutionContext::Type_BlockContext;
+
+ 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->locals.size = nLocals;
+ c->locals.alloc = nLocals;
+
+ return c;
+}
+
+Heap::CallContext *ExecutionContext::cloneBlockContext(Heap::CallContext *context)
+{
+ uint nLocals = context->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);
+
+ return c;
+
+}
Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
{
@@ -75,7 +110,7 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
uint nLocals = compiledFunction->nLocals;
c->locals.size = nLocals;
c->locals.alloc = localsAndFormals;
- // memory allocated from the JS heap is 0 initialized, so check if undefined is 0
+ // memory allocated from the JS heap is 0 initialized, so check if empty is 0
Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
Value *args = c->locals.values + nLocals;
@@ -96,11 +131,14 @@ Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with)
return c;
}
-Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue)
+Heap::ExecutionContext *ExecutionContext::newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName)
{
- Scope scope(this);
- ScopedValue e(scope, exceptionValue);
- return engine()->memoryManager->alloc<CatchContext>(d(), exceptionVarName, e);
+ Scope scope(frame->context());
+ ScopedString name(scope, exceptionVarName);
+ ScopedValue val(scope, scope.engine->catchException(nullptr));
+ ScopedContext ctx(scope, newBlockContext(frame, blockIndex));
+ ctx->setProperty(name, val);
+ return ctx->d();
}
void ExecutionContext::createMutableBinding(String *name, bool deletable)
@@ -132,6 +170,8 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
activation = ctx->d()->activation;
break;
}
+ case Heap::ExecutionContext::Type_BlockContext:
+ // never create activation records on block contexts
default:
break;
}
@@ -143,33 +183,19 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
ScopedProperty desc(scope);
PropertyAttributes attrs(Attr_Data);
attrs.setConfigurable(deletable);
- activation->__defineOwnProperty__(scope.engine, name, desc, attrs);
-}
-
-void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
- const Value &exceptionValue)
-{
- Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext);
- outer.set(internalClass->engine, outerContext);
-
- this->exceptionVarName.set(internalClass->engine, exceptionVarName);
- this->exceptionValue.set(internalClass->engine, exceptionValue);
+ if (!activation->__defineOwnProperty__(scope.engine, name, desc, attrs))
+ scope.engine->throwTypeError();
}
bool ExecutionContext::deleteProperty(String *name)
{
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
Heap::ExecutionContext *ctx = d();
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name->d()))
- return false;
- break;
- }
+ case Heap::ExecutionContext::Type_BlockContext:
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
uint index = c->internalClass->find(id);
@@ -200,21 +226,13 @@ bool ExecutionContext::deleteProperty(String *name)
ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value &value)
{
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
QV4::ExecutionEngine *v4 = engine();
Heap::ExecutionContext *ctx = d();
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name->d())) {
- c->exceptionValue.set(v4, value);
- return NoError;
- }
- break;
- }
case Heap::ExecutionContext::Type_WithContext: {
Scope scope(v4);
ScopedObject w(scope, ctx->activation);
@@ -225,6 +243,7 @@ ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value
}
break;
}
+ case Heap::ExecutionContext::Type_BlockContext:
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
uint index = c->internalClass->find(id);
@@ -267,15 +286,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
Heap::ExecutionContext *ctx = d();
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name->d()))
- return c->exceptionValue.asReturnedValue();
- break;
- }
+ case Heap::ExecutionContext::Type_BlockContext:
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
uint index = c->internalClass->find(id);
if (index < UINT_MAX)
@@ -308,16 +322,11 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
Heap::ExecutionContext *ctx = d();
for (; ctx; ctx = ctx->outer) {
switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
- if (c->exceptionVarName->isEqualTo(name->d()))
- return c->exceptionValue.asReturnedValue();
- break;
- }
+ case Heap::ExecutionContext::Type_BlockContext:
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
uint index = c->internalClass->find(id);
if (index < UINT_MAX)
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 512bfa06d8..26e64728dc 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -55,23 +55,8 @@
QT_BEGIN_NAMESPACE
-class QObject;
-class QQmlContextData;
-
namespace QV4 {
-namespace CompiledData {
-struct CompilationUnitBase;
-struct Function;
-}
-
-struct Function;
-struct Identifier;
-struct CallContext;
-struct CatchContext;
-struct QmlContext;
-struct QQmlContextWrapper;
-
struct CallData
{
enum Offsets {
@@ -113,8 +98,6 @@ Q_STATIC_ASSERT(offsetof(CallData, args) == 5*sizeof(Value));
namespace Heap {
-struct QmlContext;
-
#define ExecutionContextMembers(class, Member) \
Member(class, Pointer, ExecutionContext *, outer) \
Member(class, Pointer, Object *, activation)
@@ -124,9 +107,9 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
enum ContextType {
Type_GlobalContext = 0x1,
- Type_CatchContext = 0x2,
- Type_WithContext = 0x3,
- Type_QmlContext = 0x4,
+ Type_WithContext = 0x2,
+ Type_QmlContext = 0x3,
+ Type_BlockContext = 0x4,
Type_CallContext = 0x5
};
@@ -137,6 +120,10 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
type = t;
}
+ const VTable *vtable() const {
+ return internalClass->vtable;
+ }
+
quint32 type : 8;
quint32 nArgs : 24;
#if QT_POINTER_SIZE == 8
@@ -181,16 +168,6 @@ Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
//Q_STATIC_ASSERT(sizeof(CallContext) == sizeof(ExecutionContext) + sizeof(CallContextData));
//#endif
-#define CatchContextMembers(class, Member) \
- Member(class, Pointer, String *, exceptionVarName) \
- Member(class, HeapValue, HeapValue, exceptionValue)
-
-DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) {
- DECLARE_MARKOBJECTS(CatchContext);
-
- void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
-};
-Q_STATIC_ASSERT(std::is_trivial< CatchContext >::value);
}
@@ -204,9 +181,11 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
Q_MANAGED_TYPE(ExecutionContext)
V4_INTERNALCLASS(ExecutionContext)
+ static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex);
+ static Heap::CallContext *cloneBlockContext(Heap::CallContext *context);
static Heap::CallContext *newCallContext(QV4::CppStackFrame *frame);
Heap::ExecutionContext *newWithContext(Heap::Object *with);
- Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue);
+ static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName);
void createMutableBinding(String *name, bool deletable);
@@ -239,11 +218,6 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
}
};
-struct CatchContext : public ExecutionContext
-{
- V4_MANAGED(CatchContext, ExecutionContext)
-};
-
inline CallContext *ExecutionContext::asCallContext()
{
return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<CallContext *>(this) : nullptr;
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index d894d909ff..354eaad7dc 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -40,6 +40,7 @@
#include "qv4dataview_p.h"
#include "qv4arraybuffer_p.h"
#include "qv4string_p.h"
+#include "qv4symbol_p.h"
#include <QtCore/private/qnumeric_p.h>
#include "qendian.h"
@@ -69,7 +70,7 @@ ReturnedValue DataViewCtor::callAsConstructor(const FunctionObject *f, const Val
if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength)
return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
- Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
+ Scoped<DataView> a(scope, scope.engine->memoryManager->allocate<DataView>());
a->d()->buffer.set(scope.engine, buffer->d());
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
@@ -85,38 +86,41 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(3));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
defineDefaultProperty(engine->id_constructor(), (o = ctor));
defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr);
- defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0);
- defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 0);
- defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0);
- defineDefaultProperty(QStringLiteral("getUint16"), method_get<unsigned short>, 0);
- defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0);
- defineDefaultProperty(QStringLiteral("getUint32"), method_get<unsigned int>, 0);
- defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0);
- defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0);
-
- defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0);
- defineDefaultProperty(QStringLiteral("setUint8"), method_setChar<unsigned char>, 0);
- defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0);
- defineDefaultProperty(QStringLiteral("setUint16"), method_set<unsigned short>, 0);
- defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0);
- defineDefaultProperty(QStringLiteral("setUint32"), method_set<unsigned int>, 0);
- defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0);
- defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0);
+ defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 1);
+ defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 1);
+ defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 1);
+ defineDefaultProperty(QStringLiteral("getUint16"), method_get<unsigned short>, 1);
+ defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 1);
+ defineDefaultProperty(QStringLiteral("getUint32"), method_get<unsigned int>, 1);
+ defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 1);
+ defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 1);
+
+ defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 2);
+ defineDefaultProperty(QStringLiteral("setUint8"), method_setChar<unsigned char>, 2);
+ defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 2);
+ defineDefaultProperty(QStringLiteral("setUint16"), method_set<unsigned short>, 2);
+ defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 2);
+ defineDefaultProperty(QStringLiteral("setUint32"), method_set<unsigned int>, 2);
+ defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 2);
+ defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 2);
+
+ ScopedString name(scope, engine->newString(QStringLiteral("DataView")));
+ defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
// For backword compatibility
- defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0);
- defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0);
- defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0);
- defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0);
- defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0);
- defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0);
+ defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 1);
+ defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 1);
+ defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 1);
+ defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 1);
+ defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 1);
+ defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 1);
}
ReturnedValue DataViewPrototype::method_get_buffer(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 5bbe312146..092c36e52a 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -44,6 +44,7 @@
#include "qv4runtime_p.h"
#include "qv4string_p.h"
#include "qv4jscall_p.h"
+#include "qv4symbol_p.h"
#include <QtCore/QDebug>
#include <QtCore/QDateTime>
@@ -89,9 +90,6 @@ static const double msPerMinute = 60000.0;
static const double msPerHour = 3600000.0;
static const double msPerDay = 86400000.0;
-// The current *standard* time offset, regardless of DST:
-static double LocalTZA = 0.0; // initialized at startup
-
static inline double TimeWithinDay(double t)
{
double r = ::fmod(t, msPerDay);
@@ -318,14 +316,14 @@ static inline double MakeDate(double day, double time)
against the ECMAScript spec is https://github.com/tc39/ecma262/issues/725
*/
-static inline double DaylightSavingTA(double t) // t is a UTC time
+static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time
{
return QTimeZone::systemTimeZone().offsetFromUtc(
- QDateTime::fromMSecsSinceEpoch(qint64(t), Qt::UTC)) * 1e3 - LocalTZA;
+ QDateTime::fromMSecsSinceEpoch(qint64(t), Qt::UTC)) * 1e3 - localTZA;
}
#else
// This implementation fails to take account of past changes in standard offset.
-static inline double DaylightSavingTA(double t)
+static inline double DaylightSavingTA(double t, double /*localTZA*/)
{
struct tm tmtm;
#if defined(Q_CC_MSVC)
@@ -348,19 +346,19 @@ static inline double DaylightSavingTA(double t)
}
#endif // USE_QTZ_SYSTEM_ZONE
-static inline double LocalTime(double t)
+static inline double LocalTime(double t, double localTZA)
{
// Flawed, yet verbatim from the spec:
- return t + LocalTZA + DaylightSavingTA(t);
+ return t + localTZA + DaylightSavingTA(t, localTZA);
}
// The spec does note [*] that UTC and LocalTime are not quite mutually inverse.
// [*] http://www.ecma-international.org/ecma-262/7.0/index.html#sec-utc-t
-static inline double UTC(double t)
+static inline double UTC(double t, double localTZA)
{
// Flawed, yet verbatim from the spec:
- return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
+ return t - localTZA - DaylightSavingTA(t - localTZA, localTZA);
}
static inline double currentTime()
@@ -377,7 +375,7 @@ static inline double TimeClip(double t)
return Primitive::toInteger(t) + 0;
}
-static inline double ParseString(const QString &s)
+static inline double ParseString(const QString &s, double localTZA)
{
/*
First, try the format defined in ECMA 262's "Date Time String Format";
@@ -533,7 +531,7 @@ static inline double ParseString(const QString &s)
if (seenZ)
t -= offset * offsetSign * 60 * 1000;
else if (seenT) // No zone specified, treat date-time as local time
- t = UTC(t);
+ t = UTC(t, localTZA);
// else: treat plain date as already in UTC
return t;
}
@@ -621,12 +619,12 @@ static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec)
return QDateTime::fromMSecsSinceEpoch(t, Qt::UTC).toTimeSpec(spec);
}
-static inline QString ToString(double t)
+static inline QString ToString(double t, double localTZA)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
QString str = ToDateTime(t, Qt::LocalTime).toString() + QLatin1String(" GMT");
- double tzoffset = LocalTZA + DaylightSavingTA(t);
+ double tzoffset = localTZA + DaylightSavingTA(t, localTZA);
if (tzoffset) {
int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
int mins = int(::fabs(tzoffset) / 1000 / 60) % 60;
@@ -730,7 +728,7 @@ void Heap::DateObject::init(const QTime &time)
*/
static const double d = MakeDay(1925, 5, 8);
double t = MakeTime(time.hour(), time.minute(), time.second(), time.msec());
- date = TimeClip(UTC(MakeDate(d, t)));
+ date = TimeClip(UTC(MakeDate(d, t), internalClass->engine->localTZA));
}
QDateTime DateObject::toQDateTime() const
@@ -747,13 +745,14 @@ void Heap::DateCtor::init(QV4::ExecutionContext *scope)
ReturnedValue DateCtor::callAsConstructor(const FunctionObject *that, const Value *argv, int argc)
{
+ ExecutionEngine *e = that->engine();
double t = 0;
if (argc == 0)
t = currentTime();
else if (argc == 1) {
- Scope scope(that->engine());
+ Scope scope(e);
ScopedValue arg(scope, argv[0]);
if (DateObject *d = arg->as<DateObject>()) {
t = d->date();
@@ -761,7 +760,7 @@ ReturnedValue DateCtor::callAsConstructor(const FunctionObject *that, const Valu
arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT);
if (String *s = arg->stringValue())
- t = ParseString(s->toQString());
+ t = ParseString(s->toQString(), e->localTZA);
else
t = TimeClip(arg->toNumber());
}
@@ -778,16 +777,17 @@ ReturnedValue DateCtor::callAsConstructor(const FunctionObject *that, const Valu
if (year >= 0 && year <= 99)
year += 1900;
t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
- t = TimeClip(UTC(t));
+ t = TimeClip(UTC(t, e->localTZA));
}
- return Encode(that->engine()->newDateObject(Primitive::fromDouble(t)));
+ return Encode(e->newDateObject(Primitive::fromDouble(t)));
}
ReturnedValue DateCtor::call(const FunctionObject *m, const Value *, const Value *, int)
{
+ ExecutionEngine *e = m->engine();
double t = currentTime();
- return m->engine()->newString(ToString(t))->asReturnedValue();
+ return e->newString(ToString(t, e->localTZA))->asReturnedValue();
}
void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -796,7 +796,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7));
- LocalTZA = getLocalTZA();
+ engine->localTZA = getLocalTZA();
ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
ctor->defineDefaultProperty(QStringLiteral("UTC"), method_UTC, 7);
@@ -853,15 +853,14 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
QString toGmtString(QStringLiteral("toGMTString"));
ScopedString us(scope, engine->newIdentifier(toUtcString));
ScopedString gs(scope, engine->newIdentifier(toGmtString));
- ExecutionContext *global = engine->rootContext();
- ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(global, us, method_toUTCString));
- toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(engine, us, method_toUTCString, 0));
defineDefaultProperty(us, toUtcGmtStringFn);
defineDefaultProperty(gs, toUtcGmtStringFn);
}
defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
+ defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable);
}
double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject)
@@ -872,12 +871,12 @@ double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject)
return 0;
}
-ReturnedValue DatePrototype::method_parse(const FunctionObject *, const Value *, const Value *argv, int argc)
+ReturnedValue DatePrototype::method_parse(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
if (!argc)
return Encode(qt_qnan());
else
- return Encode(ParseString(argv[0].toQString()));
+ return Encode(ParseString(argv[0].toQString(), f->engine()->localTZA));
}
ReturnedValue DatePrototype::method_UTC(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -909,7 +908,7 @@ ReturnedValue DatePrototype::method_toString(const FunctionObject *b, const Valu
{
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
- return Encode(v4->newString(ToString(t)));
+ return Encode(v4->newString(ToString(t, v4->localTZA)));
}
ReturnedValue DatePrototype::method_toDateString(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -966,7 +965,7 @@ ReturnedValue DatePrototype::method_getYear(const FunctionObject *b, const Value
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = YearFromTime(LocalTime(t)) - 1900;
+ t = YearFromTime(LocalTime(t, v4->localTZA)) - 1900;
return Encode(t);
}
@@ -975,7 +974,7 @@ ReturnedValue DatePrototype::method_getFullYear(const FunctionObject *b, const V
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = YearFromTime(LocalTime(t));
+ t = YearFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -993,7 +992,7 @@ ReturnedValue DatePrototype::method_getMonth(const FunctionObject *b, const Valu
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = MonthFromTime(LocalTime(t));
+ t = MonthFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1011,7 +1010,7 @@ ReturnedValue DatePrototype::method_getDate(const FunctionObject *b, const Value
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = DateFromTime(LocalTime(t));
+ t = DateFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1029,7 +1028,7 @@ ReturnedValue DatePrototype::method_getDay(const FunctionObject *b, const Value
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = WeekDay(LocalTime(t));
+ t = WeekDay(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1047,7 +1046,7 @@ ReturnedValue DatePrototype::method_getHours(const FunctionObject *b, const Valu
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = HourFromTime(LocalTime(t));
+ t = HourFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1065,7 +1064,7 @@ ReturnedValue DatePrototype::method_getMinutes(const FunctionObject *b, const Va
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = MinFromTime(LocalTime(t));
+ t = MinFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1083,7 +1082,7 @@ ReturnedValue DatePrototype::method_getSeconds(const FunctionObject *b, const Va
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = SecFromTime(LocalTime(t));
+ t = SecFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1101,7 +1100,7 @@ ReturnedValue DatePrototype::method_getMilliseconds(const FunctionObject *b, con
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = msFromTime(LocalTime(t));
+ t = msFromTime(LocalTime(t, v4->localTZA));
return Encode(t);
}
@@ -1119,7 +1118,7 @@ ReturnedValue DatePrototype::method_getTimezoneOffset(const FunctionObject *b, c
ExecutionEngine *v4 = b->engine();
double t = getThisDate(v4, thisObject);
if (!std::isnan(t))
- t = (t - LocalTime(t)) / msPerMinute;
+ t = (t - LocalTime(t, v4->localTZA)) / msPerMinute;
return Encode(t);
}
@@ -1144,13 +1143,13 @@ ReturnedValue DatePrototype::method_setMilliseconds(const FunctionObject *b, con
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double ms = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)), v4->localTZA)));
return Encode(self->date());
}
@@ -1178,7 +1177,7 @@ ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Va
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double sec = argc ? argv[0].toNumber() : qt_qnan();
@@ -1187,7 +1186,7 @@ ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Va
double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1214,7 +1213,7 @@ ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Va
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double min = argc ? argv[0].toNumber() : qt_qnan();
@@ -1226,7 +1225,7 @@ ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Va
double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1254,7 +1253,7 @@ ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Valu
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double hour = argc ? argv[0].toNumber() : qt_qnan();
@@ -1269,7 +1268,7 @@ ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Valu
double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1298,13 +1297,13 @@ ReturnedValue DatePrototype::method_setDate(const FunctionObject *b, const Value
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double date = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1334,7 +1333,7 @@ ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Valu
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
double month = argc ? argv[0].toNumber() : qt_qnan();
@@ -1343,7 +1342,7 @@ ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Valu
double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1374,7 +1373,7 @@ ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value
if (std::isnan(t))
t = 0;
else
- t = LocalTime(t);
+ t = LocalTime(t, v4->localTZA);
double year = argc ? argv[0].toNumber() : qt_qnan();
double r;
if (std::isnan(year)) {
@@ -1383,7 +1382,7 @@ ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value
if ((Primitive::toInteger(year) >= 0) && (Primitive::toInteger(year) <= 99))
year += 1900;
r = MakeDay(year, MonthFromTime(t), DateFromTime(t));
- r = UTC(MakeDate(r, TimeWithinDay(t)));
+ r = UTC(MakeDate(r, TimeWithinDay(t)), v4->localTZA);
r = TimeClip(r);
}
self->setDate(r);
@@ -1413,7 +1412,7 @@ ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const V
if (!self)
return v4->throwTypeError();
- double t = LocalTime(self->date());
+ double t = LocalTime(self->date(), v4->localTZA);
if (v4->hasException)
return QV4::Encode::undefined();
if (std::isnan(t))
@@ -1427,7 +1426,7 @@ ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const V
double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+ t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)), v4->localTZA));
self->setDate(t);
return Encode(self->date());
}
@@ -1518,7 +1517,23 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value
return toIso->call(O, nullptr, 0);
}
-void DatePrototype::timezoneUpdated()
+ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *e = f->engine();
+ if (!thisObject->isObject() || !argc || !argv->isString())
+ return e->throwTypeError();
+
+ String *hint = argv->stringValue();
+ Identifier id = hint->identifier();
+ if (id == e->id_default()->identifier())
+ hint = e->id_string();
+ else if (id != e->id_string()->identifier() && id != e->id_number()->identifier())
+ return e->throwTypeError();
+
+ return RuntimeHelpers::ordinaryToPrimitive(e, static_cast<const Object *>(thisObject), hint);
+}
+
+void DatePrototype::timezoneUpdated(ExecutionEngine *e)
{
- LocalTZA = getLocalTZA();
+ e->localTZA = getLocalTZA();
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 2b9a580288..0a5a3954d1 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -101,7 +101,7 @@ struct DateObject: Object {
template<>
inline const DateObject *Value::as() const {
- return isManaged() && m()->vtable()->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : nullptr;
+ return isManaged() && m()->internalClass->vtable->type == Managed::Type_DateObject ? static_cast<const DateObject *>(this) : nullptr;
}
struct DateCtor: FunctionObject
@@ -169,8 +169,9 @@ struct DatePrototype: Object
static ReturnedValue method_toUTCString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toISOString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toJSON(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *, int);
- static void timezoneUpdated();
+ static void timezoneUpdated(ExecutionEngine *e);
};
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0ed0df89a9..1073a2abab 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -42,6 +42,9 @@
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <qv4objectiterator_p.h>
+#include <qv4setiterator_p.h>
+#include <qv4mapiterator_p.h>
+#include <qv4arrayiterator_p.h>
#include <qv4arrayobject_p.h>
#include <qv4booleanobject_p.h>
#include <qv4globalobject_p.h>
@@ -52,6 +55,9 @@
#include <qv4numberobject_p.h>
#include <qv4regexpobject_p.h>
#include <qv4regexp_p.h>
+#include "qv4symbol_p.h"
+#include "qv4setobject_p.h"
+#include "qv4mapobject_p.h"
#include <qv4variantobject_p.h>
#include <qv4runtime_p.h>
#include <private/qv4mm_p.h>
@@ -63,7 +69,15 @@
#include "qv4debugging_p.h"
#include "qv4profiling_p.h"
#include "qv4executableallocator_p.h"
+#include "qv4iterator_p.h"
+#include "qv4stringiterator_p.h"
+#include "qv4generatorobject_p.h"
+#include "qv4reflect_p.h"
+
+#if QT_CONFIG(qml_sequence_object)
#include "qv4sequenceobject_p.h"
+#endif
+
#include "qv4qobjectwrapper_p.h"
#include "qv4memberdata_p.h"
#include "qv4arraybuffer_p.h"
@@ -76,7 +90,9 @@
#include <private/qqmlvaluetype_p.h>
#include <private/qqmllistwrapper_p.h>
#include <private/qqmllist_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <QtCore/QTextStream>
#include <QDateTime>
@@ -110,7 +126,7 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const
#ifdef V4_BOOTSTRAP
QJSEngine *ExecutionEngine::jsEngine() const
{
- return v8Engine->publicEngine();
+ return publicEngine;
}
QQmlEngine *ExecutionEngine::qmlEngine() const
@@ -121,7 +137,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
-ExecutionEngine::ExecutionEngine()
+ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
: executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
@@ -129,6 +145,7 @@ ExecutionEngine::ExecutionEngine()
, gcStack(new WTF::PageAllocation)
, globalCode(nullptr)
, v8Engine(nullptr)
+ , publicEngine(jsEngine)
, argumentsAccessors(nullptr)
, nArgumentsAccessors(0)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
@@ -181,27 +198,44 @@ ExecutionEngine::ExecutionEngine()
}
exceptionValue = jsAlloca(1);
+ *exceptionValue = Encode::undefined();
globalObject = static_cast<Object *>(jsAlloca(1));
jsObjects = jsAlloca(NJSObjects);
typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes));
jsStrings = jsAlloca(NJSStrings);
+ jsSymbols = jsAlloca(NJSSymbols);
// set up stack limits
jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
identifierTable = new IdentifierTable(this);
- classPool = new InternalClassPool;
+ memset(classes, 0, sizeof(classes));
+ classes[Class_Empty] = memoryManager->allocIC<InternalClass>();
+ classes[Class_Empty]->init(this);
- internalClasses[Class_Empty] = new (classPool) InternalClass(this);
- internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable());
- internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
- internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
- internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
- internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
- internalClasses[Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable());
- internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
+ classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
+ classes[Class_SparseArrayData] = classes[Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
+ classes[Class_ExecutionContext] = classes[Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
+ classes[Class_CallContext] = classes[Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ classes[Class_QmlContext] = classes[Class_Empty]->changeVTable(QV4::QmlContext::staticVTable());
+
+ Scope scope(this);
+ Scoped<InternalClass> ic(scope);
+ ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
+ jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic->d());
+ classes[Class_Object] = ic->changePrototype(objectPrototype()->d());
+ classes[Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
+
+ ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
+ jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic->d(), /*init =*/ false);
+ classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable())->changePrototype(stringPrototype()->d());
+ Q_ASSERT(stringPrototype()->d() && classes[Class_String]->prototype);
+
+ jsObjects[SymbolProto] = memoryManager->allocate<SymbolPrototype>();
+ classes[Class_Symbol] = classes[EngineBase::Class_Empty]->changeVTable(QV4::Symbol::staticVTable())->changePrototype(symbolPrototype()->d());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -211,6 +245,8 @@ ExecutionEngine::ExecutionEngine()
jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean"));
jsStrings[String_number] = newIdentifier(QStringLiteral("number"));
jsStrings[String_string] = newIdentifier(QStringLiteral("string"));
+ jsStrings[String_default] = newIdentifier(QStringLiteral("default"));
+ jsStrings[String_symbol] = newIdentifier(QStringLiteral("symbol"));
jsStrings[String_object] = newIdentifier(QStringLiteral("object"));
jsStrings[String_function] = newIdentifier(QStringLiteral("function"));
jsStrings[String_length] = newIdentifier(QStringLiteral("length"));
@@ -239,141 +275,175 @@ ExecutionEngine::ExecutionEngine()
jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
-
- InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
- jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
- internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
- internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
+ jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
+ jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
+ jsStrings[String_return] = newIdentifier(QStringLiteral("return"));
+
+ jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance"));
+ jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable"));
+ jsSymbols[Symbol_iterator] = Symbol::create(this, QStringLiteral("@Symbol.iterator"));
+ jsSymbols[Symbol_match] = Symbol::create(this, QStringLiteral("@Symbol.match"));
+ jsSymbols[Symbol_replace] = Symbol::create(this, QStringLiteral("@Symbol.replace"));
+ jsSymbols[Symbol_search] = Symbol::create(this, QStringLiteral("@Symbol.search"));
+ jsSymbols[Symbol_species] = Symbol::create(this, QStringLiteral("@Symbol.species"));
+ jsSymbols[Symbol_split] = Symbol::create(this, QStringLiteral("@Symbol.split"));
+ jsSymbols[Symbol_toPrimitive] = Symbol::create(this, QStringLiteral("@Symbol.toPrimitive"));
+ jsSymbols[Symbol_toStringTag] = Symbol::create(this, QStringLiteral("@Symbol.toStringTag"));
+ jsSymbols[Symbol_unscopables] = Symbol::create(this, QStringLiteral("@Symbol.unscopables"));
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
- Q_ASSERT(ic->prototype);
- ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
- Q_ASSERT(ic->prototype);
- jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic, objectPrototype());
- internalClasses[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
- jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
-
- InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
- argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable);
- internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
+ Q_ASSERT(ic->d()->prototype);
+ ic = ic->addMember(id_length()->identifier(), Attr_NotConfigurable|Attr_NotEnumerable);
+ Q_ASSERT(ic->d()->prototype);
+ jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic->d());
+ classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
+ jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
+
+ Scoped<InternalClass> argsClass(scope);
+ argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
+ argsClass = argsClass->addMember(id_length()->identifier(), Attr_NotEnumerable);
+ argsClass = argsClass->addMember(symbol_iterator()->identifier(), Attr_Data|Attr_NotEnumerable);
+ classes[Class_ArgumentsObject] = argsClass->addMember(id_callee()->identifier(), Attr_Data|Attr_NotEnumerable);
argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype());
- argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable);
- argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ argsClass = argsClass->addMember(id_length()->identifier(), Attr_NotEnumerable);
+ argsClass = argsClass->addMember(symbol_iterator()->identifier(), Attr_Data|Attr_NotEnumerable);
+ classes[Class_StrictArgumentsObject] = argsClass->addMember(id_callee()->identifier(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
*static_cast<Value *>(globalObject) = newObject();
Q_ASSERT(globalObject->d()->vtable());
initRootContext();
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
- ic = ic->addMember(id_length(), Attr_ReadOnly);
- jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic);
- internalClasses[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
- Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex);
+ ic = ic->addMember(id_length()->identifier(), Attr_ReadOnly);
+ classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
+ Q_ASSERT(classes[Class_StringObject]->find(id_length()->identifier()) == Heap::StringObject::LengthPropertyIndex);
- jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>();
- jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>();
- jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>();
+ classes[Class_SymbolObject] = newInternalClass(QV4::SymbolObject::staticVTable(), symbolPrototype());
+
+ jsObjects[NumberProto] = memoryManager->allocate<NumberPrototype>();
+ jsObjects[BooleanProto] = memoryManager->allocate<BooleanPrototype>();
+ jsObjects[DateProto] = memoryManager->allocate<DatePrototype>();
uint index;
ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
- ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index);
+ ic = ic->addMember(id_prototype()->identifier(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
- jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic, objectPrototype());
+ jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic->d());
ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
- ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
+ ic = ic->addMember(id_prototype()->identifier(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
- internalClasses[EngineBase::Class_FunctionObject] = ic;
- ic = ic->addMember(id_name(), Attr_ReadOnly, &index);
+ classes[Class_FunctionObject] = ic->d();
+ ic = ic->addMember(id_name()->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
ic = ic->changeVTable(ScriptFunction::staticVTable());
- internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index);
+ ic = ic->addMember(id_length()->identifier(), Attr_ReadOnly_ButConfigurable, &index);
Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
- internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index);
+ classes[Class_ScriptFunction] = ic->d();
+ ic = ic->changeVTable(GeneratorFunction::staticVTable());
+ classes[Class_GeneratorFunction] = ic->d();
+ classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor()->identifier(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
- Scope scope(this);
+ jsObjects[GeneratorProto] = memoryManager->allocObject<GeneratorPrototype>(classes[Class_Object]);
+ classes[Class_GeneratorObject] = newInternalClass(QV4::GeneratorObject::staticVTable(), generatorPrototype());
+
ScopedString str(scope);
- internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
+ classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
- ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
+ ic = ic->addMember(id_lastIndex()->identifier(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == RegExpObject::Index_LastIndex);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("source")))->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Source);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("global")))->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Global);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase")))->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline")))->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == RegExpObject::Index_Multiline);
- jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic, objectPrototype());
- internalClasses[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
+ jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic->d());
+ classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
- ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
+ ic = classes[Class_ArrayObject]->addMember(id_index()->identifier(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
- internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index);
+ classes[Class_RegExpExecArray] = ic->addMember(id_input()->identifier(), Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
ic = newInternalClass(ErrorObject::staticVTable(), nullptr);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("stack")))->identifier(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_Stack);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName")))->identifier(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_FileName);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index);
- internalClasses[EngineBase::Class_ErrorObject] = ic;
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber")))->identifier(), Attr_Data|Attr_NotEnumerable, &index);
+ classes[Class_ErrorObject] = ic->d();
Q_ASSERT(index == ErrorObject::Index_LineNumber);
- internalClasses[EngineBase::Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
+ classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message")))->identifier(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorObject::Index_Message);
ic = newInternalClass(ErrorObject::staticVTable(), objectPrototype());
- ic = ic->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember(id_constructor()->identifier(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Constructor);
- ic = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
+ ic = ic->addMember((str = newIdentifier(QStringLiteral("message")))->identifier(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Message);
- internalClasses[EngineBase::Class_ErrorProto] = ic->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index);
+ classes[Class_ErrorProto] = ic->addMember(id_name()->identifier(), Attr_Data|Attr_NotEnumerable, &index);
Q_ASSERT(index == ErrorPrototype::Index_Name);
- jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack);
- getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
+ jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(this, str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack, 0);
- jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], objectPrototype());
- jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
- jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
- jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
- jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
- jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
- jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
+ jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(classes[Class_ErrorProto]);
+ ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d());
+ jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic->d());
+ jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic->d());
+ jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic->d());
+ jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic->d());
+ jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic->d());
+ jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d());
- jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>();
+ jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
+#if QT_CONFIG(qml_sequence_object)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
- jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic, SequencePrototype::defaultPrototype(this)));
+ jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
+#endif
ExecutionContext *global = rootContext();
- jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global);
- jsObjects[String_Ctor] = memoryManager->allocObject<StringCtor>(global);
- jsObjects[Number_Ctor] = memoryManager->allocObject<NumberCtor>(global);
- jsObjects[Boolean_Ctor] = memoryManager->allocObject<BooleanCtor>(global);
- jsObjects[Array_Ctor] = memoryManager->allocObject<ArrayCtor>(global);
- jsObjects[Function_Ctor] = memoryManager->allocObject<FunctionCtor>(global);
- jsObjects[Date_Ctor] = memoryManager->allocObject<DateCtor>(global);
- jsObjects[RegExp_Ctor] = memoryManager->allocObject<RegExpCtor>(global);
- jsObjects[Error_Ctor] = memoryManager->allocObject<ErrorCtor>(global);
- jsObjects[EvalError_Ctor] = memoryManager->allocObject<EvalErrorCtor>(global);
- jsObjects[RangeError_Ctor] = memoryManager->allocObject<RangeErrorCtor>(global);
- jsObjects[ReferenceError_Ctor] = memoryManager->allocObject<ReferenceErrorCtor>(global);
- jsObjects[SyntaxError_Ctor] = memoryManager->allocObject<SyntaxErrorCtor>(global);
- jsObjects[TypeError_Ctor] = memoryManager->allocObject<TypeErrorCtor>(global);
- jsObjects[URIError_Ctor] = memoryManager->allocObject<URIErrorCtor>(global);
+
+ jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(global);
+ jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(global);
+ jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(global);
+ jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(global);
+ jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
+ jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
+ jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(global);
+ jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(global);
+ jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(global);
+ jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(global);
+ jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(global);
+ jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(global);
+ jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(global);
+ jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(global);
+ jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(global);
+ jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
+ jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
+ jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
+ jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype()));
+ jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()));
+ jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype()));
+ jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype()));
+ jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype()));
+
+ str = newString(QStringLiteral("get [Symbol.species]"));
+ jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
+ static_cast<SymbolPrototype *>(symbolPrototype())->init(this, symbolCtor());
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
+ static_cast<GeneratorPrototype *>(generatorPrototype())->init(this, generatorFunctionCtor());
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor());
static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor());
@@ -383,25 +453,47 @@ ExecutionEngine::ExecutionEngine()
static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
+ static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
+ static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
+ static_cast<MapIteratorPrototype *>(mapIteratorPrototype())->init(this);
+ static_cast<SetIteratorPrototype *>(setIteratorPrototype())->init(this);
+ static_cast<ArrayIteratorPrototype *>(arrayIteratorPrototype())->init(this);
+ static_cast<StringIteratorPrototype *>(stringIteratorPrototype())->init(this);
+
static_cast<VariantPrototype *>(variantPrototype())->init();
+
+#if QT_CONFIG(qml_sequence_object)
sequencePrototype()->cast<SequencePrototype>()->init();
+#endif
+
+ jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
+ jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
+ static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
+ jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(global);
+ jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
+ static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
// typed arrays
- jsObjects[ArrayBuffer_Ctor] = memoryManager->allocObject<ArrayBufferCtor>(global);
- jsObjects[ArrayBufferProto] = memoryManager->allocObject<ArrayBufferPrototype>();
+ jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
+ jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
- jsObjects[DataView_Ctor] = memoryManager->allocObject<DataViewCtor>(global);
- jsObjects[DataViewProto] = memoryManager->allocObject<DataViewPrototype>();
+ jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(global);
+ jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
+ jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(global);
+ jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
+ static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
+ ->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
+
for (int i = 0; i < Heap::TypedArray::NTypes; ++i) {
- static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocObject<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
- static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocObject<TypedArrayPrototype>(Heap::TypedArray::Type(i));
+ static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
+ static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(Heap::TypedArray::Type(i));
typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
}
@@ -413,6 +505,7 @@ ExecutionEngine::ExecutionEngine()
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("Symbol"), *symbolCtor());
FunctionObject *numberObject = numberCtor();
globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
@@ -430,18 +523,22 @@ ExecutionEngine::ExecutionEngine()
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("Set"), *setCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("Map"), *mapCtor());
+
for (int i = 0; i < Heap::TypedArray::NTypes; ++i)
globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]);
ScopedObject o(scope);
- globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocObject<MathObject>()));
- globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocObject<JsonObject>()));
+ globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocate<MathObject>()));
+ globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocate<JsonObject>()));
+ globalObject->defineDefaultProperty(QStringLiteral("Reflect"), (o = memoryManager->allocate<Reflect>()));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN()));
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY));
- jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global);
+ jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(global);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
// ES6: 20.1.2.12 & 20.1.2.13:
@@ -453,11 +550,8 @@ ExecutionEngine::ExecutionEngine()
Scope scope(this);
ScopedString pi(scope, newIdentifier(piString));
ScopedString pf(scope, newIdentifier(pfString));
- ExecutionContext *global = rootContext();
- ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(global, pi, GlobalFunctions::method_parseInt));
- ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(global, pf, GlobalFunctions::method_parseFloat));
- parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
- parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
+ ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(this, pi, GlobalFunctions::method_parseInt, 2));
+ ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(this, pf, GlobalFunctions::method_parseFloat, 1));
globalObject->defineDefaultProperty(piString, parseIntFn);
globalObject->defineDefaultProperty(pfString, parseFloatFn);
numberObject->defineDefaultProperty(piString, parseIntFn);
@@ -473,8 +567,16 @@ ExecutionEngine::ExecutionEngine()
globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
- ScopedString name(scope, newString(QStringLiteral("thrower")));
- jsObjects[ThrowerObject] = FunctionObject::createBuiltinFunction(global, name, ::throwTypeError);
+ ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
+ t->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
+ t->setInternalClass(t->internalClass()->frozen());
+ jsObjects[ThrowerObject] = t;
+
+ ScopedProperty pd(scope);
+ pd->value = thrower();
+ pd->set = thrower();
+ functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
+ functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
}
ExecutionEngine::~ExecutionEngine()
@@ -487,8 +589,6 @@ ExecutionEngine::~ExecutionEngine()
while (!compilationUnits.isEmpty())
(*compilationUnits.begin())->unlink();
- internalClasses[Class_Empty]->destroy();
- delete classPool;
delete bumperPointerAllocator;
delete regExpCache;
delete regExpAllocator;
@@ -521,27 +621,32 @@ void ExecutionEngine::initRootContext()
r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext);
r->d()->activation.set(this, globalObject->d());
jsObjects[RootContext] = r;
+ jsObjects[ScriptContext] = r;
jsObjects[IntegerNull] = Encode((int)0);
}
-InternalClass *ExecutionEngine::newClass(const InternalClass &other)
+Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other)
{
- return new (classPool) InternalClass(other);
+ Heap::InternalClass *ic = memoryManager->allocIC<InternalClass>();
+ ic->init(other);
+ return ic;
}
-InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
+Heap::InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
{
- return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : nullptr);
+ Scope scope(this);
+ Scoped<InternalClass> ic(scope, internalClasses(Class_Empty)->changeVTable(vtable));
+ return ic->changePrototype(prototype ? prototype->d() : nullptr);
}
Heap::Object *ExecutionEngine::newObject()
{
- return memoryManager->allocObject<Object>();
+ return memoryManager->allocate<Object>();
}
-Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass, QV4::Object *prototype)
+Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
{
- return memoryManager->allocObject<Object>(internalClass, prototype);
+ return memoryManager->allocObject<Object>(internalClass);
}
Heap::String *ExecutionEngine::newString(const QString &s)
@@ -557,23 +662,28 @@ Heap::String *ExecutionEngine::newIdentifier(const QString &text)
Heap::Object *ExecutionEngine::newStringObject(const String *string)
{
- return memoryManager->allocObject<StringObject>(string);
+ return memoryManager->allocate<StringObject>(string);
+}
+
+Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol)
+{
+ return memoryManager->allocObject<SymbolObject>(classes[Class_SymbolObject], symbol);
}
Heap::Object *ExecutionEngine::newNumberObject(double value)
{
- return memoryManager->allocObject<NumberObject>(value);
+ return memoryManager->allocate<NumberObject>(value);
}
Heap::Object *ExecutionEngine::newBooleanObject(bool b)
{
- return memoryManager->allocObject<BooleanObject>(b);
+ return memoryManager->allocate<BooleanObject>(b);
}
Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
{
Scope scope(this);
- ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>());
+ ScopedArrayObject object(scope, memoryManager->allocate<ArrayObject>());
if (count) {
if (count < 0x1000)
@@ -586,7 +696,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length)
{
Scope scope(this);
- ScopedArrayObject a(scope, memoryManager->allocObject<ArrayObject>());
+ ScopedArrayObject a(scope, memoryManager->allocate<ArrayObject>());
if (length) {
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
@@ -607,45 +717,41 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
{
- Scope scope(this);
- ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(list));
- return object->d();
+ return memoryManager->allocate<ArrayObject>(list);
}
-Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass, Object *prototype)
+Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
{
- Scope scope(this);
- ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(internalClass, prototype));
- return object->d();
+ return memoryManager->allocObject<ArrayObject>(internalClass);
}
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
{
- return memoryManager->allocObject<ArrayBuffer>(array);
+ return memoryManager->allocate<ArrayBuffer>(array);
}
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
{
- return memoryManager->allocObject<ArrayBuffer>(length);
+ return memoryManager->allocate<ArrayBuffer>(length);
}
Heap::DateObject *ExecutionEngine::newDateObject(const Value &value)
{
- return memoryManager->allocObject<DateObject>(value);
+ return memoryManager->allocate<DateObject>(value);
}
Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
{
Scope scope(this);
- Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(dt));
+ Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(dt));
return object->d();
}
Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
{
Scope scope(this);
- Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(t));
+ Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(t));
return object->d();
}
@@ -662,12 +768,12 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int
Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
{
- return memoryManager->allocObject<RegExpObject>(re);
+ return memoryManager->allocate<RegExpObject>(re);
}
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
{
- return memoryManager->allocObject<RegExpObject>(re);
+ return memoryManager->allocate<RegExpObject>(re);
}
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
@@ -714,16 +820,31 @@ Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
{
- return memoryManager->allocObject<VariantObject>(v);
+ return memoryManager->allocate<VariantObject>(v);
}
-Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
+Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
{
Scope scope(this);
- ScopedObject obj(scope, memoryManager->allocObject<ForEachIteratorObject>(o));
+ ScopedObject obj(scope, memoryManager->allocate<ForInIteratorObject>(o));
return obj->d();
}
+Heap::Object *ExecutionEngine::newMapIteratorObject(Object *o)
+{
+ return memoryManager->allocate<MapIteratorObject>(o->d(), this);
+}
+
+Heap::Object *ExecutionEngine::newSetIteratorObject(Object *o)
+{
+ return memoryManager->allocate<SetIteratorObject>(o->d(), this);
+}
+
+Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o)
+{
+ return memoryManager->allocate<ArrayIteratorObject>(o->d(), this);
+}
+
Heap::QmlContext *ExecutionEngine::qmlContext() const
{
if (!currentStackFrame)
@@ -891,16 +1012,14 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
ExecutionContext *global = rootContext();
for (int i = oldSize; i < nArgumentsAccessors; ++i) {
- argumentsAccessors[i].value = ScopedValue(scope, memoryManager->allocObject<ArgumentsGetterFunction>(global, i));
- argumentsAccessors[i].set = ScopedValue(scope, memoryManager->allocObject<ArgumentsSetterFunction>(global, i));
+ argumentsAccessors[i].value = ScopedValue(scope, memoryManager->allocate<ArgumentsGetterFunction>(global, i));
+ argumentsAccessors[i].set = ScopedValue(scope, memoryManager->allocate<ArgumentsSetterFunction>(global, i));
}
}
}
void ExecutionEngine::markObjects(MarkStack *markStack)
{
- identifierTable->mark(markStack);
-
for (int i = 0; i < nArgumentsAccessors; ++i) {
const Property &pd = argumentsAccessors[i];
if (Heap::FunctionObject *getter = pd.getter())
@@ -909,9 +1028,13 @@ void ExecutionEngine::markObjects(MarkStack *markStack)
setter->mark(markStack);
}
- classPool->markObjects(markStack);
+ for (int i = 0; i < NClasses; ++i)
+ if (classes[i])
+ classes[i]->mark(markStack);
markStack->drain();
+ identifierTable->markObjects(markStack);
+
for (auto compilationUnit: compilationUnits) {
compilationUnit->markObjects(markStack);
markStack->drain();
@@ -1053,12 +1176,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
error.setColumn(frame.column);
}
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
- if (!!errorObj && errorObj->asSyntaxError()) {
- QV4::ScopedString m(scope, newString(QStringLiteral("message")));
- QV4::ScopedValue v(scope, errorObj->get(m));
- error.setDescription(v->toQStringNoThrow());
- } else
- error.setDescription(exception->toQStringNoThrow());
+ error.setDescription(exception->toQStringNoThrow());
return error;
}
@@ -1117,8 +1235,11 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return v->toVariant();
} else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
return l->toVariant();
- } else if (object->isListType())
+#if QT_CONFIG(qml_sequence_object)
+ } else if (object->isListType()) {
return QV4::SequencePrototype::toVariant(object);
+#endif
+ }
}
if (value.as<ArrayObject>()) {
@@ -1141,10 +1262,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
+#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
if (succeeded)
return retn;
+#endif
}
if (value.isUndefined())
@@ -1164,8 +1287,10 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return str.at(0);
return str;
}
+#if QT_CONFIG(qml_locale)
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return *ld->d()->locale;
+#endif
if (const QV4::DateObject *d = value.as<DateObject>())
return d->toQDateTime();
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
@@ -1321,6 +1446,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
+#if QT_CONFIG(qml_sequence_object)
case QMetaType::QStringList:
{
bool succeeded = false;
@@ -1330,6 +1456,7 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return retn->asReturnedValue();
return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
}
+#endif
case QMetaType::QVariantList:
return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
case QMetaType::QVariantMap:
@@ -1340,8 +1467,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
case QMetaType::QJsonArray:
return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
+#if QT_CONFIG(qml_locale)
case QMetaType::QLocale:
return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
+#endif
default:
break;
}
@@ -1381,10 +1510,12 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
if (objOk)
return QV4::QObjectWrapper::wrap(this, obj);
+#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
if (succeeded)
return retn->asReturnedValue();
+#endif
if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index c7fb743088..b007e65c4b 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -88,8 +88,6 @@ struct CompilationUnit;
}
struct Function;
-struct InternalClass;
-struct InternalClassPool;
struct Q_QML_EXPORT CppStackFrame {
CppStackFrame *parent;
@@ -98,6 +96,10 @@ struct Q_QML_EXPORT CppStackFrame {
const Value *originalArguments;
int originalArgumentsCount;
int instructionPointer;
+ const char *yield;
+ const char *unwindHandler;
+ const char *unwindLabel;
+ int unwindLevel;
QString source() const;
QString function() const;
@@ -142,8 +144,6 @@ public:
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
Value *ptr = jsStackTop;
jsStackTop = ptr + nValues;
- for (int i = 0; i < nValues; ++i)
- ptr[i] = Primitive::undefinedValue();
return ptr;
}
@@ -153,22 +153,27 @@ public:
QJSEngine *jsEngine() const;
QQmlEngine *qmlEngine() const;
#else // !V4_BOOTSTRAP
- QJSEngine *jsEngine() const { return v8Engine->publicEngine(); }
+ QJSEngine *jsEngine() const { return publicEngine; }
QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; }
#endif // V4_BOOTSTRAP
QV8Engine *v8Engine;
+ QJSEngine *publicEngine;
enum JSObjects {
RootContext,
+ ScriptContext,
IntegerNull, // Has to come after the RootContext to make the context stack safe
ObjectProto,
+ SymbolProto,
ArrayProto,
+ ArrayProtoValues,
PropertyListProto,
StringProto,
NumberProto,
BooleanProto,
DateProto,
FunctionProto,
+ GeneratorProto,
RegExpProto,
ErrorProto,
EvalErrorProto,
@@ -178,18 +183,31 @@ public:
TypeErrorProto,
URIErrorProto,
VariantProto,
+#if QT_CONFIG(qml_sequence_object)
SequenceProto,
+#endif
ArrayBufferProto,
DataViewProto,
+ SetProto,
+ MapProto,
+ IntrinsicTypedArrayProto,
ValueTypeProto,
SignalHandlerProto,
+ IteratorProto,
+ ForInIteratorProto,
+ SetIteratorProto,
+ MapIteratorProto,
+ ArrayIteratorProto,
+ StringIteratorProto,
Object_Ctor,
String_Ctor,
+ Symbol_Ctor,
Number_Ctor,
Boolean_Ctor,
Array_Ctor,
Function_Ctor,
+ GeneratorFunction_Ctor,
Date_Ctor,
RegExp_Ctor,
Error_Ctor,
@@ -201,6 +219,11 @@ public:
URIError_Ctor,
ArrayBuffer_Ctor,
DataView_Ctor,
+ Set_Ctor,
+ Map_Ctor,
+ IntrinsicTypedArray_Ctor,
+
+ GetSymbolSpecies,
Eval_Function,
GetStack_Function,
@@ -211,12 +234,16 @@ public:
enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency
ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); }
+ ExecutionContext *scriptContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + ScriptContext); }
+ void setScriptContext(ReturnedValue c) { jsObjects[ScriptContext] = c; }
FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); }
FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); }
+ FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); }
FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); }
FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); }
FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); }
FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); }
+ FunctionObject *generatorFunctionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + GeneratorFunction_Ctor); }
FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); }
FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); }
FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); }
@@ -228,16 +255,24 @@ public:
FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); }
FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
+ FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); }
+ FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
+ FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
FunctionObject *typedArrayCtors;
+ FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
+
Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
+ Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); }
Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
+ Object *arrayProtoValues() const { return reinterpret_cast<Object *>(jsObjects + ArrayProtoValues); }
Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); }
Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); }
+ Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); }
Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); }
Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); }
Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); }
@@ -247,16 +282,26 @@ public:
Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); }
Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
+#if QT_CONFIG(qml_sequence_object)
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
+#endif
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
+ Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); }
+ Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); }
+ Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); }
Object *typedArrayPrototype;
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
+ Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
+ Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
+ Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
+ Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); }
+ Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
+ Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
- InternalClassPool *classPool;
EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
@@ -273,6 +318,8 @@ public:
String_boolean,
String_number,
String_string,
+ String_default,
+ String_symbol,
String_object,
String_function,
String_length,
@@ -301,10 +348,30 @@ public:
String_byteOffset,
String_buffer,
String_lastIndex,
+ String_next,
+ String_done,
+ String_return,
+
NJSStrings
};
Value *jsStrings;
+ enum JSSymbols {
+ Symbol_hasInstance,
+ Symbol_isConcatSpreadable,
+ Symbol_iterator,
+ Symbol_match,
+ Symbol_replace,
+ Symbol_search,
+ Symbol_species,
+ Symbol_split,
+ Symbol_toPrimitive,
+ Symbol_toStringTag,
+ Symbol_unscopables,
+ NJSSymbols
+ };
+ Value *jsSymbols;
+
String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); }
String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); }
String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); }
@@ -313,6 +380,8 @@ public:
String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); }
String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); }
String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); }
+ String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); }
+ String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); }
String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); }
String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); }
String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); }
@@ -341,6 +410,21 @@ public:
String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); }
String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); }
String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); }
+ String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); }
+ String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); }
+ String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); }
+
+ Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); }
+ Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); }
+ Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); }
+ Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); }
+ Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); }
+ Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); }
+ Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); }
+ Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); }
+ Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); }
+ Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); }
+ Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); }
#ifndef V4_BOOTSTRAP
QIntrusiveList<CompiledData::CompilationUnit, &CompiledData::CompilationUnit::nextCompilationUnit> compilationUnits;
@@ -372,9 +456,9 @@ public:
const bool m_canAllocateExecutableMemory;
#endif
- int internalClassIdCount = 0;
+ quintptr protoIdCount = 1;
- ExecutionEngine();
+ ExecutionEngine(QJSEngine *jsEngine = nullptr);
~ExecutionEngine();
#if !QT_CONFIG(qml_debug)
@@ -396,24 +480,26 @@ public:
return static_cast<ExecutionContext *>(&currentStackFrame->jsFrame->context);
}
- int newInternalClassId() { return ++internalClassIdCount; }
+ // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast
+ quintptr newProtoId() { return (protoIdCount += 2); }
- InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
+ Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
Heap::Object *newObject();
- Heap::Object *newObject(InternalClass *internalClass, Object *prototype);
+ Heap::Object *newObject(Heap::InternalClass *internalClass);
Heap::String *newString(const QString &s = QString());
Heap::String *newIdentifier(const QString &text);
Heap::Object *newStringObject(const String *string);
+ Heap::Object *newSymbolObject(const Symbol *symbol);
Heap::Object *newNumberObject(double value);
Heap::Object *newBooleanObject(bool b);
Heap::ArrayObject *newArrayObject(int count = 0);
Heap::ArrayObject *newArrayObject(const Value *values, int length);
Heap::ArrayObject *newArrayObject(const QStringList &list);
- Heap::ArrayObject *newArrayObject(InternalClass *ic, Object *prototype);
+ Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic);
Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array);
Heap::ArrayBuffer *newArrayBuffer(size_t length);
@@ -437,7 +523,10 @@ public:
Heap::Object *newVariantObject(const QVariant &v);
- Heap::Object *newForEachIteratorObject(Object *o);
+ Heap::Object *newForInIteratorObject(Object *o);
+ Heap::Object *newSetIteratorObject(Object *o);
+ Heap::Object *newMapIteratorObject(Object *o);
+ Heap::Object *newArrayIteratorObject(Object *o);
Heap::QmlContext *qmlContext() const;
QObject *qmlScopeObject() const;
@@ -453,7 +542,7 @@ public:
void initRootContext();
- InternalClass *newClass(const InternalClass &other);
+ Heap::InternalClass *newClass(Heap::InternalClass *other);
StackTrace exceptionStackTrace;
@@ -492,7 +581,7 @@ public:
if (!m_canAllocateExecutableMemory)
return false;
if (f)
- return f->interpreterCallCount >= jitCallCountThreshold;
+ return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold;
return true;
#else
Q_UNUSED(f);
@@ -502,6 +591,7 @@ public:
QV4::ReturnedValue global();
+ double localTZA = 0.0; // local timezone, initialized at startup
private:
#if QT_CONFIG(qml_debug)
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 59fb4a564a..03ff25d5b5 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -88,7 +88,7 @@ struct Q_QML_EXPORT EngineBase {
// Exception handling
Value *exceptionValue = nullptr;
- enum {
+ enum InternalClassType {
Class_Empty,
Class_String,
Class_MemberData,
@@ -96,10 +96,14 @@ struct Q_QML_EXPORT EngineBase {
Class_SparseArrayData,
Class_ExecutionContext,
Class_CallContext,
+ Class_QmlContext,
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
+ Class_GeneratorFunction,
+ Class_GeneratorObject,
Class_StringObject,
+ Class_SymbolObject,
Class_ScriptFunction,
Class_ObjectProto,
Class_RegExp,
@@ -111,10 +115,11 @@ struct Q_QML_EXPORT EngineBase {
Class_ErrorObjectWithMessage,
Class_ErrorProto,
Class_QmlContextWrapper,
- Class_QmlContext,
+ Class_Symbol,
NClasses
};
- InternalClass *internalClasses[NClasses];
+ Heap::InternalClass *classes[NClasses];
+ Heap::InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; }
};
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
#pragma pack(pop)
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 90e158ba37..6541f00c8a 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -47,10 +47,6 @@
#include "qv4string_p.h"
#include <private/qv4mm_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>
#ifndef Q_OS_WIN
@@ -74,7 +70,7 @@ void Heap::ErrorObject::init()
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- if (internalClass == scope.engine->internalClasses[EngineBase::Class_ErrorProto])
+ if (internalClass == scope.engine->internalClasses(EngineBase::Class_ErrorProto))
return;
setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
@@ -316,7 +312,7 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
ScopedString s(scope);
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
obj->setProperty(Index_Constructor, ctor->d());
obj->setProperty(Index_Message, engine->id_empty()->d());
obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t))));
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 6b578e8c38..44b88f0d31 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -180,7 +180,7 @@ struct ErrorObject: Object {
template<>
inline const ErrorObject *Value::as() const {
- return isManaged() && m()->vtable()->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : nullptr;
+ return isManaged() && m()->internalClass->vtable->isErrorObject ? reinterpret_cast<const ErrorObject *>(this) : nullptr;
}
struct EvalErrorObject: ErrorObject {
@@ -328,25 +328,26 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError()
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) {
- InternalClass *ic = e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
- ic = ic->changePrototype(T::defaultPrototype(e)->d());
- return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), message);
+ EngineBase::InternalClassType klass = message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
+ Scope scope(e);
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(ic->d(), message);
}
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) {
Scope scope(e);
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
- InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
- ic = ic->changePrototype(T::defaultPrototype(e)->d());
- return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), v);
+ EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(ic->d(), v);
}
template <typename T>
Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) {
Scope scope(e);
ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue());
- InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage];
- ic = ic->changePrototype(T::defaultPrototype(e)->d());
- return e->memoryManager->allocObject<T>(ic, T::defaultPrototype(e), v, filename, line, column);
+ EngineBase::InternalClassType klass = v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage;
+ Scoped<InternalClass> ic(scope, e->internalClasses(klass)->changePrototype(T::defaultPrototype(e)->d()));
+ return e->memoryManager->allocObject<T>(ic->d(), v, filename, line, column);
}
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 6fca9ecd45..131d3406d2 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -52,27 +52,26 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Code codePtr)
+Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
: compiledFunction(function)
, compilationUnit(unit)
- , code(codePtr)
, codeData(function->code())
, jittedCode(nullptr)
, codeRef(nullptr)
, hasQmlDependencies(function->hasQmlDependencies())
{
- Q_UNUSED(engine);
-
- internalClass = engine->internalClasses[EngineBase::Class_CallContext];
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
// first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
- internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
+ ic = ic->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
const quint32_le *formalsIndices = compiledFunction->formalsTable();
for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
- internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable);
+ ic = ic->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable);
+ internalClass = ic->d();
nFormals = compiledFunction->nFormals;
}
@@ -110,7 +109,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
- internalClass = engine->internalClasses[EngineBase::Class_CallContext];
+ internalClass = engine->internalClasses(EngineBase::Class_CallContext);
// first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
@@ -120,8 +119,8 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
Scope scope(engine);
ScopedString arg(scope);
for (const QString &parameterName : parameterNames) {
- arg = engine->newString(parameterName);
- internalClass = internalClass->addMember(arg, Attr_NotConfigurable);
+ arg = engine->newIdentifier(parameterName);
+ internalClass = internalClass->addMember(arg->identifier(), Attr_NotConfigurable);
}
nFormals = parameters.size();
}
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 59a94e5dde..ff2d86b89f 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -72,21 +72,19 @@ struct Q_QML_EXPORT Function {
return Moth::VME::exec(this, thisObject, argv, argc, context);
}
- typedef ReturnedValue (*Code)(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc);
- Code code;
- const uchar *codeData;
+ const char *codeData;
typedef ReturnedValue (*JittedCode)(CppStackFrame *, ExecutionEngine *);
JittedCode jittedCode;
JSC::MacroAssemblerCodeRef *codeRef;
// first nArguments names in internalClass are the actual arguments
- InternalClass *internalClass;
+ Heap::InternalClass *internalClass;
uint nFormals;
int interpreterCallCount = 0;
bool hasQmlDependencies;
- Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Code codePtr);
+ Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
~Function();
// used when dynamically assigning signal handlers (QQmlConnection)
@@ -98,8 +96,9 @@ struct Q_QML_EXPORT Function {
inline QString sourceFile() const { return compilationUnit->fileName(); }
inline QUrl finalUrl() const { return compilationUnit->finalUrl(); }
- inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; }
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
+ inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
+ inline bool isGenerator() const { return compiledFunction->flags & CompiledData::Function::IsGenerator; }
QQmlSourceLocation sourceLocation() const
{
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 83608070ec..a9aaa344cb 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -41,6 +41,7 @@
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
#include "qv4function_p.h"
+#include "qv4symbol_p.h"
#include <private/qv4mm_p.h>
#include "qv4arrayobject_p.h"
@@ -121,7 +122,7 @@ void Heap::FunctionObject::init()
Object::init();
this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
- Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
+ Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()->identifier()) == Index_Prototype);
setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
@@ -144,10 +145,10 @@ void FunctionObject::init(String *n, bool createProto)
Scope s(internalClass()->engine);
ScopedValue protectThis(s, this);
- Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype);
+ Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()->identifier()) == Heap::FunctionObject::Index_Prototype);
if (createProto) {
- ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype()));
- Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
+ ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses(EngineBase::Class_ObjectProto)));
+ Q_ASSERT(s.engine->internalClasses(EngineBase::Class_ObjectProto)->find(s.engine->id_constructor()->identifier()) == Heap::FunctionObject::Index_ProtoConstructor);
proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d());
setProperty(Heap::FunctionObject::Index_Prototype, proto);
} else {
@@ -175,7 +176,19 @@ ReturnedValue FunctionObject::call(const FunctionObject *, const Value *, const
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
- return scope->engine()->memoryManager->allocObject<ScriptFunction>(scope, function);
+ return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
+}
+
+Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, jsCallFunction code, int argumentCount)
+{
+ Scope scope(engine);
+ ScopedString name(scope, nameOrSymbol);
+ if (!name)
+ name = engine->newString(QChar::fromLatin1('[') + nameOrSymbol->toQString().midRef(1) + QChar::fromLatin1(']'));
+
+ ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
+ function->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(argumentCount));
+ return function->d();
}
bool FunctionObject::isBinding() const
@@ -201,10 +214,8 @@ void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
}
// 15.3.2
-ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+QQmlRefPointer<CompiledData::CompilationUnit> FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t)
{
- Scope scope(f->engine());
-
QString arguments;
QString body;
if (argc > 0) {
@@ -215,35 +226,51 @@ ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Val
}
body = argv[argc - 1].toQString();
}
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (engine->hasException)
+ return nullptr;
- QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}');
+ QString function = (t == Type_Function ? QLatin1String("function anonymous(") : QLatin1String("function* anonymous(")) + arguments + QLatin1String("\n){") + body + QLatin1String("\n}");
- QQmlJS::Engine ee, *engine = &ee;
- QQmlJS::Lexer lexer(engine);
+ QQmlJS::Engine ee;
+ QQmlJS::Lexer lexer(&ee);
lexer.setCode(function, 1, false);
- QQmlJS::Parser parser(engine);
+ QQmlJS::Parser parser(&ee);
const bool parsed = parser.parseExpression();
- if (!parsed)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!parsed) {
+ engine->throwSyntaxError(QLatin1String("Parse error"));
+ return nullptr;
+ }
QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(parser.rootNode());
- if (!fe)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!fe) {
+ engine->throwSyntaxError(QLatin1String("Parse error"));
+ return nullptr;
+ }
- Compiler::Module module(scope.engine->debugger() != nullptr);
+ Compiler::Module module(engine->debugger() != nullptr);
Compiler::JSUnitGenerator jsGenerator(&module);
- RuntimeCodegen cg(scope.engine, &jsGenerator, false);
+ RuntimeCodegen cg(engine, &jsGenerator, false);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = cg.generateCompilationUnit();
- Function *vmf = compilationUnit->linkToEngine(scope.engine);
+ if (engine->hasException)
+ return nullptr;
- ExecutionContext *global = scope.engine->rootContext();
+ return cg.generateCompilationUnit();
+}
+
+ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Function);
+ if (engine->hasException)
+ return Encode::undefined();
+
+ Function *vmf = compilationUnit->linkToEngine(engine);
+ ExecutionContext *global = engine->scriptContext();
return Encode(FunctionObject::createScriptFunction(global, vmf));
}
@@ -268,13 +295,14 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+ defineReadonlyConfigurableProperty(engine->id_name(), *engine->id_empty());
defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
defineDefaultProperty(QStringLiteral("call"), method_call, 1);
defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
-
+ defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
}
ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -284,7 +312,19 @@ ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const
if (!fun)
return v4->throwTypeError();
- return Encode(v4->newString(QStringLiteral("function() { [code] }")));
+ const Scope scope(fun->engine());
+ const ScopedString scopedFunctionName(scope, fun->name());
+ const QString functionName(scopedFunctionName ? scopedFunctionName->toQString() : QString());
+ QString functionAsString = QStringLiteral("function");
+
+ // If fun->name() is empty, then there is no function name
+ // to append because the function is anonymous.
+ if (!functionName.isEmpty())
+ functionAsString.append(QLatin1Char(' ') + functionName);
+
+ functionAsString.append(QStringLiteral("() { [code] }"));
+
+ return Encode(v4->newString(functionAsString));
}
ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -304,7 +344,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
uint len = arr->getLength();
Scope scope(v4);
- Value *arguments = v4->jsAlloca(len);
+ Value *arguments = scope.alloc(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
@@ -383,6 +423,17 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
return bound->asReturnedValue();
}
+ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ if (!argc)
+ return false;
+ const Object *o = thisObject->as<Object>();
+ if (!o)
+ return f->engine()->throwTypeError();
+
+ return Object::instanceOf(o, argv[0]);
+}
+
DEFINE_OBJECT_VTABLE(ScriptFunction);
ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const Value *argv, int argc)
@@ -391,8 +442,7 @@ ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const
const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
Scope scope(v4);
- InternalClass *ic = f->classForConstructor();
- ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
+ ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(f->classForConstructor()));
ReturnedValue result = Moth::VME::exec(fo, thisObject, argv, argc);
@@ -415,38 +465,29 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
setFunction(function);
Q_ASSERT(function);
- Q_ASSERT(function->code);
Scope s(scope);
ScopedFunctionObject f(s, this);
ScopedString name(s, function->name());
f->init(name, true);
- Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length);
- setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount()));
-
- if (function->isStrict()) {
- ScopedProperty pd(s);
- pd->value = s.engine->thrower();
- pd->set = s.engine->thrower();
- f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- }
+ Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()->identifier()) == Index_Length);
+ setProperty(s.engine, Index_Length, Primitive::fromInt32(int(function->compiledFunction->length)));
}
-InternalClass *ScriptFunction::classForConstructor() const
+Heap::InternalClass *ScriptFunction::classForConstructor() const
{
const Object *o = d()->protoProperty();
- InternalClass *ic = d()->cachedClassForConstructor;
- if (ic && ic->prototype == o->d())
- return ic;
+ if (d()->cachedClassForConstructor && d()->cachedClassForConstructor->prototype == o->d())
+ return d()->cachedClassForConstructor;
- ic = engine()->internalClasses[EngineBase::Class_Object];
+ Scope scope(engine());
+ Scoped<InternalClass> ic(scope, engine()->internalClasses(EngineBase::Class_Object));
if (o)
ic = ic->changePrototype(o->d());
- d()->cachedClassForConstructor = ic;
+ d()->cachedClassForConstructor.set(scope.engine, ic->d());
- return ic;
+ return ic->d();
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 32e71a175b..e8bd574161 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -64,9 +64,6 @@ namespace QV4 {
struct IndexedBuiltinFunction;
struct JSCallData;
-typedef ReturnedValue (*jsCallFunction)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
-typedef ReturnedValue (*jsConstructFunction)(const FunctionObject *, const Value *argv, int argc);
-
namespace Heap {
@@ -111,14 +108,16 @@ struct IndexedBuiltinFunction : FunctionObject {
uint index;
};
-struct ScriptFunction : FunctionObject {
+#define ScriptFunctionMembers(class, Member) \
+ Member(class, Pointer, InternalClass *, cachedClassForConstructor)
+
+DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(ScriptFunction)
enum {
Index_Name = FunctionObject::Index_Prototype + 1,
Index_Length
};
void init(QV4::ExecutionContext *scope, Function *function);
-
- QV4::InternalClass *cachedClassForConstructor;
};
#define BoundFunctionMembers(class, Member) \
@@ -166,11 +165,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
- static Heap::FunctionObject *createBuiltinFunction(ExecutionContext *scope, String *name,
- ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc))
- {
- return scope->engine()->memoryManager->allocObject<FunctionObject>(scope, name, code);
- }
+ static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, jsCallFunction code, int argumentCount);
bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
@@ -181,7 +176,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
template<>
inline const FunctionObject *Value::as() const {
- return isManaged() && m()->vtable()->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
+ return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
}
@@ -191,6 +186,12 @@ struct FunctionCtor: FunctionObject
static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+protected:
+ enum Type {
+ Type_Function,
+ Type_Generator
+ };
+ static QQmlRefPointer<CompiledData::CompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function);
};
struct FunctionPrototype: FunctionObject
@@ -203,6 +204,7 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct IndexedBuiltinFunction : FunctionObject
@@ -227,7 +229,7 @@ struct ScriptFunction : FunctionObject {
static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- InternalClass *classForConstructor() const;
+ Heap::InternalClass *classForConstructor() const;
};
@@ -236,7 +238,7 @@ struct BoundFunction: FunctionObject {
static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
{
- return scope->engine()->memoryManager->allocObject<BoundFunction>(scope, target, boundThis, boundArgs);
+ return scope->engine()->memoryManager->allocate<BoundFunction>(scope, target, boundThis, boundArgs);
}
Heap::FunctionObject *target() const { return d()->target; }
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
new file mode 100644
index 0000000000..a29eef513c
--- /dev/null
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** 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 <qv4generatorobject_p.h>
+#include <qv4symbol_p.h>
+#include <qv4iterator_p.h>
+#include <qv4jscall_p.h>
+#include <qv4vme_moth_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(GeneratorFunctionCtor);
+DEFINE_OBJECT_VTABLE(GeneratorFunction);
+DEFINE_OBJECT_VTABLE(GeneratorObject);
+
+void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction"));
+}
+
+ReturnedValue GeneratorFunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Generator);
+ if (engine->hasException)
+ return Encode::undefined();
+
+ Function *vmf = compilationUnit->linkToEngine(engine);
+ ExecutionContext *global = engine->scriptContext();
+ return Encode(GeneratorFunction::create(global, vmf));
+}
+
+// 15.3.1: This is equivalent to new Function(...)
+ReturnedValue GeneratorFunctionCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ return callAsConstructor(f, argv, argc);
+}
+
+Heap::FunctionObject *GeneratorFunction::create(ExecutionContext *context, Function *function)
+{
+ Scope scope(context);
+ Scoped<GeneratorFunction> g(scope, context->engine()->memoryManager->allocate<GeneratorFunction>(context, function));
+ ScopedObject proto(scope, scope.engine->newObject());
+ proto->setPrototype(scope.engine->generatorPrototype());
+ g->defineDefaultProperty(scope.engine->id_prototype(), proto, Attr_NotConfigurable|Attr_NotEnumerable);
+ g->setPrototype(ScopedObject(scope, scope.engine->generatorFunctionCtor()->get(scope.engine->id_prototype())));
+ return g->d();
+}
+
+ReturnedValue GeneratorFunction::callAsConstructor(const FunctionObject *f, const Value *, int)
+{
+ return f->engine()->throwTypeError();
+}
+
+ReturnedValue GeneratorFunction::call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ const GeneratorFunction *gf = static_cast<const GeneratorFunction *>(f);
+ Function *function = gf->function();
+ ExecutionEngine *engine = gf->engine();
+
+ // We need to set up a separate stack for the generator, as it's being re-entered
+ uint stackSize = argc; // space for the original arguments
+ int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters;
+ stackSize += jsStackFrameSize;
+
+ size_t requiredMemory = sizeof(GeneratorObject::Data) - sizeof(Value) + sizeof(Value) * stackSize;
+
+ Scope scope(gf);
+ Scoped<GeneratorObject> g(scope, scope.engine->memoryManager->allocManaged<GeneratorObject>(requiredMemory, scope.engine->classes[EngineBase::Class_GeneratorObject]));
+ g->setPrototype(ScopedObject(scope, gf->get(scope.engine->id_prototype())));
+
+ Heap::GeneratorObject *gp = g->d();
+ gp->stack.size = stackSize;
+ gp->stack.alloc = stackSize;
+
+ // copy original arguments
+ memcpy(gp->stack.values, argv, argc*sizeof(Value));
+ gp->cppFrame.originalArguments = gp->stack.values;
+ gp->cppFrame.originalArgumentsCount = argc;
+
+ // setup JS stack frame
+ CallData *callData = reinterpret_cast<CallData *>(&gp->stack.values[argc]);
+ callData->function = *gf;
+ callData->context = gf->scope();
+ callData->accumulator = Encode::undefined();
+ callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue();
+ if (argc > int(function->nFormals))
+ argc = int(function->nFormals);
+ callData->setArgc(argc);
+ memcpy(callData->args, argv, argc*sizeof(Value));
+
+ gp->cppFrame.v4Function = function;
+ gp->cppFrame.instructionPointer = 0;
+ gp->cppFrame.jsFrame = callData;
+ gp->cppFrame.parent = engine->currentStackFrame;
+ engine->currentStackFrame = &gp->cppFrame;
+
+ Moth::VME::interpret(gp->cppFrame, function->codeData);
+ gp->state = GeneratorState::SuspendedStart;
+
+ engine->currentStackFrame = gp->cppFrame.parent;
+ return g->asReturnedValue();
+}
+
+
+void Heap::GeneratorPrototype::init()
+{
+ Heap::FunctionObject::init();
+}
+
+
+void GeneratorPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedValue v(scope);
+
+ ScopedObject ctorProto(scope, engine->newObject(engine->newInternalClass(Object::staticVTable(), engine->functionPrototype())));
+
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(engine->id_prototype(), ctorProto);
+
+ ctorProto->defineDefaultProperty(QStringLiteral("constructor"), (v = ctor), Attr_ReadOnly_ButConfigurable);
+ ctorProto->defineDefaultProperty(engine->symbol_toStringTag(), (v = engine->newIdentifier(QStringLiteral("GeneratorFunction"))), Attr_ReadOnly_ButConfigurable);
+ ctorProto->defineDefaultProperty(engine->id_prototype(), (v = this), Attr_ReadOnly_ButConfigurable);
+
+ setPrototype(engine->iteratorPrototype());
+ defineDefaultProperty(QStringLiteral("constructor"), ctorProto, Attr_ReadOnly_ButConfigurable);
+ defineDefaultProperty(QStringLiteral("next"), method_next, 1);
+ defineDefaultProperty(QStringLiteral("return"), method_return, 1);
+ defineDefaultProperty(QStringLiteral("throw"), method_throw, 1);
+ defineDefaultProperty(engine->symbol_toStringTag(), (v = engine->newString(QStringLiteral("Generator"))), Attr_ReadOnly_ButConfigurable);
+}
+
+ReturnedValue GeneratorPrototype::method_next(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+ Heap::GeneratorObject *gp = g->d();
+
+ if (gp->state == GeneratorState::Completed)
+ return IteratorPrototype::createIterResultObject(engine, Primitive::undefinedValue(), true);
+
+ return g->resume(engine, argc ? argv[0] : Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorPrototype::method_return(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+
+ Heap::GeneratorObject *gp = g->d();
+
+ if (gp->state == GeneratorState::SuspendedStart)
+ gp->state = GeneratorState::Completed;
+
+ if (gp->state == GeneratorState::Completed)
+ return IteratorPrototype::createIterResultObject(engine, argc ? argv[0] : Primitive::undefinedValue(), true);
+
+ // the bytecode interpreter interprets an exception with empty value as
+ // a yield called with return()
+ engine->throwError(Primitive::emptyValue());
+
+ return g->resume(engine, argc ? argv[0]: Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorPrototype::method_throw(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+
+ Heap::GeneratorObject *gp = g->d();
+
+ engine->throwError(argc ? argv[0]: Primitive::undefinedValue());
+
+ if (gp->state == GeneratorState::SuspendedStart || gp->state == GeneratorState::Completed) {
+ gp->state = GeneratorState::Completed;
+ return Encode::undefined();
+ }
+
+ return g->resume(engine, Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorObject::resume(ExecutionEngine *engine, const Value &arg) const
+{
+ Heap::GeneratorObject *gp = d();
+ gp->state = GeneratorState::Executing;
+ gp->cppFrame.parent = engine->currentStackFrame;
+ engine->currentStackFrame = &gp->cppFrame;
+
+ Q_ASSERT(gp->cppFrame.yield != nullptr);
+ const char *code = gp->cppFrame.yield;
+ gp->cppFrame.yield = nullptr;
+ gp->cppFrame.jsFrame->accumulator = arg;
+
+ Scope scope(engine);
+ ScopedValue result(scope, Moth::VME::interpret(gp->cppFrame, code));
+
+ engine->currentStackFrame = gp->cppFrame.parent;
+
+ bool done = (gp->cppFrame.yield == nullptr);
+ gp->state = done ? GeneratorState::Completed : GeneratorState::SuspendedYield;
+ if (engine->hasException)
+ return Encode::undefined();
+ return IteratorPrototype::createIterResultObject(engine, result, done);
+}
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
new file mode 100644
index 0000000000..62ffcbbad1
--- /dev/null
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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 QV4GENERATOROBJECT_P_H
+#define QV4GENERATOROBJECT_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 "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum class GeneratorState {
+ Undefined,
+ SuspendedStart,
+ SuspendedYield,
+ Executing,
+ Completed
+};
+
+namespace Heap {
+
+struct GeneratorFunctionCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct GeneratorFunction : ScriptFunction {
+};
+
+struct GeneratorPrototype : FunctionObject {
+ void init();
+};
+
+#define GeneratorObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, context) \
+ Member(class, Pointer, GeneratorFunction *, function) \
+ Member(class, NoMark, GeneratorState, state) \
+ Member(class, NoMark, CppStackFrame, cppFrame) \
+ Member(class, ValueArray, ValueArray, stack)
+
+DECLARE_HEAP_OBJECT(GeneratorObject, Object) {
+ DECLARE_MARKOBJECTS(GeneratorObject);
+};
+
+}
+
+struct GeneratorFunctionCtor : FunctionCtor
+{
+ V4_OBJECT2(GeneratorFunctionCtor, FunctionCtor)
+
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct GeneratorFunction : ScriptFunction
+{
+ V4_OBJECT2(GeneratorFunction, ScriptFunction)
+ V4_INTERNALCLASS(GeneratorFunction)
+
+ static Heap::FunctionObject *create(ExecutionContext *scope, Function *function);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct GeneratorPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_next(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_return(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_throw(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+
+struct GeneratorObject : Object {
+ V4_OBJECT2(GeneratorObject, Object)
+ Q_MANAGED_TYPE(GeneratorObject)
+ V4_INTERNALCLASS(GeneratorObject)
+ V4_PROTOTYPE(generatorPrototype)
+
+ ReturnedValue resume(ExecutionEngine *engine, const Value &arg) const;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4GENERATORFUNCTION_P_H
+
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1fa4bae049..607f8b4d28 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -153,6 +153,11 @@ namespace Compiler {
struct Module;
struct Context;
struct JSUnitGenerator;
+ class Codegen;
+}
+
+namespace Moth {
+ class BytecodeGenerator;
}
namespace Heap {
@@ -160,13 +165,17 @@ namespace Heap {
struct MemberData;
struct ArrayData;
+ struct StringOrSymbol;
struct String;
+ struct Symbol;
struct Object;
struct ObjectPrototype;
struct ExecutionContext;
struct CallContext;
+ struct QmlContext;
struct ScriptFunction;
+ struct InternalClass;
struct BooleanObject;
struct NumberObject;
@@ -188,14 +197,18 @@ namespace Heap {
template <typename T, size_t> struct Pointer;
}
+struct CppStackFrame;
class MemoryManager;
class ExecutableAllocator;
+struct StringOrSymbol;
struct String;
+struct Symbol;
struct Object;
struct ObjectPrototype;
struct ObjectIterator;
struct ExecutionContext;
struct CallContext;
+struct QmlContext;
struct ScriptFunction;
struct InternalClass;
struct Property;
@@ -236,6 +249,7 @@ struct Scope;
struct ScopedValue;
template<typename T> struct Scoped;
typedef Scoped<String> ScopedString;
+typedef Scoped<StringOrSymbol> ScopedStringOrSymbol;
typedef Scoped<Object> ScopedObject;
typedef Scoped<ArrayObject> ScopedArrayObject;
typedef Scoped<FunctionObject> ScopedFunctionObject;
@@ -244,6 +258,7 @@ typedef Scoped<ExecutionContext> ScopedContext;
struct PersistentValueStorage;
class PersistentValue;
class WeakValue;
+struct MarkStack;
struct IdentifierTable;
class RegExpCache;
@@ -357,6 +372,12 @@ struct Q_QML_EXPORT StackFrame {
};
typedef QVector<StackFrame> StackTrace;
+enum class ObjectLiteralArgument {
+ Value,
+ Getter,
+ Setter
+};
+
}
Q_DECLARE_TYPEINFO(QV4::PropertyAttributes, Q_PRIMITIVE_TYPE);
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index f419ab53fe..47a6734eda 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -351,7 +351,7 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
if (!directCall) {
// the context for eval should be the global scope
- ctx = v4->rootContext();
+ ctx = v4->scriptContext();
}
String *scode = argv[0].stringValue();
@@ -361,7 +361,7 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
const QString code = scode->toQString();
bool inheritContext = !isStrict;
- Script script(ctx, QV4::Compiler::EvalCode, code, QStringLiteral("eval code"));
+ Script script(ctx, QV4::Compiler::ContextType::Eval, code, QStringLiteral("eval code"));
script.strictMode = (directCall && isStrict);
script.inheritContext = inheritContext;
script.parse();
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index c122bcb51a..4bfae14aec 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -38,11 +38,22 @@
****************************************************************************/
#include "qv4identifier_p.h"
#include "qv4identifiertable_p.h"
+#include "qv4string_p.h"
QT_BEGIN_NAMESPACE
namespace QV4 {
+QString Identifier::toQString() const
+{
+ if (isArrayIndex())
+ return QString::number(asArrayIndex());
+ Heap::Base *b = asHeapObject();
+ Q_ASSERT(b->internalClass->vtable->isStringOrSymbol);
+ Heap::StringOrSymbol *s = static_cast<Heap::StringOrSymbol *>(b);
+ return s->toQString();
+}
+
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
@@ -54,14 +65,16 @@ static inline int primeForNumBits(int numBits)
}
-IdentifierHashData::IdentifierHashData(int numBits)
+IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits)
: size(0)
, numBits(numBits)
+ , identifierTable(table)
{
refCount.store(1);
alloc = primeForNumBits(numBits);
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
+ identifierTable->addIdentifierHash(this);
}
IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
@@ -73,12 +86,18 @@ IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
alloc = other->alloc;
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
+ identifierTable->addIdentifierHash(this);
+}
+
+IdentifierHashData::~IdentifierHashData() {
+ free(entries);
+ if (identifierTable)
+ identifierTable->removeIdentifierHash(this);
}
IdentifierHash::IdentifierHash(ExecutionEngine *engine)
{
- d = new IdentifierHashData(3);
- d->identifierTable = engine->identifierTable;
+ d = new IdentifierHashData(engine->identifierTable, 3);
}
void IdentifierHash::detach()
@@ -92,8 +111,10 @@ void IdentifierHash::detach()
}
-IdentifierHashEntry *IdentifierHash::addEntry(const Identifier *identifier)
+IdentifierHashEntry *IdentifierHash::addEntry(Identifier identifier)
{
+ Q_ASSERT(identifier.isValid());
+
// fill up to max 50%
bool grow = (d->alloc <= d->size*2);
@@ -104,10 +125,10 @@ IdentifierHashEntry *IdentifierHash::addEntry(const Identifier *identifier)
memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
for (int i = 0; i < d->alloc; ++i) {
const IdentifierHashEntry &e = d->entries[i];
- if (!e.identifier)
+ if (!e.identifier.isValid())
continue;
- uint idx = e.identifier->hashValue % newAlloc;
- while (newEntries[idx].identifier) {
+ uint idx = e.identifier.id % newAlloc;
+ while (newEntries[idx].identifier.isValid()) {
++idx;
idx %= newAlloc;
}
@@ -118,8 +139,8 @@ IdentifierHashEntry *IdentifierHash::addEntry(const Identifier *identifier)
d->alloc = newAlloc;
}
- uint idx = identifier->hashValue % d->alloc;
- while (d->entries[idx].identifier) {
+ uint idx = identifier.id % d->alloc;
+ while (d->entries[idx].identifier.isValid()) {
Q_ASSERT(d->entries[idx].identifier != identifier);
++idx;
idx %= d->alloc;
@@ -129,15 +150,15 @@ IdentifierHashEntry *IdentifierHash::addEntry(const Identifier *identifier)
return d->entries + idx;
}
-const IdentifierHashEntry *IdentifierHash::lookup(const Identifier *identifier) const
+const IdentifierHashEntry *IdentifierHash::lookup(Identifier identifier) const
{
- if (!d)
+ if (!d || !identifier.isValid())
return nullptr;
Q_ASSERT(d->entries);
- uint idx = identifier->hashValue % d->alloc;
+ uint idx = identifier.id % d->alloc;
while (1) {
- if (!d->entries[idx].identifier)
+ if (!d->entries[idx].identifier.isValid())
return nullptr;
if (d->entries[idx].identifier == identifier)
return d->entries + idx;
@@ -150,41 +171,56 @@ const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const
{
if (!d)
return nullptr;
- Q_ASSERT(d->entries);
- uint hash = String::createHashValue(str.constData(), str.length(), nullptr);
- uint idx = hash % d->alloc;
- while (1) {
- if (!d->entries[idx].identifier)
- return nullptr;
- if (d->entries[idx].identifier->string == str)
- return d->entries + idx;
- ++idx;
- idx %= d->alloc;
- }
+ Identifier id = d->identifierTable->identifier(str);
+ return lookup(id);
}
const IdentifierHashEntry *IdentifierHash::lookup(String *str) const
{
if (!d)
return nullptr;
- if (str->d()->identifier)
- return lookup(str->d()->identifier);
+ Identifier id = d->identifierTable->identifier(str);
+ if (id.isValid())
+ return lookup(id);
return lookup(str->toQString());
}
-const Identifier *IdentifierHash::toIdentifier(const QString &str) const
+const Identifier IdentifierHash::toIdentifier(const QString &str) const
{
Q_ASSERT(d);
return d->identifierTable->identifier(str);
}
-const Identifier *IdentifierHash::toIdentifier(Heap::String *str) const
+const Identifier IdentifierHash::toIdentifier(Heap::String *str) const
{
Q_ASSERT(d);
return d->identifierTable->identifier(str);
}
+QString QV4::IdentifierHash::findId(int value) const
+{
+ IdentifierHashEntry *e = d->entries;
+ IdentifierHashEntry *end = e + d->alloc;
+ while (e < end) {
+ if (e->identifier.isValid() && e->value == value)
+ return e->identifier.toQString();
+ ++e;
+ }
+ return QString();
+}
+
+void IdentifierHashData::markObjects(MarkStack *markStack) const
+{
+ IdentifierHashEntry *e = entries;
+ IdentifierHashEntry *end = e + alloc;
+ while (e < end) {
+ if (Heap::Base *o = e->identifier.asHeapObject())
+ o->mark(markStack);
+ ++e;
+ }
+}
+
}
diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h
index 82346d5f68..b167a149a2 100644
--- a/src/qml/jsruntime/qv4identifier_p.h
+++ b/src/qml/jsruntime/qv4identifier_p.h
@@ -51,38 +51,47 @@
//
#include <qstring.h>
+#include <private/qv4global_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-namespace Heap {
- struct String;
-}
-
-struct String;
-struct IdentifierTable;
-struct ExecutionEngine;
-
struct Identifier
{
- QString string;
- uint hashValue;
+ // id's are either pointers to Heap::String or Heap::Symbol from the Identifier table.
+ // For Symbol is can simply point to itself.
+ // This gives us automative GC'ing of identifiers
+ // In addition, an identifier can have the lowest bit set, and then indicates an array index
+ quint64 id;
+
+ static Identifier invalid() { return Identifier{ 0 }; }
+ static Identifier fromArrayIndex(uint idx) { return Identifier{ (quint64(idx) << 1) | 1 }; }
+ bool isValid() const { return id && !(id & 1); }
+ uint asArrayIndex() const { return (id & 1) ? (id >> 1) : std::numeric_limits<uint>::max(); }
+ uint isArrayIndex() const { return (id & 1); }
+ static Identifier fromHeapObject(Heap::Base *b) { return Identifier{ reinterpret_cast<quintptr>(b) }; }
+ Heap::Base *asHeapObject() const { return (id & 1) ? nullptr : reinterpret_cast<Heap::Base *>(id); }
+
+ Q_QML_EXPORT QString toQString() const;
+
+ bool operator ==(const Identifier &other) const { return id == other.id; }
+ bool operator !=(const Identifier &other) const { return id != other.id; }
+ bool operator <(const Identifier &other) const { return id < other.id; }
};
struct IdentifierHashEntry {
- const Identifier *identifier;
+ Identifier identifier;
int value;
};
struct IdentifierHashData
{
- IdentifierHashData(int numBits);
+ IdentifierHashData(IdentifierTable *table, int numBits);
explicit IdentifierHashData(IdentifierHashData *other);
- ~IdentifierHashData() {
- free(entries);
- }
+ ~IdentifierHashData();
+ void markObjects(MarkStack *markStack) const;
QBasicAtomicInt refCount;
int alloc;
@@ -117,12 +126,12 @@ struct IdentifierHash
QString findId(int value) const;
protected:
- IdentifierHashEntry *addEntry(const Identifier *i);
- const IdentifierHashEntry *lookup(const Identifier *identifier) const;
+ IdentifierHashEntry *addEntry(Identifier i);
+ const IdentifierHashEntry *lookup(Identifier identifier) const;
const IdentifierHashEntry *lookup(const QString &str) const;
const IdentifierHashEntry *lookup(String *str) const;
- const Identifier *toIdentifier(const QString &str) const;
- const Identifier *toIdentifier(Heap::String *str) const;
+ const Identifier toIdentifier(const QString &str) const;
+ const Identifier toIdentifier(Heap::String *str) const;
};
@@ -180,20 +189,6 @@ inline int IdentifierHash::value(String *str) const
return e ? e->value : -1;
}
-
-inline
-QString IdentifierHash::findId(int value) const
-{
- IdentifierHashEntry *e = d->entries;
- IdentifierHashEntry *end = e + d->alloc;
- while (e < end) {
- if (e->identifier && e->value == value)
- return e->identifier->string;
- ++e;
- }
- return QString();
-}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index b77f9478d3..c045ac3008 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
#include "qv4identifiertable_p.h"
+#include "qv4symbol_p.h"
QT_BEGIN_NAMESPACE
@@ -59,38 +60,38 @@ IdentifierTable::IdentifierTable(ExecutionEngine *engine)
, numBits(8)
{
alloc = primeForNumBits(numBits);
- entries = (Heap::String **)malloc(alloc*sizeof(Heap::String *));
- memset(entries, 0, alloc*sizeof(Heap::String *));
+ entriesByHash = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
+ entriesById = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
+ memset(entriesByHash, 0, alloc*sizeof(Heap::String *));
+ memset(entriesById, 0, alloc*sizeof(Heap::String *));
}
IdentifierTable::~IdentifierTable()
{
- for (int i = 0; i < alloc; ++i)
- if (entries[i])
- delete entries[i]->identifier;
- free(entries);
+ free(entriesByHash);
+ free(entriesById);
+ for (auto &h : idHashes)
+ h->identifierTable = nullptr;
}
-void IdentifierTable::addEntry(Heap::String *str)
+void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
{
uint hash = str->hashValue();
if (str->subtype == Heap::String::StringType_ArrayIndex)
return;
- str->identifier = new Identifier;
- str->identifier->string = str->toQString();
- str->identifier->hashValue = hash;
+ str->identifier = Identifier::fromHeapObject(str);
bool grow = (alloc <= size*2);
if (grow) {
++numBits;
int newAlloc = primeForNumBits(numBits);
- Heap::String **newEntries = (Heap::String **)malloc(newAlloc*sizeof(Heap::String *));
- memset(newEntries, 0, newAlloc*sizeof(Heap::String *));
+ Heap::StringOrSymbol **newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *));
+ memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *));
for (int i = 0; i < alloc; ++i) {
- Heap::String *e = entries[i];
+ Heap::StringOrSymbol *e = entriesByHash[i];
if (!e)
continue;
uint idx = e->stringHash % newAlloc;
@@ -100,17 +101,42 @@ void IdentifierTable::addEntry(Heap::String *str)
}
newEntries[idx] = e;
}
- free(entries);
- entries = newEntries;
+ free(entriesByHash);
+ entriesByHash = newEntries;
+
+ newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *));
+ memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *));
+ for (int i = 0; i < alloc; ++i) {
+ Heap::StringOrSymbol *e = entriesById[i];
+ if (!e)
+ continue;
+ uint idx = e->identifier.id % newAlloc;
+ while (newEntries[idx]) {
+ ++idx;
+ idx %= newAlloc;
+ }
+ newEntries[idx] = e;
+ }
+ free(entriesById);
+ entriesById = newEntries;
+
alloc = newAlloc;
}
uint idx = hash % alloc;
- while (entries[idx]) {
+ while (entriesByHash[idx]) {
+ ++idx;
+ idx %= alloc;
+ }
+ entriesByHash[idx] = str;
+
+ idx = str->identifier.id % alloc;
+ while (entriesById[idx]) {
++idx;
idx %= alloc;
}
- entries[idx] = str;
+ entriesById[idx] = str;
+
++size;
}
@@ -121,9 +147,9 @@ Heap::String *IdentifierTable::insertString(const QString &s)
uint subtype;
uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
uint idx = hash % alloc;
- while (Heap::String *e = entries[idx]) {
+ while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == s)
- return e;
+ return static_cast<Heap::String *>(e);
++idx;
idx %= alloc;
}
@@ -135,18 +161,42 @@ Heap::String *IdentifierTable::insertString(const QString &s)
return str;
}
+Heap::Symbol *IdentifierTable::insertSymbol(const QString &s)
+{
+ Q_ASSERT(s.at(0) == QLatin1Char('@'));
+
+ uint subtype;
+ uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ uint idx = hash % alloc;
+ while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
+ if (e->stringHash == hash && e->toQString() == s)
+ return static_cast<Heap::Symbol *>(e);
+ ++idx;
+ idx %= alloc;
+ }
+
+ Heap::Symbol *str = Symbol::create(engine, s);
+ str->stringHash = hash;
+ str->subtype = subtype;
+ addEntry(str);
+ return str;
+
+}
+
-Identifier *IdentifierTable::identifierImpl(const Heap::String *str)
+Identifier IdentifierTable::identifierImpl(const Heap::String *str)
{
- if (str->identifier)
+ if (str->identifier.isValid())
return str->identifier;
uint hash = str->hashValue();
- if (str->subtype == Heap::String::StringType_ArrayIndex)
- return nullptr;
+ if (str->subtype == Heap::String::StringType_ArrayIndex) {
+ str->identifier = Identifier::fromArrayIndex(hash);
+ return str->identifier;
+ }
uint idx = hash % alloc;
- while (Heap::String *e = entries[idx]) {
- if (e->stringHash == hash && e->isEqualTo(str)) {
+ while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
+ if (e->stringHash == hash && e->toQString() == str->toQString()) {
str->identifier = e->identifier;
return e->identifier;
}
@@ -158,28 +208,104 @@ Identifier *IdentifierTable::identifierImpl(const Heap::String *str)
return str->identifier;
}
-Heap::String *IdentifierTable::stringFromIdentifier(Identifier *i)
+Heap::StringOrSymbol *IdentifierTable::resolveId(Identifier i) const
{
- if (!i)
+ uint arrayIdx = i.asArrayIndex();
+ if (arrayIdx < UINT_MAX)
+ return engine->newString(QString::number(arrayIdx));
+ if (!i.isValid())
return nullptr;
- uint idx = i->hashValue % alloc;
+ uint idx = i.id % alloc;
while (1) {
- Heap::String *e = entries[idx];
- Q_ASSERT(e);
- if (e->identifier == i)
+ Heap::StringOrSymbol *e = entriesById[idx];
+ if (!e || e->identifier == i)
return e;
++idx;
idx %= alloc;
}
}
-Identifier *IdentifierTable::identifier(const QString &s)
+Heap::String *IdentifierTable::stringForId(Identifier i) const
+{
+ Heap::StringOrSymbol *s = resolveId(i);
+ Q_ASSERT(s && s->internalClass->vtable->isString);
+ return static_cast<Heap::String *>(s);
+}
+
+Heap::Symbol *IdentifierTable::symbolForId(Identifier i) const
+{
+ Heap::StringOrSymbol *s = resolveId(i);
+ Q_ASSERT(!s || !s->internalClass->vtable->isString);
+ return static_cast<Heap::Symbol *>(s);
+}
+
+void IdentifierTable::markObjects(MarkStack *markStack)
+{
+ for (const auto &h : idHashes)
+ h->markObjects(markStack);
+}
+
+template <typename Key>
+int sweepTable(Heap::StringOrSymbol **table, int alloc, std::function<Key(Heap::StringOrSymbol *)> f) {
+ int freed = 0;
+ Key lastKey = 0;
+ int lastEntry = -1;
+ int start = 0;
+ // start at an empty entry so we compress properly
+ for (; start < alloc; ++start) {
+ if (!table[start])
+ break;
+ }
+
+ for (int i = 0; i < alloc; ++i) {
+ int idx = (i + start) % alloc;
+ Heap::StringOrSymbol *entry = table[idx];
+ if (!entry) {
+ lastEntry = -1;
+ continue;
+ }
+ if (entry->isMarked()) {
+ if (lastEntry >= 0 && lastKey == f(entry)) {
+ Q_ASSERT(table[lastEntry] == nullptr);
+ table[lastEntry] = entry;
+ table[idx] = nullptr;
+ lastEntry = (lastEntry + 1) % alloc;
+ Q_ASSERT(table[lastEntry] == nullptr);
+ }
+ continue;
+ }
+ if (lastEntry == -1) {
+ lastEntry = idx;
+ lastKey = f(entry);
+ }
+ table[idx] = nullptr;
+ ++freed;
+ }
+ for (int i = 0; i < alloc; ++i) {
+ Heap::StringOrSymbol *entry = table[i];
+ if (!entry)
+ continue;
+ Q_ASSERT(entry->isMarked());
+ }
+ return freed;
+}
+
+void IdentifierTable::sweep()
+{
+ int f = sweepTable<int>(entriesByHash, alloc, [](Heap::StringOrSymbol *entry) {return entry->hashValue(); });
+ int freed = sweepTable<quint64>(entriesById, alloc, [](Heap::StringOrSymbol *entry) {return entry->identifier.id; });
+ Q_UNUSED(f);
+ Q_ASSERT(f == freed);
+ size -= freed;
+}
+
+Identifier IdentifierTable::identifier(const QString &s)
{
return insertString(s)->identifier;
}
-Identifier *IdentifierTable::identifier(const char *s, int len)
+Identifier IdentifierTable::identifier(const char *s, int len)
{
uint subtype;
uint hash = String::createHashValue(s, len, &subtype);
@@ -188,7 +314,7 @@ Identifier *IdentifierTable::identifier(const char *s, int len)
QLatin1String latin(s, len);
uint idx = hash % alloc;
- while (Heap::String *e = entries[idx]) {
+ while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == latin)
return e->identifier;
++idx;
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index b0b08f1e54..6e6600d055 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -53,6 +53,7 @@
#include "qv4identifier_p.h"
#include "qv4string_p.h"
#include "qv4engine_p.h"
+#include <qset.h>
#include <limits.h>
QT_BEGIN_NAMESPACE
@@ -66,9 +67,12 @@ struct IdentifierTable
int alloc;
int size;
int numBits;
- Heap::String **entries;
+ Heap::StringOrSymbol **entriesByHash;
+ Heap::StringOrSymbol **entriesById;
- void addEntry(Heap::String *str);
+ QSet<IdentifierHashData *> idHashes;
+
+ void addEntry(Heap::StringOrSymbol *str);
public:
@@ -76,32 +80,34 @@ public:
~IdentifierTable();
Heap::String *insertString(const QString &s);
+ Heap::Symbol *insertSymbol(const QString &s);
- Identifier *identifier(const Heap::String *str) {
- if (str->identifier)
+ Identifier identifier(const Heap::String *str) {
+ if (str->identifier.isValid())
return str->identifier;
return identifierImpl(str);
}
- Identifier *identifier(const QV4::String *str) {
+ Identifier identifier(const QV4::String *str) {
return identifier(str->d());
}
- Identifier *identifier(const QString &s);
- Identifier *identifier(const char *s, int len);
+ Identifier identifier(const QString &s);
+ Identifier identifier(const char *s, int len);
+
+ Identifier identifierImpl(const Heap::String *str);
- Identifier *identifierImpl(const Heap::String *str);
+ Heap::StringOrSymbol *resolveId(Identifier i) const;
+ Q_QML_PRIVATE_EXPORT Heap::String *stringForId(Identifier i) const;
+ Q_QML_PRIVATE_EXPORT Heap::Symbol *symbolForId(Identifier i) const;
- Heap::String *stringFromIdentifier(Identifier *i);
+ void markObjects(MarkStack *markStack);
+ void sweep();
- void mark(MarkStack *markStack) {
- for (int i = 0; i < alloc; ++i) {
- Heap::String *entry = entries[i];
- if (!entry || entry->isMarked())
- continue;
- entry->setMarkBit();
- Q_ASSERT(entry->vtable()->markObjects);
- entry->vtable()->markObjects(entry, markStack);
- }
+ void addIdentifierHash(IdentifierHashData *h) {
+ idHashes.insert(h);
+ }
+ void removeIdentifierHash(IdentifierHashData *h) {
+ idHashes.remove(h);
}
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 3bfcf358bf..a913d5ca75 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE
-using namespace QV4;
+namespace QV4 {
static const uchar prime_deltas[] = {
0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
@@ -74,27 +74,11 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
// fill up to max 50%
bool grow = (d->alloc <= d->size*2);
- if (classSize < d->size || grow) {
- PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
- for (int i = 0; i < d->alloc; ++i) {
- const Entry &e = d->entries[i];
- if (!e.identifier || e.index >= static_cast<unsigned>(classSize))
- continue;
- uint idx = e.identifier->hashValue % dd->alloc;
- while (dd->entries[idx].identifier) {
- ++idx;
- idx %= dd->alloc;
- }
- dd->entries[idx] = e;
- }
- dd->size = classSize;
- Q_ASSERT(d->refCount > 1);
- --d->refCount;
- d = dd;
- }
+ if (classSize < d->size || grow)
+ detach(grow, classSize);
- uint idx = entry.identifier->hashValue % d->alloc;
- while (d->entries[idx].identifier) {
+ uint idx = entry.identifier.id % d->alloc;
+ while (d->entries[idx].identifier.isValid()) {
++idx;
idx %= d->alloc;
}
@@ -102,38 +86,125 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
+int PropertyHash::removeIdentifier(Identifier identifier, int classSize)
+{
+ int val = -1;
+ PropertyHashData *dd = new PropertyHashData(d->numBits);
+ for (int i = 0; i < d->alloc; ++i) {
+ const Entry &e = d->entries[i];
+ if (!e.identifier.isValid() || e.index >= static_cast<unsigned>(classSize))
+ continue;
+ if (e.identifier == identifier) {
+ val = e.index;
+ continue;
+ }
+ uint idx = e.identifier.id % dd->alloc;
+ while (dd->entries[idx].identifier.isValid()) {
+ ++idx;
+ idx %= dd->alloc;
+ }
+ dd->entries[idx] = e;
+ }
+ dd->size = classSize;
+ if (!--d->refCount)
+ delete d;
+ d = dd;
+
+ Q_ASSERT(val != -1);
+ return val;
+}
+
+void PropertyHash::detach(bool grow, int classSize)
+{
+ if (d->refCount == 1 && !grow)
+ return;
-InternalClass::InternalClass(ExecutionEngine *engine)
- : engine(engine)
- , vtable(nullptr)
- , prototype(nullptr)
- , m_sealed(nullptr)
- , m_frozen(nullptr)
- , size(0)
- , extensible(true)
+ PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
+ for (int i = 0; i < d->alloc; ++i) {
+ const Entry &e = d->entries[i];
+ if (!e.identifier.isValid() || e.index >= static_cast<unsigned>(classSize))
+ continue;
+ uint idx = e.identifier.id % dd->alloc;
+ while (dd->entries[idx].identifier.isValid()) {
+ ++idx;
+ idx %= dd->alloc;
+ }
+ dd->entries[idx] = e;
+ }
+ dd->size = classSize;
+ if (!--d->refCount)
+ delete d;
+ d = dd;
+}
+
+namespace Heap {
+
+void InternalClass::init(ExecutionEngine *engine)
{
- id = engine->newInternalClassId();
+ Base::init();
+ new (&propertyTable) PropertyHash();
+ new (&nameMap) SharedInternalClassData<Identifier>();
+ new (&propertyData) SharedInternalClassData<PropertyAttributes>();
+ new (&transitions) std::vector<Transition>();
+
+ this->engine = engine;
+ vtable = QV4::InternalClass::staticVTable();
+// prototype = nullptr;
+// parent = nullptr;
+// size = 0;
+ extensible = true;
+ isFrozen = false;
+ isSealed = false;
+ isUsedAsProto = false;
+ protoId = engine->newProtoId();
+
+ // Also internal classes need an internal class pointer. Simply make it point to itself
+ internalClass.set(engine, this);
}
-InternalClass::InternalClass(const QV4::InternalClass &other)
- : QQmlJS::Managed()
- , engine(other.engine)
- , vtable(other.vtable)
- , prototype(other.prototype)
- , propertyTable(other.propertyTable)
- , nameMap(other.nameMap)
- , propertyData(other.propertyData)
- , m_sealed(nullptr)
- , m_frozen(nullptr)
- , size(other.size)
- , extensible(other.extensible)
- , isUsedAsProto(other.isUsedAsProto)
+void InternalClass::init(Heap::InternalClass *other)
+{
+ Base::init();
+ Q_ASSERT(!other->isFrozen);
+ new (&propertyTable) PropertyHash(other->propertyTable);
+ new (&nameMap) SharedInternalClassData<Identifier>(other->nameMap);
+ new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
+ new (&transitions) std::vector<Transition>();
+
+ engine = other->engine;
+ vtable = other->vtable;
+ prototype = other->prototype;
+ parent = other;
+ size = other->size;
+ extensible = other->extensible;
+ isSealed = other->isSealed;
+ isFrozen = other->isFrozen;
+ isUsedAsProto = other->isUsedAsProto;
+ protoId = engine->newProtoId();
+
+ internalClass.set(engine, other->internalClass);
+}
+
+void InternalClass::destroy()
{
- id = engine->newInternalClassId();
+#ifndef QT_NO_DEBUG
+ for (const auto &t : transitions) {
+ Q_ASSERT(!t.lookup || !t.lookup->isMarked());
+ }
+#endif
+ if (parent && parent->engine && parent->isMarked())
+ parent->removeChildEntry(this);
+
+ propertyTable.~PropertyHash();
+ nameMap.~SharedInternalClassData<Identifier>();
+ propertyData.~SharedInternalClassData<PropertyAttributes>();
+ transitions.~vector<Transition>();
+ engine = nullptr;
+ Base::destroy();
}
-static void insertHoleIntoPropertyData(Object *object, int idx)
+static void insertHoleIntoPropertyData(QV4::Object *object, int idx)
{
Heap::Object *o = object->d();
ExecutionEngine *v4 = o->internalClass->engine;
@@ -142,7 +213,7 @@ static void insertHoleIntoPropertyData(Object *object, int idx)
o->setProperty(v4, i, *o->propertyData(i - 1));
}
-static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
+static void removeFromPropertyData(QV4::Object *object, int idx, bool accessor = false)
{
Heap::Object *o = object->d();
ExecutionEngine *v4 = o->internalClass->engine;
@@ -154,20 +225,23 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals
o->setProperty(v4, size + 1, Primitive::undefinedValue());
}
-void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
+void InternalClass::changeMember(QV4::Object *object, Identifier id, PropertyAttributes data, uint *index)
{
+ Q_ASSERT(id.isValid());
uint idx;
- InternalClass *oldClass = object->internalClass();
- InternalClass *newClass = oldClass->changeMember(string->identifier(), data, &idx);
+ Heap::InternalClass *oldClass = object->internalClass();
+ Heap::InternalClass *newClass = oldClass->changeMember(id, data, &idx);
if (index)
*index = idx;
+ uint oldSize = oldClass->size;
object->setInternalClass(newClass);
- if (newClass->size > oldClass->size) {
- Q_ASSERT(newClass->size == oldClass->size + 1);
+ // don't use oldClass anymore, it could be GC'ed
+ if (newClass->size > oldSize) {
+ Q_ASSERT(newClass->size == oldSize + 1);
insertHoleIntoPropertyData(object, idx);
- } else if (newClass->size < oldClass->size) {
- Q_ASSERT(newClass->size == oldClass->size - 1);
+ } else if (newClass->size < oldSize) {
+ Q_ASSERT(newClass->size == oldSize - 1);
removeFromPropertyData(object, idx + 1);
}
}
@@ -183,7 +257,16 @@ InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalC
}
}
-InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttributes data, uint *index)
+static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
+{
+ // add a dummy entry, since we need two entries for accessors
+ newClass->propertyTable.addEntry(e, newClass->size);
+ newClass->nameMap.add(newClass->size, Identifier::invalid());
+ newClass->propertyData.add(newClass->size, PropertyAttributes());
+ ++newClass->size;
+}
+
+Heap::InternalClass *InternalClass::changeMember(Identifier identifier, PropertyAttributes data, uint *index)
{
data.resolve();
uint idx = find(identifier);
@@ -193,7 +276,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
*index = idx;
if (data == propertyData.at(idx))
- return this;
+ return static_cast<Heap::InternalClass *>(this);
Transition temp = { { identifier }, nullptr, (int)data.flags() };
Transition &t = lookupOrInsertTransition(temp);
@@ -201,14 +284,34 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- newClass = newClass->changePrototype(prototype);
- for (uint i = 0; i < size; ++i) {
- if (i == idx) {
- newClass = newClass->addMember(nameMap.at(i), data);
- } else if (!propertyData.at(i).isEmpty()) {
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ Heap::InternalClass *newClass = engine->newClass(this);
+ if (data.isAccessor() != propertyData.at(idx).isAccessor()) {
+ // this changes the layout of the class, so we need to rebuild the data
+ newClass->propertyTable = PropertyHash();
+ newClass->nameMap = SharedInternalClassData<Identifier>();
+ newClass->propertyData = SharedInternalClassData<PropertyAttributes>();
+ newClass->size = 0;
+ for (uint i = 0; i < size; ++i) {
+ Identifier identifier = nameMap.at(i);
+ PropertyHash::Entry e = { identifier, newClass->size };
+ if (i && !identifier.isValid())
+ e.identifier = nameMap.at(i - 1);
+ newClass->propertyTable.addEntry(e, newClass->size);
+ newClass->nameMap.add(newClass->size, identifier);
+ if (i == idx) {
+ newClass->propertyData.add(newClass->size, data);
+ ++newClass->size;
+ if (data.isAccessor())
+ addDummyEntry(newClass, e);
+ else
+ ++i;
+ } else {
+ newClass->propertyData.add(newClass->size, propertyData.at(i));
+ ++newClass->size;
+ }
}
+ } else {
+ newClass->propertyData.set(idx, data);
}
t.lookup = newClass;
@@ -216,14 +319,16 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri
return newClass;
}
-InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
+Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
{
+ Scope scope(engine);
+ ScopedValue protectThis(scope, this);
if (proto)
proto->setUsedAsProto();
Q_ASSERT(prototype != proto);
Q_ASSERT(!proto || proto->internalClass->isUsedAsProto);
- Transition temp = { { nullptr }, nullptr, Transition::PrototypeChange };
+ Transition temp = { { Identifier::invalid() }, nullptr, Transition::PrototypeChange };
temp.prototype = proto;
Transition &t = lookupOrInsertTransition(temp);
@@ -231,29 +336,19 @@ InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass;
- if (!size && !prototype) {
- newClass = engine->newClass(*this);
- newClass->prototype = proto;
- } else {
- newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- newClass = newClass->changePrototype(proto);
- for (uint i = 0; i < size; ++i) {
- if (!propertyData.at(i).isEmpty())
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
- }
- }
+ Heap::InternalClass *newClass = engine->newClass(this);
+ newClass->prototype = proto;
t.lookup = newClass;
return newClass;
}
-InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
+Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
{
Q_ASSERT(vtable != vt);
- Transition temp = { { nullptr }, nullptr, Transition::VTableChange };
+ Transition temp = { { Identifier::invalid() }, nullptr, Transition::VTableChange };
temp.vtable = vt;
Transition &t = lookupOrInsertTransition(temp);
@@ -261,18 +356,8 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass;
- if (this == engine->internalClasses[EngineBase::Class_Empty]) {
- newClass = engine->newClass(*this);
- newClass->vtable = vt;
- } else {
- newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vt);
- newClass = newClass->changePrototype(prototype);
- for (uint i = 0; i < size; ++i) {
- if (!propertyData.at(i).isEmpty())
- newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
- }
- }
+ Heap::InternalClass *newClass = engine->newClass(this);
+ newClass->vtable = vt;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -280,17 +365,17 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
return newClass;
}
-InternalClass *InternalClass::nonExtensible()
+Heap::InternalClass *InternalClass::nonExtensible()
{
if (!extensible)
return this;
- Transition temp = { { nullptr }, nullptr, Transition::NotExtensible};
+ Transition temp = { { Identifier::invalid() }, nullptr, Transition::NotExtensible};
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup)
return t.lookup;
- InternalClass *newClass = engine->newClass(*this);
+ Heap::InternalClass *newClass = engine->newClass(this);
newClass->extensible = false;
t.lookup = newClass;
@@ -298,31 +383,26 @@ InternalClass *InternalClass::nonExtensible()
return newClass;
}
-void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index)
+void InternalClass::addMember(QV4::Object *object, Identifier id, PropertyAttributes data, uint *index)
{
+ Q_ASSERT(id.isValid());
data.resolve();
- object->internalClass()->engine->identifierTable->identifier(string);
- if (object->internalClass()->propertyTable.lookup(string->d()->identifier) < object->internalClass()->size) {
- changeMember(object, string, data, index);
+ if (object->internalClass()->propertyTable.lookup(id) < object->internalClass()->size) {
+ changeMember(object, id, data, index);
return;
}
uint idx;
- InternalClass *newClass = object->internalClass()->addMemberImpl(string->identifier(), data, &idx);
+ Heap::InternalClass *newClass = object->internalClass()->addMemberImpl(id, data, &idx);
if (index)
*index = idx;
object->setInternalClass(newClass);
}
-InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index)
-{
- engine->identifierTable->identifier(string);
- return addMember(string->identifier(), data, index);
-}
-
-InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttributes data, uint *index)
+Heap::InternalClass *InternalClass::addMember(Identifier identifier, PropertyAttributes data, uint *index)
{
+ Q_ASSERT(identifier.isValid());
data.resolve();
if (propertyTable.lookup(identifier) < size)
@@ -331,7 +411,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut
return addMemberImpl(identifier, data, index);
}
-InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index)
+Heap::InternalClass *InternalClass::addMemberImpl(Identifier identifier, PropertyAttributes data, uint *index)
{
Transition temp = { { identifier }, nullptr, (int)data.flags() };
Transition &t = lookupOrInsertTransition(temp);
@@ -343,109 +423,156 @@ InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttr
return t.lookup;
// create a new class and add it to the tree
- InternalClass *newClass = engine->newClass(*this);
+ Heap::InternalClass *newClass = engine->newClass(this);
PropertyHash::Entry e = { identifier, newClass->size };
newClass->propertyTable.addEntry(e, newClass->size);
newClass->nameMap.add(newClass->size, identifier);
newClass->propertyData.add(newClass->size, data);
++newClass->size;
- if (data.isAccessor()) {
- // add a dummy entry, since we need two entries for accessors
- newClass->propertyTable.addEntry(e, newClass->size);
- newClass->nameMap.add(newClass->size, 0);
- newClass->propertyData.add(newClass->size, PropertyAttributes());
- ++newClass->size;
- }
+ if (data.isAccessor())
+ addDummyEntry(newClass, e);
t.lookup = newClass;
Q_ASSERT(t.lookup);
return newClass;
}
-void InternalClass::removeMember(Object *object, Identifier *id)
+void InternalClass::removeChildEntry(InternalClass *child)
{
- InternalClass *oldClass = object->internalClass();
- uint propIdx = oldClass->propertyTable.lookup(id);
- Q_ASSERT(propIdx < oldClass->size);
+ Q_ASSERT(engine);
+ for (auto &t : transitions) {
+ if (t.lookup == child) {
+ t.lookup = nullptr;
+ return;
+ }
+ }
+ Q_UNREACHABLE();
- Transition temp = { { id }, nullptr, -1 };
- Transition &t = object->internalClass()->lookupOrInsertTransition(temp);
+}
- bool accessor = oldClass->propertyData.at(propIdx).isAccessor();
+void InternalClass::removeMember(QV4::Object *object, Identifier identifier)
+{
+ Heap::InternalClass *oldClass = object->internalClass();
+ Q_ASSERT(oldClass->propertyTable.lookup(identifier) < oldClass->size);
- if (t.lookup) {
- object->setInternalClass(t.lookup);
- } else {
+ Transition temp = { { identifier }, nullptr, Transition::RemoveMember };
+ Transition &t = object->internalClass()->lookupOrInsertTransition(temp);
+
+ if (!t.lookup) {
// create a new class and add it to the tree
- InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable);
- newClass = newClass->changePrototype(oldClass->prototype);
- for (uint i = 0; i < oldClass->size; ++i) {
- if (i == propIdx)
- continue;
- if (!oldClass->propertyData.at(i).isEmpty())
- newClass = newClass->addMember(oldClass->nameMap.at(i), oldClass->propertyData.at(i));
- }
- object->setInternalClass(newClass);
+ Heap::InternalClass *newClass = oldClass->engine->newClass(oldClass);
+ // simply make the entry inaccessible
+ int idx = newClass->propertyTable.removeIdentifier(identifier, oldClass->size);
+ newClass->nameMap.set(idx, Identifier::invalid());
+ newClass->propertyData.set(idx, PropertyAttributes());
+ t.lookup = newClass;
+ Q_ASSERT(t.lookup);
}
+ object->setInternalClass(t.lookup);
- Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1));
-
- // remove the entry in the property data
- removeFromPropertyData(object, propIdx, accessor);
-
- t.lookup = object->internalClass();
- Q_ASSERT(t.lookup);
+ // we didn't remove the data slot, just made it inaccessible
+ Q_ASSERT(object->internalClass()->size == oldClass->size);
}
-uint InternalClass::find(const String *string)
+Heap::InternalClass *InternalClass::sealed()
{
- engine->identifierTable->identifier(string);
- const Identifier *id = string->d()->identifier;
+ if (isSealed)
+ return this;
- uint index = propertyTable.lookup(id);
- if (index < size)
- return index;
+ 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;
+ }
+ }
- return UINT_MAX;
-}
+ if (alreadySealed) {
+ isSealed = true;
+ return this;
+ }
-InternalClass *InternalClass::sealed()
-{
- if (m_sealed)
- return m_sealed;
+ Transition temp = { { Identifier::invalid() }, nullptr, InternalClassTransition::Sealed };
+ Transition &t = lookupOrInsertTransition(temp);
+
+ if (t.lookup) {
+ Q_ASSERT(t.lookup && t.lookup->isSealed);
+ return t.lookup;
+ }
+
+ Heap::InternalClass *s = engine->newClass(this);
- m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
- m_sealed = m_sealed->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
continue;
attrs.setConfigurable(false);
- m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
+ s->propertyData.set(i, attrs);
}
- m_sealed = m_sealed->nonExtensible();
+ s->extensible = false;
+ s->isSealed = true;
- m_sealed->m_sealed = m_sealed;
- return m_sealed;
+ t.lookup = s;
+ return s;
}
-InternalClass *InternalClass::frozen()
+Heap::InternalClass *InternalClass::frozen()
{
- if (m_frozen)
- return m_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 = { { Identifier::invalid() }, nullptr, InternalClassTransition::Frozen };
+ Transition &t = lookupOrInsertTransition(temp);
+
+ if (t.lookup) {
+ Q_ASSERT(t.lookup && t.lookup->isSealed && t.lookup->isFrozen);
+ return t.lookup;
+ }
+
+ Heap::InternalClass *f = engine->newClass(this);
- m_frozen = propertiesFrozen();
- m_frozen = m_frozen->nonExtensible();
+ for (uint i = 0; i < size; ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ if (attrs.isEmpty())
+ continue;
+ if (attrs.isData())
+ attrs.setWritable(false);
+ attrs.setConfigurable(false);
+ f->propertyData.set(i, attrs);
+ }
+ f->extensible = false;
+ f->isSealed = true;
+ f->isFrozen = true;
- m_frozen->m_frozen = m_frozen;
- m_frozen->m_sealed = m_frozen;
- return m_frozen;
+ t.lookup = f;
+ return f;
}
-InternalClass *InternalClass::propertiesFrozen() const
+Heap::InternalClass *InternalClass::propertiesFrozen() const
{
- InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable);
+ Scope scope(engine);
+ Scoped<QV4::InternalClass> frozen(scope, engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable));
frozen = frozen->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
@@ -455,20 +582,20 @@ InternalClass *InternalClass::propertiesFrozen() const
attrs.setConfigurable(false);
frozen = frozen->addMember(nameMap.at(i), attrs);
}
- return frozen;
+ return frozen->d();
}
-InternalClass *InternalClass::asProtoClass()
+Heap::InternalClass *InternalClass::asProtoClass()
{
if (isUsedAsProto)
return this;
- Transition temp = { { nullptr }, nullptr, Transition::ProtoClass };
+ Transition temp = { { Identifier::invalid() }, nullptr, Transition::ProtoClass };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup)
return t.lookup;
- InternalClass *newClass = engine->newClass(*this);
+ Heap::InternalClass *newClass = engine->newClass(this);
newClass->isUsedAsProto = true;
t.lookup = newClass;
@@ -476,90 +603,43 @@ InternalClass *InternalClass::asProtoClass()
return newClass;
}
-void InternalClass::destroy()
+static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
{
- std::vector<InternalClass *> destroyStack;
- destroyStack.reserve(64);
- destroyStack.push_back(this);
-
- while (!destroyStack.empty()) {
- InternalClass *next = destroyStack.back();
- destroyStack.pop_back();
- if (!next->engine)
- continue;
- next->engine = nullptr;
- next->propertyTable.~PropertyHash();
- next->nameMap.~SharedInternalClassData<Identifier *>();
- next->propertyData.~SharedInternalClassData<PropertyAttributes>();
- if (next->m_sealed)
- destroyStack.push_back(next->m_sealed);
- if (next->m_frozen)
- destroyStack.push_back(next->m_frozen);
-
- for (size_t i = 0; i < next->transitions.size(); ++i) {
- Q_ASSERT(next->transitions.at(i).lookup);
- destroyStack.push_back(next->transitions.at(i).lookup);
- }
-
- next->transitions.~vector<Transition>();
+ if (ic->prototype == o)
+ ic->protoId = ic->engine->newProtoId();
+ for (auto &t : ic->transitions) {
+ if (t.lookup)
+ updateProtoUsage(o, t.lookup);
}
}
+
void InternalClass::updateProtoUsage(Heap::Object *o)
{
Q_ASSERT(isUsedAsProto);
- InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
+ Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
Q_ASSERT(!ic->prototype);
- // only need to go two levels into the IC hierarchy, as prototype changes
- // can only happen there
- for (auto &t : ic->transitions) {
- Q_ASSERT(t.lookup);
- if (t.flags == InternalClassTransition::VTableChange) {
- InternalClass *ic2 = t.lookup;
- for (auto &t2 : ic2->transitions) {
- if (t2.flags == InternalClassTransition::PrototypeChange &&
- t2.lookup->prototype == o)
- ic2->updateInternalClassIdRecursive();
- }
- } else if (t.flags == InternalClassTransition::PrototypeChange && t.lookup->prototype == o) {
- ic->updateInternalClassIdRecursive();
- }
- }
+ Heap::updateProtoUsage(o, ic);
}
-void InternalClass::updateInternalClassIdRecursive()
+void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
{
- id = engine->newInternalClassId();
- for (auto &t : transitions) {
- Q_ASSERT(t.lookup);
- if (t.flags == InternalClassTransition::VTableChange || t.flags == InternalClassTransition::PrototypeChange)
- continue;
- t.lookup->updateInternalClassIdRecursive();
+ Heap::InternalClass *ic = static_cast<Heap::InternalClass *>(b);
+ if (ic->prototype)
+ ic->prototype->mark(stack);
+ if (ic->parent)
+ ic->parent->mark(stack);
+
+ for (uint i = 0; i < ic->size; ++i) {
+ Identifier id = ic->nameMap.at(i);
+ if (Heap::Base *b = id.asHeapObject())
+ b->mark(stack);
}
}
+}
-
-void InternalClassPool::markObjects(MarkStack *markStack)
-{
- InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty];
- Q_ASSERT(!ic->prototype);
-
- // only need to go two levels into the IC hierarchy, as prototype changes
- // can only happen there
- for (auto &t : ic->transitions) {
- Q_ASSERT(t.lookup);
- if (t.flags == InternalClassTransition::VTableChange) {
- InternalClass *ic2 = t.lookup;
- for (auto &t2 : ic2->transitions) {
- if (t2.flags == InternalClassTransition::PrototypeChange)
- t2.lookup->prototype->mark(markStack);
- }
- } else if (t.flags == InternalClassTransition::PrototypeChange) {
- t.lookup->prototype->mark(markStack);
- }
- }
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index b689272006..290251f4ba 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -53,16 +53,13 @@
#include "qv4global_p.h"
#include <QHash>
-#include <private/qqmljsmemorypool_p.h>
#include <private/qv4identifier_p.h>
+#include <private/qv4heap_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct String;
-struct Object;
-struct Identifier;
struct VTable;
struct MarkStack;
@@ -70,7 +67,7 @@ struct PropertyHashData;
struct PropertyHash
{
struct Entry {
- const Identifier *identifier;
+ Identifier identifier;
uint index;
};
@@ -79,12 +76,12 @@ struct PropertyHash
inline PropertyHash();
inline PropertyHash(const PropertyHash &other);
inline ~PropertyHash();
+ PropertyHash &operator=(const PropertyHash &other);
void addEntry(const Entry &entry, int classSize);
- uint lookup(const Identifier *identifier) const;
-
-private:
- PropertyHash &operator=(const PropertyHash &other);
+ uint lookup(Identifier identifier) const;
+ int removeIdentifier(Identifier identifier, int classSize);
+ void detach(bool grow, int classSize);
};
struct PropertyHashData
@@ -118,15 +115,26 @@ inline PropertyHash::~PropertyHash()
delete d;
}
-inline uint PropertyHash::lookup(const Identifier *identifier) const
+inline PropertyHash &PropertyHash::operator=(const PropertyHash &other)
+{
+ ++other.d->refCount;
+ if (!--d->refCount)
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+
+
+inline uint PropertyHash::lookup(Identifier identifier) const
{
Q_ASSERT(d->entries);
- uint idx = identifier->hashValue % d->alloc;
+ uint idx = identifier.id % d->alloc;
while (1) {
if (d->entries[idx].identifier == identifier)
return d->entries[idx].index;
- if (!d->entries[idx].identifier)
+ if (!d->entries[idx].identifier.isValid())
return UINT_MAX;
++idx;
idx %= d->alloc;
@@ -163,6 +171,13 @@ struct SharedInternalClassData {
if (!--d->refcount)
delete d;
}
+ SharedInternalClassData &operator=(const SharedInternalClassData &other) {
+ ++other.d->refcount;
+ if (!--d->refcount)
+ delete d;
+ d = other.d;
+ return *this;
+ }
void add(uint pos, T value) {
if (pos < d->size) {
@@ -214,26 +229,26 @@ struct SharedInternalClassData {
Q_ASSERT(i < d->size);
return d->data[i];
}
-
-private:
- SharedInternalClassData &operator=(const SharedInternalClassData &other);
};
struct InternalClassTransition
{
union {
- Identifier *id;
+ Identifier id;
const VTable *vtable;
Heap::Object *prototype;
};
- InternalClass *lookup;
+ Heap::InternalClass *lookup;
int flags;
enum {
// range 0-0xff is reserved for attribute changes
NotExtensible = 0x100,
VTableChange = 0x200,
PrototypeChange = 0x201,
- ProtoClass = 0x202
+ ProtoClass = 0x202,
+ Sealed = 0x203,
+ Frozen = 0x204,
+ RemoveMember = -1
};
bool operator==(const InternalClassTransition &other) const
@@ -243,48 +258,44 @@ struct InternalClassTransition
{ return id < other.id || (id == other.id && flags < other.flags); }
};
-struct InternalClass : public QQmlJS::Managed {
- int id = 0; // unique across the engine, gets changed also when proto chain changes
+namespace Heap {
+
+struct InternalClass : Base {
ExecutionEngine *engine;
const VTable *vtable;
+ quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes
Heap::Object *prototype;
+ InternalClass *parent;
PropertyHash propertyTable; // id to valueIndex
- SharedInternalClassData<Identifier *> nameMap;
+ SharedInternalClassData<Identifier> nameMap;
SharedInternalClassData<PropertyAttributes> propertyData;
typedef InternalClassTransition Transition;
std::vector<Transition> transitions;
InternalClassTransition &lookupOrInsertTransition(const InternalClassTransition &t);
- InternalClass *m_sealed;
- InternalClass *m_frozen;
-
uint size;
bool extensible;
- bool isUsedAsProto = false;
+ bool isSealed;
+ bool isFrozen;
+ bool isUsedAsProto;
+
+ void init(ExecutionEngine *engine);
+ void init(InternalClass *other);
+ void destroy();
Q_REQUIRED_RESULT InternalClass *nonExtensible();
- Q_REQUIRED_RESULT InternalClass *changeVTable(const VTable *vt) {
- if (vtable == vt)
- return this;
- return changeVTableImpl(vt);
- }
- Q_REQUIRED_RESULT InternalClass *changePrototype(Heap::Object *proto) {
- if (prototype == proto)
- return this;
- return changePrototypeImpl(proto);
- }
- static void addMember(Object *object, String *string, PropertyAttributes data, uint *index);
- Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = nullptr);
- Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr);
- Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = nullptr);
- static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = nullptr);
- static void removeMember(Object *object, Identifier *id);
- uint find(const String *string);
- uint find(const Identifier *id)
+ static void addMember(QV4::Object *object, Identifier id, PropertyAttributes data, uint *index);
+ Q_REQUIRED_RESULT InternalClass *addMember(Identifier identifier, PropertyAttributes data, uint *index = nullptr);
+ Q_REQUIRED_RESULT InternalClass *changeMember(Identifier identifier, PropertyAttributes data, uint *index = nullptr);
+ static void changeMember(QV4::Object *object, Identifier id, PropertyAttributes data, uint *index = nullptr);
+ static void removeMember(QV4::Object *object, Identifier identifier);
+ uint find(const Identifier id)
{
+ Q_ASSERT(id.isValid());
+
uint index = propertyTable.lookup(id);
if (index < size)
return index;
@@ -298,24 +309,37 @@ struct InternalClass : public QQmlJS::Managed {
Q_REQUIRED_RESULT InternalClass *asProtoClass();
- void destroy();
+ Q_REQUIRED_RESULT InternalClass *changeVTable(const VTable *vt) {
+ if (vtable == vt)
+ return this;
+ return changeVTableImpl(vt);
+ }
+ Q_REQUIRED_RESULT InternalClass *changePrototype(Heap::Object *proto) {
+ if (prototype == proto)
+ return this;
+ return changePrototypeImpl(proto);
+ }
void updateProtoUsage(Heap::Object *o);
+ static void markObjects(Heap::Base *ic, MarkStack *stack);
+
private:
Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt);
Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto);
- InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index);
- void updateInternalClassIdRecursive();
+ InternalClass *addMemberImpl(Identifier identifier, PropertyAttributes data, uint *index);
+
+ void removeChildEntry(InternalClass *child);
friend struct ExecutionEngine;
- InternalClass(ExecutionEngine *engine);
- InternalClass(const InternalClass &other);
};
-struct InternalClassPool : public QQmlJS::MemoryPool
+inline
+void Base::markObjects(Base *b, MarkStack *stack)
{
- void markObjects(MarkStack *markStack);
-};
+ b->internalClass->mark(stack);
+}
+
+}
}
diff --git a/src/qml/jsruntime/qv4iterator.cpp b/src/qml/jsruntime/qv4iterator.cpp
new file mode 100644
index 0000000000..df8000a8f7
--- /dev/null
+++ b/src/qml/jsruntime/qv4iterator.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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 <qv4iterator_p.h>
+#include <qv4symbol_p.h>
+#include <qv4engine_p.h>
+
+using namespace QV4;
+
+void IteratorPrototype::init(ExecutionEngine *engine)
+{
+ defineDefaultProperty(engine->symbol_iterator(), method_iterator, 0);
+}
+
+ReturnedValue IteratorPrototype::method_iterator(const FunctionObject *, const Value *thisObject, const Value *, int)
+{
+ return thisObject->asReturnedValue();
+}
+
+
+ReturnedValue IteratorPrototype::createIterResultObject(ExecutionEngine *engine, const Value &value, bool done)
+{
+ Scope scope(engine);
+ ScopedObject obj(scope, engine->newObject());
+ obj->set(ScopedString(scope, engine->newString(QStringLiteral("value"))), value, Object::DoNotThrow);
+ obj->set(ScopedString(scope, engine->newString(QStringLiteral("done"))), Primitive::fromBoolean(done), Object::DoNotThrow);
+ return obj->asReturnedValue();
+}
+
diff --git a/src/qml/jsruntime/qv4iterator_p.h b/src/qml/jsruntime/qv4iterator_p.h
new file mode 100644
index 0000000000..28e337d21b
--- /dev/null
+++ b/src/qml/jsruntime/qv4iterator_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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 QV4ITERATOR_P_H
+#define QV4ITERATOR_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 "qv4object_p.h"
+#include "qv4arraydata_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace QV4 {
+
+enum IteratorKind {
+ KeyIteratorKind,
+ ValueIteratorKind,
+ KeyValueIteratorKind
+};
+
+struct IteratorPrototype : Object
+{
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_iterator(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue createIterResultObject(ExecutionEngine *engine, const Value &value, bool done);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ARRAYITERATOR_P_H
+
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index c676b57c51..e186285025 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -67,7 +67,7 @@ struct JSCallData {
if (thisObject)
this->thisObject = const_cast<Value *>(thisObject);
else
- this->thisObject = scope.alloc(1);
+ this->thisObject = scope.alloc();
if (argv)
this->args = const_cast<Value *>(argv);
else
@@ -80,8 +80,7 @@ struct JSCallData {
CallData *callData(const FunctionObject *f = nullptr) const {
int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
- CallData *ptr = reinterpret_cast<CallData *>(scope.engine->jsStackTop);
- scope.engine->jsStackTop += size;
+ CallData *ptr = reinterpret_cast<CallData *>(scope.alloc<Scope::Uninitialized>(size));
ptr->function = Encode::undefined();
ptr->context = Encode::undefined();
ptr->accumulator = Encode::undefined();
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index c3569c29d2..75a9bf4111 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -47,6 +47,7 @@
#include <qv4variantobject_p.h>
#include "qv4string_p.h"
#include "qv4jscall_p.h"
+#include <qv4symbol_p.h>
#include <qstack.h>
#include <qstringlist.h>
@@ -743,7 +744,7 @@ QString Stringify::Str(const QString &key, const Value &v)
o = value->asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
- if (o->as<ArrayObject>() || o->isListType()) {
+ if (o->isArrayLike()) {
return JA(o.getPointer());
} else {
return JO(o);
@@ -881,6 +882,8 @@ void Heap::JsonObject::init()
o->defineDefaultProperty(QStringLiteral("parse"), QV4::JsonObject::method_parse, 2);
o->defineDefaultProperty(QStringLiteral("stringify"), QV4::JsonObject::method_stringify, 3);
+ ScopedString json(scope, scope.engine->newString(QStringLiteral("JSON")));
+ o->defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), json);
}
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 52ab03cd94..67b4b9dc38 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-void Lookup::resolveProtoGetter(Identifier *name, const Heap::Object *proto)
+void Lookup::resolveProtoGetter(Identifier name, const Heap::Object *proto)
{
while (proto) {
uint index = proto->internalClass->find(name);
@@ -70,7 +70,12 @@ void Lookup::resolveProtoGetter(Identifier *name, const Heap::Object *proto)
ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *object)
{
Heap::Object *obj = object->d();
- Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ Identifier name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ if (name.isArrayIndex()) {
+ indexedLookup.index = name.asArrayIndex();
+ getter = getterIndexed;
+ return getter(this, engine, *object);
+ }
uint index = obj->internalClass->find(name);
if (index != UINT_MAX) {
@@ -92,7 +97,7 @@ ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *objec
return getter(this, engine, *object);
}
- protoLookup.icIdentifier = obj->internalClass->id;
+ protoLookup.protoId = obj->internalClass->protoId;
resolveProtoGetter(name, obj->prototype());
return getter(this, engine, *object);
}
@@ -109,11 +114,12 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
break;
case Value::Managed_Type: {
// ### Should move this over to the Object path, as strings also have an internalClass
- Q_ASSERT(object.isString());
- primitiveLookup.proto = engine->stringPrototype()->d();
+ Q_ASSERT(object.isStringOrSymbol());
+ primitiveLookup.proto = static_cast<const Managed &>(object).internalClass()->prototype;
+ Q_ASSERT(primitiveLookup.proto);
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- if (name->equals(engine->id_length())) {
+ if (object.isString() && name->equals(engine->id_length())) {
// special case, as the property is on the object itself
getter = stringLengthGetter;
return stringLengthGetter(this, engine, object);
@@ -125,8 +131,8 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
primitiveLookup.proto = engine->numberPrototype()->d();
}
- Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- protoLookup.icIdentifier = primitiveLookup.proto->internalClass->id;
+ Identifier name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ protoLookup.protoId = primitiveLookup.proto->internalClass->protoId;
resolveProtoGetter(name, primitiveLookup.proto);
if (getter == getterProto)
@@ -139,8 +145,8 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
ReturnedValue Lookup::resolveGlobalGetter(ExecutionEngine *engine)
{
Object *o = engine->globalObject;
- Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- protoLookup.icIdentifier = o->internalClass()->id;
+ Identifier name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ protoLookup.protoId = o->internalClass()->protoId;
resolveProtoGetter(name, o->d());
if (getter == getterProto)
@@ -188,16 +194,16 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const
return result;
}
if (first.getter == getterProto && second.getter == getterProto) {
- l->protoLookupTwoClasses.icIdentifier = first.protoLookup.icIdentifier;
- l->protoLookupTwoClasses.icIdentifier2 = second.protoLookup.icIdentifier;
+ l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
+ l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
l->protoLookupTwoClasses.data = first.protoLookup.data;
l->protoLookupTwoClasses.data2 = second.protoLookup.data;
l->getter = getterProtoTwoClasses;
return result;
}
if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
- l->protoLookupTwoClasses.icIdentifier = first.protoLookup.icIdentifier;
- l->protoLookupTwoClasses.icIdentifier2 = second.protoLookup.icIdentifier;
+ l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
+ l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
l->protoLookupTwoClasses.data = first.protoLookup.data;
l->protoLookupTwoClasses.data2 = second.protoLookup.data;
l->getter = getterProtoAccessorTwoClasses;
@@ -250,7 +256,7 @@ ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Valu
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
- if (l->protoLookup.icIdentifier == o->internalClass->id)
+ if (l->protoLookup.protoId == o->internalClass->protoId)
return l->protoLookup.data->asReturnedValue();
}
return getterTwoClasses(l, engine, object);
@@ -307,9 +313,9 @@ ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
- if (l->protoLookupTwoClasses.icIdentifier == o->internalClass->id)
+ if (l->protoLookupTwoClasses.protoId == o->internalClass->protoId)
return l->protoLookupTwoClasses.data->asReturnedValue();
- if (l->protoLookupTwoClasses.icIdentifier2 == o->internalClass->id)
+ if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
return l->protoLookupTwoClasses.data2->asReturnedValue();
return getterFallback(l, engine, object);
}
@@ -340,14 +346,13 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
- if (o && l->protoLookup.icIdentifier == o->internalClass->id) {
+ if (o && l->protoLookup.protoId == o->internalClass->protoId) {
const Value *getter = l->protoLookup.data;
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
}
- l->getter = getterTwoClasses;
return getterTwoClasses(l, engine, object);
}
@@ -358,9 +363,9 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
const Value *getter = nullptr;
- if (l->protoLookupTwoClasses.icIdentifier == o->internalClass->id)
+ if (l->protoLookupTwoClasses.protoId == o->internalClass->protoId)
getter = l->protoLookupTwoClasses.data;
- else if (l->protoLookupTwoClasses.icIdentifier2 == o->internalClass->id)
+ else if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
getter = l->protoLookupTwoClasses.data2;
if (getter) {
if (!getter->isFunctionObject()) // ### catch at resolve time
@@ -373,11 +378,29 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *
return getterFallback(l, engine, object);
}
+ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ Object *o = object.objectValue();
+ if (o) {
+ Heap::Object *ho = o->d();
+ if (ho->arrayData && ho->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = ho->arrayData.cast<Heap::SimpleArrayData>();
+ if (l->indexedLookup.index < s->values.size)
+ if (!s->data(l->indexedLookup.index).isEmpty())
+ return s->data(l->indexedLookup.index).asReturnedValue();
+ }
+ return o->getIndexed(l->indexedLookup.index);
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+
+}
+
ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->primitiveLookup.type) {
Heap::Object *o = l->primitiveLookup.proto;
- if (l->primitiveLookup.icIdentifier == o->internalClass->id)
+ if (l->primitiveLookup.protoId == o->internalClass->protoId)
return l->primitiveLookup.data->asReturnedValue();
}
l->getter = getterGeneric;
@@ -388,7 +411,7 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine
{
if (object.type() == l->primitiveLookup.type) {
Heap::Object *o = l->primitiveLookup.proto;
- if (l->primitiveLookup.icIdentifier == o->internalClass->id) {
+ if (l->primitiveLookup.protoId == o->internalClass->protoId) {
const Value *getter = l->primitiveLookup.data;
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
@@ -417,7 +440,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine)
{
Heap::Object *o = engine->globalObject->d();
- if (l->protoLookup.icIdentifier == o->internalClass->id)
+ if (l->protoLookup.protoId == o->internalClass->protoId)
return l->protoLookup.data->asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -426,7 +449,7 @@ ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine)
ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine)
{
Heap::Object *o = engine->globalObject->d();
- if (l->protoLookup.icIdentifier == o->internalClass->id) {
+ if (l->protoLookup.protoId == o->internalClass->protoId) {
const Value *getter = l->protoLookup.data;
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
@@ -442,8 +465,9 @@ bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value
Scope scope(engine);
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- InternalClass *c = object->internalClass();
- uint idx = c->find(name);
+ Heap::InternalClass *c = object->internalClass();
+ name->makeIdentifier();
+ uint idx = c->find(name->identifier());
if (idx != UINT_MAX) {
if (object->isArrayObject() && idx == Heap::ArrayObject::LengthPropertyIndex) {
setter = arrayLengthSetter;
@@ -460,7 +484,7 @@ bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value
return setter(this, engine, *object, value);
}
- insertionLookup.icIdentifier = c->id;
+ insertionLookup.protoId = c->protoId;
if (!object->put(name, value)) {
setter = Lookup::setterFallback;
return false;
@@ -471,7 +495,8 @@ bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value
setter = setterFallback;
return true;
}
- idx = object->internalClass()->find(name);
+ name->makeIdentifier();
+ idx = object->internalClass()->find(name->identifier());
if (idx == UINT_MAX) { // ### can this even happen?
setter = setterFallback;
return false;
@@ -574,7 +599,7 @@ bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c
bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
- if (o && o->internalClass()->id == l->insertionLookup.icIdentifier) {
+ if (o && o->internalClass()->protoId == l->insertionLookup.protoId) {
o->setInternalClass(l->insertionLookup.newClass);
o->d()->setProperty(engine, l->insertionLookup.offset, value);
return true;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 5f507733fd..7fb9976135 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -65,7 +65,6 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
struct Lookup {
- enum { Size = 4 };
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
@@ -73,44 +72,57 @@ struct Lookup {
};
union {
struct {
- InternalClass *ic;
+ Heap::Base *h1;
+ Heap::Base *h2;
+ quintptr unused;
+ quintptr unused2;
+ } markDef;
+ struct {
+ Heap::InternalClass *ic;
+ quintptr _unused;
int offset;
} objectLookup;
struct {
+ quintptr protoId;
+ quintptr _unused;
const Value *data;
- int icIdentifier;
} protoLookup;
struct {
- InternalClass *ic;
- InternalClass *ic2;
+ Heap::InternalClass *ic;
+ Heap::InternalClass *ic2;
int offset;
int offset2;
} objectLookupTwoClasses;
struct {
+ quintptr protoId;
+ quintptr protoId2;
const Value *data;
const Value *data2;
- int icIdentifier;
- int icIdentifier2;
} protoLookupTwoClasses;
struct {
// Make sure the next two values are in sync with protoLookup
- const Value *data;
- int icIdentifier;
- unsigned type;
+ quintptr protoId;
Heap::Object *proto;
+ const Value *data;
+ quintptr type;
} primitiveLookup;
struct {
- InternalClass *newClass;
- int icIdentifier;
+ Heap::InternalClass *newClass;
+ quintptr protoId;
int offset;
} insertionLookup;
+ struct {
+ quintptr _unused;
+ quintptr _unused2;
+ uint index;
+ } indexedLookup;
};
uint nameIndex;
ReturnedValue resolveGetter(ExecutionEngine *engine, const Object *object);
ReturnedValue resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object);
ReturnedValue resolveGlobalGetter(ExecutionEngine *engine);
- void resolveProtoGetter(Identifier *name, const Heap::Object *proto);
+ void resolveProtoGetter(Identifier name, const Heap::Object *proto);
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -126,6 +138,7 @@ struct Lookup {
static ReturnedValue getterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -144,6 +157,17 @@ struct Lookup {
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+
+ void markObjects(MarkStack *stack) {
+ if (markDef.h1 && !(reinterpret_cast<quintptr>(markDef.h1) & 1))
+ markDef.h1->mark(stack);
+ if (markDef.h2 && !(reinterpret_cast<quintptr>(markDef.h2) & 1))
+ markDef.h2->mark(stack);
+ }
+
+ void clear() {
+ memset(&markDef, 0, sizeof(markDef));
+ }
};
Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index b50e5f0355..58f5b0051f 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -55,22 +55,30 @@ const VTable Managed::static_vtbl =
Managed::IsFunctionObject,
Managed::IsErrorObject,
Managed::IsArrayData,
- 0,
+ Managed::IsStringOrSymbol,
Managed::MyType,
+ { 0, 0, 0, 0 },
"Managed",
nullptr,
nullptr /*markObjects*/,
isEqualTo
};
+DEFINE_MANAGED_VTABLE(InternalClass);
+
QString Managed::className() const
{
const char *s = nullptr;
- switch (Type(d()->vtable()->type)) {
+ switch (Type(vtable()->type)) {
case Type_Invalid:
- case Type_String:
return QString();
+ case Type_String:
+ s = "String";
+ break;
+ case Type_Symbol:
+ s = "Symbol";
+ break;
case Type_Object:
s = "Object";
break;
@@ -80,6 +88,9 @@ QString Managed::className() const
case Type_FunctionObject:
s = "Function";
break;
+ case Type_GeneratorObject:
+ s = "Generator";
+ break;
case Type_BooleanObject:
s = "Boolean";
break;
@@ -89,6 +100,9 @@ QString Managed::className() const
case Type_StringObject:
s = "String";
break;
+ case Type_SymbolObject:
+ s = "Symbol";
+ break;
case Type_DateObject:
s = "Date";
break;
@@ -96,7 +110,7 @@ QString Managed::className() const
s = "RegExp";
break;
case Type_ErrorObject:
- s = ErrorObject::className(static_cast<Heap::ErrorObject *>(d())->errorType);
+ s = "Error";
break;
case Type_ArgumentsObject:
s = "Arguments";
@@ -111,8 +125,23 @@ QString Managed::className() const
case Type_ExecutionContext:
s = "__ExecutionContext";
break;
- case Type_ForeachIteratorObject:
- s = "__ForeachIterator";
+ case Type_MapIteratorObject:
+ s = "Map Iterator";
+ break;
+ case Type_SetIteratorObject:
+ s = "Set Iterator";
+ break;
+ case Type_ArrayIteratorObject:
+ s = "Array Iterator";
+ break;
+ case Type_StringIteratorObject:
+ s = "String Iterator";
+ break;
+ case Type_ForInIterator:
+ s = "__ForIn Iterator";
+ break;
+ case Type_InternalClass:
+ s = "__InternalClass";
break;
case Type_RegExp:
s = "__RegExp";
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 092c61b81c..f16bf3dc58 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -92,14 +92,14 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
QV4::Heap::DataClass *dptr = d_unchecked(); \
dptr->_checkIsInitialized(); \
return dptr; \
- } \
- Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value);
+ }
#define V4_MANAGED(DataClass, superClass) \
private: \
DataClass() Q_DECL_EQ_DELETE; \
Q_DISABLE_COPY(DataClass) \
- V4_MANAGED_ITSELF(DataClass, superClass)
+ V4_MANAGED_ITSELF(DataClass, superClass) \
+ Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value);
#define Q_MANAGED_TYPE(type) \
public: \
@@ -140,8 +140,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
classname::IsFunctionObject, \
classname::IsErrorObject, \
classname::IsArrayData, \
- 0, \
+ classname::IsStringOrSymbol, \
classname::MyType, \
+ { 0, 0, 0, 0 }, \
#classname, \
Q_VTABLE_FUNCTION(classname, destroy), \
classname::Data::markObjects, \
@@ -154,8 +155,8 @@ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname,
QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF
#define V4_INTERNALCLASS(c) \
- static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \
- { return e->internalClasses[QV4::EngineBase::Class_##c]; }
+ static Heap::InternalClass *defaultInternalClass(QV4::EngineBase *e) \
+ { return e->internalClasses(QV4::EngineBase::Class_##c); }
struct Q_QML_PRIVATE_EXPORT Managed : Value
{
@@ -163,6 +164,7 @@ struct Q_QML_PRIVATE_EXPORT Managed : Value
enum {
IsExecutionContext = false,
IsString = false,
+ IsStringOrSymbol = false,
IsObject = false,
IsFunctionObject = false,
IsErrorObject = false,
@@ -180,11 +182,14 @@ public:
Type_Invalid,
Type_String,
Type_Object,
+ Type_Symbol,
Type_ArrayObject,
Type_FunctionObject,
+ Type_GeneratorObject,
Type_BooleanObject,
Type_NumberObject,
Type_StringObject,
+ Type_SymbolObject,
Type_DateObject,
Type_RegExpObject,
Type_ErrorObject,
@@ -193,25 +198,33 @@ public:
Type_MathObject,
Type_ExecutionContext,
- Type_ForeachIteratorObject,
+ Type_InternalClass,
+ Type_SetIteratorObject,
+ Type_MapIteratorObject,
+ Type_ArrayIteratorObject,
+ Type_StringIteratorObject,
+ Type_ForInIterator,
Type_RegExp,
Type_QmlSequence
};
Q_MANAGED_TYPE(Invalid)
- InternalClass *internalClass() const { return d()->internalClass; }
+ Heap::InternalClass *internalClass() const { return d()->internalClass; }
+ const VTable *vtable() const { return d()->internalClass->vtable; }
inline ExecutionEngine *engine() const { return internalClass()->engine; }
- bool isListType() const { return d()->vtable()->type == Type_QmlSequence; }
+ bool isListType() const { return d()->internalClass->vtable->type == Type_QmlSequence; }
+ bool isArrayLike() const { return isArrayObject() || isListType(); }
- bool isArrayObject() const { return d()->vtable()->type == Type_ArrayObject; }
- bool isStringObject() const { return d()->vtable()->type == Type_StringObject; }
+ bool isArrayObject() const { return d()->internalClass->vtable->type == Type_ArrayObject; }
+ bool isStringObject() const { return d()->internalClass->vtable->type == Type_StringObject; }
+ bool isSymbolObject() const { return d()->internalClass->vtable->type == Type_SymbolObject; }
QString className() const;
bool isEqualTo(const Managed *other) const
- { return d()->vtable()->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); }
+ { return d()->internalClass->vtable->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); }
static bool isEqualTo(Managed *m, Managed *other);
@@ -254,6 +267,29 @@ inline const Object *Value::as() const {
return objectValue();
}
+
+struct InternalClass : Managed
+{
+ V4_MANAGED_ITSELF(InternalClass, Managed)
+ Q_MANAGED_TYPE(InternalClass)
+ V4_INTERNALCLASS(Empty)
+ V4_NEEDS_DESTROY
+
+ Q_REQUIRED_RESULT Heap::InternalClass *changeVTable(const VTable *vt) {
+ return d()->changeVTable(vt);
+ }
+ Q_REQUIRED_RESULT Heap::InternalClass *changePrototype(Heap::Object *proto) {
+ return d()->changePrototype(proto);
+ }
+ Q_REQUIRED_RESULT Heap::InternalClass *addMember(Identifier identifier, PropertyAttributes data, uint *index = 0) {
+ return d()->addMember(identifier, data, index);
+ }
+
+ void operator =(Heap::InternalClass *ic) {
+ Value::operator=(ic);
+ }
+};
+
}
diff --git a/src/qml/jsruntime/qv4mapiterator.cpp b/src/qml/jsruntime/qv4mapiterator.cpp
new file mode 100644
index 0000000000..74b0dda791
--- /dev/null
+++ b/src/qml/jsruntime/qv4mapiterator.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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/qv4iterator_p.h>
+#include <private/qv4mapiterator_p.h>
+#include <private/qv4mapobject_p.h>
+#include <private/qv4symbol_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(MapIteratorObject);
+
+void MapIteratorPrototype::init(ExecutionEngine *e)
+{
+ defineDefaultProperty(QStringLiteral("next"), method_next, 0);
+
+ Scope scope(e);
+ ScopedString val(scope, e->newString(QLatin1String("Map Iterator")));
+ defineReadonlyConfigurableProperty(e->symbol_toStringTag(), val);
+}
+
+ReturnedValue MapIteratorPrototype::method_next(const FunctionObject *b, const Value *that, const Value *, int)
+{
+ Scope scope(b);
+ const MapIteratorObject *thisObject = that->as<MapIteratorObject>();
+ if (!thisObject)
+ return scope.engine->throwTypeError(QLatin1String("Not a Map Iterator instance"));
+
+ Scoped<MapObject> s(scope, thisObject->d()->iteratedMap);
+ quint32 index = thisObject->d()->mapNextIndex;
+ IteratorKind itemKind = thisObject->d()->iterationKind;
+
+ if (!s) {
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ Scoped<ArrayObject> keys(scope, s->d()->mapKeys);
+ Scoped<ArrayObject> values(scope, s->d()->mapValues);
+
+ while (index < keys->getLength()) {
+ ScopedValue sk(scope, keys->getIndexed(index));
+ ScopedValue sv(scope, values->getIndexed(index));
+ index += 1;
+ thisObject->d()->mapNextIndex = index;
+
+ ScopedValue result(scope);
+
+ if (itemKind == KeyIteratorKind) {
+ result = sk;
+ } else if (itemKind == ValueIteratorKind) {
+ result = sv;
+ } else {
+ Q_ASSERT(itemKind == KeyValueIteratorKind);
+
+ result = scope.engine->newArrayObject();
+
+ Scoped<ArrayObject> resultArray(scope, result);
+ resultArray->arrayReserve(2);
+ resultArray->arrayPut(0, sk);
+ resultArray->arrayPut(1, sv);
+ resultArray->setArrayLengthUnchecked(2);
+ }
+
+ return IteratorPrototype::createIterResultObject(scope.engine, result, false);
+ }
+
+ thisObject->d()->iteratedMap.set(scope.engine, nullptr);
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+}
+
+
diff --git a/src/qml/jsruntime/qv4mapiterator_p.h b/src/qml/jsruntime/qv4mapiterator_p.h
new file mode 100644
index 0000000000..836ba14663
--- /dev/null
+++ b/src/qml/jsruntime/qv4mapiterator_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 QV4MAPITERATOR_P_H
+#define QV4MAPITERATOR_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 "qv4object_p.h"
+#include "qv4iterator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+
+#define MapIteratorObjectMembers(class, Member) \
+ Member(class, Pointer, Object *, iteratedMap) \
+ Member(class, NoMark, IteratorKind, iterationKind) \
+ Member(class, NoMark, quint32, mapNextIndex)
+
+DECLARE_HEAP_OBJECT(MapIteratorObject, Object) {
+ DECLARE_MARKOBJECTS(MapIteratorObject);
+ void init(Object *obj, QV4::ExecutionEngine *engine)
+ {
+ Object::init();
+ this->iteratedMap.set(engine, obj);
+ this->mapNextIndex = 0;
+ }
+};
+
+}
+
+struct MapIteratorPrototype : Object
+{
+ V4_PROTOTYPE(iteratorPrototype)
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct MapIteratorObject : Object
+{
+ V4_OBJECT2(MapIteratorObject, Object)
+ Q_MANAGED_TYPE(MapIteratorObject)
+ V4_PROTOTYPE(mapIteratorPrototype)
+
+ void init(ExecutionEngine *engine);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4MAPITERATOR_P_H
+
+
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
new file mode 100644
index 0000000000..e3ca75b951
--- /dev/null
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 "qv4setobject_p.h" // ### temporary
+#include "qv4mapobject_p.h"
+#include "qv4mapiterator_p.h"
+#include "qv4symbol_p.h"
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(MapCtor);
+DEFINE_OBJECT_VTABLE(MapObject);
+
+void Heap::MapCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("Map"));
+}
+
+ReturnedValue MapCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ Scope scope(f);
+ Scoped<MapObject> a(scope, scope.engine->memoryManager->allocate<MapObject>());
+ a->d()->mapKeys.set(scope.engine, scope.engine->newArrayObject());
+ a->d()->mapValues.set(scope.engine, scope.engine->newArrayObject());
+
+ if (argc > 0) {
+ ScopedValue iterable(scope, argv[0]);
+
+ // ### beware, hack alert!
+ // Object iteration seems broken right now. if we allow any object to
+ // iterate, it endlessly loops in the Map/prototype tests in test262...
+ // disable these for now until Object iteration is fixed, just so we can
+ // test this.
+ Scoped<MapObject> mapObjectCheck(scope, argv[0]);
+ Scoped<SetObject> setObjectCheck(scope, argv[0]);
+
+ if (!iterable->isUndefined() && !iterable->isNull() && (mapObjectCheck || setObjectCheck)) {
+
+
+ ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("set")))));
+ if (!adder) {
+ return scope.engine->throwTypeError();
+ }
+ ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true));
+
+ CHECK_EXCEPTION();
+ if (!iter) {
+ return a.asReturnedValue();
+ }
+
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+ forever {
+ done = Runtime::method_iteratorNext(scope.engine, iter, nextValue);
+ CHECK_EXCEPTION();
+ if (done->toBoolean()) {
+ return a.asReturnedValue();
+ }
+
+ adder->call(a, nextValue, 1);
+ if (scope.engine->hasException) {
+ ScopedValue falsey(scope, Encode(false));
+ return Runtime::method_iteratorClose(scope.engine, iter, falsey);
+ }
+ }
+ }
+ }
+ return a.asReturnedValue();
+}
+
+ReturnedValue MapCtor::call(const FunctionObject *f, const Value *, const Value *, int)
+{
+ Scope scope(f);
+ return scope.engine->throwTypeError(QString::fromLatin1("Map requires new"));
+}
+
+void MapPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+ ctor->addSymbolSpecies();
+ defineDefaultProperty(engine->id_constructor(), (o = ctor));
+
+ defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
+ defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
+ defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
+ defineDefaultProperty(QStringLiteral("get"), method_get, 1);
+ defineDefaultProperty(QStringLiteral("has"), method_has, 1);
+ defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
+ defineDefaultProperty(QStringLiteral("set"), method_set, 0);
+ defineAccessorProperty(QStringLiteral("size"), method_get_size, nullptr);
+ defineDefaultProperty(QStringLiteral("values"), method_values, 0);
+
+ // Per the spec, the value for entries/@@iterator is the same
+ ScopedString valString(scope, scope.engine->newIdentifier(QStringLiteral("entries")));
+ ScopedFunctionObject entriesFn(scope, FunctionObject::createBuiltinFunction(engine, valString, MapPrototype::method_entries, 0));
+ defineDefaultProperty(QStringLiteral("entries"), entriesFn);
+ defineDefaultProperty(engine->symbol_iterator(), entriesFn);
+
+ ScopedString val(scope, engine->newString(QLatin1String("Map")));
+ defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
+}
+
+ReturnedValue MapPrototype::method_clear(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ that->d()->mapKeys.set(scope.engine, scope.engine->newArrayObject());
+ that->d()->mapValues.set(scope.engine, scope.engine->newArrayObject());
+ return Encode::undefined();
+}
+
+// delete value
+ReturnedValue MapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ qint64 len = keys->getLength();
+
+ bool found = false;
+ int idx = 0;
+ ScopedValue sk(scope);
+
+ for (; idx < len; ++idx) {
+ sk = keys->getIndexed(idx);
+ if (sk->sameValueZero(argv[0])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == true) {
+ Scoped<ArrayObject> values(scope, that->d()->mapValues);
+ Scoped<ArrayObject> newKeys(scope, scope.engine->newArrayObject());
+ Scoped<ArrayObject> newValues(scope, scope.engine->newArrayObject());
+ for (int j = 0, newIdx = 0; j < len; ++j, newIdx++) {
+ if (j == idx) {
+ newIdx--; // skip the entry
+ continue;
+ }
+ newKeys->putIndexed(newIdx, ScopedValue(scope, keys->getIndexed(j)));
+ newValues->putIndexed(newIdx, ScopedValue(scope, values->getIndexed(j)));
+ }
+
+ that->d()->mapKeys.set(scope.engine, newKeys->d());
+ that->d()->mapValues.set(scope.engine, newValues->d());
+ return Encode(true);
+ } else {
+ return Encode(false);
+ }
+}
+
+ReturnedValue MapPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
+ ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue MapPrototype::method_forEach(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ ScopedFunctionObject callbackfn(scope, argv[0]);
+ if (!callbackfn)
+ return scope.engine->throwTypeError();
+
+ ScopedValue thisArg(scope, Primitive::undefinedValue());
+ if (argc > 1)
+ thisArg = ScopedValue(scope, argv[1]);
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ Scoped<ArrayObject> values(scope, that->d()->mapKeys);
+ qint64 len = keys->getLength();
+
+ Value *arguments = scope.alloc(3);
+ ScopedValue sk(scope);
+ ScopedValue sv(scope);
+ for (int i = 0; i < len; ++i) {
+ sk = keys->getIndexed(i);
+ sv = values->getIndexed(i);
+
+ arguments[0] = sv;
+ arguments[1] = sk;
+ arguments[2] = that;
+ callbackfn->call(thisArg, arguments, 3);
+ CHECK_EXCEPTION();
+ }
+ return Encode::undefined();
+}
+
+ReturnedValue MapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ ScopedValue sk(scope);
+ qint64 len = keys->getLength();
+
+ for (int i = 0; i < len; ++i) {
+ sk = keys->getIndexed(i);
+ if (sk->sameValueZero(argv[0])) {
+ Scoped<ArrayObject> values(scope, that->d()->mapValues);
+ return values->getIndexed(i);
+ }
+ }
+
+ return Encode::undefined();
+}
+
+ReturnedValue MapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ ScopedValue sk(scope);
+ qint64 len = keys->getLength();
+
+ for (int i = 0; i < len; ++i) {
+ sk = keys->getIndexed(i);
+ if (sk->sameValueZero(argv[0]))
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
+ReturnedValue MapPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
+ ao->d()->iterationKind = IteratorKind::KeyIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ Scoped<ArrayObject> values(scope, that->d()->mapValues);
+ ScopedValue sk(scope, argv[1]);
+ qint64 len = keys->getLength();
+
+ for (int i = 0; i < len; ++i) {
+ sk = keys->getIndexed(i);
+ if (sk->sameValueZero(argv[0])) {
+ values->putIndexed(len, argv[1]);
+ return that.asReturnedValue();
+ }
+ }
+
+ sk = argv[0];
+ if (sk->isDouble()) {
+ if (sk->doubleValue() == 0 && std::signbit(sk->doubleValue()))
+ sk = Primitive::fromDouble(+0);
+ }
+
+ keys->putIndexed(len, sk);
+ values->putIndexed(len, argv[1]);
+ return that.asReturnedValue();
+}
+
+ReturnedValue MapPrototype::method_get_size(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> keys(scope, that->d()->mapKeys);
+ qint64 len = keys->getLength();
+ return Encode((uint)len);
+}
+
+ReturnedValue MapPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<MapObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that));
+ ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
new file mode 100644
index 0000000000..9c64e25c3d
--- /dev/null
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 QV4MAPOBJECT_P_H
+#define QV4MAPOBJECT_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 "qv4object_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4string_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+
+struct MapCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+#define MapObjectMembers(class, Member) \
+ Member(class, Pointer, ArrayObject *, mapKeys) \
+ Member(class, Pointer, ArrayObject *, mapValues)
+
+DECLARE_HEAP_OBJECT(MapObject, Object) {
+ DECLARE_MARKOBJECTS(MapObject);
+ void init() { Object::init(); }
+};
+
+}
+
+struct MapCtor: FunctionObject
+{
+ V4_OBJECT2(MapCtor, FunctionObject)
+
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct MapObject : Object
+{
+ V4_OBJECT2(MapObject, Object)
+ V4_PROTOTYPE(mapPrototype)
+};
+
+struct MapPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_clear(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_size(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+
+} // namespace QV4
+
+
+QT_END_NAMESPACE
+
+#endif // QV4MAPOBJECT_P_H
+
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 0c18d908de..652f6c603e 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -39,6 +39,7 @@
#include "qv4mathobject_p.h"
#include "qv4objectproto_p.h"
+#include "qv4symbol_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qmath.h>
@@ -70,14 +71,27 @@ void Heap::MathObject::init()
m->defineDefaultProperty(QStringLiteral("abs"), QV4::MathObject::method_abs, 1);
m->defineDefaultProperty(QStringLiteral("acos"), QV4::MathObject::method_acos, 1);
- m->defineDefaultProperty(QStringLiteral("asin"), QV4::MathObject::method_asin, 0);
+ m->defineDefaultProperty(QStringLiteral("acosh"), QV4::MathObject::method_acosh, 1);
+ m->defineDefaultProperty(QStringLiteral("asin"), QV4::MathObject::method_asin, 1);
+ m->defineDefaultProperty(QStringLiteral("asinh"), QV4::MathObject::method_asinh, 1);
m->defineDefaultProperty(QStringLiteral("atan"), QV4::MathObject::method_atan, 1);
+ m->defineDefaultProperty(QStringLiteral("atanh"), QV4::MathObject::method_atanh, 1);
m->defineDefaultProperty(QStringLiteral("atan2"), QV4::MathObject::method_atan2, 2);
+ m->defineDefaultProperty(QStringLiteral("cbrt"), QV4::MathObject::method_cbrt, 1);
m->defineDefaultProperty(QStringLiteral("ceil"), QV4::MathObject::method_ceil, 1);
+ m->defineDefaultProperty(QStringLiteral("clz32"), QV4::MathObject::method_clz32, 1);
m->defineDefaultProperty(QStringLiteral("cos"), QV4::MathObject::method_cos, 1);
+ m->defineDefaultProperty(QStringLiteral("cosh"), QV4::MathObject::method_cosh, 1);
m->defineDefaultProperty(QStringLiteral("exp"), QV4::MathObject::method_exp, 1);
+ m->defineDefaultProperty(QStringLiteral("expm1"), QV4::MathObject::method_expm1, 1);
m->defineDefaultProperty(QStringLiteral("floor"), QV4::MathObject::method_floor, 1);
+ m->defineDefaultProperty(QStringLiteral("fround"), QV4::MathObject::method_fround, 1);
+ m->defineDefaultProperty(QStringLiteral("hypot"), QV4::MathObject::method_hypot, 2);
+ m->defineDefaultProperty(QStringLiteral("imul"), QV4::MathObject::method_imul, 2);
m->defineDefaultProperty(QStringLiteral("log"), QV4::MathObject::method_log, 1);
+ m->defineDefaultProperty(QStringLiteral("log10"), QV4::MathObject::method_log10, 1);
+ m->defineDefaultProperty(QStringLiteral("log1p"), QV4::MathObject::method_log1p, 1);
+ m->defineDefaultProperty(QStringLiteral("log2"), QV4::MathObject::method_log2, 1);
m->defineDefaultProperty(QStringLiteral("max"), QV4::MathObject::method_max, 2);
m->defineDefaultProperty(QStringLiteral("min"), QV4::MathObject::method_min, 2);
m->defineDefaultProperty(QStringLiteral("pow"), QV4::MathObject::method_pow, 2);
@@ -85,8 +99,14 @@ void Heap::MathObject::init()
m->defineDefaultProperty(QStringLiteral("round"), QV4::MathObject::method_round, 1);
m->defineDefaultProperty(QStringLiteral("sign"), QV4::MathObject::method_sign, 1);
m->defineDefaultProperty(QStringLiteral("sin"), QV4::MathObject::method_sin, 1);
+ m->defineDefaultProperty(QStringLiteral("sinh"), QV4::MathObject::method_sinh, 1);
m->defineDefaultProperty(QStringLiteral("sqrt"), QV4::MathObject::method_sqrt, 1);
m->defineDefaultProperty(QStringLiteral("tan"), QV4::MathObject::method_tan, 1);
+ m->defineDefaultProperty(QStringLiteral("tanh"), QV4::MathObject::method_tanh, 1);
+ m->defineDefaultProperty(QStringLiteral("trunc"), QV4::MathObject::method_trunc, 1);
+
+ ScopedString name(scope, scope.engine->newString(QStringLiteral("Math")));
+ m->defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
}
static Q_ALWAYS_INLINE double copySign(double x, double y)
@@ -120,6 +140,19 @@ ReturnedValue MathObject::method_acos(const FunctionObject *, const Value *, con
RETURN_RESULT(Encode(std::acos(v)));
}
+ReturnedValue MathObject::method_acosh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : 2;
+ if (v < 1)
+ RETURN_RESULT(Encode(qt_qnan()));
+
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ RETURN_RESULT(Encode(std::log(v +std::sqrt(v + 1) * std::sqrt(v - 1))));
+#else
+ RETURN_RESULT(Encode(std::acosh(v)));
+#endif
+}
+
ReturnedValue MathObject::method_asin(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : 2;
@@ -129,6 +162,19 @@ ReturnedValue MathObject::method_asin(const FunctionObject *, const Value *, con
RETURN_RESULT(Encode(std::asin(v)));
}
+ReturnedValue MathObject::method_asinh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : 2;
+ if (v == 0.0)
+ RETURN_RESULT(Encode(v));
+
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ RETURN_RESULT(Encode(std::log(v +std::sqrt(1 + v * v))));
+#else
+ RETURN_RESULT(Encode(std::asinh(v)));
+#endif
+}
+
ReturnedValue MathObject::method_atan(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
@@ -138,6 +184,25 @@ ReturnedValue MathObject::method_atan(const FunctionObject *, const Value *, con
RETURN_RESULT(Encode(std::atan(v)));
}
+ReturnedValue MathObject::method_atanh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v == 0.0)
+ RETURN_RESULT(Encode(v));
+
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ if (-1 < v && v < 1)
+ RETURN_RESULT(Encode(0.5 * (std::log(v + 1) - std::log(v - 1))));
+
+ if (v > 1 || v < -1)
+ RETURN_RESULT(Encode(qt_qnan()));
+
+ RETURN_RESULT(Encode(copySign(qt_inf(), v)));
+#else
+ RETURN_RESULT(Encode(std::atanh(v)));
+#endif
+}
+
ReturnedValue MathObject::method_atan2(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v1 = argc ? argv[0].toNumber() : qt_qnan();
@@ -156,6 +221,16 @@ ReturnedValue MathObject::method_atan2(const FunctionObject *, const Value *, co
RETURN_RESULT(Encode(std::atan2(v1, v2)));
}
+ReturnedValue MathObject::method_cbrt(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ RETURN_RESULT(Encode(copySign(std::exp(std::log(std::abs(v)) / 3), v)));
+#else
+ RETURN_RESULT(Encode(std::cbrt(v))); // cube root
+#endif
+}
+
ReturnedValue MathObject::method_ceil(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
@@ -165,12 +240,24 @@ ReturnedValue MathObject::method_ceil(const FunctionObject *, const Value *, con
RETURN_RESULT(Encode(std::ceil(v)));
}
+ReturnedValue MathObject::method_clz32(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ quint32 v = argc ? argv[0].toUInt32() : 0;
+ RETURN_RESULT(Encode(qint32(qCountLeadingZeroBits(v))));
+}
+
ReturnedValue MathObject::method_cos(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
RETURN_RESULT(Encode(std::cos(v)));
}
+ReturnedValue MathObject::method_cosh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::cosh(v)));
+}
+
ReturnedValue MathObject::method_exp(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
@@ -184,6 +271,25 @@ ReturnedValue MathObject::method_exp(const FunctionObject *, const Value *, cons
}
}
+ReturnedValue MathObject::method_expm1(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (std::isnan(v) || qIsNull(v)) {
+ RETURN_RESULT(Encode(v));
+ } else if (qt_is_inf(v)) {
+ if (copySign(1.0, v) == -1.0)
+ RETURN_RESULT(Encode(-1.0));
+ else
+ RETURN_RESULT(Encode(qt_inf()));
+ } else {
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ RETURN_RESULT(Encode(std::exp(v) - 1));
+#else
+ RETURN_RESULT(Encode(std::expm1(v)));
+#endif
+ }
+}
+
ReturnedValue MathObject::method_floor(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
@@ -192,6 +298,53 @@ ReturnedValue MathObject::method_floor(const FunctionObject *, const Value *, co
RETURN_RESULT(result);
}
+ReturnedValue MathObject::method_fround(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (std::isnan(v) || qt_is_inf(v) || qIsNull(v))
+ RETURN_RESULT(Encode(v));
+ else // convert to 32-bit float using roundTiesToEven, then convert back to 64-bit double
+ RETURN_RESULT(Encode(double(float(v))));
+}
+
+ReturnedValue MathObject::method_hypot(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ // ES6 Math.hypot(v1, ..., vn) -> sqrt(sum(vi**2)) but "should take care to
+ // avoid the loss of precision from overflows and underflows" (as std::hypot does).
+ double v = argc ? argv[0].toNumber() : 0;
+ // Spec mandates +0 on no args; and says nothing about what to do if toNumber() signals ...
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ bool big = qt_is_inf(v), bad = std::isnan(v);
+ v *= v;
+ for (int i = 1; !big && i < argc; i++) {
+ double u = argv[i].toNumber();
+ if (qt_is_inf(u))
+ big = true;
+ if (std::isnan(u))
+ bad = true;
+ v += u * u;
+ }
+ if (big)
+ RETURN_RESULT(Encode(qt_inf()));
+ if (bad)
+ RETURN_RESULT(Encode(qt_qnan()));
+ // Should actually check for {und,ov}erflow, but too fiddly !
+ RETURN_RESULT(Primitive::fromDouble(sqrt(v)));
+#else
+ for (int i = 1; i < argc; i++)
+ v = std::hypot(v, argv[i].toNumber());
+#endif
+ RETURN_RESULT(Primitive::fromDouble(v));
+}
+
+ReturnedValue MathObject::method_imul(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ quint32 a = argc ? argv[0].toUInt32() : 0;
+ quint32 b = argc > 0 ? argv[1].toUInt32() : 0;
+ qint32 product = a * b;
+ RETURN_RESULT(Encode(product));
+}
+
ReturnedValue MathObject::method_log(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
@@ -201,6 +354,43 @@ ReturnedValue MathObject::method_log(const FunctionObject *, const Value *, cons
RETURN_RESULT(Encode(std::log(v)));
}
+ReturnedValue MathObject::method_log10(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v < 0)
+ RETURN_RESULT(Encode(qt_qnan()));
+ else
+ RETURN_RESULT(Encode(std::log10(v)));
+}
+
+ReturnedValue MathObject::method_log1p(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+#if !defined(__ANDROID__)
+ using std::log1p;
+#endif
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v < -1)
+ RETURN_RESULT(Encode(qt_qnan()));
+ else
+ RETURN_RESULT(Encode(log1p(v)));
+}
+
+ReturnedValue MathObject::method_log2(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v < 0) {
+ RETURN_RESULT(Encode(qt_qnan()));
+ } else {
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ // Android ndk r10e doesn't have std::log2, so fall back.
+ const double ln2 = std::log(2.0);
+ RETURN_RESULT(Encode(std::log(v) / ln2));
+#else
+ RETURN_RESULT(Encode(std::log2(v)));
+#endif
+ }
+}
+
ReturnedValue MathObject::method_max(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double mx = -qt_inf();
@@ -283,8 +473,11 @@ ReturnedValue MathObject::method_random(const FunctionObject *, const Value *, c
ReturnedValue MathObject::method_round(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
- v = copySign(std::floor(v + 0.5), v);
- RETURN_RESULT(Encode(v));
+ if (std::isnan(v) || qt_is_inf(v) || qIsNull(v))
+ RETURN_RESULT(Encode(v));
+
+ v = copySign(std::floor(v + 0.5), v);
+ RETURN_RESULT(Encode(v));
}
ReturnedValue MathObject::method_sign(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -303,7 +496,19 @@ ReturnedValue MathObject::method_sign(const FunctionObject *, const Value *, con
ReturnedValue MathObject::method_sin(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
- RETURN_RESULT(Encode(std::sin(v)));
+ if (v == 0.0)
+ RETURN_RESULT(Encode(v));
+ else
+ RETURN_RESULT(Encode(std::sin(v)));
+}
+
+ReturnedValue MathObject::method_sinh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v == 0.0)
+ RETURN_RESULT(Encode(v));
+ else
+ RETURN_RESULT(Encode(std::sinh(v)));
}
ReturnedValue MathObject::method_sqrt(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -321,3 +526,25 @@ ReturnedValue MathObject::method_tan(const FunctionObject *, const Value *, cons
RETURN_RESULT(Encode(std::tan(v)));
}
+ReturnedValue MathObject::method_tanh(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+ if (v == 0.0)
+ RETURN_RESULT(Encode(v));
+ else
+ RETURN_RESULT(Encode(std::tanh(v)));
+}
+
+ReturnedValue MathObject::method_trunc(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ double v = argc ? argv[0].toNumber() : qt_qnan();
+#ifdef Q_OS_ANDROID // incomplete std :-(
+ if (std::isnan(v) || qt_is_inf(v) || qIsNull(v))
+ RETURN_RESULT(Encode(v));
+ // Nearest integer not greater in magnitude:
+ quint64 whole = std::abs(v);
+ RETURN_RESULT(Encode(copySign(whole, v)));
+#else
+ RETURN_RESULT(Encode(std::trunc(v)));
+#endif
+}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index 0bf5da9404..2658e25438 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -71,14 +71,27 @@ struct MathObject: Object
static ReturnedValue method_abs(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_acos(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_acosh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_asin(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_asinh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_atan(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_atanh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_atan2(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_cbrt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_ceil(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_clz32(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_cos(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_cosh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_exp(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_expm1(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_floor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_fround(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_hypot(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_imul(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_log(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_log10(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_log1p(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_log2(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_max(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_min(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_pow(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -86,8 +99,11 @@ struct MathObject: Object
static ReturnedValue method_round(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_sign(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_sin(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_sinh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_sqrt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_tan(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_tanh(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_trunc(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index ac9671254d..186083b83a 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -74,18 +74,6 @@ struct MemberData : Managed
V4_MANAGED(MemberData, Managed)
V4_INTERNALCLASS(MemberData)
- struct Index {
- Heap::Base *base;
- Value *slot;
-
- void set(EngineBase *e, Value newVal) {
- WriteBarrier::write(e, base, slot->data_ptr(), newVal.asReturnedValue());
- }
- const Value *operator->() const { return slot; }
- const Value &operator*() const { return *slot; }
- bool isNull() const { return !slot; }
- };
-
const Value &operator[] (uint idx) const { return d()->values[idx]; }
const Value *data() const { return d()->values.data(); }
void set(EngineBase *e, uint index, Value v) { d()->values.set(e, index, v); }
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 0c6cde84ad..79a63d1ee6 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -50,6 +50,7 @@
#include "qv4string_p.h"
#include "qv4identifiertable_p.h"
#include "qv4jscall_p.h"
+#include "qv4symbol_p.h"
#include <stdint.h>
@@ -57,9 +58,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(Object);
-void Object::setInternalClass(InternalClass *ic)
+void Object::setInternalClass(Heap::InternalClass *ic)
{
- d()->internalClass = ic;
+ d()->internalClass.set(engine(), ic);
if (ic->isUsedAsProto)
ic->updateProtoUsage(d());
Q_ASSERT(ic && ic->vtable);
@@ -89,7 +90,7 @@ void Object::setProperty(uint index, const Property *p)
void Heap::Object::setUsedAsProto()
{
- internalClass = internalClass->asProtoClass();
+ internalClass.set(internalClass->engine, internalClass->asProtoClass());
}
bool Object::setPrototype(Object *proto)
@@ -121,7 +122,7 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
bool Object::putValue(uint memberIndex, const Value &value)
{
- QV4::InternalClass *ic = internalClass();
+ Heap::InternalClass *ic = internalClass();
if (ic->engine->hasException)
return false;
@@ -148,37 +149,34 @@ bool Object::putValue(uint memberIndex, const Value &value)
return true;
}
-void Object::defineDefaultProperty(const QString &name, const Value &value)
+void Object::defineDefaultProperty(const QString &name, const Value &value, PropertyAttributes attributes)
{
ExecutionEngine *e = engine();
Scope scope(e);
ScopedString s(scope, e->newIdentifier(name));
- defineDefaultProperty(s, value);
+ defineDefaultProperty(s, value, attributes);
}
-void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount)
+void Object::defineDefaultProperty(const QString &name, jsCallFunction code,
+ int argumentCount, PropertyAttributes attributes)
{
ExecutionEngine *e = engine();
Scope scope(e);
ScopedString s(scope, e->newIdentifier(name));
- ExecutionContext *global = e->rootContext();
- ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, s, code));
- function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
- defineDefaultProperty(s, function);
+ ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, s, code, argumentCount));
+ defineDefaultProperty(s, function, attributes);
}
-void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount)
+void Object::defineDefaultProperty(StringOrSymbol *nameOrSymbol, jsCallFunction code,
+ int argumentCount, PropertyAttributes attributes)
{
ExecutionEngine *e = engine();
Scope scope(e);
- ExecutionContext *global = e->rootContext();
- ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, name, code));
- function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
- defineDefaultProperty(name, function);
+ ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, nameOrSymbol, code, argumentCount));
+ defineDefaultProperty(nameOrSymbol, function, attributes);
}
-void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int),
- ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int))
+void Object::defineAccessorProperty(const QString &name, jsCallFunction getter, jsCallFunction setter)
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -186,16 +184,27 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)
defineAccessorProperty(s, getter, setter);
}
-void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int),
- ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int))
+void Object::defineAccessorProperty(StringOrSymbol *name, jsCallFunction getter, jsCallFunction setter)
{
ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
ScopedProperty p(scope);
- ExecutionContext *global = v4->rootContext();
- p->setGetter(ScopedFunctionObject(scope, (getter ? FunctionObject::createBuiltinFunction(global, name, getter) : nullptr)));
- p->setSetter(ScopedFunctionObject(scope, (setter ? FunctionObject::createBuiltinFunction(global, name, setter) : nullptr)));
- insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ QString n = name->toQString();
+ if (n.at(0) == QLatin1Char('@'))
+ n = QChar::fromLatin1('[') + n.midRef(1) + QChar::fromLatin1(']');
+ if (getter) {
+ ScopedString getName(scope, v4->newString(QString::fromLatin1("get ") + n));
+ p->setGetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, getName, getter, 0)));
+ } else {
+ p->setGetter(nullptr);
+ }
+ if (setter) {
+ ScopedString setName(scope, v4->newString(QString::fromLatin1("set ") + n));
+ p->setSetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, setName, setter, 0)));
+ } else {
+ p->setSetter(nullptr);
+ }
+ insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable);
}
@@ -221,13 +230,23 @@ void Object::defineReadonlyConfigurableProperty(const QString &name, const Value
defineReadonlyConfigurableProperty(s, value);
}
-void Object::defineReadonlyConfigurableProperty(String *name, const Value &value)
+void Object::defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value)
{
insertMember(name, value, Attr_ReadOnly_ButConfigurable);
}
+void Object::addSymbolSpecies()
+{
+ Scope scope(engine());
+ ScopedProperty p(scope);
+ p->setGetter(scope.engine->getSymbolSpecies());
+ p->setSetter(nullptr);
+ insertMember(scope.engine->symbol_species(), p, QV4::Attr_Accessor|QV4::Attr_NotWritable|QV4::Attr_NotEnumerable);
+}
+
void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
{
+ Base::markObjects(b, stack);
Object *o = static_cast<Object *>(b);
if (o->memberData)
o->memberData->mark(stack);
@@ -242,10 +261,11 @@ void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
}
}
-void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
+void Object::insertMember(StringOrSymbol *s, const Property *p, PropertyAttributes attributes)
{
uint idx;
- InternalClass::addMember(this, s, attributes, &idx);
+ s->makeIdentifier();
+ Heap::InternalClass::addMember(this, s->identifier(), attributes, &idx);
if (attributes.isAccessor()) {
setProperty(idx + GetterOffset, p->value);
@@ -256,14 +276,14 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri
}
// Section 8.12.1
-void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p)
+void Object::getOwnProperty(StringOrSymbol *name, PropertyAttributes *attrs, Property *p)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return getOwnProperty(idx, attrs, p);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
uint member = internalClass()->find(id);
if (member < UINT_MAX) {
@@ -300,12 +320,12 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
}
// Section 8.12.2
-MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
+PropertyIndex Object::getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs)
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
Heap::Object *o = d();
while (o) {
@@ -321,7 +341,7 @@ MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *att
return { nullptr, nullptr };
}
-ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
+PropertyIndex Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
Heap::Object *o = d();
while (o) {
@@ -329,7 +349,7 @@ ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
uint idx = o->arrayData->mappedIndex(index);
if (idx != UINT_MAX) {
*attrs = o->arrayData->attributes(index);
- return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx };
+ return { o->arrayData , o->arrayData->values.values + (attrs->isAccessor() ? idx + SetterOffset : idx) };
}
}
if (o->vtable()->type == Type_StringObject) {
@@ -346,7 +366,7 @@ ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
return { nullptr, 0 };
}
-bool Object::hasProperty(String *name) const
+bool Object::hasProperty(StringOrSymbol *name) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -378,14 +398,14 @@ bool Object::hasProperty(uint index) const
return false;
}
-bool Object::hasOwnProperty(String *name) const
+bool Object::hasOwnProperty(StringOrSymbol *name) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return hasOwnProperty(idx);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
if (internalClass()->find(id) < UINT_MAX)
return true;
@@ -418,7 +438,7 @@ ReturnedValue Object::call(const FunctionObject *f, const Value *, const Value *
return f->engine()->throwTypeError();
}
-ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue Object::get(const Managed *m, StringOrSymbol *name, bool *hasProperty)
{
return static_cast<const Object *>(m)->internalGet(name, hasProperty);
}
@@ -428,7 +448,7 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty
return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
}
-bool Object::put(Managed *m, String *name, const Value &value)
+bool Object::put(Managed *m, StringOrSymbol *name, const Value &value)
{
return static_cast<Object *>(m)->internalPut(name, value);
}
@@ -438,14 +458,14 @@ bool Object::putIndexed(Managed *m, uint index, const Value &value)
return static_cast<Object *>(m)->internalPutIndexed(index, value);
}
-PropertyAttributes Object::query(const Managed *m, String *name)
+PropertyAttributes Object::query(const Managed *m, StringOrSymbol *name)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return queryIndexed(m, idx);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
const Object *o = static_cast<const Object *>(m);
idx = o->internalClass()->find(id);
@@ -468,7 +488,7 @@ PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
return Attr_Invalid;
}
-bool Object::deleteProperty(Managed *m, String *name)
+bool Object::deleteProperty(Managed *m, StringOrSymbol *name)
{
return static_cast<Object *>(m)->internalDeleteProperty(name);
}
@@ -525,9 +545,10 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
}
while (it->memberIndex < o->internalClass()->size) {
- Identifier *n = o->internalClass()->nameMap.at(it->memberIndex);
- if (!n) {
+ Identifier n = o->internalClass()->nameMap.at(it->memberIndex);
+ if (!n.isValid() || !n.asHeapObject()->internalClass->vtable->isString) {
// accessor properties have a dummy entry with n == 0
+ // symbol entries are supposed to be skipped
++it->memberIndex;
continue;
}
@@ -536,7 +557,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex];
++it->memberIndex;
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
- name->setM(o->engine()->identifierTable->stringFromIdentifier(n));
+ name->setM(n.asHeapObject());
*attrs = a;
pd->value = *o->propertyData(idx);
if (a.isAccessor())
@@ -549,14 +570,14 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
}
// Section 8.12.3
-ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
+ReturnedValue Object::internalGet(StringOrSymbol *name, bool *hasProperty) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
return getIndexed(idx, hasProperty);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
Heap::Object *o = d();
while (o) {
@@ -612,7 +633,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
-bool Object::internalPut(String *name, const Value &value)
+bool Object::internalPut(StringOrSymbol *name, const Value &value)
{
ExecutionEngine *engine = this->engine();
if (engine->hasException)
@@ -623,9 +644,9 @@ bool Object::internalPut(String *name, const Value &value)
return putIndexed(idx, value);
name->makeIdentifier();
- Identifier *id = name->identifier();
+ Identifier id = name->identifier();
- MemberData::Index memberIndex{nullptr, nullptr};
+ PropertyIndex memberIndex{nullptr, nullptr};
uint member = internalClass()->find(id);
PropertyAttributes attrs;
if (member < UINT_MAX) {
@@ -641,7 +662,7 @@ bool Object::internalPut(String *name, const Value &value)
return false;
} else if (!attrs.isWritable())
return false;
- else if (isArrayObject() && name->equals(engine->id_length())) {
+ else if (isArrayObject() && id == engine->id_length()->identifier()) {
bool ok;
uint l = value.asArrayLength(&ok);
if (!ok) {
@@ -701,7 +722,7 @@ bool Object::internalPutIndexed(uint index, const Value &value)
PropertyAttributes attrs;
- ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ nullptr, 0 };
+ PropertyIndex arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : PropertyIndex{ nullptr, 0 };
if (arrayIndex.isNull() && isStringObject()) {
if (index < static_cast<StringObject *>(this)->length())
@@ -759,7 +780,7 @@ bool Object::internalPutIndexed(uint index, const Value &value)
}
// Section 8.12.7
-bool Object::internalDeleteProperty(String *name)
+bool Object::internalDeleteProperty(StringOrSymbol *name)
{
if (internalClass()->engine->hasException)
return false;
@@ -769,11 +790,12 @@ bool Object::internalDeleteProperty(String *name)
return deleteIndexedProperty(idx);
name->makeIdentifier();
+ Identifier id = name->identifier();
- uint memberIdx = internalClass()->find(name->identifier());
+ uint memberIdx = internalClass()->find(id);
if (memberIdx != UINT_MAX) {
if (internalClass()->propertyData[memberIdx].isConfigurable()) {
- InternalClass::removeMember(this, name->identifier());
+ Heap::InternalClass::removeMember(this, id);
return true;
}
return false;
@@ -796,7 +818,7 @@ bool Object::internalDeleteIndexedProperty(uint index)
}
// Section 8.12.9
-bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs)
+bool Object::__defineOwnProperty__(ExecutionEngine *engine, StringOrSymbol *name, const Property *p, PropertyAttributes attrs)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -807,8 +829,8 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
uint memberIndex;
- if (isArrayObject() && name->equals(engine->id_length())) {
- Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length()));
+ if (isArrayObject() && name->identifier() == engine->id_length()->identifier()) {
+ Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length()->identifier()));
ScopedProperty lp(scope);
PropertyAttributes cattrs;
getProperty(Heap::ArrayObject::LengthPropertyIndex, lp, &cattrs);
@@ -829,7 +851,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
}
if (attrs.hasWritable() && !attrs.isWritable()) {
cattrs.setWritable(false);
- InternalClass::changeMember(this, engine->id_length(), cattrs);
+ Heap::InternalClass::changeMember(this, engine->id_length()->identifier(), cattrs);
}
if (!succeeded)
return false;
@@ -898,7 +920,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
return __defineOwnProperty__(engine, index, nullptr, p, attrs);
}
-bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs)
+bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, StringOrSymbol *member, const Property *p, PropertyAttributes attrs)
{
// clause 5
if (attrs.isEmpty())
@@ -977,7 +999,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
current->merge(cattrs, p, attrs);
if (member) {
- InternalClass::changeMember(this, member, cattrs);
+ Heap::InternalClass::changeMember(this, member->identifier(), cattrs);
setProperty(index, current);
} else {
setArrayAttributes(index, cattrs);
@@ -1030,11 +1052,11 @@ void Object::copyArrayData(Object *other)
setArrayLengthUnchecked(other->getLength());
}
-uint Object::getLength(const Managed *m)
+qint64 Object::getLength(const Managed *m)
{
Scope scope(static_cast<const Object *>(m)->engine());
ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length()));
- return v->toUInt32();
+ return v->toLength();
}
// 'var' is 'V' in 15.3.5.3.
@@ -1132,12 +1154,10 @@ void Heap::ArrayObject::init(const QStringList &list)
a->setArrayLengthUnchecked(len);
}
-uint ArrayObject::getLength(const Managed *m)
+qint64 ArrayObject::getLength(const Managed *m)
{
const ArrayObject *a = static_cast<const ArrayObject *>(m);
- if (a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->isInteger())
- return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->integerValue();
- return Primitive::toUInt32(a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->doubleValue());
+ return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->toLength();
}
QStringList ArrayObject::toQStringList() const
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 1731ae3c76..5ad67635db 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -64,6 +64,9 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+typedef ReturnedValue (*jsCallFunction)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+typedef ReturnedValue (*jsConstructFunction)(const FunctionObject *, const Value *argv, int argc);
+
namespace Heap {
#define ObjectMembers(class, Member) \
@@ -74,6 +77,10 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) {
static void markObjects(Heap::Base *base, MarkStack *stack);
void init() { Base::init(); }
+ const VTable *vtable() const {
+ return internalClass->vtable;
+ }
+
const Value *inlinePropertyDataWithOffset(uint indexWithOffset) const {
Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < vtable()->inlinePropertyOffset + vtable()->nInlineProperties);
return reinterpret_cast<const Value *>(this) + indexWithOffset;
@@ -90,15 +97,15 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) {
void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
Q_ASSERT(index < vtable()->nInlineProperties);
Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
- WriteBarrier::write(e, this, prop->data_ptr(), b->asReturnedValue());
+ WriteBarrier::write(e, this, prop->data_ptr(), Value::fromHeapObject(b).asReturnedValue());
}
- QV4::MemberData::Index writablePropertyData(uint index) {
+ PropertyIndex writablePropertyData(uint index) {
uint nInline = vtable()->nInlineProperties;
if (index < nInline)
- return { this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
+ return PropertyIndex{ this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
index -= nInline;
- return { memberData, memberData->values.values + index };
+ return PropertyIndex{ memberData, memberData->values.values + index };
}
const Value *propertyData(uint index) const {
@@ -162,15 +169,15 @@ struct ObjectVTable
VTable vTable;
ReturnedValue (*call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
ReturnedValue (*callAsConstructor)(const FunctionObject *, const Value *argv, int argc);
- ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
+ ReturnedValue (*get)(const Managed *, StringOrSymbol *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
- bool (*put)(Managed *, String *name, const Value &value);
+ bool (*put)(Managed *, StringOrSymbol *name, const Value &value);
bool (*putIndexed)(Managed *, uint index, const Value &value);
- PropertyAttributes (*query)(const Managed *, String *name);
+ PropertyAttributes (*query)(const Managed *, StringOrSymbol *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
- bool (*deleteProperty)(Managed *m, String *name);
+ bool (*deleteProperty)(Managed *m, StringOrSymbol *name);
bool (*deleteIndexedProperty)(Managed *m, uint index);
- uint (*getLength)(const Managed *m);
+ qint64 (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
};
@@ -218,7 +225,7 @@ struct Q_QML_EXPORT Object: Managed {
SetterOffset = 1
};
- void setInternalClass(InternalClass *ic);
+ void setInternalClass(Heap::InternalClass *ic);
const Value *propertyData(uint index) const { return d()->propertyData(index); }
@@ -236,20 +243,20 @@ struct Q_QML_EXPORT Object: Managed {
Heap::Object *prototype() const { return d()->prototype(); }
bool setPrototype(Object *proto);
- void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = nullptr);
+ void getOwnProperty(StringOrSymbol *name, PropertyAttributes *attrs, Property *p = nullptr);
void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = nullptr);
- MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs);
- ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs);
+ PropertyIndex getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs);
+ PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs);
- bool hasProperty(String *name) const;
+ bool hasProperty(StringOrSymbol *name) const;
bool hasProperty(uint index) const;
- bool hasOwnProperty(String *name) const;
+ bool hasOwnProperty(StringOrSymbol *name) const;
bool hasOwnProperty(uint index) const;
- bool __defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs);
- bool __defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionEngine *engine, uint index, StringOrSymbol *member, const Property *p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionEngine *engine, StringOrSymbol *name, const Property *p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs);
bool __defineOwnProperty__(ExecutionEngine *engine, const QString &name, const Property *p, PropertyAttributes attrs);
bool defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs);
@@ -267,31 +274,33 @@ struct Q_QML_EXPORT Object: Managed {
bool putValue(uint memberIndex, const Value &value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
- void defineDefaultProperty(String *name, const Value &value) {
- insertMember(name, value, Attr_Data|Attr_NotEnumerable);
+ void defineDefaultProperty(StringOrSymbol *name, const Value &value, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable) {
+ insertMember(name, value, attributes);
}
- void defineDefaultProperty(const QString &name, const Value &value);
- void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0);
- void defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0);
- void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int),
- ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int));
- void defineAccessorProperty(String *name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int),
- ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int));
+ void defineDefaultProperty(const QString &name, const Value &value, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable);
+ void defineDefaultProperty(const QString &name, jsCallFunction code,
+ int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable);
+ void defineDefaultProperty(StringOrSymbol *name, jsCallFunction code,
+ int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable);
+ void defineAccessorProperty(const QString &name, jsCallFunction getter, jsCallFunction setter);
+ void defineAccessorProperty(StringOrSymbol *name, jsCallFunction getter, jsCallFunction setter);
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
/* Fixed: Writable: false, Enumerable: false, Configurable: true */
void defineReadonlyConfigurableProperty(const QString &name, const Value &value);
- void defineReadonlyConfigurableProperty(String *name, const Value &value);
+ void defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value);
+
+ void addSymbolSpecies();
- void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
+ void insertMember(StringOrSymbol *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
Scope scope(engine());
ScopedProperty p(scope);
p->value = v;
insertMember(s, p, attributes);
}
- void insertMember(String *s, const Property *p, PropertyAttributes attributes);
+ void insertMember(StringOrSymbol *s, const Property *p, PropertyAttributes attributes);
bool isExtensible() const { return d()->internalClass->extensible; }
@@ -360,13 +369,13 @@ public:
return false;
}
- inline ReturnedValue get(String *name, bool *hasProperty = nullptr) const
+ inline ReturnedValue get(StringOrSymbol *name, bool *hasProperty = nullptr) const
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = nullptr) const
{ return vtable()->getIndexed(this, idx, hasProperty); }
// use the set variants instead, to customize throw behavior
- inline bool put(String *name, const Value &v)
+ inline bool put(StringOrSymbol *name, const Value &v)
{ return vtable()->put(this, name, v); }
inline bool putIndexed(uint idx, const Value &v)
{ return vtable()->putIndexed(this, idx, v); }
@@ -376,8 +385,25 @@ public:
DoNotThrow
};
+ // This is the same as set(), but it doesn't require creating a string key,
+ // which is much more efficient for the array case.
+ inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->putIndexed(this, idx, v);
+ // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ QString::number(idx) + QLatin1Char('\"');
+ e->throwTypeError(message);
+ }
+ }
+ return ret;
+ }
+
// ES6: 7.3.3 Set (O, P, V, Throw)
- inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow)
+ inline bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow)
{
bool ret = vtable()->put(this, name, v);
// ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
@@ -392,41 +418,41 @@ public:
return ret;
}
- PropertyAttributes query(String *name) const
+ PropertyAttributes query(StringOrSymbol *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
{ return vtable()->queryIndexed(this, index); }
- bool deleteProperty(String *name)
+ bool deleteProperty(StringOrSymbol *name)
{ return vtable()->deleteProperty(this, name); }
bool deleteIndexedProperty(uint index)
{ return vtable()->deleteIndexedProperty(this, index); }
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
- uint getLength() const { return vtable()->getLength(this); }
+ qint64 getLength() const { return vtable()->getLength(this); }
ReturnedValue instanceOf(const Value &var) const
{ return vtable()->instanceOf(this, var); }
protected:
static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
static bool putIndexed(Managed *m, uint index, const Value &value);
- static PropertyAttributes query(const Managed *m, String *name);
+ static PropertyAttributes query(const Managed *m, StringOrSymbol *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static bool deleteProperty(Managed *m, String *name);
+ static bool deleteProperty(Managed *m, StringOrSymbol *name);
static bool deleteIndexedProperty(Managed *m, uint index);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static uint getLength(const Managed *m);
+ static qint64 getLength(const Managed *m);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
private:
- ReturnedValue internalGet(String *name, bool *hasProperty) const;
+ ReturnedValue internalGet(StringOrSymbol *name, bool *hasProperty) const;
ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
- bool internalPut(String *name, const Value &value);
+ bool internalPut(StringOrSymbol *name, const Value &value);
bool internalPutIndexed(uint index, const Value &value);
- bool internalDeleteProperty(String *name);
+ bool internalDeleteProperty(StringOrSymbol *name);
bool internalDeleteIndexedProperty(uint index);
friend struct ObjectIterator;
@@ -500,7 +526,7 @@ struct ArrayObject: Object {
void init(ExecutionEngine *engine);
using Object::getLength;
- static uint getLength(const Managed *m);
+ static qint64 getLength(const Managed *m);
QStringList toQStringList() const;
};
@@ -551,7 +577,7 @@ inline void Object::arraySet(uint index, const Value &value)
template<>
inline const ArrayObject *Value::as() const {
- return isManaged() && m()->vtable()->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr;
+ return isManaged() && m()->internalClass->vtable->type == Managed::Type_ArrayObject ? static_cast<const ArrayObject *>(this) : nullptr;
}
#ifndef V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 7bf7e1aa04..1290a2c1b2 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -42,9 +42,29 @@
#include "qv4identifier_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4string_p.h"
+#include "qv4iterator_p.h"
using namespace QV4;
+void ForInIteratorPrototype::init(ExecutionEngine *)
+{
+ defineDefaultProperty(QStringLiteral("next"), method_next, 0);
+}
+
+ReturnedValue ForInIteratorPrototype::method_next(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ const ForInIteratorObject *forIn = thisObject->as<ForInIteratorObject>();
+ Q_ASSERT(forIn);
+ Scope scope(b->engine());
+ ScopedValue n(scope, forIn->nextPropertyName());
+ bool done = false;
+ if (n->asReturnedValue() == Encode::null()) {
+ done = true;
+ n = Primitive::undefinedValue();
+ }
+ return IteratorPrototype::createIterResultObject(scope.engine, n, done);
+}
+
void ObjectIterator::init(const Object *o)
{
object->setM(o ? o->m() : nullptr);
@@ -175,11 +195,11 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
}
-DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
+DEFINE_OBJECT_VTABLE(ForInIteratorObject);
-void Heap::ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
+void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
- ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that);
+ ForInIteratorObject *o = static_cast<ForInIteratorObject *>(that);
o->workArea[0].mark(markStack);
o->workArea[1].mark(markStack);
Object::markObjects(that, markStack);
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 744d16301a..1e7000ad1f 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -92,8 +92,8 @@ struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData
ObjectIterator(Scope &scope, const Object *o, uint flags)
{
engine = scope.engine;
- object = scope.alloc(1);
- current = scope.alloc(1);
+ object = scope.alloc();
+ current = scope.alloc();
arrayNode = nullptr;
arrayIndex = 0;
memberIndex = 0;
@@ -111,7 +111,7 @@ private:
};
namespace Heap {
-struct ForEachIteratorObject : Object {
+struct ForInIteratorObject : Object {
void init(QV4::Object *o);
ObjectIterator &it() { return *reinterpret_cast<ObjectIterator*>(&itData); }
Value workArea[2];
@@ -123,15 +123,24 @@ private:
}
-struct ForEachIteratorObject: Object {
- V4_OBJECT2(ForEachIteratorObject, Object)
- Q_MANAGED_TYPE(ForeachIteratorObject)
+struct ForInIteratorPrototype : Object
+{
+ V4_PROTOTYPE(iteratorPrototype)
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct ForInIteratorObject: Object {
+ V4_OBJECT2(ForInIteratorObject, Object)
+ Q_MANAGED_TYPE(ForInIterator)
+ V4_PROTOTYPE(forInIteratorPrototype)
- ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
+ ReturnedValue nextPropertyName() const { return d()->it().nextPropertyNameAsString(); }
};
inline
-void Heap::ForEachIteratorObject::init(QV4::Object *o)
+void Heap::ForInIteratorObject::init(QV4::Object *o)
{
Object::init();
it() = ObjectIterator(internalClass->engine, workArea, workArea + 1, o,
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index b998b78520..a61b5d5136 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -47,6 +47,7 @@
#include "qv4objectiterator_p.h"
#include "qv4string_p.h"
#include "qv4jscall_p.h"
+#include "qv4symbol_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QStringList>
@@ -97,6 +98,7 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor->defineDefaultProperty(QStringLiteral("getOwnPropertySymbols"), method_getOwnPropertySymbols, 1);
ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
@@ -104,10 +106,12 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ctor->defineDefaultProperty(QStringLiteral("seal"), method_seal, 1);
ctor->defineDefaultProperty(QStringLiteral("freeze"), method_freeze, 1);
ctor->defineDefaultProperty(QStringLiteral("preventExtensions"), method_preventExtensions, 1);
+ ctor->defineDefaultProperty(QStringLiteral("is"), method_is, 2);
ctor->defineDefaultProperty(QStringLiteral("isSealed"), method_isSealed, 1);
ctor->defineDefaultProperty(QStringLiteral("isFrozen"), method_isFrozen, 1);
ctor->defineDefaultProperty(QStringLiteral("isExtensible"), method_isExtensible, 1);
ctor->defineDefaultProperty(QStringLiteral("keys"), method_keys, 1);
+ ctor->defineDefaultProperty(QStringLiteral("setPrototypeOf"), method_setPrototypeOf, 2);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(v4->id_toString(), method_toString, 0);
@@ -119,11 +123,7 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2);
defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2);
- ExecutionContext *global = v4->rootContext();
- ScopedProperty p(scope);
- p->value = FunctionObject::createBuiltinFunction(global, v4->id___proto__(), method_get_proto);
- p->set = FunctionObject::createBuiltinFunction(global, v4->id___proto__(), method_set_proto);
- insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable);
+ defineAccessorProperty(v4->id___proto__(), method_get_proto, method_set_proto);
}
ReturnedValue ObjectPrototype::method_getPrototypeOf(const FunctionObject *b, const Value *, const Value *argv, int argc)
@@ -140,6 +140,15 @@ ReturnedValue ObjectPrototype::method_getPrototypeOf(const FunctionObject *b, co
return (!!p ? p->asReturnedValue() : Encode::null());
}
+ReturnedValue ObjectPrototype::method_is(const FunctionObject *, const Value *, const Value *argv, int argc)
+{
+ if (!argc)
+ return Encode(true);
+ if (argc == 1)
+ return Encode((argv[0].isUndefined() ? true : false));
+ return Encode(argv[0].sameValue(argv[1]));
+}
+
ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
Scope scope(b);
@@ -154,7 +163,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObj
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
ScopedValue v(scope, argc > 1 ? argv[1] : Primitive::undefinedValue());
- ScopedString name(scope, v->toString(scope.engine));
+ ScopedStringOrSymbol name(scope, v->toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
@@ -177,6 +186,28 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(const FunctionObject *
return Encode(getOwnPropertyNames(scope.engine, argv[0]));
}
+ReturnedValue ObjectPrototype::method_getOwnPropertySymbols(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (!argc)
+ return scope.engine->throwTypeError();
+
+ ScopedObject O(scope, argv[0].toObject(scope.engine));
+ if (!O)
+ return Encode::undefined();
+ Heap::InternalClass *ic = O->d()->internalClass;
+ ScopedValue n(scope);
+ ScopedArrayObject array(scope, scope.engine->newArrayObject());
+ for (uint i = 0; i < ic->size; ++i) {
+ Identifier id = ic->nameMap.at(i);
+ n = id.asHeapObject();
+ if (!n || !n->isSymbol())
+ continue;
+ array->push_back(n);
+ }
+ return array->asReturnedValue();
+}
+
// 19.1.2.1
ReturnedValue ObjectPrototype::method_assign(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -255,7 +286,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, co
return scope.engine->throwTypeError();
ScopedObject O(scope, argv[0]);
- ScopedString name(scope, argc > 1 ? argv[1] : Primitive::undefinedValue(), ScopedString::Convert);
+ ScopedStringOrSymbol name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
@@ -287,7 +318,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b,
ScopedValue val(scope);
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
- ScopedString name(scope);
+ ScopedStringOrSymbol name(scope);
ScopedProperty pd(scope);
ScopedProperty n(scope);
while (1) {
@@ -477,19 +508,60 @@ ReturnedValue ObjectPrototype::method_keys(const FunctionObject *b, const Value
return a.asReturnedValue();
}
+ReturnedValue ObjectPrototype::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f->engine());
+ if (argc < 2 || argv[0].isNullOrUndefined() || !(argv[1].isObject() || argv[1].isNull()))
+ return scope.engine->throwTypeError();
+
+ if (!argv[0].isObject())
+ return argv[0].asReturnedValue();
+
+ ScopedObject o(scope, argv[0]);
+ ScopedObject p(scope, argv[1]);
+ Q_ASSERT(!!o);
+
+ if (o->prototype() != p->d()) {
+ bool ok = false;
+ if (o->isExtensible()) {
+ ok = o->setPrototype(p);
+ }
+ if (!ok)
+ return scope.engine->throwTypeError(QStringLiteral("Object.setPrototypeOf: Could not change prototype"));
+ }
+ return o->asReturnedValue();
+}
+
ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
+ QString string;
if (thisObject->isUndefined()) {
- return Encode(v4->newString(QStringLiteral("[object Undefined]")));
+ string = QStringLiteral("[object Undefined]");
} else if (thisObject->isNull()) {
- return Encode(v4->newString(QStringLiteral("[object Null]")));
+ string = QStringLiteral("[object Null]");
} else {
+ const Object *o = thisObject->as<Object>();
+ if (!o) {
+ // primitive, get the proper prototype
+ if (thisObject->isBoolean())
+ o = v4->booleanPrototype();
+ else if (thisObject->isNumber())
+ o = v4->numberPrototype();
+ else if (thisObject->isString())
+ o = v4->stringPrototype();
+ else if (thisObject->isSymbol())
+ o = v4->symbolPrototype();
+ Q_ASSERT(o);
+ }
+ QString name = o->className();
Scope scope(v4);
- ScopedObject obj(scope, thisObject->toObject(scope.engine));
- QString className = obj->className();
- return Encode(v4->newString(QStringLiteral("[object %1]").arg(className)));
+ ScopedString toStringTag(scope, o->get(v4->symbol_toStringTag()));
+ if (toStringTag)
+ name = toStringTag->toQString();
+ string = QStringLiteral("[object %1]").arg(name);
}
+ return Encode(v4->newString(string));
}
ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -514,7 +586,7 @@ ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Val
ReturnedValue ObjectPrototype::method_hasOwnProperty(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- ScopedString P(scope, argc ? argv[0] : Primitive::undefinedValue(), ScopedString::Convert);
+ ScopedStringOrSymbol P(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
ScopedObject O(scope, thisObject->toObject(scope.engine));
@@ -548,7 +620,7 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, con
ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- ScopedString p(scope, argc ? argv[0] : Primitive::undefinedValue(), ScopedString::Convert);
+ ScopedStringOrSymbol p(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
@@ -734,29 +806,28 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c
// is the standard built-in constructor with that name.
ScopedObject o(scope, engine->newObject());
ScopedString s(scope);
+ ScopedValue v(scope);
- ScopedProperty pd(scope);
if (attrs.isData()) {
- pd->value = desc->value;
s = engine->newString(QStringLiteral("value"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
- pd->value = Primitive::fromBoolean(attrs.isWritable());
+ o->put(s, desc->value);
+ v = Primitive::fromBoolean(attrs.isWritable());
s = engine->newString(QStringLiteral("writable"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
+ o->put(s, v);
} else {
- pd->value = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
+ v = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
s = engine->newString(QStringLiteral("get"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
- pd->value = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
+ o->put(s, v);
+ v = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
s = engine->newString(QStringLiteral("set"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
+ o->put(s, v);
}
- pd->value = Primitive::fromBoolean(attrs.isEnumerable());
+ v = Primitive::fromBoolean(attrs.isEnumerable());
s = engine->newString(QStringLiteral("enumerable"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
- pd->value = Primitive::fromBoolean(attrs.isConfigurable());
+ o->put(s, v);
+ v = Primitive::fromBoolean(attrs.isConfigurable());
s = engine->newString(QStringLiteral("configurable"));
- o->__defineOwnProperty__(scope.engine, s, pd, Attr_Data);
+ o->put(s, v);
return o.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 2b231d46ad..1a93685093 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -78,20 +78,23 @@ struct ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_getPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_getOwnPropertyDescriptor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_getOwnPropertyNames(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_assign(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_create(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_defineProperty(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_defineProperties(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_seal(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_defineProperty(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_freeze(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_preventExtensions(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_isSealed(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_isFrozen(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getOwnPropertyDescriptor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getOwnPropertyNames(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getOwnPropertySymbols(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_is(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_isExtensible(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_isFrozen(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_isSealed(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_preventExtensions(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_seal(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_setPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toLocaleString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 7fc74173e3..f8bc28160e 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -98,9 +98,9 @@ Page *allocatePage(PersistentValueStorage *storage)
p->header.freeList = 0;
insertInFront(storage, p);
for (int i = 0; i < kEntriesPerPage - 1; ++i) {
- p->values[i].setEmpty(i + 1);
+ p->values[i] = Encode(i + 1);
}
- p->values[kEntriesPerPage - 1].setEmpty(-1);
+ p->values[kEntriesPerPage - 1] = Encode(-1);
return p;
}
@@ -226,7 +226,7 @@ void PersistentValueStorage::free(Value *v)
Page *p = getPage(v);
- v->setEmpty(p->header.freeList);
+ *v = Encode(p->header.freeList);
p->header.freeList = v - p->values;
if (!--p->header.refCount)
freePage(p);
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 5fd200efc1..b337243204 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -78,7 +78,7 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(
void Profiler::stopProfiling()
{
featuresEnabled = 0;
- reportData(true);
+ reportData();
m_sentLocations.clear();
}
@@ -89,7 +89,7 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
(call1.m_end == call2.m_end && call1.m_function < call2.m_function)));
}
-void Profiler::reportData(bool trackLocations)
+void Profiler::reportData()
{
std::sort(m_data.begin(), m_data.end());
QVector<FunctionCallProperties> properties;
@@ -100,12 +100,11 @@ void Profiler::reportData(bool trackLocations)
properties.append(call.properties());
Function *function = call.function();
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
- if (!trackLocations || !marker.isValid()) {
+ if (!marker.isValid()) {
FunctionLocation &location = locations[properties.constLast().id];
if (!location.isValid())
location = call.resolveLocation();
- if (trackLocations)
- marker.setFunction(function);
+ marker.setFunction(function);
}
}
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index e8c154e4e7..8461384e9a 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -251,7 +251,7 @@ public:
void stopProfiling();
void startProfiling(quint64 features);
- void reportData(bool trackLocations);
+ void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 7cb106c424..26dc7a83c3 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -142,6 +142,19 @@ inline void Property::merge(PropertyAttributes &attrs, const Property *other, Pr
}
}
+struct PropertyIndex {
+ Heap::Base *base;
+ Value *slot;
+
+ void set(EngineBase *e, Value newVal) {
+ WriteBarrier::write(e, base, slot->data_ptr(), newVal.asReturnedValue());
+ }
+ const Value *operator->() const { return slot; }
+ const Value &operator*() const { return *slot; }
+ bool isNull() const { return !slot; }
+};
+
+
}
Q_DECLARE_TYPEINFO(QV4::Property, Q_MOVABLE_TYPE);
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 040f060476..4226bf7972 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -78,30 +78,26 @@ void Heap::QQmlContextWrapper::destroy()
Object::destroy();
}
-ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlContextWrapper::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlContextWrapper>());
+
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const QQmlContextWrapper *resource = static_cast<const QQmlContextWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
- // In V8 the JS global object would come _before_ the QML global object,
- // so simulate that here.
- bool hasProp;
- QV4::ScopedValue result(scope, v4->globalObject->get(name, &hasProp));
- if (hasProp) {
- if (hasProperty)
- *hasProperty = hasProp;
- return result->asReturnedValue();
- }
-
if (resource->d()->isNullWrapper)
return Object::get(m, name, hasProperty);
if (v4->callingQmlContext() != *resource->d()->context)
return Object::get(m, name, hasProperty);
- result = Object::get(m, name, &hasProp);
+ bool hasProp = false;
+ ScopedValue result(scope, Object::get(m, name, &hasProp));
if (hasProp) {
if (hasProperty)
*hasProperty = hasProp;
@@ -219,14 +215,28 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP
context = context->parent;
}
+ // Do a lookup in the global object here to avoid expressionContext->unresolvedNames becoming
+ // true if we access properties of the global object.
+ result = v4->globalObject->get(name, &hasProp);
+ if (hasProp) {
+ if (hasProperty)
+ *hasProperty = hasProp;
+ return result->asReturnedValue();
+ }
+
expressionContext->unresolvedNames = true;
return Encode::undefined();
}
-bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlContextWrapper::put(Managed *m, StringOrSymbol *n, const Value &value)
{
Q_ASSERT(m->as<QQmlContextWrapper>());
+
+ if (n->isSymbol())
+ return Object::put(m, n, value);
+ String *name = static_cast<String *>(n);
+
QQmlContextWrapper *resource = static_cast<QQmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
@@ -234,7 +244,8 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
return false;
QV4::Scoped<QQmlContextWrapper> wrapper(scope, resource);
- uint member = wrapper->internalClass()->find(name);
+ name->makeIdentifier();
+ uint member = wrapper->internalClass()->find(name->identifier());
if (member < UINT_MAX)
return wrapper->putValue(member, value);
@@ -312,7 +323,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)nullptr));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocate<QQmlContextWrapper>(context, (QObject*)nullptr));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
@@ -330,7 +341,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
{
Scope scope(parent);
- Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, scopeObject));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocate<QQmlContextWrapper>(context, scopeObject));
Heap::QmlContext *c = scope.engine->memoryManager->alloc<QmlContext>(parent, qml);
Q_ASSERT(c->vtable() == staticVTable());
return c;
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 647bef7fc1..86c5b62da2 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -98,8 +98,8 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
void setReadOnly(bool b) { d()->readOnly = b; }
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index d63d42478a..e17ce55f7b 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -56,7 +56,11 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4variantobject_p.h>
+
+#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
+#endif
+
#include <private/qv4objectproto_p.h>
#include <private/qv4jsonobject_p.h>
#include <private/qv4regexpobject_p.h>
@@ -181,11 +185,13 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object
if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType()))
return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, property.propType());
} else {
+#if QT_CONFIG(qml_sequence_object)
// see if it's a sequence type
bool succeeded = false;
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), &succeeded));
+ QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), !property.isWritable(), &succeeded));
if (succeeded)
return retn->asReturnedValue();
+#endif
}
if (property.propType() == QMetaType::UnknownType) {
@@ -242,7 +248,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
return QV4::QObjectMethod::create(global, object, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
+ return engine->memoryManager->allocate<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
} else {
ExecutionContext *global = engine->rootContext();
return QV4::QObjectMethod::create(global, object, property->coreIndex());
@@ -684,18 +690,25 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
return result;
}
}
- return (engine->memoryManager->allocObject<QV4::QObjectWrapper>(object))->asReturnedValue();
+ return (engine->memoryManager->allocate<QV4::QObjectWrapper>(object))->asReturnedValue();
}
-QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *hasProperty)
+QV4::ReturnedValue QObjectWrapper::get(const Managed *m, StringOrSymbol *name, bool *hasProperty)
{
+ if (name->isSymbol())
+ return Object::get(m, name, hasProperty);
+ String *n = static_cast<String *>(name);
const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
QQmlContextData *qmlContext = that->engine()->callingQmlContext();
- return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
+ return that->getQmlProperty(qmlContext, n, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
+bool QObjectWrapper::put(Managed *m, StringOrSymbol *n, const Value &value)
{
+ if (n->isSymbol())
+ return Object::put(m, n, value);
+ String *name = static_cast<String *>(n);
+
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
@@ -720,8 +733,12 @@ bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
return true;
}
-PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
+PropertyAttributes QObjectWrapper::query(const Managed *m, StringOrSymbol *name)
{
+ if (name->isSymbol())
+ return QV4::Object::query(m, name);
+ String *n = static_cast<String *>(name);
+
const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
const QObject *thatObject = that->d()->object();
if (QQmlData::wasDeleted(thatObject))
@@ -730,8 +747,8 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
ExecutionEngine *engine = that->engine();
QQmlContextData *qmlContext = engine->callingQmlContext();
QQmlPropertyData local;
- if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local)
- || name->equals(engine->id_destroy()) || name->equals(engine->id_toString()))
+ if (that->findProperty(engine, qmlContext, n, IgnoreRevision, &local)
+ || n->equals(engine->id_destroy()) || n->equals(engine->id_toString()))
return QV4::Attr_Data;
else
return QV4::Object::query(m, name);
@@ -1619,6 +1636,7 @@ void CallArgument::initAsType(int callType)
}
}
+#if QT_CONFIG(qml_sequence_object)
template <class T, class M>
void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
{
@@ -1631,6 +1649,7 @@ void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M
}
}
}
+#endif
void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
@@ -1713,6 +1732,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
+#if QT_CONFIG(qml_sequence_object)
} else if (callType == qMetaTypeId<std::vector<int>>()
|| callType == qMetaTypeId<std::vector<qreal>>()
|| callType == qMetaTypeId<std::vector<bool>>()
@@ -1740,6 +1760,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
}
+#endif
} else {
queryEngine = true;
}
@@ -1833,7 +1854,7 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
+ Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
method->d()->setObject(object);
if (QQmlData *ddata = QQmlData::get(object))
@@ -1846,7 +1867,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
+ Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
method->d()->setPropertyCache(valueType->d()->propertyCache());
method->d()->index = index;
method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
@@ -2019,7 +2040,7 @@ void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
QV4::Scope scope(engine);
- Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocObject<QV4::QMetaObjectWrapper>(metaObject)->asReturnedValue());
+ Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocate<QV4::QMetaObjectWrapper>(metaObject)->asReturnedValue());
mo->init(engine);
return mo->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 1455acc1b3..56e20adbfa 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -193,9 +193,9 @@ protected:
static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
- static PropertyAttributes query(const Managed *, String *name);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
+ static PropertyAttributes query(const Managed *, StringOrSymbol *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static ReturnedValue method_connect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
new file mode 100644
index 0000000000..69baecd337
--- /dev/null
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** 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 "qv4reflect_p.h"
+#include "qv4symbol_p.h"
+#include "qv4runtimeapi_p.h"
+#include "qv4objectproto_p.h"
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(Reflect);
+
+void Heap::Reflect::init()
+{
+ Object::init();
+ Scope scope(internalClass->engine);
+ ScopedObject r(scope, this);
+
+ r->defineDefaultProperty(QStringLiteral("apply"), QV4::Reflect::method_apply, 3);
+ r->defineDefaultProperty(QStringLiteral("construct"), QV4::Reflect::method_construct, 2);
+ r->defineDefaultProperty(QStringLiteral("defineProperty"), QV4::Reflect::method_defineProperty, 3);
+ r->defineDefaultProperty(QStringLiteral("deleteProperty"), QV4::Reflect::method_deleteProperty, 2);
+ r->defineDefaultProperty(QStringLiteral("get"), QV4::Reflect::method_get, 2);
+ r->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), QV4::Reflect::method_getOwnPropertyDescriptor, 2);
+ r->defineDefaultProperty(QStringLiteral("getPrototypeOf"), QV4::Reflect::method_getPrototypeOf, 1);
+ r->defineDefaultProperty(QStringLiteral("has"), QV4::Reflect::method_has, 2);
+ r->defineDefaultProperty(QStringLiteral("isExtensible"), QV4::Reflect::method_isExtensible, 1);
+ r->defineDefaultProperty(QStringLiteral("ownKeys"), QV4::Reflect::method_ownKeys, 1);
+ r->defineDefaultProperty(QStringLiteral("preventExtensions"), QV4::Reflect::method_preventExtensions, 1);
+ r->defineDefaultProperty(QStringLiteral("set"), QV4::Reflect::method_set, 3);
+ r->defineDefaultProperty(QStringLiteral("setPrototypeOf"), QV4::Reflect::method_setPrototypeOf, 2);
+}
+
+struct CallArgs {
+ Value *argv;
+ int argc;
+};
+
+static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
+{
+ int len = o->getLength();
+ Value *arguments = scope.alloc(len);
+
+ for (int i = 0; i < len; ++i) {
+ arguments[i] = o->getIndexed(i);
+ if (scope.hasException())
+ return { nullptr, 0 };
+ }
+ return { arguments, len };
+}
+
+ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (argc < 3 || !argv[0].isFunctionObject() || !argv[2].isObject())
+ return scope.engine->throwTypeError();
+
+ const Object *o = static_cast<const Object *>(argv + 2);
+ CallArgs arguments = createListFromArrayLike(scope, o);
+ if (scope.hasException())
+ return Encode::undefined();
+
+ return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc);
+}
+
+ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (argc < 2 || !argv[0].isFunctionObject() || !argv[1].isObject())
+ return scope.engine->throwTypeError();
+
+ const Object *o = static_cast<const Object *>(argv + 1);
+ CallArgs arguments = createListFromArrayLike(scope, o);
+ if (scope.hasException())
+ return Encode::undefined();
+
+ return static_cast<const FunctionObject &>(argv[0]).callAsConstructor(arguments.argv, arguments.argc);
+}
+
+ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (!argc || !argv[0].isObject())
+ return scope.engine->throwTypeError();
+
+ ScopedObject O(scope, argv[0]);
+ ScopedStringOrSymbol name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
+
+ ScopedValue attributes(scope, argc > 2 ? argv[2] : Primitive::undefinedValue());
+ ScopedProperty pd(scope);
+ PropertyAttributes attrs;
+ ObjectPrototype::toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
+
+ bool result = O->__defineOwnProperty__(scope.engine, name, pd, attrs);
+
+ return Encode(result);
+}
+
+ReturnedValue Reflect::method_deleteProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ ExecutionEngine *e = f->engine();
+ if (!argc || !argv[0].isObject())
+ return e->throwTypeError();
+
+ bool result = Runtime::method_deleteProperty(e, argv[0], argc > 1 ? argv[1] : Primitive::undefinedValue());
+ return Encode(result);
+}
+
+ReturnedValue Reflect::method_get(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ // ### Fix third receiver argument
+ Scope scope(f);
+ if (!argc || !argv[0].isObject())
+ return scope.engine->throwTypeError();
+
+ ScopedObject o(scope, static_cast<const Object *>(argv));
+ Value undef = Primitive::undefinedValue();
+ const Value *index = argc > 1 ? &argv[1] : &undef;
+
+ uint n = index->asArrayIndex();
+ if (n < UINT_MAX)
+ return Encode(o->getIndexed(n));
+
+ ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine));
+ if (scope.engine->hasException)
+ return false;
+ return Encode(o->get(name));
+}
+
+ReturnedValue Reflect::method_getOwnPropertyDescriptor(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ if (!argc || !argv[0].isObject())
+ return f->engine()->throwTypeError();
+
+ return ObjectPrototype::method_getOwnPropertyDescriptor(f, thisObject, argv, argc);
+}
+
+ReturnedValue Reflect::method_getPrototypeOf(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ if (!argc || !argv[0].isObject())
+ return f->engine()->throwTypeError();
+
+ return ObjectPrototype::method_getPrototypeOf(f, thisObject, argv, argc);
+}
+
+ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (!argc || !argv[0].isObject())
+ return scope.engine->throwTypeError();
+
+ ScopedObject o(scope, static_cast<const Object *>(argv));
+ Value undef = Primitive::undefinedValue();
+ const Value *index = argc > 1 ? &argv[1] : &undef;
+
+ bool hasProperty = false;
+ uint n = index->asArrayIndex();
+ if (n < UINT_MAX) {
+ (void) o->getIndexed(n, &hasProperty);
+ return Encode(hasProperty);
+ }
+
+ ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine));
+ if (scope.engine->hasException)
+ return false;
+ (void) o->get(name, &hasProperty);
+ return Encode(hasProperty);
+}
+
+ReturnedValue Reflect::method_isExtensible(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ if (!argc || !argv[0].isObject())
+ return f->engine()->throwTypeError();
+
+ const Object *o = static_cast<const Object *>(argv);
+ return Encode(o->isExtensible());
+}
+
+
+ReturnedValue Reflect::method_ownKeys(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ if (!argc || !argv[0].isObject())
+ return f->engine()->throwTypeError();
+
+ return ObjectPrototype::method_getOwnPropertyNames(f, thisObject, argv, argc);
+}
+
+ReturnedValue Reflect::method_preventExtensions(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ if (!argc || !argv[0].isObject())
+ return scope.engine->throwTypeError();
+
+ ScopedObject o(scope, static_cast<const Object *>(argv));
+ o->setInternalClass(o->internalClass()->nonExtensible());
+ return Encode(true);
+}
+
+ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ // ### Fix third receiver argument
+ Scope scope(f);
+ if (!argc || !argv[0].isObject())
+ return scope.engine->throwTypeError();
+
+ ScopedObject o(scope, static_cast<const Object *>(argv));
+ Value undef = Primitive::undefinedValue();
+ const Value *index = argc > 1 ? &argv[1] : &undef;
+ const Value &val = argc > 2 ? argv[2] : undef;
+
+ uint n = index->asArrayIndex();
+ if (n < UINT_MAX) {
+ bool result = o->putIndexed(n, val);
+ return Encode(result);
+ }
+
+ ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine));
+ if (scope.engine->hasException)
+ return false;
+ bool result = o->put(name, val);
+ return Encode(result);
+}
+
+ReturnedValue Reflect::method_setPrototypeOf(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ if (argc < 2 || !argv[0].isObject())
+ return f->engine()->throwTypeError();
+
+ return ObjectPrototype::method_setPrototypeOf(f, thisObject, argv, argc);
+}
diff --git a/src/qml/jsruntime/qv4reflect_p.h b/src/qml/jsruntime/qv4reflect_p.h
new file mode 100644
index 0000000000..73d257e006
--- /dev/null
+++ b/src/qml/jsruntime/qv4reflect_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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 QV4REFLECT_H
+#define QV4REFLECT_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 "qv4object_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+
+struct Reflect : Object {
+ void init();
+};
+
+}
+
+struct Reflect : Object {
+ V4_OBJECT2(Reflect, Object)
+
+ static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_construct(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_defineProperty(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_deleteProperty(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getOwnPropertyDescriptor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_getPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_isExtensible(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_ownKeys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_preventExtensions(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_setPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 000e2c3a7e..4fce63c5cf 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -45,10 +45,6 @@
#include "qv4scopedvalue_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 "private/qlocale_tools_p.h"
#include <QtCore/QDebug>
@@ -280,7 +276,8 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
ScopedObject ctor(scope, constructor);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(2));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(2));
+ ctor->addSymbolSpecies();
// Properties deprecated in the spec but required by "the web" :(
ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, nullptr);
@@ -387,7 +384,7 @@ ReturnedValue RegExpPrototype::method_exec(const FunctionObject *b, const Value
}
// fill in result data
- ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->internalClasses[EngineBase::Class_RegExpExecArray], scope.engine->arrayPrototype()));
+ ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->internalClasses(EngineBase::Class_RegExpExecArray)));
int len = r->value()->captureCount();
array->arrayReserve(len);
ScopedValue v(scope);
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 181628241b..a9ebe8384f 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -129,11 +129,11 @@ struct RegExpObject: Object {
void initProperties();
int lastIndex() const {
- Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()->identifier()));
return propertyData(Index_LastIndex)->toInt32();
}
void setLastIndex(int index) {
- Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()->identifier()));
return setProperty(Index_LastIndex, Primitive::fromInt32(index));
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 9729228511..8759a72074 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -61,6 +61,8 @@
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include "qv4qobjectwrapper_p.h"
+#include "qv4symbol_p.h"
+#include "qv4generatorobject_p.h"
#include <private/qv8engine_p.h>
#endif
@@ -314,37 +316,27 @@ ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
Q_ASSERT(clos);
ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ if (clos->isGenerator())
+ return GeneratorFunction::create(current, clos)->asReturnedValue();
return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
}
-bool Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, const Value &index)
+bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base, const Value &index)
{
Scope scope(engine);
- ScopedObject o(scope, base);
- if (o) {
- uint n = index.asArrayIndex();
- if (n < UINT_MAX)
- return o->deleteIndexedProperty(n);
- }
-
- ScopedString name(scope, index.toString(engine));
- return method_deleteMemberString(engine, base, name);
-}
-
-bool Runtime::method_deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return method_deleteMemberString(engine, base, name);
-}
-
-bool Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, String *name)
-{
- Scope scope(engine);
- ScopedObject obj(scope, base.toObject(engine));
+ ScopedObject o(scope, base.toObject(engine));
if (scope.engine->hasException)
return Encode::undefined();
- return obj->deleteProperty(name);
+ Q_ASSERT(o);
+
+ uint n = index.asArrayIndex();
+ if (n < UINT_MAX)
+ return o->deleteIndexedProperty(n);
+
+ ScopedStringOrSymbol name(scope, index.toPropertyKey(engine));
+ if (engine->hasException)
+ return false;
+ return o->deleteProperty(name);
}
bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
@@ -361,8 +353,16 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
if (!rhs)
return engine->throwTypeError();
- // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
- return rhs->instanceOf(lval);
+ Scope scope(engine);
+ ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance()));
+ if (hasInstance->isUndefined())
+ return rhs->instanceOf(lval);
+ FunctionObject *f = hasInstance->as<FunctionObject>();
+ if (!f)
+ return engine->throwTypeError();
+
+ ScopedValue result(scope, f->call(&rval, &lval, 1));
+ return Encode(result->toBoolean());
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -371,7 +371,7 @@ QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left
if (!ro)
return engine->throwTypeError();
Scope scope(engine);
- ScopedString s(scope, left.toString(engine));
+ ScopedStringOrSymbol s(scope, left.toPropertyKey(engine));
if (scope.hasException())
return Encode::undefined();
bool r = ro->hasProperty(s);
@@ -408,27 +408,59 @@ Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double n
ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeHint)
{
- if (typeHint == PREFERREDTYPE_HINT) {
- if (object->as<DateObject>())
- typeHint = STRING_HINT;
- else
- typeHint = NUMBER_HINT;
+ ExecutionEngine *engine = object->internalClass()->engine;
+ if (engine->hasException)
+ return Encode::undefined();
+
+ String *hint;
+ switch (typeHint) {
+ case STRING_HINT:
+ hint = engine->id_string();
+ break;
+ case NUMBER_HINT:
+ hint = engine->id_number();
+ break;
+ default:
+ hint = engine->id_default();
+ break;
}
- ExecutionEngine *engine = object->internalClass()->engine;
+ Scope scope(engine);
+ ScopedFunctionObject toPrimitive(scope, object->get(engine->symbol_toPrimitive()));
if (engine->hasException)
return Encode::undefined();
+ if (toPrimitive) {
+ ScopedValue result(scope, toPrimitive->call(object, hint, 1));
+ if (engine->hasException)
+ return Encode::undefined();
+ if (!result->isPrimitive())
+ return engine->throwTypeError();
+ return result->asReturnedValue();
+ }
+
+ if (hint == engine->id_default())
+ hint = engine->id_number();
+ return ordinaryToPrimitive(engine, object, hint);
+}
+
+
+ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint)
+{
+ Q_ASSERT(!engine->hasException);
String *meth1 = engine->id_toString();
String *meth2 = engine->id_valueOf();
- if (typeHint == NUMBER_HINT)
+ if (typeHint->identifier() == engine->id_number()->identifier()) {
qSwap(meth1, meth2);
+ } else {
+ Q_ASSERT(typeHint->identifier() == engine->id_string()->identifier());
+ }
Scope scope(engine);
ScopedValue result(scope);
- ScopedValue conv(scope, object->get(meth1));
+ ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
if (result->isPrimitive())
@@ -449,7 +481,6 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
}
-
Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Value &value)
{
Q_ASSERT(!value.isObject());
@@ -461,7 +492,9 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val
case Value::Boolean_Type:
return engine->newBooleanObject(value.booleanValue());
case Value::Managed_Type:
- Q_ASSERT(value.isString());
+ Q_ASSERT(value.isStringOrSymbol());
+ if (!value.isString())
+ return engine->newSymbolObject(value.symbolValue());
return engine->newStringObject(value.stringValue());
case Value::Integer_Type:
default: // double
@@ -488,6 +521,10 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value val
case Value::Managed_Type: {
if (value.isString())
return static_cast<const String &>(value).d();
+ if (value.isSymbol()) {
+ engine->throwTypeError(QLatin1String("Cannot convert a symbol to a string."));
+ return nullptr;
+ }
value = Primitive::fromReturnedValue(RuntimeHelpers::toPrimitive(value, hint));
Q_ASSERT(value.isPrimitive());
if (value.isString())
@@ -598,7 +635,7 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine,
Q_ASSERT(!!o); // can't fail as null/undefined is covered above
}
- ScopedString name(scope, index.toString(engine));
+ ScopedStringOrSymbol name(scope, index.toPropertyKey(engine));
if (scope.hasException())
return Encode::undefined();
return o->get(name);
@@ -617,7 +654,7 @@ ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &
uint idx = 0;
if (index.asArrayIndex(idx)) {
if (Heap::Base *b = object.heapObject()) {
- if (b->vtable()->isObject) {
+ 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>();
@@ -652,7 +689,9 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val
return o->putIndexed(idx, value);
}
- ScopedString name(scope, index.toString(engine));
+ ScopedStringOrSymbol name(scope, index.toPropertyKey(engine));
+ if (engine->hasException)
+ return false;
return o->put(name, value);
}
@@ -661,7 +700,7 @@ bool Runtime::method_storeElement(ExecutionEngine *engine, const Value &object,
uint idx = 0;
if (index.asArrayIndex(idx)) {
if (Heap::Base *b = object.heapObject()) {
- if (b->vtable()->isObject) {
+ 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>();
@@ -677,25 +716,105 @@ bool Runtime::method_storeElement(ExecutionEngine *engine, const Value &object,
return setElementFallback(engine, object, index, value);
}
-ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in)
+ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &in, int iterator)
{
Scope scope(engine);
ScopedObject o(scope, (Object *)nullptr);
if (!in.isNullOrUndefined())
o = in.toObject(engine);
- return engine->newForEachIteratorObject(o)->asReturnedValue();
+ if (engine->hasException)
+ return Encode::undefined();
+ if (iterator) {
+ if (!o)
+ return engine->throwTypeError();
+ ScopedFunctionObject f(scope, o->get(engine->symbol_iterator()));
+ if (!f)
+ return engine->throwTypeError();
+ JSCallData cData(scope, 0, nullptr, o);
+ ScopedObject it(scope, f->call(cData));
+ if (!it)
+ return engine->throwTypeError();
+ return it->asReturnedValue();
+ }
+ return engine->newForInIteratorObject(o)->asReturnedValue();
}
-ReturnedValue Runtime::method_foreachNextPropertyName(const Value &foreach_iterator)
+ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value &iterator, Value *value)
{
- Q_ASSERT(foreach_iterator.isObject());
+ Q_ASSERT(iterator.isObject());
+
+ Scope scope(engine);
+ ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(engine->id_next()));
+ if (!f)
+ return engine->throwTypeError();
+ JSCallData cData(scope, 0, nullptr, &iterator);
+ ScopedObject o(scope, f->call(cData));
+ if (!o)
+ return engine->throwTypeError();
+ ScopedValue d(scope, o->get(engine->id_done()));
+ bool done = d->toBoolean();
+ if (done) {
+ *value = Encode::undefined();
+ } else {
+ *value = o->get(engine->id_value());
+ }
+ return Encode(done);
+}
- ForEachIteratorObject *it = static_cast<ForEachIteratorObject *>(foreach_iterator.objectValue());
- Q_ASSERT(it->as<ForEachIteratorObject>());
+ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value &iterator, const Value &done)
+{
+ Q_ASSERT(iterator.isObject());
+ Q_ASSERT(done.isBoolean());
+ if (done.booleanValue())
+ return Encode::undefined();
- return it->nextPropertyName();
+ Scope scope(engine);
+ bool hadException = engine->hasException;
+ ScopedValue e(scope);
+ if (hadException) {
+ e = *engine->exceptionValue;
+ engine->hasException = false;
+ }
+ ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(engine->id_return()));
+ ScopedObject o(scope);
+ if (f) {
+ JSCallData cData(scope, 0, nullptr, &iterator);
+ o = f->call(cData);
+ }
+ if (hadException || !f) {
+ *engine->exceptionValue = e;
+ engine->hasException = hadException;
+ return Encode::undefined();
+ }
+ if (engine->hasException)
+ return Encode::undefined();
+
+ if (!o)
+ return engine->throwTypeError();
+ return Encode::undefined();
}
+ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, const Value &iterator)
+{
+ Q_ASSERT(iterator.isObject());
+
+ Scope scope(engine);
+ ScopedArrayObject array(scope, engine->newArrayObject());
+ array->arrayCreate();
+ uint index = 0;
+ while (1) {
+ ScopedValue n(scope);
+ ScopedValue done(scope, method_iteratorNext(engine, iterator, n));
+ if (engine->hasException)
+ return Encode::undefined();
+ Q_ASSERT(done->isBoolean());
+ if (done->booleanValue())
+ break;
+ array->arraySet(index, n);
+ ++index;
+ }
+ return array->asReturnedValue();
+}
void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value)
{
@@ -1033,24 +1152,31 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
{
Scope scope(engine);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedObject lookupObject(scope, base);
- if (!base->isObject()) {
+ if (!lookupObject) {
Q_ASSERT(!base->isEmpty());
if (base->isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
- base->toQStringNoThrow());
+ .arg(name->toQString(), base->toQStringNoThrow());
return engine->throwTypeError(message);
}
- ScopedValue thisObject(scope, RuntimeHelpers::convertToObject(engine, *base));
- if (engine->hasException) // type error
- return Encode::undefined();
- base = thisObject;
+ if (base->isManaged()) {
+ Managed *m = static_cast<Managed *>(base);
+ lookupObject = m->internalClass()->prototype;
+ Q_ASSERT(m->internalClass()->prototype);
+ } else {
+ lookupObject = RuntimeHelpers::convertToObject(engine, *base);
+ if (engine->hasException) // type error
+ return Encode::undefined();
+ if (!engine->currentStackFrame->v4Function->isStrict())
+ base = lookupObject;
+ }
}
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(name));
+ ScopedFunctionObject f(scope, static_cast<Object *>(lookupObject)->get(name));
if (!f) {
QString error = QStringLiteral("Property '%1' of object %2 is not a function")
@@ -1080,7 +1206,7 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
ScopedValue thisObject(scope, base->toObject(engine));
base = thisObject;
- ScopedString str(scope, index.toString(engine));
+ ScopedStringOrSymbol str(scope, index.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
@@ -1130,6 +1256,60 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi
return fo->call(qmlContextValue, argv, argc);
}
+struct CallArgs {
+ Value *argv;
+ int argc;
+};
+
+static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
+{
+ ScopedValue it(scope);
+ ScopedValue done(scope);
+
+ int argCount = 0;
+
+ Value *v = scope.alloc<Scope::Uninitialized>();
+ Value *arguments = v;
+ for (int i = 0; i < argc; ++i) {
+ if (!argv[i].isEmpty()) {
+ *v = argv[i];
+ ++argCount;
+ v = scope.alloc<Scope::Uninitialized>();
+ continue;
+ }
+ // spread element
+ ++i;
+ it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1);
+ if (scope.engine->hasException)
+ return { nullptr, 0 };
+ while (1) {
+ done = Runtime::method_iteratorNext(scope.engine, it, v);
+ if (scope.engine->hasException)
+ return { nullptr, 0 };
+ Q_ASSERT(done->isBoolean());
+ if (done->booleanValue())
+ break;
+ ++argCount;
+ v = scope.alloc<Scope::Uninitialized>();
+ }
+ }
+ return { arguments, argCount };
+}
+
+ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
+{
+ Q_ASSERT(argc >= 1);
+ if (!function.isFunctionObject())
+ return engine->throwTypeError();
+
+ Scope scope(engine);
+ CallArgs arguments = createSpreadArguments(scope, argv, argc);
+ if (engine->hasException)
+ return Encode::undefined();
+
+ return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
+}
+
ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, Value *argv, int argc)
{
if (!function.isFunctionObject())
@@ -1138,6 +1318,20 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu
return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc);
}
+ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, Value *argv, int argc)
+{
+ Q_UNIMPLEMENTED();
+ if (!function.isFunctionObject())
+ return engine->throwTypeError();
+
+ Scope scope(engine);
+ CallArgs arguments = createSpreadArguments(scope, argv, argc);
+ if (engine->hasException)
+ return Encode::undefined();
+
+ return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc);
+}
+
void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)
{
if (!value.isEmpty())
@@ -1161,6 +1355,8 @@ ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &
case Value::Managed_Type:
if (value.isString())
res = engine->id_string();
+ else if (value.isSymbol())
+ res = engine->id_symbol();
else if (value.objectValue()->as<FunctionObject>())
res = engine->id_function();
else
@@ -1183,25 +1379,54 @@ QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameI
return method_typeofValue(engine, prop);
}
-/* The next three methods are a bit tricky. They can't open up a Scope, as that
- * would mess up the pushing of the context.
- *
- * Instead the push/pop pair acts as a non local scope.
- */
-ReturnedValue Runtime::method_createWithContext(ExecutionContext *parent, const Value &o)
+ReturnedValue Runtime::method_createWithContext(ExecutionEngine *engine, Value *jsStackFrame)
{
- Q_ASSERT(o.isObject());
- const Object &obj = static_cast<const Object &>(o);
- return parent->newWithContext(obj.d())->asReturnedValue();
+ 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();
+}
+
+ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex)
+{
+ ExecutionEngine *e = parent->engine();
+ return parent->newCatchContext(e->currentStackFrame, blockIndex,
+ e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex])->asReturnedValue();
}
-ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int exceptionVarNameIndex)
+ReturnedValue Runtime::method_createBlockContext(ExecutionContext *parent, int index)
{
ExecutionEngine *e = parent->engine();
- return parent->newCatchContext(e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex],
- e->catchException(nullptr))->asReturnedValue();
+ return parent->newBlockContext(e->currentStackFrame, index)->asReturnedValue();
+}
+
+ReturnedValue Runtime::method_cloneBlockContext(ExecutionContext *previous)
+{
+ return ExecutionContext::cloneBlockContext(static_cast<Heap::CallContext *>(previous->d()))->asReturnedValue();
+}
+
+
+ReturnedValue Runtime::method_createScriptContext(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;
+}
+
+ReturnedValue Runtime::method_popScriptContext(ExecutionEngine *engine)
+{
+ ReturnedValue root = engine->rootContext()->asReturnedValue();
+ engine->setScriptContext(root);
+ return root;
}
+
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
{
Scope scope(engine);
@@ -1214,61 +1439,71 @@ ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *value
return engine->newArrayObject(values, length)->asReturnedValue();
}
-ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
+ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId, int argc, const QV4::Value *args)
{
Scope scope(engine);
- QV4::InternalClass *klass = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeClasses[classId];
- ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype()));
+ Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]);
+ ScopedObject o(scope, engine->newObject(klass->d()));
- {
- bool needSparseArray = arrayGetterSetterCountAndFlags >> 30;
- if (needSparseArray)
- o->initSparseArray();
- }
+ Q_ASSERT(uint(argc) >= klass->d()->size);
- for (uint i = 0; i < klass->size; ++i)
+ for (uint i = 0; i < klass->d()->size; ++i)
o->setProperty(i, *args++);
- if (arrayValueCount > 0) {
- ScopedValue entry(scope);
- for (int i = 0; i < arrayValueCount; ++i) {
- uint idx = args->toUInt32();
- ++args;
- entry = *args++;
- o->arraySet(idx, entry);
- }
- }
+ Q_ASSERT((argc - klass->d()->size) % 3 == 0);
+ int additionalArgs = (argc - int(klass->d()->size))/3;
+
+ if (!additionalArgs)
+ return o->asReturnedValue();
- uint arrayGetterSetterCount = arrayGetterSetterCountAndFlags & ((1 << 30) - 1);
- if (arrayGetterSetterCount > 0) {
- ScopedProperty pd(scope);
- for (uint i = 0; i < arrayGetterSetterCount; ++i) {
- uint idx = args->toUInt32();
- ++args;
- pd->value = *args;
- ++args;
- pd->set = *args;
- ++args;
- o->arraySet(idx, pd, Attr_Accessor);
+ Scoped<StringOrSymbol> name(scope);
+ ScopedProperty pd(scope);
+ for (int i = 0; i < additionalArgs; ++i) {
+ Q_ASSERT(args->isInteger());
+ ObjectLiteralArgument arg = ObjectLiteralArgument(args->integerValue());
+ name = args[1].toPropertyKey(engine);
+ if (engine->hasException)
+ return Encode::undefined();
+ Q_ASSERT(arg == ObjectLiteralArgument::Value || args[2].isFunctionObject());
+ if (arg == ObjectLiteralArgument::Value || arg == ObjectLiteralArgument::Getter) {
+ pd->value = args[2];
+ pd->set = Primitive::emptyValue();
+ } else {
+ pd->value = Primitive::emptyValue();
+ pd->set = args[2];
}
- }
+ bool ok = o->__defineOwnProperty__(scope.engine, name, pd, (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor));
+ if (!ok)
+ return engine->throwTypeError();
+ args += 3;
+ }
return o.asReturnedValue();
}
QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine)
{
Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
- QV4::InternalClass *ic = engine->internalClasses[EngineBase::Class_ArgumentsObject];
- return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), engine->currentStackFrame)->asReturnedValue();
+ 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::InternalClass *ic = engine->internalClasses[EngineBase::Class_StrictArgumentsObject];
- return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->objectPrototype(), engine->currentStackFrame)->asReturnedValue();
+ 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)
+{
+ const Value *values = engine->currentStackFrame->originalArguments + argIndex;
+ int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
+ if (nValues <= 0)
+ return engine->newArrayObject(0)->asReturnedValue();
+ return engine->newArrayObject(values, nValues)->asReturnedValue();
+}
+
+
ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine)
{
Heap::QmlContext *ctx = engine->qmlContext();
@@ -1485,24 +1720,133 @@ ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right)
return Encode(r);
}
+struct LazyScope
+{
+ ExecutionEngine *engine = nullptr;
+ Value *stackMark = nullptr;
+ ~LazyScope() {
+ if (engine)
+ engine->jsStackTop = stackMark;
+ }
+ template <typename T>
+ void set(Value **scopedValue, T value, ExecutionEngine *e) {
+ if (!engine) {
+ engine = e;
+ stackMark = engine->jsStackTop;
+ }
+ if (!*scopedValue)
+ *scopedValue = e->jsAlloca(1);
+ **scopedValue = value;
+ }
+};
+
Bool Runtime::method_compareEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
- if (left.rawValue() == right.rawValue())
- // NaN != NaN
- return !left.isNaN();
+ Value lhs = left;
+ Value rhs = right;
- if (left.type() == right.type()) {
- if (left.isDouble() && left.doubleValue() == 0 && right.doubleValue() == 0)
- return true; // this takes care of -0 == +0 (which obviously have different raw values)
- if (!left.isManaged())
- return false;
- if (left.isString() == right.isString())
- return left.cast<Managed>()->isEqualTo(right.cast<Managed>());
+#ifndef V4_BOOTSTRAP
+ LazyScope scope;
+ Value *lhsGuard = nullptr;
+ Value *rhsGuard = nullptr;
+#endif
+
+ redo:
+ if (lhs.asReturnedValue() == rhs.asReturnedValue())
+ return !lhs.isNaN();
+
+ int lt = lhs.quickType();
+ int rt = rhs.quickType();
+ if (rt < lt) {
+ qSwap(lhs, rhs);
+ qSwap(lt, rt);
}
- return RuntimeHelpers::equalHelper(left, right);
+ switch (lt) {
+ case QV4::Value::QT_ManagedOrUndefined:
+ if (lhs.isUndefined())
+ return rhs.isNullOrUndefined();
+ Q_FALLTHROUGH();
+ case QV4::Value::QT_ManagedOrUndefined1:
+ case QV4::Value::QT_ManagedOrUndefined2:
+ case QV4::Value::QT_ManagedOrUndefined3:
+ // LHS: Managed
+ switch (rt) {
+ case QV4::Value::QT_ManagedOrUndefined:
+ if (rhs.isUndefined())
+ return false;
+ Q_FALLTHROUGH();
+ 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();
+ Q_ASSERT(l);
+ Q_ASSERT(r);
+ if (l->internalClass->vtable->isStringOrSymbol == r->internalClass->vtable->isStringOrSymbol)
+ return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs));
+ if (l->internalClass->vtable->isStringOrSymbol) {
+ scope.set(&rhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT), r->internalClass->engine);
+ rhs = rhsGuard->asReturnedValue();
+ break;
+ } else {
+ Q_ASSERT(r->internalClass->vtable->isStringOrSymbol);
+ scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), l->internalClass->engine);
+ lhs = lhsGuard->asReturnedValue();
+ break;
+ }
+#endif
+ return false;
+ }
+ case QV4::Value::QT_Empty:
+ Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return false;
+ case QV4::Value::QT_Bool:
+ case QV4::Value::QT_Int:
+ rhs = Primitive::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:
+ Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return rhs.isNull();
+ case QV4::Value::QT_Bool:
+ case QV4::Value::QT_Int:
+ switch (rt) {
+ case QV4::Value::QT_ManagedOrUndefined:
+ case QV4::Value::QT_ManagedOrUndefined1:
+ case QV4::Value::QT_ManagedOrUndefined2:
+ case QV4::Value::QT_ManagedOrUndefined3:
+ case QV4::Value::QT_Empty:
+ case QV4::Value::QT_Null:
+ Q_UNREACHABLE();
+ case QV4::Value::QT_Bool:
+ case QV4::Value::QT_Int:
+ return lhs.int_32() == rhs.int_32();
+ default: // double
+ return lhs.int_32() == rhs.doubleValue();
+ }
+ default: // double
+ Q_ASSERT(rhs.isDouble());
+ return lhs.doubleValue() == rhs.doubleValue();
+ }
}
ReturnedValue Runtime::method_equal(const Value &left, const Value &right)
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 3a26c23990..72af90d1dc 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -100,6 +100,7 @@ enum TypeHint {
struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
static ReturnedValue objectDefaultValue(const Object *object, int typeHint);
static ReturnedValue toPrimitive(const Value &value, TypeHint typeHint);
+ static ReturnedValue ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint);
static double stringToNumber(const QString &s);
static Heap::String *stringFromNumber(ExecutionEngine *engine, double number);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 91232256a9..09f6a65dde 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -99,9 +99,11 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
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, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \
+ F(ReturnedValue, callWithSpread, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \
\
/* construct */ \
F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \
+ F(ReturnedValue, constructWithSpread, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \
\
/* load & store */ \
F(void, storeNameStrict, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
@@ -117,15 +119,17 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \
\
/* delete */ \
- F(bool, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
- F(bool, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
- F(bool, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \
+ 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, (ExecutionContext *parent, const Value &o)) \
- F(ReturnedValue, createCatchContext, (ExecutionContext *parent, int exceptionVarNameIndex)) \
+ 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)) \
\
/* closures */ \
F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \
@@ -134,14 +138,17 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
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, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)) \
+ F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, int classId, int argc, const Value *args)) \
\
- /* foreach */ \
- F(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in)) \
- F(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator)) \
+ /* 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, 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)) \
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
index fe18ddf9ed..9866966936 100644
--- a/src/qml/jsruntime/qv4runtimecodegen.cpp
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -52,13 +52,16 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
_module->finalUrl = fileName;
_context = nullptr;
- Compiler::ScanFunctions scan(this, sourceCode, Compiler::GlobalCode);
+ Compiler::ScanFunctions scan(this, sourceCode, Compiler::ContextType::Global);
// fake a global environment
- scan.enterEnvironment(nullptr, Compiler::FunctionCode);
+ scan.enterEnvironment(nullptr, Compiler::ContextType::Function, QString());
scan(ast);
scan.leaveEnvironment();
- int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : nullptr);
+ if (hasError)
+ return;
+
+ int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body);
_module->rootContext = _module->functions.at(index);
}
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index bb20f384b3..73ee17cd40 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -117,8 +117,45 @@ struct Scope {
engine->jsStackTop = mark;
}
- QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const {
- return engine->jsAlloca(nValues);
+ enum AllocMode {
+ Undefined,
+ Empty,
+ /* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */
+ Uninitialized
+ };
+ template <AllocMode mode = Undefined>
+ QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const
+ {
+ Value *ptr = engine->jsAlloca(nValues);
+ switch (mode) {
+ case Undefined:
+ for (int i = 0; i < nValues; ++i)
+ ptr[i] = Primitive::undefinedValue();
+ break;
+ case Empty:
+ for (int i = 0; i < nValues; ++i)
+ ptr[i] = Primitive::emptyValue();
+ break;
+ case Uninitialized:
+ break;
+ }
+ return ptr;
+ }
+ template <AllocMode mode = Undefined>
+ QML_NEARLY_ALWAYS_INLINE Value *alloc() const
+ {
+ Value *ptr = engine->jsAlloca(1);
+ switch (mode) {
+ case Undefined:
+ *ptr = Primitive::undefinedValue();
+ break;
+ case Empty:
+ *ptr = Primitive::emptyValue();
+ break;
+ case Uninitialized:
+ break;
+ }
+ return ptr;
}
bool hasException() const {
@@ -136,31 +173,31 @@ struct ScopedValue
{
ScopedValue(const Scope &scope)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setRawValue(0);
}
ScopedValue(const Scope &scope, const Value &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.alloc<Scope::Uninitialized>();
*ptr = v;
}
ScopedValue(const Scope &scope, Heap::Base *o)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setM(o);
}
ScopedValue(const Scope &scope, Managed *m)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setRawValue(m->asReturnedValue());
}
ScopedValue(const Scope &scope, const ReturnedValue &v)
{
- ptr = scope.engine->jsStackTop++;
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setRawValue(v);
}
@@ -214,66 +251,66 @@ struct Scoped
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Undefined>();
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(v.as<T>());
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o)
{
Value v;
v = o;
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(v.as<T>());
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(v.ptr->as<T>());
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setRawValue(value_convert<T>(scope.engine, v));
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(v ? v->as<T>() : nullptr);
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(t);
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(t);
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
*ptr = t;
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
setPointer(QV4::Value::fromReturnedValue(v).as<T>());
}
QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType)
{
- ptr = scope.engine->jsAlloca(1);
+ ptr = scope.alloc<Scope::Uninitialized>();
ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v)));
}
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 5cd62c90f1..efd528860f 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -60,7 +60,7 @@
using namespace QV4;
-Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit)
+Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer<CompiledData::CompilationUnit> &compilationUnit)
: line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
, compilationUnit(compilationUnit), vmFunction(nullptr), parseAsBinding(true)
{
@@ -128,7 +128,7 @@ void Script::parse()
RuntimeCodegen cg(v4, &jsGenerator, strictMode);
if (inheritContext)
cg.setUseFastLookups(false);
- cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, compilationMode);
+ cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, contextType);
if (v4->hasException)
return;
@@ -171,19 +171,16 @@ Function *Script::function()
return vmFunction;
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
+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, Directives *directivesCollector)
+ QList<QQmlError> *reportedErrors)
{
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
- Engine ee;
- if (directivesCollector)
- ee.setDirectives(directivesCollector);
- Lexer lexer(&ee);
+ Lexer lexer(jsEngine);
lexer.setCode(source, /*line*/1, /*qml mode*/false);
- Parser parser(&ee);
+ Parser parser(jsEngine);
parser.parseProgram();
@@ -219,7 +216,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
Codegen cg(unitGenerator, /*strict mode*/false);
cg.setUseFastLookups(false);
- cg.generateFromProgram(fileName, finalUrl, source, program, module, GlobalCode);
+ cg.generateFromProgram(fileName, finalUrl, source, program, module, ContextType::Global);
errors = cg.qmlErrors();
if (!errors.isEmpty()) {
if (reportedErrors)
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index b4ac150044..e7189664e2 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -62,12 +62,16 @@ QT_BEGIN_NAMESPACE
class QQmlContextData;
+namespace QQmlJS {
+class Engine;
+}
+
namespace QV4 {
struct Q_QML_EXPORT Script {
- Script(ExecutionContext *scope, QV4::Compiler::CompilationMode mode, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
+ Script(ExecutionContext *scope, QV4::Compiler::ContextType mode, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
- , context(scope), strictMode(false), inheritContext(false), parsed(false), compilationMode(mode)
+ , context(scope), strictMode(false), inheritContext(false), parsed(false), contextType(mode)
, vmFunction(nullptr), parseAsBinding(false) {}
Script(ExecutionEngine *engine, QmlContext *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
@@ -76,7 +80,7 @@ struct Q_QML_EXPORT Script {
if (qml)
qmlContext.set(engine, *qml);
}
- Script(ExecutionEngine *engine, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit);
+ Script(ExecutionEngine *engine, QmlContext *qml, const QQmlRefPointer<CompiledData::CompilationUnit> &compilationUnit);
~Script();
QString sourceFile;
int line;
@@ -86,7 +90,7 @@ struct Q_QML_EXPORT Script {
bool strictMode;
bool inheritContext;
bool parsed;
- QV4::Compiler::CompilationMode compilationMode = QV4::Compiler::EvalCode;
+ QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Eval;
QV4::PersistentValue qmlContext;
QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit;
Function *vmFunction;
@@ -97,10 +101,9 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QQmlRefPointer<CompiledData::CompilationUnit> precompile(
- QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
+ static QQmlRefPointer<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, QQmlJS::Directives *directivesCollector = nullptr);
+ QList<QQmlError> *reportedErrors = nullptr);
static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 7d29d0b517..f0aa39b786 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -227,7 +227,7 @@ namespace Heap {
template <typename Container>
struct QQmlSequence : Object {
void init(const Container &container);
- void init(QObject *object, int propertyIndex);
+ void init(QObject *object, int propertyIndex, bool readOnly);
void destroy() {
delete container;
object.destroy();
@@ -237,7 +237,8 @@ struct QQmlSequence : Object {
mutable Container *container;
QQmlQPointer<QObject> object;
int propertyIndex;
- bool isReference;
+ bool isReference : 1;
+ bool isReadOnly : 1;
};
}
@@ -294,6 +295,9 @@ public:
return false;
}
+ if (d()->isReadOnly)
+ return false;
+
if (d()->isReference) {
if (!d()->object)
return false;
@@ -366,6 +370,8 @@ public:
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX)
return false;
+ if (d()->isReadOnly)
+ return false;
if (d()->isReference) {
if (!d()->object)
return false;
@@ -432,11 +438,13 @@ public:
const QV4::Value *m_compareFn;
};
- void sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
+ bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
+ if (d()->isReadOnly)
+ return false;
if (d()->isReference) {
if (!d()->object)
- return;
+ return false;
loadReference();
}
@@ -450,6 +458,8 @@ public:
if (d()->isReference)
storeReference();
+
+ return true;
}
static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -480,6 +490,10 @@ public:
generateWarning(scope.engine, QLatin1String("Index out of range during length set"));
RETURN_UNDEFINED();
}
+
+ if (This->d()->isReadOnly)
+ THROW_TYPE_ERROR();
+
/* Read the sequence from the QObject property if we're a reference */
if (This->d()->isReference) {
if (!This->d()->object)
@@ -572,6 +586,7 @@ void Heap::QQmlSequence<Container>::init(const Container &container)
this->container = new Container(container);
propertyIndex = -1;
isReference = false;
+ isReadOnly = false;
object.init();
QV4::Scope scope(internalClass->engine);
@@ -581,12 +596,13 @@ void Heap::QQmlSequence<Container>::init(const Container &container)
}
template <typename Container>
-void Heap::QQmlSequence<Container>::init(QObject *object, int propertyIndex)
+void Heap::QQmlSequence<Container>::init(QObject *object, int propertyIndex, bool readOnly)
{
Object::init();
this->container = new Container;
this->propertyIndex = propertyIndex;
isReference = true;
+ this->isReadOnly = readOnly;
this->object.init(object);
QV4::Scope scope(internalClass->engine);
QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this);
@@ -668,7 +684,8 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu
#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
- s->sort(b, thisObject, argv, argc); \
+ if (!s->sort(b, thisObject, argv, argc)) \
+ THROW_TYPE_ERROR(); \
} else
FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
@@ -691,11 +708,11 @@ bool SequencePrototype::isSequenceType(int sequenceTypeId)
#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(object, propertyIndex)); \
+ QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QQml##ElementTypeName##List>(object, propertyIndex, readOnly)); \
return obj.asReturnedValue(); \
} else
-ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int sequenceType, QObject *object, int propertyIndex, bool *succeeded)
+ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int sequenceType, QObject *object, int propertyIndex, bool readOnly, bool *succeeded)
{
QV4::Scope scope(engine);
// This function is called when the property is a QObject Q_PROPERTY of
@@ -709,7 +726,7 @@ ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int s
#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::ScopedObject obj(scope, engine->memoryManager->allocObject<QQml##ElementTypeName##List>(v.value<SequenceType >())); \
+ QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QQml##ElementTypeName##List>(v.value<SequenceType >())); \
return obj.asReturnedValue(); \
} else
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index e9bef2f604..da71215bed 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -59,6 +59,8 @@
#include "qv4context_p.h"
#include "qv4string_p.h"
+QT_REQUIRE_CONFIG(qml_sequence_object);
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -72,7 +74,7 @@ struct SequencePrototype : public QV4::Object
static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static bool isSequenceType(int sequenceTypeId);
- static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
+ static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool readOnly, bool *succeeded);
static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded);
static int metaTypeForSequence(const Object *object);
static QVariant toVariant(Object *object);
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 14def49d0a..31b51cbfe3 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -40,13 +40,17 @@
#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>
@@ -82,8 +86,12 @@ enum Type {
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)
@@ -228,6 +236,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
} 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();
@@ -236,9 +245,13 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
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();
@@ -256,6 +269,7 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
return;
}
+#endif
// regular object
QV4::ScopedValue val(scope, v);
@@ -353,6 +367,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
data += ALIGN(length * sizeof(quint16));
return Encode(engine->newRegExpObject(pattern, flags));
}
+#if QT_CONFIG(qml_list_model)
case WorkerListModel:
{
void *ptr = popPtr(data);
@@ -369,6 +384,8 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
agent->setEngine(engine);
return rv->asReturnedValue();
}
+#endif
+#if QT_CONFIG(qml_sequence_object)
case WorkerSequence:
{
ScopedValue value(scope);
@@ -387,6 +404,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded);
return QV4::SequencePrototype::fromVariant(engine, seqVariant, &succeeded);
}
+#endif
}
Q_ASSERT(!"Unreachable");
return QV4::Encode::undefined();
diff --git a/src/qml/jsruntime/qv4setiterator.cpp b/src/qml/jsruntime/qv4setiterator.cpp
new file mode 100644
index 0000000000..715a4e30d5
--- /dev/null
+++ b/src/qml/jsruntime/qv4setiterator.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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/qv4iterator_p.h>
+#include <private/qv4setiterator_p.h>
+#include <private/qv4setobject_p.h>
+#include <private/qv4symbol_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(SetIteratorObject);
+
+void SetIteratorPrototype::init(ExecutionEngine *e)
+{
+ defineDefaultProperty(QStringLiteral("next"), method_next, 0);
+
+ Scope scope(e);
+ ScopedString val(scope, e->newString(QLatin1String("Set Iterator")));
+ defineReadonlyConfigurableProperty(e->symbol_toStringTag(), val);
+}
+
+ReturnedValue SetIteratorPrototype::method_next(const FunctionObject *b, const Value *that, const Value *, int)
+{
+ Scope scope(b);
+ const SetIteratorObject *thisObject = that->as<SetIteratorObject>();
+ if (!thisObject)
+ return scope.engine->throwTypeError(QLatin1String("Not a Set Iterator instance"));
+
+ Scoped<SetObject> s(scope, thisObject->d()->iteratedSet);
+ quint32 index = thisObject->d()->setNextIndex;
+ IteratorKind itemKind = thisObject->d()->iterationKind;
+
+
+ if (!s) {
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ Scoped<ArrayObject> arr(scope, s->d()->setArray);
+
+ while (index < arr->getLength()) {
+ ScopedValue e(scope, arr->getIndexed(index));
+ index += 1;
+ thisObject->d()->setNextIndex = index;
+
+ if (itemKind == KeyValueIteratorKind) {
+ // Return CreateIterResultObject(CreateArrayFromList(« e, e »), false).
+ ScopedArrayObject resultArray(scope, scope.engine->newArrayObject());
+ resultArray->arrayReserve(2);
+ resultArray->arrayPut(0, e);
+ resultArray->arrayPut(1, e);
+ resultArray->setArrayLengthUnchecked(2);
+
+ return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false);
+ }
+
+ return IteratorPrototype::createIterResultObject(scope.engine, e, false);
+ }
+
+ thisObject->d()->iteratedSet.set(scope.engine, nullptr);
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+}
+
diff --git a/src/qml/jsruntime/qv4setiterator_p.h b/src/qml/jsruntime/qv4setiterator_p.h
new file mode 100644
index 0000000000..78eda6d57b
--- /dev/null
+++ b/src/qml/jsruntime/qv4setiterator_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 QV4SETITERATOR_P_H
+#define QV4SETITERATOR_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 "qv4object_p.h"
+#include "qv4iterator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+
+#define SetIteratorObjectMembers(class, Member) \
+ Member(class, Pointer, Object *, iteratedSet) \
+ Member(class, NoMark, IteratorKind, iterationKind) \
+ Member(class, NoMark, quint32, setNextIndex)
+
+DECLARE_HEAP_OBJECT(SetIteratorObject, Object) {
+ DECLARE_MARKOBJECTS(SetIteratorObject);
+ void init(Object *obj, QV4::ExecutionEngine *engine)
+ {
+ Object::init();
+ this->iteratedSet.set(engine, obj);
+ this->setNextIndex = 0;
+ }
+};
+
+}
+
+struct SetIteratorPrototype : Object
+{
+ V4_PROTOTYPE(iteratorPrototype)
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct SetIteratorObject : Object
+{
+ V4_OBJECT2(SetIteratorObject, Object)
+ Q_MANAGED_TYPE(SetIteratorObject)
+ V4_PROTOTYPE(setIteratorPrototype)
+
+ void init(ExecutionEngine *engine);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4SETITERATOR_P_H
+
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
new file mode 100644
index 0000000000..4245cd2ea3
--- /dev/null
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -0,0 +1,297 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 "qv4setobject_p.h"
+#include "qv4setiterator_p.h"
+#include "qv4symbol_p.h"
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(SetCtor);
+DEFINE_OBJECT_VTABLE(SetObject);
+
+void Heap::SetCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("Set"));
+}
+
+ReturnedValue SetCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ Scope scope(f);
+ Scoped<SetObject> a(scope, scope.engine->memoryManager->allocate<SetObject>());
+ Scoped<ArrayObject> arr(scope, scope.engine->newArrayObject());
+ a->d()->setArray.set(scope.engine, arr->d());
+
+ if (argc > 0) {
+ ScopedValue iterable(scope, argv[0]);
+ if (!iterable->isUndefined() && !iterable->isNull()) {
+ 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));
+ CHECK_EXCEPTION();
+ if (!iter) {
+ return a.asReturnedValue();
+ }
+
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+ forever {
+ done = Runtime::method_iteratorNext(scope.engine, iter, nextValue);
+ CHECK_EXCEPTION();
+ if (done->toBoolean()) {
+ return a.asReturnedValue();
+ }
+
+ adder->call(a, nextValue, 1);
+ if (scope.engine->hasException) {
+ ScopedValue falsey(scope, Encode(false));
+ return Runtime::method_iteratorClose(scope.engine, iter, falsey);
+ }
+ }
+ }
+ }
+
+ return a.asReturnedValue();
+}
+
+ReturnedValue SetCtor::call(const FunctionObject *f, const Value *, const Value *, int)
+{
+ Scope scope(f);
+ return scope.engine->throwTypeError(QString::fromLatin1("Set requires new"));
+}
+
+void SetPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+ ctor->addSymbolSpecies();
+ defineDefaultProperty(engine->id_constructor(), (o = ctor));
+
+ defineDefaultProperty(QStringLiteral("add"), method_add, 1);
+ defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
+ defineDefaultProperty(QStringLiteral("delete"), method_delete, 1);
+ defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
+ defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1);
+ defineDefaultProperty(QStringLiteral("has"), method_has, 1);
+ defineAccessorProperty(QStringLiteral("size"), method_get_size, nullptr);
+
+ // Per the spec, the value for 'keys' is the same as 'values'.
+ ScopedString valString(scope, scope.engine->newIdentifier(QStringLiteral("values")));
+ ScopedFunctionObject valuesFn(scope, FunctionObject::createBuiltinFunction(engine, valString, SetPrototype::method_values, 0));
+ defineDefaultProperty(QStringLiteral("keys"), valuesFn);
+ defineDefaultProperty(QStringLiteral("values"), valuesFn);
+
+ defineDefaultProperty(engine->symbol_iterator(), valuesFn);
+
+ ScopedString val(scope, engine->newString(QLatin1String("Set")));
+ defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val);
+}
+
+ReturnedValue SetPrototype::method_add(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> arr(scope, that->d()->setArray);
+ ScopedValue sk(scope);
+ qint64 len = arr->getLength();
+
+ for (int i = 0; i < len; ++i) {
+ sk = arr->getIndexed(i);
+ if (sk->sameValueZero(argv[0]))
+ return that.asReturnedValue();
+ }
+
+ sk = argv[0];
+ if (sk->isDouble()) {
+ if (sk->doubleValue() == 0 && std::signbit(sk->doubleValue()))
+ sk = Primitive::fromDouble(+0);
+ }
+
+ arr->putIndexed(len, sk);
+ return that.asReturnedValue();
+}
+
+ReturnedValue SetPrototype::method_clear(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> arr(scope, scope.engine->newArrayObject());
+ that->d()->setArray.set(scope.engine, arr->d());
+ return Encode::undefined();
+}
+
+// delete value
+ReturnedValue SetPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> arr(scope, that->d()->setArray);
+ ScopedValue sk(scope);
+ qint64 len = arr->getLength();
+
+ bool found = false;
+ int idx = 0;
+
+ for (; idx < len; ++idx) {
+ sk = arr->getIndexed(idx);
+ if (sk->sameValueZero(argv[0])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == true) {
+ Scoped<ArrayObject> newArr(scope, scope.engine->newArrayObject());
+ for (int j = 0, newIdx = 0; j < len; ++j, newIdx++) {
+ if (j == idx) {
+ newIdx--; // skip the entry
+ continue;
+ }
+ newArr->putIndexed(newIdx, ScopedValue(scope, arr->getIndexed(j)));
+ }
+
+ that->d()->setArray.set(scope.engine, newArr->d());
+ return Encode(true);
+ } else {
+ return Encode(false);
+ }
+}
+
+ReturnedValue SetPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<SetIteratorObject> ao(scope, scope.engine->newSetIteratorObject(that));
+ ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue SetPrototype::method_forEach(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ ScopedFunctionObject callbackfn(scope, argv[0]);
+ if (!callbackfn)
+ return scope.engine->throwTypeError();
+
+ ScopedValue thisArg(scope, Primitive::undefinedValue());
+ if (argc > 1)
+ thisArg = ScopedValue(scope, argv[1]);
+
+ Scoped<ArrayObject> arr(scope, that->d()->setArray);
+ ScopedValue sk(scope);
+ qint64 len = arr->getLength();
+
+ Value *arguments = scope.alloc(3);
+ for (int i = 0; i < len; ++i) {
+ sk = arr->getIndexed(i);
+
+ arguments[0] = sk;
+ arguments[1] = sk;
+ arguments[2] = that;
+ callbackfn->call(thisArg, arguments, 3);
+ CHECK_EXCEPTION();
+ }
+ return Encode::undefined();
+}
+
+ReturnedValue SetPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> arr(scope, that->d()->setArray);
+ ScopedValue sk(scope);
+ qint64 len = arr->getLength();
+
+ for (int i = 0; i < len; ++i) {
+ sk = arr->getIndexed(i);
+ if (sk->sameValueZero(argv[0]))
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
+ReturnedValue SetPrototype::method_get_size(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<ArrayObject> arr(scope, that->d()->setArray);
+ qint64 len = arr->getLength();
+ return Encode((uint)len);
+}
+
+ReturnedValue SetPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<SetObject> that(scope, thisObject);
+ if (!that)
+ return scope.engine->throwTypeError();
+
+ Scoped<SetIteratorObject> ao(scope, scope.engine->newSetIteratorObject(that));
+ ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
diff --git a/src/qml/jsruntime/qv4setobject_p.h b/src/qml/jsruntime/qv4setobject_p.h
new file mode 100644
index 0000000000..ba0ed6bfe7
--- /dev/null
+++ b/src/qml/jsruntime/qv4setobject_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Crimson AS <info@crimson.no>
+** 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 QV4SETOBJECT_P_H
+#define QV4SETOBJECT_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 "qv4object_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4string_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace Heap {
+
+struct SetCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+#define SetObjectMembers(class, Member) \
+ Member(class, Pointer, ArrayObject *, setArray)
+
+DECLARE_HEAP_OBJECT(SetObject, Object) {
+ DECLARE_MARKOBJECTS(SetObject);
+ void init() { Object::init(); }
+};
+
+}
+
+struct SetCtor: FunctionObject
+{
+ V4_OBJECT2(SetCtor, FunctionObject)
+
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct SetObject : Object
+{
+ V4_OBJECT2(SetObject, Object)
+ V4_PROTOTYPE(setPrototype)
+};
+
+struct SetPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_clear(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_size(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+
+} // namespace QV4
+
+
+QT_END_NAMESPACE
+
+#endif // QV4SETOBJECT_P_H
diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp
index 2a3e28bf63..8930c9a94d 100644
--- a/src/qml/jsruntime/qv4sparsearray.cpp
+++ b/src/qml/jsruntime/qv4sparsearray.cpp
@@ -395,7 +395,7 @@ void SparseArray::freeTree(SparseArrayNode *root, int alignment)
SparseArray::SparseArray()
: numEntries(0)
{
- freeList = Primitive::emptyValue(UINT_MAX).asReturnedValue();
+ freeList = Encode(-1);
header.p = 0;
header.left = nullptr;
header.right = nullptr;
diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h
index 51869b259f..c1e50c8dcf 100644
--- a/src/qml/jsruntime/qv4sparsearray_p.h
+++ b/src/qml/jsruntime/qv4sparsearray_p.h
@@ -52,6 +52,7 @@
//
#include "qv4global_p.h"
+#include "qv4value_p.h"
#include <QtCore/qlist.h>
//#define Q_MAP_DEBUG
@@ -151,7 +152,7 @@ struct Q_QML_EXPORT SparseArray
SparseArray(const SparseArray &other);
- ReturnedValue freeList;
+ Value freeList;
private:
SparseArray &operator=(const SparseArray &other);
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 447992ebec..27c73a2b77 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -52,8 +52,17 @@ using namespace QV4;
#ifndef V4_BOOTSTRAP
+void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack)
+{
+ StringOrSymbol *s = static_cast<StringOrSymbol *>(that);
+ Heap::Base *id = s->identifier.asHeapObject();
+ if (id)
+ id->mark(markStack);
+}
+
void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
{
+ StringOrSymbol::markObjects(that, markStack);
String *s = static_cast<String *>(that);
if (s->subtype < StringType_Complex)
return;
@@ -68,6 +77,7 @@ void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack)
}
}
+DEFINE_MANAGED_VTABLE(StringOrSymbol);
DEFINE_MANAGED_VTABLE(String);
@@ -76,7 +86,7 @@ bool String::isEqualTo(Managed *t, Managed *o)
if (t == o)
return true;
- if (!o->d()->vtable()->isString)
+ if (!o->vtable()->isString)
return false;
return static_cast<String *>(t)->isEqualTo(static_cast<String *>(o));
@@ -128,7 +138,8 @@ void Heap::ComplexString::init(Heap::String *ref, int from, int len)
this->len = len;
}
-void Heap::String::destroy() {
+void Heap::StringOrSymbol::destroy()
+{
if (text) {
internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
if (!text->ref.deref())
@@ -174,7 +185,7 @@ void Heap::String::simplifyString() const
text = result.data_ptr();
text->ref.ref();
const ComplexString *cs = static_cast<const ComplexString *>(this);
- identifier = nullptr;
+ identifier = Identifier::invalid();
cs->left = cs->right = nullptr;
internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
@@ -227,10 +238,12 @@ void Heap::String::append(const String *data, QChar *ch)
}
}
-void Heap::String::createHashValue() const
+void Heap::StringOrSymbol::createHashValue() const
{
- if (!text)
- simplifyString();
+ if (!text) {
+ Q_ASSERT(internalClass->vtable->isString);
+ static_cast<const Heap::String *>(this)->simplifyString();
+ }
Q_ASSERT(text);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
@@ -248,4 +261,3 @@ 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 5466cc274d..0deb542ea2 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -64,9 +64,10 @@ struct Identifier;
namespace Heap {
-struct Q_QML_PRIVATE_EXPORT String : Base {
- static void markObjects(Heap::Base *that, MarkStack *markStack);
+struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
+{
enum StringType {
+ StringType_Symbol,
StringType_Regular,
StringType_ArrayIndex,
StringType_Unknown,
@@ -75,13 +76,20 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
StringType_Complex = StringType_AddedString
};
-#ifndef V4_BOOTSTRAP
- void init(const QString &text);
+ mutable QStringData *text;
+ mutable Identifier identifier;
+ mutable uint subtype;
+ mutable uint stringHash;
+
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
void destroy();
- void simplifyString() const;
- int length() const;
- std::size_t retainedTextSize() const {
- return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar));
+
+ inline QString toQString() const {
+ if (!text)
+ return QString();
+ QStringDataPtr ptr = { text };
+ text->ref.ref();
+ return QString(ptr);
}
void createHashValue() const;
inline unsigned hashValue() const {
@@ -91,6 +99,22 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
return stringHash;
}
+};
+
+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;
+ }
+
+ void init(const QString &text);
+ void simplifyString() const;
+ int length() const;
+ std::size_t retainedTextSize() const {
+ return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar));
+ }
inline QString toQString() const {
if (subtype >= StringType_Complex)
simplifyString();
@@ -104,7 +128,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
if (hashValue() != other->hashValue())
return false;
Q_ASSERT(subtype < StringType_Complex);
- if (identifier && identifier == other->identifier)
+ if (identifier.isValid() && identifier == other->identifier)
return true;
if (subtype == Heap::String::StringType_ArrayIndex && other->subtype == Heap::String::StringType_ArrayIndex)
return true;
@@ -114,10 +138,6 @@ struct Q_QML_PRIVATE_EXPORT String : Base {
bool startsWithUpper() const;
- mutable QStringData *text;
- mutable Identifier *identifier;
- mutable uint subtype;
- mutable uint stringHash;
private:
static void append(const String *data, QChar *ch);
#endif
@@ -146,9 +166,27 @@ int String::length() const {
}
-struct Q_QML_PRIVATE_EXPORT String : public Managed {
+struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
#ifndef V4_BOOTSTRAP
- V4_MANAGED(String, Managed)
+ V4_MANAGED(StringOrSymbol, Managed)
+ enum {
+ IsStringOrSymbol = true
+ };
+
+ inline void makeIdentifier() const;
+ Identifier identifier() const { return d()->identifier; }
+
+ uint asArrayIndex() const;
+
+ 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)
V4_NEEDS_DESTROY
@@ -187,12 +225,6 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
}
uint toUInt(bool *ok) const;
- void makeIdentifier() const {
- if (d()->identifier)
- return;
- makeIdentifierImpl();
- }
-
// slow path
Q_NEVER_INLINE void makeIdentifierImpl() const;
@@ -210,8 +242,6 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
bool startsWithUpper() const { return d()->startsWithUpper(); }
- Identifier *identifier() const { return d()->identifier; }
-
protected:
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
@@ -254,7 +284,7 @@ public:
uint h = toArrayIndex(ch, end);
if (h != UINT_MAX) {
if (subtype)
- *subtype = Heap::String::StringType_ArrayIndex;
+ *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
return h;
}
@@ -264,7 +294,7 @@ public:
}
if (subtype)
- *subtype = Heap::String::StringType_Regular;
+ *subtype = (toUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
return h;
}
};
@@ -280,9 +310,29 @@ struct ComplexString : String {
}
};
+inline
+void StringOrSymbol::makeIdentifier() const {
+ if (d()->identifier.isValid())
+ return;
+ Q_ASSERT(isString());
+ static_cast<const String *>(this)->makeIdentifierImpl();
+}
+
+inline
+uint StringOrSymbol::asArrayIndex() const {
+ if (isString())
+ return static_cast<const String *>(this)->asArrayIndex();
+ return UINT_MAX;
+}
+
+template<>
+inline const StringOrSymbol *Value::as() const {
+ return isManaged() && m()->internalClass->vtable->isStringOrSymbol ? static_cast<const String *>(this) : nullptr;
+}
+
template<>
inline const String *Value::as() const {
- return isManaged() && m()->vtable()->isString ? static_cast<const String *>(this) : nullptr;
+ return isManaged() && m()->internalClass->vtable->isString ? static_cast<const String *>(this) : nullptr;
}
template<>
diff --git a/src/qml/jsruntime/qv4stringiterator.cpp b/src/qml/jsruntime/qv4stringiterator.cpp
new file mode 100644
index 0000000000..810ed333e4
--- /dev/null
+++ b/src/qml/jsruntime/qv4stringiterator.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
+** 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 <private/qv4iterator_p.h>
+#include <private/qv4stringiterator_p.h>
+#include <private/qv4symbol_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(StringIteratorObject);
+
+void StringIteratorPrototype::init(ExecutionEngine *e)
+{
+ defineDefaultProperty(QStringLiteral("next"), method_next, 0);
+
+ Scope scope(e);
+ ScopedString val(scope, e->newString(QLatin1String("String Iterator")));
+ defineReadonlyConfigurableProperty(e->symbol_toStringTag(), val);
+}
+
+ReturnedValue StringIteratorPrototype::method_next(const FunctionObject *b, const Value *that, const Value *, int)
+{
+ Scope scope(b);
+ const StringIteratorObject *thisObject = that->as<StringIteratorObject>();
+ if (!thisObject)
+ return scope.engine->throwTypeError(QLatin1String("Not an String Iterator instance"));
+
+ ScopedString s(scope, thisObject->d()->iteratedString);
+ if (!s) {
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ quint32 index = thisObject->d()->nextIndex;
+
+ QString str = s->toQString();
+ quint32 len = str.length();
+
+ if (index >= len) {
+ thisObject->d()->iteratedString.set(scope.engine, nullptr);
+ QV4::Value undefined = Primitive::undefinedValue();
+ return IteratorPrototype::createIterResultObject(scope.engine, undefined, true);
+ }
+
+ QChar ch = str.at(index);
+ int num = 1;
+ if (ch.unicode() >= 0xd800 && ch.unicode() <= 0xdbff && index + 1 != len) {
+ ch = str.at(index + 1);
+ if (ch.unicode() >= 0xdc00 && ch.unicode() <= 0xdfff)
+ num = 2;
+ }
+
+ thisObject->d()->nextIndex += num;
+
+ ScopedString resultString(scope, scope.engine->newString(s->toQString().mid(index, num)));
+ return IteratorPrototype::createIterResultObject(scope.engine, resultString, false);
+}
+
diff --git a/src/qml/jsruntime/qv4stringiterator_p.h b/src/qml/jsruntime/qv4stringiterator_p.h
new file mode 100644
index 0000000000..672ccc9963
--- /dev/null
+++ b/src/qml/jsruntime/qv4stringiterator_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 QV4STRINGITERATOR_P_H
+#define QV4STRINGITERATOR_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 "qv4object_p.h"
+#include "qv4string_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace QV4 {
+
+namespace Heap {
+
+#define StringIteratorObjectMembers(class, Member) \
+ Member(class, Pointer, String *, iteratedString) \
+ Member(class, NoMark, quint32, nextIndex)
+
+DECLARE_HEAP_OBJECT(StringIteratorObject, Object) {
+ DECLARE_MARKOBJECTS(StringIteratorObject);
+ void init(String *str, QV4::ExecutionEngine *engine)
+ {
+ Object::init();
+ this->iteratedString.set(engine, str);
+ this->nextIndex = 0;
+ }
+};
+
+}
+
+struct StringIteratorPrototype : Object
+{
+ V4_PROTOTYPE(iteratorPrototype)
+ void init(ExecutionEngine *engine);
+
+ static ReturnedValue method_next(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct StringIteratorObject : Object
+{
+ V4_OBJECT2(StringIteratorObject, Object)
+ Q_MANAGED_TYPE(StringIteratorObject)
+ V4_PROTOTYPE(stringIteratorPrototype)
+
+ void init(ExecutionEngine *engine);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ARRAYITERATOR_P_H
+
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 61176b3706..3639edac17 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -44,8 +44,10 @@
#include "qv4objectproto_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
+#include "qv4symbol_p.h"
#include "qv4alloca_p.h"
#include "qv4jscall_p.h"
+#include "qv4stringiterator_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QStringList>
@@ -152,16 +154,58 @@ ReturnedValue StringCtor::callAsConstructor(const FunctionObject *f, const Value
value = argv[0].toString(v4);
else
value = v4->newString();
+ CHECK_EXCEPTION();
return Encode(v4->newStringObject(value));
}
ReturnedValue StringCtor::call(const FunctionObject *m, const Value *, const Value *argv, int argc)
{
ExecutionEngine *v4 = m->engine();
- if (argc)
- return argv[0].toString(v4)->asReturnedValue();
- else
+ if (!argc)
return v4->newString()->asReturnedValue();
+ if (argv[0].isSymbol())
+ return v4->newString(argv[0].symbolValue()->descriptiveString())->asReturnedValue();
+ return argv[0].toString(v4)->asReturnedValue();
+}
+
+ReturnedValue StringCtor::method_fromCharCode(const FunctionObject *b, const Value *, const Value *argv, int argc)
+{
+ QString str(argc, Qt::Uninitialized);
+ QChar *ch = str.data();
+ for (int i = 0, ei = argc; i < ei; ++i) {
+ *ch = QChar(argv[i].toUInt16());
+ ++ch;
+ }
+ *ch = 0;
+ return Encode(b->engine()->newString(str));
+}
+
+
+
+ReturnedValue StringCtor::method_fromCodePoint(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ ExecutionEngine *e = f->engine();
+ QString result(argc*2, Qt::Uninitialized); // assume worst case
+ QChar *ch = result.data();
+ for (int i = 0; i < argc; ++i) {
+ double num = argv[i].toNumber();
+ if (e->hasException)
+ return Encode::undefined();
+ int cp = static_cast<int>(num);
+ if (cp != num || cp < 0 || cp > 0x10ffff)
+ return e->throwRangeError(QStringLiteral("String.fromCodePoint: argument out of range."));
+ if (cp > 0xffff) {
+ *ch = QChar::highSurrogate(cp);
+ ++ch;
+ *ch = QChar::lowSurrogate(cp);
+ } else {
+ *ch = cp;
+ }
+ ++ch;
+ }
+ *ch = 0;
+ result.truncate(ch - result.constData());
+ return e->newString(result)->asReturnedValue();
}
void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -169,15 +213,23 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
+ // need to set this once again, as these were not fully defined when creating the string proto
+ Heap::InternalClass *ic = scope.engine->classes[ExecutionEngine::Class_StringObject]->changePrototype(scope.engine->objectPrototype()->d());
+ d()->internalClass.set(scope.engine, ic);
+ d()->string.set(scope.engine, scope.engine->id_empty()->d());
+ setProperty(scope.engine, Heap::StringObject::LengthPropertyIndex, Primitive::fromInt32(0));
+
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
- ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), method_fromCharCode, 1);
+ ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), StringCtor::method_fromCharCode, 1);
+ ctor->defineDefaultProperty(QStringLiteral("fromCodePoint"), StringCtor::method_fromCodePoint, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString);
defineDefaultProperty(engine->id_valueOf(), method_toString); // valueOf and toString are identical
defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1);
defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1);
+ defineDefaultProperty(QStringLiteral("codePointAt"), method_codePointAt, 1);
defineDefaultProperty(QStringLiteral("concat"), method_concat, 1);
defineDefaultProperty(QStringLiteral("endsWith"), method_endsWith, 1);
defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
@@ -185,6 +237,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(QStringLiteral("normalize"), method_normalize, 0);
+ defineDefaultProperty(QStringLiteral("padEnd"), method_padEnd, 1);
+ defineDefaultProperty(QStringLiteral("padStart"), method_padStart, 1);
defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1);
defineDefaultProperty(QStringLiteral("replace"), method_replace, 2);
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
@@ -198,6 +253,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toUpperCase"), method_toUpperCase);
defineDefaultProperty(QStringLiteral("toLocaleUpperCase"), method_toLocaleUpperCase);
defineDefaultProperty(QStringLiteral("trim"), method_trim);
+ defineDefaultProperty(engine->symbol_iterator(), method_iterator);
}
static Heap::String *thisAsString(ExecutionEngine *v4, const QV4::Value *thisObject)
@@ -270,6 +326,29 @@ ReturnedValue StringPrototype::method_charCodeAt(const FunctionObject *b, const
return Encode(qt_qnan());
}
+ReturnedValue StringPrototype::method_codePointAt(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = f->engine();
+ QString value = getThisString(v4, thisObject);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+
+ int index = argc ? argv[0].toInteger() : 0;
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+
+ if (index < 0 || index >= value.size())
+ return Encode::undefined();
+
+ uint first = value.at(index).unicode();
+ if (QChar::isHighSurrogate(first) && index + 1 < value.size()) {
+ uint second = value.at(index + 1).unicode();
+ if (QChar::isLowSurrogate(second))
+ return Encode(QChar::surrogateToUcs4(first, second));
+ }
+ return Encode(first);
+}
+
ReturnedValue StringPrototype::method_concat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
ExecutionEngine *v4 = b->engine();
@@ -298,12 +377,11 @@ ReturnedValue StringPrototype::method_endsWith(const FunctionObject *b, const Va
if (v4->hasException)
return QV4::Encode::undefined();
- QString searchString;
- if (argc) {
- if (argv[0].as<RegExpObject>())
- return v4->throwTypeError();
- searchString = argv[0].toQString();
- }
+ if (argc && argv[0].as<RegExpObject>())
+ return v4->throwTypeError();
+ QString searchString = (argc ? argv[0] : Primitive::undefinedValue()).toQString();
+ if (v4->hasException)
+ return Encode::undefined();
int pos = value.length();
if (argc > 1)
@@ -323,9 +401,9 @@ ReturnedValue StringPrototype::method_indexOf(const FunctionObject *b, const Val
if (v4->hasException)
return QV4::Encode::undefined();
- QString searchString;
- if (argc)
- searchString = argv[0].toQString();
+ QString searchString = (argc ? argv[0] : Primitive::undefinedValue()).toQString();
+ if (v4->hasException)
+ return Encode::undefined();
int pos = 0;
if (argc > 1)
@@ -345,12 +423,11 @@ ReturnedValue StringPrototype::method_includes(const FunctionObject *b, const Va
if (v4->hasException)
return QV4::Encode::undefined();
- QString searchString;
- if (argc) {
- if (argv[0].as<RegExpObject>())
- return v4->throwTypeError();
- searchString = argv[0].toQString();
- }
+ if (argc && argv[0].as<RegExpObject>())
+ return v4->throwTypeError();
+ QString searchString = (argc ? argv[0] : Primitive::undefinedValue()).toQString();
+ if (v4->hasException)
+ return Encode::undefined();
int pos = 0;
if (argc > 1) {
@@ -374,9 +451,9 @@ ReturnedValue StringPrototype::method_lastIndexOf(const FunctionObject *b, const
if (v4->hasException)
return QV4::Encode::undefined();
- QString searchString;
- if (argc)
- searchString = argv[0].toQString();
+ QString searchString = (argc ? argv[0] : Primitive::undefinedValue()).toQString();
+ if (v4->hasException)
+ return Encode::undefined();
double position = argc > 1 ? RuntimeHelpers::toNumber(argv[1]) : +qInf();
if (std::isnan(position))
@@ -455,6 +532,115 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
return a.asReturnedValue();
}
+ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = f->engine();
+ const QString value = getThisString(v4, thisObject);
+ if (v4->hasException)
+ return Encode::undefined();
+
+ QString::NormalizationForm form = QString::NormalizationForm_C;
+ if (argc >= 1 && !argv[0].isUndefined()) {
+ QString f = argv[0].toQString();
+ if (v4->hasException)
+ return Encode::undefined();
+ if (f == QLatin1String("NFC"))
+ form = QString::NormalizationForm_C;
+ else if (f == QLatin1String("NFD"))
+ form = QString::NormalizationForm_D;
+ else if (f == QLatin1String("NFKC"))
+ form = QString::NormalizationForm_KC;
+ else if (f == QLatin1String("NFKD"))
+ form = QString::NormalizationForm_KD;
+ else
+ return v4->throwRangeError(QLatin1String("String.prototype.normalize: Invalid normalization form."));
+ }
+ QString normalized = value.normalized(form);
+ return v4->newString(normalized)->asReturnedValue();
+}
+
+ReturnedValue StringPrototype::method_padEnd(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = f->engine();
+ if (thisObject->isNullOrUndefined())
+ return v4->throwTypeError();
+
+ Scope scope(v4);
+ ScopedString s(scope, thisAsString(v4, thisObject));
+ if (v4->hasException)
+ return Encode::undefined();
+ if (!argc)
+ return s->asReturnedValue();
+
+ int maxLen = argv[0].toInteger();
+ if (maxLen <= s->d()->length())
+ return s->asReturnedValue();
+ QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : QString::fromLatin1(" ");
+ if (v4->hasException)
+ return Encode::undefined();
+
+ if (fillString.isEmpty())
+ return s->asReturnedValue();
+
+ QString padded = s->toQString();
+ int oldLength = padded.length();
+ int toFill = maxLen - oldLength;
+ padded.resize(maxLen);
+ QChar *ch = padded.data() + oldLength;
+ while (toFill) {
+ int copy = qMin(fillString.length(), toFill);
+ memcpy(ch, fillString.constData(), copy*sizeof(QChar));
+ toFill -= copy;
+ ch += copy;
+ }
+ *ch = 0;
+
+ return v4->newString(padded)->asReturnedValue();
+}
+
+ReturnedValue StringPrototype::method_padStart(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = f->engine();
+ if (thisObject->isNullOrUndefined())
+ return v4->throwTypeError();
+
+ Scope scope(v4);
+ ScopedString s(scope, thisAsString(v4, thisObject));
+ if (v4->hasException)
+ return Encode::undefined();
+ if (!argc)
+ return s->asReturnedValue();
+
+ int maxLen = argv[0].toInteger();
+ if (maxLen <= s->d()->length())
+ return s->asReturnedValue();
+ QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : QString::fromLatin1(" ");
+ if (v4->hasException)
+ return Encode::undefined();
+
+ if (fillString.isEmpty())
+ return s->asReturnedValue();
+
+ QString original = s->toQString();
+ int oldLength = original.length();
+ int toFill = maxLen - oldLength;
+ QString padded;
+ padded.resize(maxLen);
+ QChar *ch = padded.data();
+ while (toFill) {
+ int copy = qMin(fillString.length(), toFill);
+ memcpy(ch, fillString.constData(), copy*sizeof(QChar));
+ toFill -= copy;
+ ch += copy;
+ }
+ memcpy(ch, original.constData(), oldLength*sizeof(QChar));
+ ch += oldLength;
+ *ch = 0;
+
+ return v4->newString(padded)->asReturnedValue();
+}
+
+
ReturnedValue StringPrototype::method_repeat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
ExecutionEngine *v4 = b->engine();
@@ -777,12 +963,11 @@ ReturnedValue StringPrototype::method_startsWith(const FunctionObject *b, const
if (v4->hasException)
return QV4::Encode::undefined();
- QString searchString;
- if (argc) {
- if (argv[0].as<RegExpObject>())
- return v4->throwTypeError();
- searchString = argv[0].toQString();
- }
+ if (argc && argv[0].as<RegExpObject>())
+ return v4->throwTypeError();
+ QString searchString = (argc ? argv[0] : Primitive::undefinedValue()).toQString();
+ if (v4->hasException)
+ return Encode::undefined();
int pos = 0;
if (argc > 1)
@@ -892,17 +1077,6 @@ ReturnedValue StringPrototype::method_toLocaleUpperCase(const FunctionObject *b,
return method_toUpperCase(b, thisObject, argv, argc);
}
-ReturnedValue StringPrototype::method_fromCharCode(const FunctionObject *b, const Value *, const Value *argv, int argc)
-{
- QString str(argc, Qt::Uninitialized);
- QChar *ch = str.data();
- for (int i = 0, ei = argc; i < ei; ++i) {
- *ch = QChar(argv[i].toUInt16());
- ++ch;
- }
- return Encode(b->engine()->newString(str));
-}
-
ReturnedValue StringPrototype::method_trim(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
@@ -923,3 +1097,16 @@ ReturnedValue StringPrototype::method_trim(const FunctionObject *b, const Value
return Encode(v4->newString(QString(chars + start, end - start + 1)));
}
+
+
+
+ReturnedValue StringPrototype::method_iterator(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedString s(scope, thisObject->toString(scope.engine));
+ if (!s || thisObject->isNullOrUndefined())
+ return scope.engine->throwTypeError();
+
+ Scoped<StringIteratorObject> si(scope, scope.engine->memoryManager->allocate<StringIteratorObject>(s->d(), scope.engine));
+ return si->asReturnedValue();
+}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 7d25678b61..407d617d57 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -70,6 +70,8 @@ DECLARE_HEAP_OBJECT(StringObject, Object) {
LengthPropertyIndex = 0
};
+ void init(bool /*don't init*/)
+ { Object::init(); }
void init();
void init(const QV4::String *string);
@@ -108,6 +110,9 @@ struct StringCtor: FunctionObject
static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue method_fromCharCode(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_fromCodePoint(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct StringPrototype: StringObject
@@ -118,6 +123,7 @@ struct StringPrototype: StringObject
static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_charAt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_charCodeAt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_codePointAt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_concat(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_endsWith(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_indexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -125,6 +131,9 @@ struct StringPrototype: StringObject
static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_localeCompare(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_match(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_normalize(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_padEnd(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_padStart(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_repeat(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_replace(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_search(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -137,8 +146,8 @@ struct StringPrototype: StringObject
static ReturnedValue method_toLocaleLowerCase(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toUpperCase(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_toLocaleUpperCase(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_fromCharCode(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_trim(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_iterator(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
}
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
new file mode 100644
index 0000000000..7bb33dce69
--- /dev/null
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** 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 <qv4symbol_p.h>
+#include <qv4functionobject_p.h>
+#include <qv4identifiertable_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(SymbolCtor);
+DEFINE_MANAGED_VTABLE(Symbol);
+DEFINE_OBJECT_VTABLE(SymbolObject);
+
+void Heap::Symbol::init(const QString &s)
+{
+ Q_ASSERT(s.at(0) == QLatin1Char('@'));
+ identifier = Identifier::fromHeapObject(this);
+ QString desc(s);
+ text = desc.data_ptr();
+ text->ref.ref();
+}
+
+void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
+}
+
+void Heap::SymbolObject::init(const QV4::Symbol *s)
+{
+ Object::init();
+ symbol.set(internalClass->engine, s->d());
+}
+
+ReturnedValue QV4::SymbolCtor::call(const QV4::FunctionObject *f, const QV4::Value *, const QV4::Value *argv, int argc)
+{
+ Scope scope(f);
+ QString desc = QChar::fromLatin1('@');
+ if (argc && !argv[0].isUndefined()) {
+ ScopedString s(scope, argv[0].toString(scope.engine));
+ if (scope.hasException())
+ return Encode::undefined();
+ desc += s->toQString();
+ }
+ return Symbol::create(scope.engine, desc)->asReturnedValue();
+}
+
+ReturnedValue SymbolCtor::method_for(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ScopedValue k(scope, argc ? argv[0]: Primitive::undefinedValue());
+ ScopedString key(scope, k->toString(scope.engine));
+ if (scope.hasException())
+ return Encode::undefined();
+ QString desc = QLatin1Char('@') + key->toQString();
+ return scope.engine->identifierTable->insertSymbol(desc)->asReturnedValue();
+}
+
+ReturnedValue SymbolCtor::method_keyFor(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ ExecutionEngine *e = f->engine();
+ if (!argc || !argv[0].isSymbol())
+ return e->throwTypeError(QLatin1String("Symbol.keyFor: Argument is not a symbol."));
+ const Symbol &arg = static_cast<const Symbol &>(argv[0]);
+ Heap::Symbol *s = e->identifierTable->symbolForId(arg.identifier());
+ Q_ASSERT(!s || s == arg.d());
+ if (s)
+ return e->newString(arg.toQString().mid((1)))->asReturnedValue();
+ return Encode::undefined();
+}
+
+void SymbolPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedValue v(scope);
+ ctor->defineReadonlyProperty(engine->id_prototype(), (v = this));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+
+ ctor->defineDefaultProperty(QStringLiteral("for"), SymbolCtor::method_for, 1);
+ ctor->defineDefaultProperty(QStringLiteral("keyFor"), SymbolCtor::method_keyFor, 1);
+ ctor->defineReadonlyProperty(QStringLiteral("hasInstance"), *engine->symbol_hasInstance());
+ ctor->defineReadonlyProperty(QStringLiteral("isConcatSpreadable"), *engine->symbol_isConcatSpreadable());
+ ctor->defineReadonlyProperty(QStringLiteral("iterator"), *engine->symbol_iterator());
+ ctor->defineReadonlyProperty(QStringLiteral("match"), *engine->symbol_match());
+ ctor->defineReadonlyProperty(QStringLiteral("replace"), *engine->symbol_replace());
+ ctor->defineReadonlyProperty(QStringLiteral("search"), *engine->symbol_search());
+ ctor->defineReadonlyProperty(QStringLiteral("species"), *engine->symbol_species());
+ ctor->defineReadonlyProperty(QStringLiteral("split"), *engine->symbol_split());
+ ctor->defineReadonlyProperty(QStringLiteral("toPrimitive"), *engine->symbol_toPrimitive());
+ ctor->defineReadonlyProperty(QStringLiteral("toStringTag"), *engine->symbol_toStringTag());
+ ctor->defineReadonlyProperty(QStringLiteral("unscopables"), *engine->symbol_unscopables());
+
+ defineDefaultProperty(QStringLiteral("constructor"), (v = ctor));
+ defineDefaultProperty(QStringLiteral("toString"), method_toString);
+ defineDefaultProperty(QStringLiteral("valueOf"), method_valueOf);
+ defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable);
+
+ v = engine->newString(QStringLiteral("Symbol"));
+ defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), v);
+
+}
+
+ReturnedValue SymbolPrototype::method_toString(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<Symbol> s(scope, thisObject->as<Symbol>());
+ if (!s) {
+ if (const SymbolObject *o = thisObject->as<SymbolObject>())
+ s = o->d()->symbol;
+ else
+ return scope.engine->throwTypeError();
+ }
+ return scope.engine->newString(s->descriptiveString())->asReturnedValue();
+}
+
+ReturnedValue SymbolPrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ Scope scope(f);
+ Scoped<Symbol> s(scope, thisObject->as<Symbol>());
+ if (!s) {
+ if (const SymbolObject *o = thisObject->as<SymbolObject>())
+ s = o->d()->symbol;
+ else
+ return scope.engine->throwTypeError();
+ }
+ return s->asReturnedValue();
+}
+
+ReturnedValue SymbolPrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ if (thisObject->isSymbol())
+ return thisObject->asReturnedValue();
+ if (const SymbolObject *o = thisObject->as<SymbolObject>())
+ return o->d()->symbol->asReturnedValue();
+ return f->engine()->throwTypeError();
+}
+
+Heap::Symbol *Symbol::create(ExecutionEngine *e, const QString &s)
+{
+ Q_ASSERT(s.at(0) == QLatin1Char('@'));
+ return e->memoryManager->alloc<Symbol>(s);
+}
+
+QString Symbol::descriptiveString() const
+{
+ return QLatin1String("Symbol(") + toQString().midRef(1) + QLatin1String(")");
+}
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
new file mode 100644
index 0000000000..3cf6bc5dde
--- /dev/null
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 QV4_SYMBOL_H
+#define QV4_SYMBOL_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 "qv4string_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace QV4 {
+
+namespace Heap {
+
+struct SymbolCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct Symbol : StringOrSymbol {
+ void init(const QString &s);
+};
+
+#define SymbolObjectMembers(class, Member) \
+ Member(class, Pointer, Symbol *, symbol)
+
+DECLARE_HEAP_OBJECT(SymbolObject, Object) {
+ DECLARE_MARKOBJECTS(SymbolObject);
+ void init(const QV4::Symbol *s);
+};
+
+}
+
+struct SymbolCtor : FunctionObject
+{
+ V4_OBJECT2(SymbolCtor, FunctionObject)
+
+ static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_for(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_keyFor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct SymbolPrototype : Object
+{
+ V4_PROTOTYPE(objectPrototype)
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue method_symbolToPrimitive(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct Symbol : StringOrSymbol
+{
+ V4_MANAGED(Symbol, StringOrSymbol)
+ Q_MANAGED_TYPE(Symbol)
+ V4_INTERNALCLASS(Symbol)
+ V4_NEEDS_DESTROY
+
+ static Heap::Symbol *create(ExecutionEngine *e, const QString &s);
+
+ QString descriptiveString() const;
+};
+
+struct SymbolObject : Object
+{
+ V4_OBJECT2(SymbolObject, Object)
+ Q_MANAGED_TYPE(SymbolObject)
+ V4_INTERNALCLASS(SymbolObject)
+ V4_PROTOTYPE(symbolPrototype)
+
+ static bool put(Managed *, StringOrSymbol *, const Value &) { return false; }
+ static bool putIndexed(Managed *, uint, const Value &) { return false; }
+
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index ea1532b8ce..3eadfe04a6 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -36,15 +36,20 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
#include "qv4typedarray_p.h"
+#include "qv4arrayiterator_p.h"
#include "qv4arraybuffer_p.h"
#include "qv4string_p.h"
#include "qv4jscall_p.h"
+#include "qv4symbol_p.h"
#include <cmath>
using namespace QV4;
+DEFINE_OBJECT_VTABLE(IntrinsicTypedArrayCtor);
+DEFINE_OBJECT_VTABLE(IntrinsicTypedArrayPrototype);
DEFINE_OBJECT_VTABLE(TypedArrayCtor);
DEFINE_OBJECT_VTABLE(TypedArrayPrototype);
DEFINE_OBJECT_VTABLE(TypedArray);
@@ -216,9 +221,12 @@ ReturnedValue TypedArrayCtor::callAsConstructor(const FunctionObject *f, const V
if (!argc || !argv[0].isObject()) {
// ECMA 6 22.2.1.1
- double l = argc ? argv[0].toNumber() : 0;
+ qint64 l = argc ? argv[0].toIndex() : 0;
if (scope.engine->hasException)
return Encode::undefined();
+ // ### lift UINT_MAX restriction
+ if (l < 0 || l > UINT_MAX)
+ return scope.engine->throwRangeError(QLatin1String("Index out of range."));
uint len = (uint)l;
if (l != len)
scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array."));
@@ -312,7 +320,10 @@ ReturnedValue TypedArrayCtor::callAsConstructor(const FunctionObject *f, const V
return scope.engine->throwTypeError();
uint elementSize = operations[that->d()->type].bytesPerElement;
- Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize));
+ size_t bufferSize;
+ if (mul_overflow(size_t(l), size_t(elementSize), &bufferSize))
+ return scope.engine->throwRangeError(QLatin1String("new TypedArray: invalid length"));
+ Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(bufferSize));
if (scope.engine->hasException)
return Encode::undefined();
@@ -337,9 +348,9 @@ ReturnedValue TypedArrayCtor::callAsConstructor(const FunctionObject *f, const V
return array.asReturnedValue();
}
-ReturnedValue TypedArrayCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
+ReturnedValue TypedArrayCtor::call(const FunctionObject *f, const Value *, const Value *, int)
{
- return callAsConstructor(f, argv, argc);
+ return f->engine()->throwTypeError(QStringLiteral("calling a TypedArray constructor without new is invalid"));
}
void Heap::TypedArray::init(Type t)
@@ -351,9 +362,9 @@ void Heap::TypedArray::init(Type t)
Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t)
{
- QV4::InternalClass *ic = e->internalClasses[EngineBase::Class_Empty]->changeVTable(staticVTable());
- ic = ic->changePrototype(e->typedArrayPrototype[t].d());
- return e->memoryManager->allocObject<TypedArray>(ic, e->typedArrayPrototype + t, t);
+ Scope scope(e);
+ Scoped<InternalClass> ic(scope, e->newInternalClass(staticVTable(), e->typedArrayPrototype + t));
+ return e->memoryManager->allocObject<TypedArray>(ic->d(), t);
}
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
@@ -395,21 +406,18 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(3));
- ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(3));
+ ctor->defineReadonlyProperty(engine->id_prototype(), *this);
ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement));
+ ctor->setPrototype(engine->intrinsicTypedArrayCtor());
+
+ setPrototype(engine->intrinsicTypedArrayPrototype());
defineDefaultProperty(engine->id_constructor(), (o = ctor));
- defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
- defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
- defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr);
- defineAccessorProperty(QStringLiteral("length"), method_get_length, nullptr);
defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement));
-
- defineDefaultProperty(QStringLiteral("set"), method_set, 1);
- defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0);
}
-ReturnedValue TypedArrayPrototype::method_get_buffer(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue IntrinsicTypedArrayPrototype::method_get_buffer(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
const TypedArray *v = thisObject->as<TypedArray>();
@@ -419,7 +427,7 @@ ReturnedValue TypedArrayPrototype::method_get_buffer(const FunctionObject *b, co
return v->d()->buffer->asReturnedValue();
}
-ReturnedValue TypedArrayPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue IntrinsicTypedArrayPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
const TypedArray *v = thisObject->as<TypedArray>();
@@ -429,7 +437,7 @@ ReturnedValue TypedArrayPrototype::method_get_byteLength(const FunctionObject *b
return Encode(v->d()->byteLength);
}
-ReturnedValue TypedArrayPrototype::method_get_byteOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue IntrinsicTypedArrayPrototype::method_get_byteOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
const TypedArray *v = thisObject->as<TypedArray>();
@@ -439,7 +447,7 @@ ReturnedValue TypedArrayPrototype::method_get_byteOffset(const FunctionObject *b
return Encode(v->d()->byteOffset);
}
-ReturnedValue TypedArrayPrototype::method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue IntrinsicTypedArrayPrototype::method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
const TypedArray *v = thisObject->as<TypedArray>();
@@ -449,7 +457,43 @@ ReturnedValue TypedArrayPrototype::method_get_length(const FunctionObject *b, co
return Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
}
-ReturnedValue TypedArrayPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue IntrinsicTypedArrayPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<TypedArray> O(scope, thisObject);
+ if (!O)
+ THROW_TYPE_ERROR();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue IntrinsicTypedArrayPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<TypedArray> O(scope, thisObject);
+ if (!O)
+ THROW_TYPE_ERROR();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::KeyIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue IntrinsicTypedArrayPrototype::method_values(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<TypedArray> O(scope, thisObject);
+ if (!O)
+ THROW_TYPE_ERROR();
+
+ Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(O));
+ ao->d()->iterationKind = IteratorKind::ValueIteratorKind;
+ return ao->asReturnedValue();
+}
+
+ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
Scoped<TypedArray> a(scope, *thisObject);
@@ -538,7 +582,7 @@ ReturnedValue TypedArrayPrototype::method_set(const FunctionObject *b, const Val
RETURN_UNDEFINED();
}
-ReturnedValue TypedArrayPrototype::method_subarray(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue IntrinsicTypedArrayPrototype::method_subarray(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(builtin);
Scoped<TypedArray> a(scope, *thisObject);
@@ -578,3 +622,47 @@ ReturnedValue TypedArrayPrototype::method_subarray(const FunctionObject *builtin
arguments[2] = Encode(newLen);
return constructor->callAsConstructor(arguments, 3);
}
+
+ReturnedValue IntrinsicTypedArrayPrototype::method_get_toStringTag(const FunctionObject *, const Value *thisObject, const Value *, int)
+{
+ const TypedArray *a = thisObject->as<TypedArray>();
+ if (!a)
+ return Encode::undefined();
+
+ return a->engine()->newString(QString::fromLatin1(a->d()->type->name))->asReturnedValue();
+}
+
+ReturnedValue IntrinsicTypedArrayCtor::callAsConstructor(const FunctionObject *f, const Value *, int)
+{
+ return f->engine()->throwTypeError();
+}
+
+ReturnedValue IntrinsicTypedArrayCtor::call(const FunctionObject *f, const Value *, const Value *, int)
+{
+ return f->engine()->throwTypeError();
+}
+
+void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor)
+{
+ ctor->defineReadonlyProperty(engine->id_prototype(), *this);
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ ctor->addSymbolSpecies();
+
+ defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
+ defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
+ defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr);
+ defineAccessorProperty(QStringLiteral("length"), method_get_length, nullptr);
+
+ defineDefaultProperty(QStringLiteral("entries"), method_entries, 0);
+ defineDefaultProperty(QStringLiteral("keys"), method_keys, 0);
+ defineDefaultProperty(QStringLiteral("set"), method_set, 1);
+ defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0);
+
+ Scope scope(engine);
+ ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral("values")));
+ ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0));
+ defineDefaultProperty(QStringLiteral("values"), values);
+ defineDefaultProperty(engine->symbol_iterator(), values);
+
+ defineAccessorProperty(engine->symbol_toStringTag(), method_get_toStringTag, nullptr);
+}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 129c662c97..43ff1ec5b7 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -97,12 +97,18 @@ DECLARE_HEAP_OBJECT(TypedArray, Object) {
void init(Type t);
};
+struct IntrinsicTypedArrayCtor : FunctionObject {
+};
+
struct TypedArrayCtor : FunctionObject {
void init(QV4::ExecutionContext *scope, TypedArray::Type t);
TypedArray::Type type;
};
+struct IntrinsicTypedArrayPrototype : Object {
+};
+
struct TypedArrayPrototype : Object {
inline void init(TypedArray::Type t);
TypedArray::Type type;
@@ -137,6 +143,14 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
static bool putIndexed(Managed *m, uint index, const Value &value);
};
+struct IntrinsicTypedArrayCtor: FunctionObject
+{
+ V4_OBJECT2(IntrinsicTypedArrayCtor, FunctionObject)
+
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
struct TypedArrayCtor: FunctionObject
{
V4_OBJECT2(TypedArrayCtor, FunctionObject)
@@ -145,21 +159,34 @@ struct TypedArrayCtor: FunctionObject
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-
-struct TypedArrayPrototype : Object
+struct IntrinsicTypedArrayPrototype : Object
{
- V4_OBJECT2(TypedArrayPrototype, Object)
+ V4_OBJECT2(IntrinsicTypedArrayPrototype, Object)
V4_PROTOTYPE(objectPrototype)
- void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
+ void init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor);
static ReturnedValue method_get_buffer(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_byteLength(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_byteOffset(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_subarray(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue method_get_toStringTag(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+};
+
+struct TypedArrayPrototype : Object
+{
+ V4_OBJECT2(TypedArrayPrototype, Object)
+ V4_PROTOTYPE(objectPrototype)
+
+ void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
};
inline void
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 0d4711df3c..9febd41a00 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -40,6 +40,7 @@
#include <qv4runtime_p.h>
#include <qv4string_p.h>
#ifndef V4_BOOTSTRAP
+#include <qv4symbol_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <private/qv4mm_p.h>
@@ -84,7 +85,7 @@ bool Value::toBooleanImpl(Value val)
#ifdef V4_BOOTSTRAP
Q_UNIMPLEMENTED();
#else
- if (b->vtable()->isString)
+ if (b->internalClass->vtable->isString)
return static_cast<Heap::String *>(b)->length() > 0;
#endif
return true;
@@ -107,6 +108,11 @@ double Value::toNumberImpl(Value val)
#else
if (String *s = val.stringValue())
return RuntimeHelpers::stringToNumber(s->toQString());
+ if (val.isSymbol()) {
+ Managed &m = static_cast<Managed &>(val);
+ m.engine()->throwTypeError();
+ return 0;
+ }
{
Q_ASSERT(val.isObject());
Scope scope(val.objectValue()->engine());
@@ -145,6 +151,8 @@ QString Value::toQStringNoThrow() const
case Value::Managed_Type:
if (String *s = stringValue())
return s->toQString();
+ if (Symbol *s = symbolValue())
+ return s->descriptiveString();
{
Q_ASSERT(isObject());
Scope scope(objectValue()->engine());
@@ -197,9 +205,12 @@ QString Value::toQString() const
else
return QStringLiteral("false");
case Value::Managed_Type:
- if (String *s = stringValue())
+ if (String *s = stringValue()) {
return s->toQString();
- {
+ } else if (isSymbol()) {
+ static_cast<const Managed *>(this)->engine()->throwTypeError();
+ return QString();
+ } else {
Q_ASSERT(isObject());
Scope scope(objectValue()->engine());
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
@@ -217,6 +228,17 @@ QString Value::toQString() const
}
} // switch
}
+
+Heap::StringOrSymbol *Value::toPropertyKey(ExecutionEngine *e) const
+{
+ Scope scope(e);
+ ScopedValue v(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
+ if (!v->isStringOrSymbol())
+ v = v->toString(e);
+ if (e->hasException)
+ return nullptr;
+ return static_cast<Heap::StringOrSymbol *>(v->m());
+}
#endif // V4_BOOTSTRAP
bool Value::sameValue(Value other) const {
@@ -235,6 +257,25 @@ bool Value::sameValue(Value other) const {
return false;
}
+bool Value::sameValueZero(Value other) const {
+ if (_val == other._val)
+ return true;
+ String *s = stringValue();
+ String *os = other.stringValue();
+ if (s && os)
+ return s->isEqualTo(os);
+ if (isInteger() && other.isDouble())
+ return double(int_32()) == other.doubleValue();
+ if (isDouble() && other.isInteger())
+ return other.int_32() == doubleValue();
+ if (isDouble() && other.isDouble()) {
+ if (doubleValue() == 0 && other.doubleValue() == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
#ifndef V4_BOOTSTRAP
Heap::String *Value::toString(ExecutionEngine *e, Value val)
{
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index a5ee6b5373..16bbf241ff 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -56,6 +56,7 @@
#include <QtCore/QString>
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
+#include <private/qv4internalclass_p.h>
#include <private/qnumeric_p.h>
@@ -184,23 +185,7 @@ public:
QML_NEARLY_ALWAYS_INLINE void setEmpty()
{
- setTagValue(quint32(ValueTypeInternal::Empty), value());
- }
-
- QML_NEARLY_ALWAYS_INLINE void setEmpty(int i)
- {
- setTagValue(quint32(ValueTypeInternal::Empty), quint32(i));
- }
-
- QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i)
- {
- setTagValue(quint32(ValueTypeInternal::Empty), i);
- }
-
- QML_NEARLY_ALWAYS_INLINE quint32 emptyValue()
- {
- Q_ASSERT(isEmpty());
- return quint32(value());
+ setTagValue(quint32(ValueTypeInternal::Empty), 0);
}
// ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
@@ -248,7 +233,8 @@ public:
IsManagedOrUndefined_Shift = 64-15,
IsIntegerConvertible_Shift = 64-15,
IsIntegerOrBool_Shift = 64-16,
- QuickType_Shift = 64 - 17
+ QuickType_Shift = 64 - 17,
+ IsPositiveIntShift = 31
};
static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
@@ -315,6 +301,14 @@ public:
}
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;
@@ -331,6 +325,8 @@ public:
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() {
@@ -362,7 +358,17 @@ public:
QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
if (!isString())
return nullptr;
- return reinterpret_cast<String*>(const_cast<Value *>(this));
+ return reinterpret_cast<String *>(const_cast<Value *>(this));
+ }
+ QML_NEARLY_ALWAYS_INLINE StringOrSymbol *stringOrSymbolValue() const {
+ if (!isStringOrSymbol())
+ return nullptr;
+ return reinterpret_cast<StringOrSymbol *>(const_cast<Value *>(this));
+ }
+ QML_NEARLY_ALWAYS_INLINE Symbol *symbolValue() const {
+ if (!isSymbol())
+ return nullptr;
+ return reinterpret_cast<Symbol *>(const_cast<Value *>(this));
}
QML_NEARLY_ALWAYS_INLINE Object *objectValue() const {
if (!isObject())
@@ -388,6 +394,8 @@ public:
int toUInt16() const;
inline int toInt32() const;
inline unsigned int toUInt32() const;
+ qint64 toLength() const;
+ inline qint64 toIndex() const;
bool toBoolean() const {
if (integerCompatible())
@@ -407,6 +415,8 @@ public:
return reinterpret_cast<Heap::String *>(m());
return toString(e, *this);
}
+ Heap::StringOrSymbol *toPropertyKey(ExecutionEngine *e) const;
+
static Heap::String *toString(ExecutionEngine *e, Value val);
Heap::Object *toObject(ExecutionEngine *e) const {
if (isObject())
@@ -428,11 +438,11 @@ public:
if (!isManaged())
return nullptr;
- Q_ASSERT(m()->vtable());
+ Q_ASSERT(m()->internalClass->vtable);
#if !defined(QT_NO_QOBJECT_CHECK)
static_cast<const T *>(this)->qt_check_for_QMANAGED_macro(static_cast<const T *>(this));
#endif
- const VTable *vt = m()->vtable();
+ const VTable *vt = m()->internalClass->vtable;
while (vt) {
if (vt == T::staticVTable())
return static_cast<const T *>(this);
@@ -465,8 +475,9 @@ public:
ReturnedValue asReturnedValue() const { return _val; }
static Value fromReturnedValue(ReturnedValue val) { Value v; v._val = val; return v; }
- // Section 9.12
+ // As per ES specs
bool sameValue(Value other) const;
+ bool sameValueZero(Value other) const;
inline void mark(MarkStack *markStack);
@@ -500,18 +511,32 @@ inline void Value::mark(MarkStack *markStack)
inline bool Value::isString() const
{
Heap::Base *b = heapObject();
- return b && b->vtable()->isString;
+ return b && b->internalClass->vtable->isString;
+}
+
+bool Value::isStringOrSymbol() const
+{
+ Heap::Base *b = heapObject();
+ return b && b->internalClass->vtable->isStringOrSymbol;
}
+
+bool Value::isSymbol() const
+{
+ Heap::Base *b = heapObject();
+ return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
+}
+
inline bool Value::isObject() const
+
{
Heap::Base *b = heapObject();
- return b && b->vtable()->isObject;
+ return b && b->internalClass->vtable->isObject;
}
inline bool Value::isFunctionObject() const
{
Heap::Base *b = heapObject();
- return b && b->vtable()->isFunctionObject;
+ return b && b->internalClass->vtable->isFunctionObject;
}
inline bool Value::isPrimitive() const
@@ -532,33 +557,26 @@ inline double Value::toNumber() const
#ifndef V4_BOOTSTRAP
inline uint Value::asArrayIndex() const
{
-#if QT_POINTER_SIZE == 8
- if (!isNumber())
- return UINT_MAX;
- if (isInteger())
- return int_32() >= 0 ? (uint)int_32() : UINT_MAX;
-#else
- if (isInteger() && int_32() >= 0)
+ if (Q_LIKELY(isPositiveInt())) {
return (uint)int_32();
- if (!isDouble())
+ }
+ if (Q_UNLIKELY(!isDouble()))
return UINT_MAX;
-#endif
double d = doubleValue();
uint idx = (uint)d;
- if (idx != d)
- return UINT_MAX;
- return idx;
+ if (idx == d)
+ return idx;
+ return UINT_MAX;
}
inline bool Value::asArrayIndex(uint &idx) const
{
- if (Q_LIKELY(!isDouble())) {
- if (Q_LIKELY(isInteger() && int_32() >= 0)) {
- idx = (uint)int_32();
- return true;
- }
- return false;
+ if (Q_LIKELY(isPositiveInt())) {
+ idx = (uint)int_32();
+ return true;
}
+ if (Q_UNLIKELY(!isDouble()))
+ return false;
double d = doubleValue();
idx = (uint)d;
return (idx == d && idx != UINT_MAX);
@@ -576,7 +594,6 @@ ReturnedValue Heap::Base::asReturnedValue() const
struct Q_QML_PRIVATE_EXPORT Primitive : public Value
{
inline static Primitive emptyValue();
- inline static Primitive emptyValue(uint v);
static inline Primitive fromBoolean(bool b);
static inline Primitive fromInt32(int i);
inline static Primitive undefinedValue();
@@ -602,14 +619,7 @@ inline Primitive Primitive::undefinedValue()
inline Primitive Primitive::emptyValue()
{
Primitive v;
- v.setEmpty(0);
- return v;
-}
-
-inline Primitive Primitive::emptyValue(uint e)
-{
- Primitive v;
- v.setEmpty(e);
+ v.setEmpty();
return v;
}
@@ -788,6 +798,31 @@ inline unsigned int Value::toUInt32() const
return static_cast<unsigned int>(toInt32());
}
+inline qint64 Value::toLength() const
+{
+ if (Q_LIKELY(integerCompatible()))
+ return int_32() < 0 ? 0 : int_32();
+ double i = Primitive::toInteger(isDouble() ? doubleValue() : toNumberImpl());
+ if (i <= 0)
+ return 0;
+ if (i > (static_cast<qint64>(1) << 53) - 1)
+ return (static_cast<qint64>(1) << 53) - 1;
+ return static_cast<qint64>(i);
+}
+
+inline qint64 Value::toIndex() const
+{
+ qint64 idx;
+ if (Q_LIKELY(integerCompatible())) {
+ idx = int_32();
+ } else {
+ idx = static_cast<qint64>(Primitive::toInteger(isDouble() ? doubleValue() : toNumberImpl()));
+ }
+ if (idx > (static_cast<qint64>(1) << 53) - 1)
+ idx = -1;
+ return idx;
+}
+
inline double Value::toInteger() const
{
if (integerCompatible())
@@ -831,7 +866,7 @@ struct ValueArray {
WriteBarrier::write(e, base(), values[index].data_ptr(), v.asReturnedValue());
}
void set(EngineBase *e, uint index, Heap::Base *b) {
- WriteBarrier::write(e, base(), values[index].data_ptr(), b->asReturnedValue());
+ WriteBarrier::write(e, base(), values[index].data_ptr(), Value::fromHeapObject(b).asReturnedValue());
}
inline const Value &operator[] (uint index) const {
Q_ASSERT(index < alloc);
@@ -884,7 +919,6 @@ struct ValueArray {
// have wrong offsets between host and target.
Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index a1f5b01fa9..f625368b62 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -55,12 +55,13 @@
#include <private/qv4string_p.h>
#include <private/qv4profiling_p.h>
#include <private/qv4jscall_p.h>
+#include <private/qv4generatorobject_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
#include "qv4alloca_p.h"
-#include <private/qv4jit_p.h>
+#include <private/qv4baselinejit_p.h>
#undef COUNT_INSTRUCTIONS
@@ -343,7 +344,7 @@ static struct InstrCount {
#endif
#define CHECK_EXCEPTION \
if (engine->hasException) \
- goto catchException
+ goto handleUnwind
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
{
@@ -361,95 +362,6 @@ static inline const QV4::Value &constant(Function *function, int index)
return function->compilationUnit->constants[index];
}
-
-static bool compareEqual(QV4::Value lhs, QV4::Value rhs)
-{
- redo:
- if (lhs.asReturnedValue() == rhs.asReturnedValue())
- return !lhs.isNaN();
-
- int lt = lhs.quickType();
- int rt = rhs.quickType();
- if (rt < lt) {
- qSwap(lhs, rhs);
- qSwap(lt, rt);
- }
-
- switch (lt) {
- case QV4::Value::QT_ManagedOrUndefined:
- if (lhs.isUndefined())
- return rhs.isNullOrUndefined();
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
- // LHS: Managed
- switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
- if (rhs.isUndefined())
- return false;
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3: {
- // RHS: Managed
- Heap::Base *l = lhs.m();
- Heap::Base *r = rhs.m();
- Q_ASSERT(l);
- Q_ASSERT(r);
- if (l->vtable()->isString == r->vtable()->isString)
- return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs));
- if (l->vtable()->isString) {
- rhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT));
- break;
- } else {
- Q_ASSERT(r->vtable()->isString);
- lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
- break;
- }
- return false;
- }
- case QV4::Value::QT_Empty:
- Q_UNREACHABLE();
- case QV4::Value::QT_Null:
- return false;
- case QV4::Value::QT_Bool:
- case QV4::Value::QT_Int:
- rhs = Primitive::fromDouble(rhs.int_32());
- // fall through
- default: // double
- if (lhs.m()->vtable()->isString)
- return RuntimeHelpers::toNumber(lhs) == rhs.doubleValue();
- else
- lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
- }
- goto redo;
- case QV4::Value::QT_Empty:
- Q_UNREACHABLE();
- case QV4::Value::QT_Null:
- return rhs.isNull();
- case QV4::Value::QT_Bool:
- case QV4::Value::QT_Int:
- switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
- case QV4::Value::QT_Empty:
- case QV4::Value::QT_Null:
- Q_UNREACHABLE();
- case QV4::Value::QT_Bool:
- case QV4::Value::QT_Int:
- return lhs.int_32() == rhs.int_32();
- default: // double
- return lhs.int_32() == rhs.doubleValue();
- }
- default: // double
- Q_ASSERT(rhs.isDouble());
- return lhs.doubleValue() == rhs.doubleValue();
- }
-}
-
static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
{
redo:
@@ -462,7 +374,7 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
case QV4::Value::QT_ManagedOrUndefined2:
case QV4::Value::QT_ManagedOrUndefined3:
// LHS: Managed
- if (lhs.m()->vtable()->isString)
+ if (lhs.m()->internalClass->vtable->isString)
return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs;
accumulator = lhs;
lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT));
@@ -479,7 +391,7 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
}
}
-#define STORE_IP() frame.instructionPointer = int(code - codeStart);
+#define STORE_IP() frame.instructionPointer = int(code - function->codeData);
#define STORE_ACC() accumulator = acc;
#define ACC Primitive::fromReturnedValue(acc)
#define VALUE_TO_INT(i, val) \
@@ -508,6 +420,11 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
CppStackFrame frame;
frame.originalArguments = argv;
frame.originalArgumentsCount = argc;
+ frame.yield = nullptr;
+ frame.unwindHandler = nullptr;
+ frame.unwindLabel = nullptr;
+ frame.unwindLevel = 0;
+
Function *function;
{
@@ -553,10 +470,6 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
- const uchar *exceptionHandler = nullptr;
-
- QV4::Value &accumulator = frame.jsFrame->accumulator;
- QV4::ReturnedValue acc = Encode::undefined();
#ifdef V4_ENABLE_JIT
if (function->jittedCode == nullptr && debugger == nullptr) {
@@ -570,12 +483,29 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
if (debugger)
debugger->enteringFunction();
+ ReturnedValue result;
if (function->jittedCode != nullptr && debugger == nullptr) {
- acc = function->jittedCode(&frame, engine);
+ result = function->jittedCode(&frame, engine);
} else {
// interpreter
- const uchar *code = function->codeData;
- const uchar *codeStart = code;
+ result = interpret(frame, function->codeData);
+ }
+
+ if (QV4::Debugging::Debugger *debugger = engine->debugger())
+ debugger->leavingFunction(result);
+ engine->currentStackFrame = frame.parent;
+ engine->jsStackTop = stack;
+
+ return result;
+}
+
+QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const char *code)
+{
+ QV4::Function *function = frame.v4Function;
+ QV4::Value &accumulator = frame.jsFrame->accumulator;
+ QV4::ReturnedValue acc = accumulator.asReturnedValue();
+ Value *stack = reinterpret_cast<Value *>(frame.jsFrame);
+ ExecutionEngine *engine = function->internalClass->engine;
MOTH_JUMP_TABLE;
@@ -629,12 +559,14 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_BEGIN_INSTR(LoadLocal)
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
CHECK_EXCEPTION;
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
MOTH_END_INSTR(StoreLocal)
@@ -689,16 +621,10 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_BEGIN_INSTR(LoadElement)
STORE_IP();
- acc = Runtime::method_loadElement(engine, STACK_VALUE(base), STACK_VALUE(index));
- CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadElement)
-
- MOTH_BEGIN_INSTR(LoadElementA)
- STORE_IP();
STORE_ACC();
acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator);
CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadElementA)
+ MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
STORE_IP();
@@ -710,16 +636,10 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_BEGIN_INSTR(LoadProperty)
STORE_IP();
- acc = Runtime::method_loadProperty(engine, STACK_VALUE(base), name);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadProperty)
-
- MOTH_BEGIN_INSTR(LoadPropertyA)
- STORE_IP();
STORE_ACC();
acc = Runtime::method_loadProperty(engine, accumulator, name);
CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadPropertyA)
+ MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
STORE_IP();
@@ -784,12 +704,30 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(Yield)
+ frame.yield = code;
+ return acc;
+ MOTH_END_INSTR(Yield)
+
+ MOTH_BEGIN_INSTR(Resume)
+ // check exception, in case the generator was called with throw() or return()
+ if (engine->hasException) {
+ // an empty value indicates that the generator was called with return()
+ if (engine->exceptionValue->asReturnedValue() != Primitive::emptyValue().asReturnedValue())
+ goto handleUnwind;
+ engine->hasException = false;
+ *engine->exceptionValue = Primitive::undefinedValue();
+ } else {
+ code += offset;
+ }
+ MOTH_END_INSTR(Resume)
+
MOTH_BEGIN_INSTR(CallValue)
STORE_IP();
Value func = STACK_VALUE(name);
if (Q_UNLIKELY(!func.isFunctionObject())) {
acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- goto catchException;
+ goto handleUnwind;
}
acc = static_cast<const FunctionObject &>(func).call(nullptr, stack + argv, argc);
CHECK_EXCEPTION;
@@ -809,7 +747,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
if (Q_UNLIKELY(!f.isFunctionObject())) {
acc = engine->throwTypeError();
- goto catchException;
+ goto handleUnwind;
}
acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
@@ -852,15 +790,49 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
CHECK_EXCEPTION;
MOTH_END_INSTR(CallContextObjectProperty)
- MOTH_BEGIN_INSTR(SetExceptionHandler)
- exceptionHandler = offset ? code + offset : nullptr;
- MOTH_END_INSTR(SetExceptionHandler)
+ MOTH_BEGIN_INSTR(CallWithSpread)
+ STORE_IP();
+ acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CallWithSpread)
+
+ MOTH_BEGIN_INSTR(Construct)
+ STORE_IP();
+ acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(Construct)
+
+ MOTH_BEGIN_INSTR(ConstructWithSpread)
+ STORE_IP();
+ acc = Runtime::method_constructWithSpread(engine, STACK_VALUE(func), stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(ConstructWithSpread)
+
+ MOTH_BEGIN_INSTR(SetUnwindHandler)
+ frame.unwindHandler = offset ? code + offset : nullptr;
+ MOTH_END_INSTR(SetUnwindHandler)
+
+ MOTH_BEGIN_INSTR(UnwindDispatch)
+ CHECK_EXCEPTION;
+ if (frame.unwindLevel) {
+ --frame.unwindLevel;
+ if (frame.unwindLevel)
+ goto handleUnwind;
+ code = frame.unwindLabel;
+ }
+ MOTH_END_INSTR(UnwindDispatch)
+
+ MOTH_BEGIN_INSTR(UnwindToLabel)
+ frame.unwindLevel = level;
+ frame.unwindLabel = code + offset;
+ goto handleUnwind;
+ MOTH_END_INSTR(UnwindToLabel)
MOTH_BEGIN_INSTR(ThrowException)
STORE_IP();
STORE_ACC();
Runtime::method_throwException(engine, accumulator);
- goto catchException;
+ goto handleUnwind;
MOTH_END_INSTR(ThrowException)
MOTH_BEGIN_INSTR(GetException)
@@ -870,14 +842,15 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_END_INSTR(HasException)
MOTH_BEGIN_INSTR(SetException)
- *engine->exceptionValue = acc;
- engine->hasException = true;
+ if (acc != Primitive::emptyValue().asReturnedValue()) {
+ *engine->exceptionValue = acc;
+ engine->hasException = true;
+ }
MOTH_END_INSTR(SetException)
MOTH_BEGIN_INSTR(PushCatchContext)
- STACK_VALUE(reg) = STACK_VALUE(CallData::Context);
ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, name);
+ STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, index, name);
MOTH_END_INSTR(PushCatchContext)
MOTH_BEGIN_INSTR(CreateCallContext)
@@ -887,54 +860,72 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_BEGIN_INSTR(PushWithContext)
STORE_IP();
STORE_ACC();
- accumulator = accumulator.toObject(engine);
+ auto ctx = Runtime::method_createWithContext(engine, stack);
CHECK_EXCEPTION;
- STACK_VALUE(reg) = STACK_VALUE(CallData::Context);
- ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
- STACK_VALUE(CallData::Context) = Runtime::method_createWithContext(c, accumulator);
+ 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);
+ 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);
+ MOTH_END_INSTR(CloneBlockContext)
+
+ MOTH_BEGIN_INSTR(PushScriptContext)
+ STACK_VALUE(CallData::Context) = Runtime::method_createScriptContext(engine, index);
+ MOTH_END_INSTR(PushScriptContext)
+
+ MOTH_BEGIN_INSTR(PopScriptContext)
+ STACK_VALUE(CallData::Context) = Runtime::method_popScriptContext(engine);
+ MOTH_END_INSTR(PopScriptContext)
+
MOTH_BEGIN_INSTR(PopContext)
- STACK_VALUE(CallData::Context) = STACK_VALUE(reg);
+ ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
+ STACK_VALUE(CallData::Context) = c->d()->outer;
MOTH_END_INSTR(PopContext)
- MOTH_BEGIN_INSTR(ForeachIteratorObject)
+ MOTH_BEGIN_INSTR(GetIterator)
STORE_ACC();
- acc = Runtime::method_foreachIterator(engine, accumulator);
+ acc = Runtime::method_getIterator(engine, accumulator, iterator);
CHECK_EXCEPTION;
- MOTH_END_INSTR(ForeachIteratorObject)
+ MOTH_END_INSTR(GetIterator)
- MOTH_BEGIN_INSTR(ForeachNextPropertyName)
+ MOTH_BEGIN_INSTR(IteratorNext)
STORE_ACC();
- acc = Runtime::method_foreachNextPropertyName(accumulator);
+ acc = Runtime::method_iteratorNext(engine, accumulator, &STACK_VALUE(value));
CHECK_EXCEPTION;
- MOTH_END_INSTR(ForeachNextPropertyName)
+ MOTH_END_INSTR(IteratorNext)
- MOTH_BEGIN_INSTR(DeleteMember)
- if (!Runtime::method_deleteMember(engine, STACK_VALUE(base), member)) {
- if (function->isStrict()) {
- STORE_IP();
- engine->throwTypeError();
- goto catchException;
- }
- acc = Encode(false);
- } else {
- acc = Encode(true);
- }
- MOTH_END_INSTR(DeleteMember)
+ MOTH_BEGIN_INSTR(IteratorClose)
+ STORE_ACC();
+ acc = Runtime::method_iteratorClose(engine, accumulator, STACK_VALUE(done));
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(IteratorClose)
+
+ MOTH_BEGIN_INSTR(DestructureRestElement)
+ STORE_ACC();
+ acc = Runtime::method_destructureRestElement(engine, ACC);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(DestructureRestElement)
- MOTH_BEGIN_INSTR(DeleteSubscript)
- if (!Runtime::method_deleteElement(engine, STACK_VALUE(base), STACK_VALUE(index))) {
+ MOTH_BEGIN_INSTR(DeleteProperty)
+ if (!Runtime::method_deleteProperty(engine, STACK_VALUE(base), STACK_VALUE(index))) {
if (function->isStrict()) {
STORE_IP();
engine->throwTypeError();
- goto catchException;
+ goto handleUnwind;
}
acc = Encode(false);
} else {
acc = Encode(true);
}
- MOTH_END_INSTR(DeleteSubscript)
+ MOTH_END_INSTR(DeleteProperty)
MOTH_BEGIN_INSTR(DeleteName)
if (!Runtime::method_deleteName(engine, name)) {
@@ -942,7 +933,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
STORE_IP();
QString n = function->compilationUnit->runtimeStrings[name]->toQString();
engine->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(n));
- goto catchException;
+ goto handleUnwind;
}
acc = Encode(false);
} else {
@@ -970,7 +961,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_BEGIN_INSTR(DefineObjectLiteral)
QV4::Value *arguments = stack + args;
- acc = Runtime::method_objectLiteral(engine, arguments, internalClassId, arrayValueCount, arrayGetterSetterCountAndFlags);
+ acc = Runtime::method_objectLiteral(engine, internalClassId, argc, arguments);
MOTH_END_INSTR(DefineObjectLiteral)
MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
@@ -981,6 +972,10 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
acc = Runtime::method_createUnmappedArgumentsObject(engine);
MOTH_END_INSTR(CreateUnmappedArgumentsObject)
+ MOTH_BEGIN_INSTR(CreateRestParameter)
+ acc = Runtime::method_createRestParameter(engine, argIndex);
+ MOTH_END_INSTR(CreateRestParameter)
+
MOTH_BEGIN_INSTR(ConvertThisToObject)
Value *t = &stack[CallData::This];
if (!t->isObject()) {
@@ -993,11 +988,10 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
}
MOTH_END_INSTR(ConvertThisToObject)
- MOTH_BEGIN_INSTR(Construct)
- STORE_IP();
- acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc);
+ MOTH_BEGIN_INSTR(ToObject)
+ acc = ACC.toObject(engine)->asReturnedValue();
CHECK_EXCEPTION;
- MOTH_END_INSTR(Construct)
+ MOTH_END_INSTR(ToObject)
MOTH_BEGIN_INSTR(Jump)
code += offset;
@@ -1023,6 +1017,16 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
}
MOTH_END_INSTR(JumpFalse)
+ MOTH_BEGIN_INSTR(JumpNoException)
+ if (!engine->hasException)
+ code += offset;
+ MOTH_END_INSTR(JumpNoException)
+
+ MOTH_BEGIN_INSTR(JumpNotUndefined)
+ if (Q_LIKELY(acc != QV4::Encode::undefined()))
+ code += offset;
+ MOTH_END_INSTR(JumpNotUndefined)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)
@@ -1059,7 +1063,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
acc = Encode(left.int_32() == ACC.int_32());
} else {
STORE_ACC();
- acc = Encode(compareEqual(left, accumulator));
+ acc = Encode(bool(Runtime::method_compareEqual(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpEq)
@@ -1070,7 +1074,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
acc = Encode(bool(left.int_32() != ACC.int_32()));
} else {
STORE_ACC();
- acc = Encode(!compareEqual(left, accumulator));
+ acc = Encode(bool(!Runtime::method_compareEqual(left, accumulator)));
CHECK_EXCEPTION;
}
MOTH_END_INSTR(CmpNe)
@@ -1154,27 +1158,11 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_END_INSTR(CmpIn)
MOTH_BEGIN_INSTR(CmpInstanceOf)
- // 11.8.6, 5: rval must be an Object
- if (Q_UNLIKELY(!Primitive::fromReturnedValue(acc).isObject())) {
- acc = engine->throwTypeError();
- goto catchException;
- }
-
- // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
- acc = Primitive::fromReturnedValue(acc).objectValue()->instanceOf(STACK_VALUE(lhs));
+ STORE_ACC();
+ acc = Runtime::method_instanceof(engine, STACK_VALUE(lhs), ACC);
CHECK_EXCEPTION;
MOTH_END_INSTR(CmpInstanceOf)
- MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
- if (STACK_VALUE(lhs).int_32() != rhs || STACK_VALUE(lhs).isUndefined())
- code += offset;
- MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
-
- MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
- if (STACK_VALUE(lhs).int_32() == rhs && !STACK_VALUE(lhs).isUndefined())
- code += offset;
- MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
-
MOTH_BEGIN_INSTR(UNot)
if (ACC.integerCompatible()) {
acc = Encode(!static_cast<bool>(ACC.int_32()));
@@ -1259,6 +1247,16 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
}
MOTH_END_INSTR(Sub)
+ MOTH_BEGIN_INSTR(Exp)
+ const Value left = STACK_VALUE(lhs);
+ double base = left.toNumber();
+ double exp = ACC.toNumber();
+ if (qIsInf(exp) && (base == 1 || base == -1))
+ acc = Encode(qSNaN());
+ else
+ acc = Encode(pow(base,exp));
+ MOTH_END_INSTR(Exp)
+
MOTH_BEGIN_INSTR(Mul)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
@@ -1351,7 +1349,7 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_END_INSTR(ShlConst)
MOTH_BEGIN_INSTR(Ret)
- goto functionExit;
+ return acc;
MOTH_END_INSTR(Ret)
MOTH_BEGIN_INSTR(Debug)
@@ -1369,21 +1367,12 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
- catchException:
- Q_ASSERT(engine->hasException);
- if (!exceptionHandler) {
+ handleUnwind:
+ Q_ASSERT(engine->hasException || frame.unwindLevel);
+ if (!frame.unwindHandler) {
acc = Encode::undefined();
- goto functionExit;
+ return acc;
}
- code = exceptionHandler;
- }
+ code = frame.unwindHandler;
}
-
-functionExit:
- if (QV4::Debugging::Debugger *debugger = engine->debugger())
- debugger->leavingFunction(ACC.asReturnedValue());
- engine->currentStackFrame = frame.parent;
- engine->jsStackTop = stack;
-
- return acc;
}
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 3b7723ca7e..67bfd537c5 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -72,6 +72,7 @@ public:
return exec(reinterpret_cast<const FunctionObject *>(d), thisObject, argv, argc);
}
static QV4::ReturnedValue exec(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc);
+ static QV4::ReturnedValue interpret(CppStackFrame &frame, const char *codeEntry);
};
} // namespace Moth
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 53933cd090..84208b51e0 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -54,7 +54,6 @@
#include <private/qv4global_p.h>
#include <private/qv4mmdefs_p.h>
#include <private/qv4writebarrier_p.h>
-#include <private/qv4internalclass_p.h>
#include <QSharedPointer>
// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
@@ -65,21 +64,20 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct InternalClass;
-
struct VTable
{
const VTable * const parent;
- uint inlinePropertyOffset : 16;
- uint nInlineProperties : 16;
- uint isExecutionContext : 1;
- uint isString : 1;
- uint isObject : 1;
- uint isFunctionObject : 1;
- uint isErrorObject : 1;
- uint isArrayData : 1;
- uint unused : 18;
- uint type : 8;
+ quint32 inlinePropertyOffset : 16;
+ quint32 nInlineProperties : 16;
+ quint8 isExecutionContext;
+ quint8 isString;
+ quint8 isObject;
+ quint8 isFunctionObject;
+ quint8 isErrorObject;
+ quint8 isArrayData;
+ quint8 isStringOrSymbol;
+ quint8 type;
+ quint8 unused[4];
const char *className;
void (*destroy)(Heap::Base *);
void (*markObjects)(Heap::Base *, MarkStack *markStack);
@@ -88,17 +86,41 @@ struct VTable
namespace Heap {
+template <typename T, size_t o>
+struct Pointer {
+ static Q_CONSTEXPR size_t offset = o;
+ T operator->() const { return get(); }
+ operator T () const { return get(); }
+
+ Base *base();
+
+ void set(EngineBase *e, T newVal) {
+ WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Base *>(newVal));
+ }
+
+ T get() const { return reinterpret_cast<T>(ptr); }
+
+ template <typename Type>
+ Type *cast() { return static_cast<Type *>(ptr); }
+
+ Base *heapObject() const { return ptr; }
+
+private:
+ Base *ptr;
+};
+typedef Pointer<char *, 0> V4PointerCheck;
+Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
+
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
- static void markObjects(Heap::Base *, MarkStack *) {}
+ static void markObjects(Base *, MarkStack *);
- InternalClass *internalClass;
+ Pointer<InternalClass *, 0> internalClass;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::MarkStack *markStack);
- const VTable *vtable() const { return internalClass->vtable; }
inline bool isMarked() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
Chunk *c = h->chunk();
@@ -125,13 +147,9 @@ struct Q_QML_EXPORT Base {
return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
- inline void markChildren(MarkStack *markStack) {
- vtable()->markObjects(this, markStack);
- }
-
void *operator new(size_t, Managed *m) { return m; }
- void *operator new(size_t, Heap::Base *m) { return m; }
- void operator delete(void *, Heap::Base *) {}
+ void *operator new(size_t, Base *m) { return m; }
+ void operator delete(void *, Base *) {}
void init() { _setInitialized(); }
void destroy() { _setDestroyed(); }
@@ -178,10 +196,8 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
-}
-
inline
-void Heap::Base::mark(QV4::MarkStack *markStack)
+void Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -196,36 +212,12 @@ void Heap::Base::mark(QV4::MarkStack *markStack)
}
}
-namespace Heap {
-
-template <typename T, size_t o>
-struct Pointer {
- static Q_CONSTEXPR size_t offset = o;
- T operator->() const { return get(); }
- operator T () const { return get(); }
-
- Heap::Base *base() {
- Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
- Q_ASSERT(base->inUse());
- return base;
- }
-
- void set(EngineBase *e, T newVal) {
- WriteBarrier::write(e, base(), &ptr, reinterpret_cast<Heap::Base *>(newVal));
- }
-
- T get() const { return reinterpret_cast<T>(ptr); }
-
- template <typename Type>
- Type *cast() { return static_cast<Type *>(ptr); }
-
- Heap::Base *heapObject() const { return ptr; }
-
-private:
- Heap::Base *ptr;
-};
-typedef Pointer<char *, 0> V4PointerCheck;
-Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
+template<typename T, size_t o>
+Base *Pointer<T, o>::base() {
+ Base *base = reinterpret_cast<Base *>(this) - (offset/sizeof(Base *));
+ Q_ASSERT(base->inUse());
+ return base;
+}
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 4e83abebdf..d9772e608e 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -42,6 +42,7 @@
#include "qv4objectproto_p.h"
#include "qv4mm_p.h"
#include "qv4qobjectwrapper_p.h"
+#include "qv4identifiertable_p.h"
#include <QtCore/qalgorithms.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qloggingcategory.h>
@@ -335,7 +336,7 @@ bool Chunk::sweep(ExecutionEngine *engine)
HeapItem *itemToFree = o + index;
Heap::Base *b = *itemToFree;
- const VTable *v = b->vtable();
+ const VTable *v = b->internalClass->vtable;
// if (Q_UNLIKELY(classCountPtr))
// classCountPtr(v->className);
if (v->destroy) {
@@ -389,8 +390,8 @@ void Chunk::freeAll(ExecutionEngine *engine)
HeapItem *itemToFree = o + index;
Heap::Base *b = *itemToFree;
- if (b->vtable()->destroy) {
- b->vtable()->destroy(b);
+ if (b->internalClass->vtable->destroy) {
+ b->internalClass->vtable->destroy(b);
b->_checkIsDestroyed();
}
#ifdef V4_USE_HEAPTRACK
@@ -412,10 +413,6 @@ void Chunk::resetBlackBits()
memset(blackBitmap, 0, sizeof(blackBitmap));
}
-#ifdef MM_STATS
-static uint nGrayItems = 0;
-#endif
-
void Chunk::collectGrayItems(MarkStack *markStack)
{
// DEBUG << "sweeping chunk" << this << (*freeList);
@@ -438,10 +435,6 @@ void Chunk::collectGrayItems(MarkStack *markStack)
Heap::Base *b = *itemToFree;
Q_ASSERT(b->inUse());
markStack->push(b);
-#ifdef MM_STATS
- ++nGrayItems;
-// qDebug() << "adding gray item" << b << "to mark stack";
-#endif
}
grayBitmap[i] = 0;
o += Chunk::Bits;
@@ -459,7 +452,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
#else
const int start = 1;
#endif
-#ifdef MM_STATS
+#ifndef QT_NO_DEBUG
uint freeSlots = 0;
uint allocatedSlots = 0;
#endif
@@ -469,7 +462,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
if (!i)
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
-#ifdef MM_STATS
+#ifndef QT_NO_DEBUG
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -486,7 +479,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
break;
}
usedSlots = (objectBitmap[i]|extendsBitmap[i]);
-#ifdef MM_STATS
+#ifndef QT_NO_DEBUG
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -497,7 +490,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
usedSlots |= (quintptr(1) << index) - 1;
uint freeEnd = i*Bits + index;
uint nSlots = freeEnd - freeStart;
-#ifdef MM_STATS
+#ifndef QT_NO_DEBUG
// qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots;
freeSlots += nSlots;
#endif
@@ -508,7 +501,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
bins[bin] = freeItem;
}
}
-#ifdef MM_STATS
+#ifndef QT_NO_DEBUG
Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr));
#endif
}
@@ -643,8 +636,9 @@ void BlockAllocator::sweep()
void BlockAllocator::freeAll()
{
- for (auto c : chunks) {
+ for (auto c : chunks)
c->freeAll(engine);
+ for (auto c : chunks) {
Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
chunkAllocator->free(c);
}
@@ -691,7 +685,7 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato
{
HeapItem *itemToFree = c.chunk->first();
Heap::Base *b = *itemToFree;
- const VTable *v = b->vtable();
+ const VTable *v = b->internalClass->vtable;
if (Q_UNLIKELY(classCountPtr))
classCountPtr(v->className);
@@ -758,6 +752,7 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
: engine(engine)
, chunkAllocator(new ChunkAllocator)
, blockAllocator(chunkAllocator, engine)
+ , icAllocator(chunkAllocator, engine)
, hugeItemAllocator(chunkAllocator, engine)
, m_persistentValues(new PersistentValueStorage(engine))
, m_weakValues(new PersistentValueStorage(engine))
@@ -774,11 +769,6 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
blockAllocator.allocationStats = statistics.allocations;
}
-#ifdef MM_STATS
-static int allocationCount = 0;
-static size_t lastAllocRequestedSlots = 0;
-#endif
-
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
const size_t stringSize = align(sizeof(Heap::String));
@@ -884,7 +874,7 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable
Chunk::clearBit(c->extendsBitmap, index);
}
o->memberData.set(engine, m);
- m->internalClass = engine->internalClasses[EngineBase::Class_MemberData];
+ m->internalClass.set(engine, engine->internalClasses(EngineBase::Class_MemberData));
Q_ASSERT(o->memberData->internalClass);
m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
m->values.size = o->memberData->values.alloc;
@@ -911,7 +901,7 @@ void MarkStack::drain()
Heap::Base *h = pop();
++markStackSize;
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
- h->markChildren(this);
+ h->internalClass->vtable->markObjects(h, this);
}
}
@@ -1017,8 +1007,13 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
}
}
- blockAllocator.sweep();
- hugeItemAllocator.sweep(classCountPtr);
+
+ if (!lastSweep) {
+ engine->identifierTable->sweep();
+ blockAllocator.sweep(/*classCountPtr*/);
+ hugeItemAllocator.sweep(classCountPtr);
+ icAllocator.sweep(/*classCountPtr*/);
+ }
}
bool MemoryManager::shouldRunGC() const
@@ -1096,10 +1091,6 @@ void MemoryManager::runGC()
qDebug(stats) << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
-#ifdef MM_STATS
- nGrayItems = 0;
-#endif
-
QElapsedTimer t;
t.start();
mark();
@@ -1159,7 +1150,8 @@ void MemoryManager::runGC()
if (aggressiveGC) {
// ensure we don't 'loose' any memory
- Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
+ Q_ASSERT(blockAllocator.allocatedMem()
+ == blockAllocator.usedMem() + dumpBins(&blockAllocator, false));
}
usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
@@ -1167,16 +1159,17 @@ void MemoryManager::runGC()
// reset all black bits
blockAllocator.resetBlackBits();
hugeItemAllocator.resetBlackBits();
+ icAllocator.resetBlackBits();
}
size_t MemoryManager::getUsedMem() const
{
- return blockAllocator.usedMem();
+ return blockAllocator.usedMem() + icAllocator.usedMem();
}
size_t MemoryManager::getAllocatedMem() const
{
- return blockAllocator.allocatedMem() + hugeItemAllocator.usedMem();
+ return blockAllocator.allocatedMem() + icAllocator.allocatedMem() + hugeItemAllocator.usedMem();
}
size_t MemoryManager::getLargeItemsMem() const
@@ -1193,6 +1186,7 @@ MemoryManager::~MemoryManager()
sweep(/*lastSweep*/true);
blockAllocator.freeAll();
hugeItemAllocator.freeAll();
+ icAllocator.freeAll();
delete m_weakValues;
#ifdef V4_USE_VALGRIND
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 40670bcdc7..e3a011caf9 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -160,224 +160,98 @@ public:
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
template<typename ManagedType>
- inline typename ManagedType::Data *allocManaged(std::size_t size)
+ inline typename ManagedType::Data *allocManaged(std::size_t size, Heap::InternalClass *ic)
{
Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value);
size = align(size);
- Heap::Base *o = allocData(size);
- InternalClass *ic = ManagedType::defaultInternalClass(engine);
- ic = ic->changeVTable(ManagedType::staticVTable());
- o->internalClass = ic;
- Q_ASSERT(o->internalClass && o->internalClass->vtable);
- return static_cast<typename ManagedType::Data *>(o);
+ typename ManagedType::Data *d = static_cast<typename ManagedType::Data *>(allocData(size));
+ d->internalClass.set(engine, ic);
+ Q_ASSERT(d->internalClass && d->internalClass->vtable);
+ Q_ASSERT(ic->vtable == ManagedType::staticVTable());
+ return d;
}
template<typename ManagedType>
inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic)
{
- Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value);
- size = align(size);
- Heap::Base *o = allocData(size);
- o->internalClass = ic;
- Q_ASSERT(o->internalClass && o->internalClass->vtable);
- Q_ASSERT(ic->vtable == ManagedType::staticVTable());
- return static_cast<typename ManagedType::Data *>(o);
+ return allocManaged<ManagedType>(size, ic->d());
+ }
+
+ template<typename ManagedType>
+ inline typename ManagedType::Data *allocManaged(std::size_t size)
+ {
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, ManagedType::defaultInternalClass(engine));
+ return allocManaged<ManagedType>(size, ic);
}
template <typename ObjectType>
- typename ObjectType::Data *allocateObject(InternalClass *ic)
+ typename ObjectType::Data *allocateObject(Heap::InternalClass *ic)
{
Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
- o->internalClass = ic;
- Q_ASSERT(o->internalClass && o->internalClass->vtable);
- Q_ASSERT(ic->vtable == ObjectType::staticVTable());
+ o->internalClass.set(engine, ic);
+ Q_ASSERT(o->internalClass.get() && o->vtable());
+ Q_ASSERT(o->vtable() == ObjectType::staticVTable());
return static_cast<typename ObjectType::Data *>(o);
}
template <typename ObjectType>
+ typename ObjectType::Data *allocateObject(InternalClass *ic)
+ {
+ return allocateObject<ObjectType>(ic->d());
+ }
+
+ template <typename ObjectType>
typename ObjectType::Data *allocateObject()
{
- InternalClass *ic = ObjectType::defaultInternalClass(engine);
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, ObjectType::defaultInternalClass(engine));
ic = ic->changeVTable(ObjectType::staticVTable());
ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d());
- Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
- o->internalClass = ic;
- Q_ASSERT(o->internalClass && o->internalClass->vtable);
- Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d());
- return static_cast<typename ObjectType::Data *>(o);
+ return allocateObject<ObjectType>(ic);
}
template <typename ManagedType, typename Arg1>
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
{
typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
- o->internalClass = ManagedType::defaultInternalClass(engine);
+ o->internalClass.set(engine, ManagedType::defaultInternalClass(engine));
Q_ASSERT(o->internalClass && o->internalClass->vtable);
o->init(arg1);
return o;
}
- template <typename ObjectType>
- typename ObjectType::Data *allocObject(InternalClass *ic)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- t->d_unchecked()->init();
- return t->d();
- }
-
- template <typename ObjectType>
- typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : nullptr));
- Q_UNUSED(prototype);
- t->d_unchecked()->init();
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1>
- typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : nullptr));
- Q_UNUSED(prototype);
- t->d_unchecked()->init(arg1);
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1, typename Arg2>
- typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : nullptr));
- Q_UNUSED(prototype);
- t->d_unchecked()->init(arg1, arg2);
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3>
- typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2, Arg3 arg3)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : nullptr));
- Q_UNUSED(prototype);
- t->d_unchecked()->init(arg1, arg2, arg3);
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- typename ObjectType::Data *allocObject(InternalClass *ic, Object *prototype, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic));
- Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : nullptr));
- Q_UNUSED(prototype);
- t->d_unchecked()->init(arg1, arg2, arg3, arg4);
- return t->d();
- }
-
- template <typename ObjectType>
- typename ObjectType::Data *allocObject()
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init();
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1>
- typename ObjectType::Data *allocObject(Arg1 arg1)
+ template <typename ObjectType, typename... Args>
+ typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args)
{
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init(arg1);
- return t->d();
- }
-
- template <typename ObjectType, typename Arg1, typename Arg2>
- typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2)
- {
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init(arg1, arg2);
- return t->d();
+ typename ObjectType::Data *d = allocateObject<ObjectType>(ic);
+ d->init(args...);
+ return d;
}
- template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3>
- typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ template <typename ObjectType, typename... Args>
+ typename ObjectType::Data *allocObject(InternalClass *ic, Args... args)
{
- Scope scope(engine);
- Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init(arg1, arg2, arg3);
- return t->d();
+ typename ObjectType::Data *d = allocateObject<ObjectType>(ic);
+ d->init(args...);
+ return d;
}
- template <typename ObjectType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- typename ObjectType::Data *allocObject(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ template <typename ObjectType, typename... Args>
+ typename ObjectType::Data *allocate(Args... args)
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init(arg1, arg2, arg3, arg4);
- return t->d();
- }
-
-
- template <typename ManagedType>
- typename ManagedType::Data *alloc()
- {
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init();
- return t->d();
- }
-
- template <typename ManagedType, typename Arg1>
- typename ManagedType::Data *alloc(Arg1 arg1)
- {
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(arg1);
- return t->d();
- }
-
- template <typename ManagedType, typename Arg1, typename Arg2>
- typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2)
- {
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(arg1, arg2);
- return t->d();
- }
-
- template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3>
- typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3)
- {
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(arg1, arg2, arg3);
- return t->d();
- }
-
- template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
- {
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(arg1, arg2, arg3, arg4);
+ t->d_unchecked()->init(args...);
return t->d();
}
- template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
- typename ManagedType::Data *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ template <typename ManagedType, typename... Args>
+ typename ManagedType::Data *alloc(Args... args)
{
Scope scope(engine);
Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(arg1, arg2, arg3, arg4, arg5);
+ t->d_unchecked()->init(args...);
return t->d();
}
@@ -392,6 +266,14 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+ template<typename ManagedType>
+ typename ManagedType::Data *allocIC()
+ {
+ size_t size = align(sizeof(typename ManagedType::Data));
+ Heap::Base *b = *icAllocator.allocate(size, true);
+ return static_cast<typename ManagedType::Data *>(b);
+ }
+
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -409,6 +291,7 @@ public:
QV4::ExecutionEngine *engine;
ChunkAllocator *chunkAllocator;
BlockAllocator blockAllocator;
+ BlockAllocator icAllocator;
HugeItemAllocator hugeItemAllocator;
PersistentValueStorage *m_persistentValues;
PersistentValueStorage *m_weakValues;
@@ -423,6 +306,9 @@ public:
bool gcStats = false;
bool gcCollectorStats = false;
+ int allocationCount = 0;
+ size_t lastAllocRequestedSlots = 0;
+
struct {
size_t maxReservedMem = 0;
size_t maxAllocatedMem = 0;
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri
index e5b8ae2749..adab4ef9a2 100644
--- a/src/qml/parser/parser.pri
+++ b/src/qml/parser/parser.pri
@@ -3,20 +3,24 @@ HEADERS += \
$$PWD/qqmljsastfwd_p.h \
$$PWD/qqmljsastvisitor_p.h \
$$PWD/qqmljsengine_p.h \
- $$PWD/qqmljsgrammar_p.h \
$$PWD/qqmljslexer_p.h \
$$PWD/qqmljsmemorypool_p.h \
- $$PWD/qqmljsparser_p.h \
$$PWD/qqmljsglobal_p.h \
$$PWD/qqmljskeywords_p.h \
+ $$PWD/qqmljsengine_p.h \
+ $$PWD/qqmljsglobal_p.h
SOURCES += \
$$PWD/qqmljsast.cpp \
$$PWD/qqmljsastvisitor.cpp \
$$PWD/qqmljsengine_p.cpp \
- $$PWD/qqmljsgrammar.cpp \
$$PWD/qqmljslexer.cpp \
- $$PWD/qqmljsparser.cpp \
-OTHER_FILES += \
- $$PWD/qqmljs.g
+CONFIG += qlalr
+QLALRSOURCES = $$PWD/qqmljs.g
+QMAKE_QLALRFLAGS = --no-debug --qt
+
+OTHER_FILES += $$QLALRSOURCES
+
+# make sure we install the headers generated by qlalr
+private_headers.CONFIG += no_check_exist
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index d2d947e55c..7928881d8c 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -40,8 +40,7 @@
%parser QQmlJSGrammar
%decl qqmljsparser_p.h
%impl qqmljsparser.cpp
-%expect 5
-%expect-rr 2
+%expect 1
%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
%token T_BREAK "break" T_CASE "case" T_CATCH "catch"
@@ -64,7 +63,8 @@
%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")"
%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*"
-%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal"
+%token T_STAR_STAR "**" T_STAR_STAR_EQ "**=" T_STAR_EQ "*="
+%token T_STRING_LITERAL "string literal"
%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly"
%token T_SWITCH "switch" T_THIS "this" T_THROW "throw"
%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof"
@@ -77,14 +77,29 @@
%token T_MULTILINE_STRING_LITERAL "multiline string literal"
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
+%token T_ARROW "=>"
%token T_ENUM "enum"
+%token T_ELLIPSIS "..."
+%token T_YIELD "yield"
+%token T_SUPER "super"
+%token T_CLASS "class"
+%token T_EXTENDS "extends"
+%token T_STATIC "static"
+%token T_EXPORT "export"
+%token T_FROM "from"
+
+--- template strings
+%token T_NO_SUBSTITUTION_TEMPLATE"(no subst template)"
+%token T_TEMPLATE_HEAD "(template head)"
+%token T_TEMPLATE_MIDDLE "(template middle)"
+%token T_TEMPLATE_TAIL "(template tail)"
--- context keywords.
%token T_PUBLIC "public"
%token T_IMPORT "import"
%token T_PRAGMA "pragma"
%token T_AS "as"
-%token T_ON "on"
+%token T_OF "of"
%token T_GET "get"
%token T_SET "set"
@@ -95,11 +110,16 @@
%token T_FEED_UI_OBJECT_MEMBER
%token T_FEED_JS_STATEMENT
%token T_FEED_JS_EXPRESSION
-%token T_FEED_JS_SOURCE_ELEMENT
-%token T_FEED_JS_PROGRAM
+%token T_FEED_JS_SCRIPT
+%token T_FEED_JS_MODULE
-%nonassoc SHIFT_THERE
-%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET
+--- Lookahead handling
+%token T_FORCE_DECLARATION "(force decl)"
+%token T_FORCE_BLOCK "(force block)"
+%token T_FOR_LOOKAHEAD_OK "(for lookahead ok)"
+
+--%left T_PLUS T_MINUS
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM
%nonassoc REDUCE_HERE
%start TopLevel
@@ -143,10 +163,10 @@
**
****************************************************************************/
-#include "qqmljsengine_p.h"
-#include "qqmljslexer_p.h"
-#include "qqmljsast_p.h"
-#include "qqmljsmemorypool_p.h"
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsmemorypool_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qcoreapplication.h>
@@ -221,10 +241,10 @@
#ifndef QQMLJSPARSER_P_H
#define QQMLJSPARSER_P_H
-#include "qqmljsglobal_p.h"
-#include "qqmljsgrammar_p.h"
-#include "qqmljsast_p.h"
-#include "qqmljsengine_p.h"
+#include <private/qqmljsglobal_p.h>
+#include <private/qqmljsgrammar_p.h>
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
@@ -241,30 +261,32 @@ public:
union Value {
int ival;
double dval;
+ AST::VariableScope scope;
+ AST::ForEachType forEachType;
AST::ArgumentList *ArgumentList;
AST::CaseBlock *CaseBlock;
AST::CaseClause *CaseClause;
AST::CaseClauses *CaseClauses;
AST::Catch *Catch;
AST::DefaultClause *DefaultClause;
- AST::ElementList *ElementList;
AST::Elision *Elision;
AST::ExpressionNode *Expression;
+ AST::TemplateLiteral *Template;
AST::Finally *Finally;
AST::FormalParameterList *FormalParameterList;
- AST::FunctionBody *FunctionBody;
AST::FunctionDeclaration *FunctionDeclaration;
AST::Node *Node;
AST::PropertyName *PropertyName;
- AST::PropertyAssignment *PropertyAssignment;
- AST::PropertyAssignmentList *PropertyAssignmentList;
- AST::SourceElement *SourceElement;
- AST::SourceElements *SourceElements;
AST::Statement *Statement;
AST::StatementList *StatementList;
AST::Block *Block;
- AST::VariableDeclaration *VariableDeclaration;
AST::VariableDeclarationList *VariableDeclarationList;
+ AST::Pattern *Pattern;
+ AST::PatternElement *PatternElement;
+ AST::PatternElementList *PatternElementList;
+ AST::PatternProperty *PatternProperty;
+ AST::PatternPropertyList *PatternPropertyList;
+ AST::ClassElementList *ClassElementList;
AST::UiProgram *UiProgram;
AST::UiHeaderItemList *UiHeaderItemList;
@@ -290,12 +312,13 @@ public:
~Parser();
// parse a UI program
- bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parse() { ++functionNestingLevel; bool r = parse(T_FEED_UI_PROGRAM); --functionNestingLevel; return r; }
bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
- bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
- bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
- bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+ bool parseUiObjectMember() { ++functionNestingLevel; bool r = parse(T_FEED_UI_OBJECT_MEMBER); --functionNestingLevel; return r; }
+ bool parseProgram() { return parse(T_FEED_JS_SCRIPT); }
+ bool parseScript() { return parse(T_FEED_JS_SCRIPT); }
+ bool parseModule() { return parse(T_FEED_JS_MODULE); }
AST::UiProgram *ast() const
{ return AST::cast<AST::UiProgram *>(program); }
@@ -366,20 +389,30 @@ protected:
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
+ void pushToken(int token);
+ int lookaheadToken(Lexer *lexer);
+
+ void syntaxError(const AST::SourceLocation &location, const char *message) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, QLatin1String(message)));
+ }
+ void syntaxError(const AST::SourceLocation &location, const QString &message) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, message));
+ }
+
protected:
Engine *driver;
MemoryPool *pool;
- int tos;
- int stack_size;
- Value *sym_stack;
- int *state_stack;
- AST::SourceLocation *location_stack;
- QStringRef *string_stack;
+ int tos = 0;
+ int stack_size = 0;
+ Value *sym_stack = nullptr;
+ int *state_stack = nullptr;
+ AST::SourceLocation *location_stack = nullptr;
+ QVector<QStringRef> string_stack;
- AST::Node *program;
+ AST::Node *program = nullptr;
- // error recovery
- enum { TOKEN_BUFFER_SIZE = 3 };
+ // error recovery and lookahead handling
+ enum { TOKEN_BUFFER_SIZE = 5 };
struct SavedToken {
int token;
@@ -388,14 +421,25 @@ protected:
QStringRef spell;
};
- double yylval;
+ int yytoken = -1;
+ double yylval = 0.;
QStringRef yytokenspell;
AST::SourceLocation yylloc;
AST::SourceLocation yyprevlloc;
SavedToken token_buffer[TOKEN_BUFFER_SIZE];
- SavedToken *first_token;
- SavedToken *last_token;
+ SavedToken *first_token = nullptr;
+ SavedToken *last_token = nullptr;
+
+ int functionNestingLevel = 0;
+
+ enum CoverExpressionType {
+ CE_Invalid,
+ CE_ParenthesizedExpression,
+ CE_FormalParameterList
+ };
+ AST::SourceLocation coverExpressionErrorLocation;
+ CoverExpressionType coverExpressionType = CE_Invalid;
QList<DiagnosticMessage> diagnostic_messages;
};
@@ -424,6 +468,8 @@ protected:
// qlalr --no-debug --no-lines --qt qqmljs.g
//
+#define UNIMPLEMENTED syntaxError(loc(1), "Unimplemented"); return false
+
using namespace QQmlJS;
QT_QML_BEGIN_NAMESPACE
@@ -438,22 +484,12 @@ void Parser::reallocateStack()
sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
- string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+ string_stack.resize(stack_size);
}
Parser::Parser(Engine *engine):
driver(engine),
- pool(engine->pool()),
- tos(0),
- stack_size(0),
- sym_stack(0),
- state_stack(0),
- location_stack(0),
- string_stack(0),
- program(0),
- yylval(0),
- first_token(0),
- last_token(0)
+ pool(engine->pool())
{
}
@@ -463,7 +499,6 @@ Parser::~Parser()
free(sym_stack);
free(state_stack);
free(location_stack);
- free(string_stack);
}
}
@@ -517,17 +552,39 @@ AST::UiQualifiedPragmaId *Parser::reparseAsQualifiedPragmaId(AST::ExpressionNode
return 0;
}
+void Parser::pushToken(int token)
+{
+ last_token->token = yytoken;
+ last_token->dval = yylval;
+ last_token->spell = yytokenspell;
+ last_token->loc = yylloc;
+ ++last_token;
+ yytoken = token;
+}
+
+int Parser::lookaheadToken(Lexer *lexer)
+{
+ if (yytoken < 0) {
+ yytoken = lexer->lex();
+ yylval = lexer->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ }
+ return yytoken;
+}
+
+//#define PARSER_DEBUG
bool Parser::parse(int startToken)
{
Lexer *lexer = driver->lexer();
bool hadErrors = false;
- int yytoken = -1;
+ yytoken = -1;
int action = 0;
token_buffer[0].token = startToken;
first_token = &token_buffer[0];
- if (startToken == T_FEED_JS_PROGRAM && !lexer->qmlMode()) {
+ if (startToken == T_FEED_JS_SCRIPT && !lexer->qmlMode()) {
Directives ignoreDirectives;
Directives *directives = driver->directives();
if (!directives)
@@ -570,10 +627,19 @@ bool Parser::parse(int startToken)
yytokenspell = first_token->spell;
yylloc = first_token->loc;
++first_token;
+ if (first_token == last_token)
+ first_token = last_token = &token_buffer[0];
}
}
+#ifdef PARSER_DEBUG
+ qDebug() << " in state" << action;
+#endif
+
action = t_action(action, yytoken);
+#ifdef PARSER_DEBUG
+ qDebug() << " current token" << yytoken << (yytoken >= 0 ? spell[yytoken] : "(null)") << "new state" << action;
+#endif
if (action > 0) {
if (action != ACCEPT_STATE) {
yytoken = -1;
@@ -588,6 +654,10 @@ bool Parser::parse(int startToken)
const int r = -action - 1;
tos -= rhs[r];
+#ifdef PARSER_DEBUG
+ qDebug() << " reducing through rule " << -action;
+#endif
+
switch (r) {
./
@@ -595,2582 +665,3428 @@ bool Parser::parse(int startToken)
-- Declarative UI
--------------------------------------------------------------------------------------------------------
-TopLevel: T_FEED_UI_PROGRAM UiProgram ;
+TopLevel: T_FEED_UI_PROGRAM UiProgram;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
-TopLevel: T_FEED_JS_STATEMENT Statement ;
+TopLevel: T_FEED_JS_STATEMENT Statement;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
-TopLevel: T_FEED_JS_EXPRESSION Expression ;
+TopLevel: T_FEED_JS_EXPRESSION Expression;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
-TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ;
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
-TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ;
+TopLevel: T_FEED_JS_SCRIPT Script;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
-TopLevel: T_FEED_JS_PROGRAM Program ;
+TopLevel: T_FEED_JS_MODULE Module;
/.
-case $rule_number: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+ } break;
./
+
UiProgram: UiHeaderItemListOpt UiRootMember;
/.
-case $rule_number: {
- sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiHeaderItemList,
- sym(2).UiObjectMemberList->finish());
-} break;
+ case $rule_number: {
+ sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiHeaderItemList, sym(2).UiObjectMemberList->finish());
+ } break;
./
-UiHeaderItemListOpt: Empty ;
-UiHeaderItemListOpt: UiHeaderItemList ;
+UiHeaderItemListOpt: Empty;
+UiHeaderItemListOpt: UiHeaderItemList;
/.
-case $rule_number: {
- sym(1).Node = sym(1).UiHeaderItemList->finish();
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).UiHeaderItemList->finish();
+ } break;
./
-UiHeaderItemList: UiPragma ;
+UiHeaderItemList: UiPragma;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
+ } break;
./
-UiHeaderItemList: UiImport ;
+UiHeaderItemList: UiImport;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
+ } break;
./
-UiHeaderItemList: UiHeaderItemList UiPragma ;
+UiHeaderItemList: UiHeaderItemList UiPragma;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiPragma);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiPragma);
+ } break;
./
-UiHeaderItemList: UiHeaderItemList UiImport ;
+UiHeaderItemList: UiHeaderItemList UiImport;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiImport);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiImport);
+ } break;
./
-PragmaId: MemberExpression ;
+PragmaId: MemberExpression;
-ImportId: MemberExpression ;
+ImportId: MemberExpression;
-UiPragma: UiPragmaHead T_AUTOMATIC_SEMICOLON ;
-UiPragma: UiPragmaHead T_SEMICOLON ;
+UiPragma: UiPragmaHead T_AUTOMATIC_SEMICOLON;
+UiPragma: UiPragmaHead T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).UiPragma->semicolonToken = loc(2);
-} break;
+ case $rule_number: {
+ sym(1).UiPragma->semicolonToken = loc(2);
+ } break;
./
-UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
-UiImport: UiImportHead T_SEMICOLON ;
+UiImport: UiImportHead T_AUTOMATIC_SEMICOLON;
+UiImport: UiImportHead T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).UiImport->semicolonToken = loc(2);
-} break;
+ 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 ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).UiImport->versionToken = loc(2);
- sym(1).UiImport->semicolonToken = loc(3);
-} break;
+ case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+ } break;
./
-UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).UiImport->versionToken = loc(2);
- sym(1).UiImport->asToken = loc(3);
- sym(1).UiImport->importIdToken = loc(4);
- sym(1).UiImport->importId = stringRef(4);
- sym(1).UiImport->semicolonToken = loc(5);
-} break;
+ case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = stringRef(4);
+ sym(1).UiImport->semicolonToken = loc(5);
+ } break;
./
-UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ;
+UiImport: UiImportHead T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON;
+UiImport: UiImportHead T_AS QmlIdentifier T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).UiImport->asToken = loc(2);
- sym(1).UiImport->importIdToken = loc(3);
- sym(1).UiImport->importId = stringRef(3);
- sym(1).UiImport->semicolonToken = loc(4);
-} break;
+ case $rule_number: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = stringRef(3);
+ sym(1).UiImport->semicolonToken = loc(4);
+ } break;
./
-UiPragmaHead: T_PRAGMA PragmaId ;
+UiPragmaHead: T_PRAGMA PragmaId;
/.
-case $rule_number: {
- AST::UiPragma *node = 0;
+ case $rule_number: {
+ AST::UiPragma *node = 0;
- if (AST::UiQualifiedPragmaId *qualifiedId = reparseAsQualifiedPragmaId(sym(2).Expression)) {
- node = new (pool) AST::UiPragma(qualifiedId);
- }
+ if (AST::UiQualifiedPragmaId *qualifiedId = reparseAsQualifiedPragmaId(sym(2).Expression))
+ node = new (pool) AST::UiPragma(qualifiedId);
- sym(1).Node = node;
+ sym(1).Node = node;
- if (node) {
- node->pragmaToken = loc(1);
- } else {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id")));
+ if (node) {
+ node->pragmaToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
- return false; // ### remove me
- }
-} break;
+ return false; // ### remove me
+ }
+ } break;
./
-UiImportHead: T_IMPORT ImportId ;
+UiImportHead: T_IMPORT ImportId;
/.
-case $rule_number: {
- AST::UiImport *node = 0;
-
- if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
- node = new (pool) AST::UiImport(importIdLiteral->value);
- node->fileNameToken = loc(2);
- } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
- node = new (pool) AST::UiImport(qualifiedId);
- node->fileNameToken = loc(2);
- }
+ case $rule_number: {
+ AST::UiImport *node = 0;
- sym(1).Node = node;
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(qualifiedId);
+ node->fileNameToken = loc(2);
+ }
- if (node) {
- node->importToken = loc(1);
- } else {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id or a string literal")));
+ sym(1).Node = node;
- return false; // ### remove me
- }
-} break;
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+ } break;
./
Empty: ;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-UiRootMember: UiObjectDefinition ;
+UiRootMember: UiObjectDefinition;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+ } break;
./
-UiObjectMemberList: UiObjectMember ;
+UiObjectMemberList: UiObjectMember;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+ } break;
./
-UiObjectMemberList: UiObjectMemberList UiObjectMember ;
+UiObjectMemberList: UiObjectMemberList UiObjectMember;
/.
-case $rule_number: {
- AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
- sym(1).UiObjectMemberList, sym(2).UiObjectMember);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+ } break;
./
-UiArrayMemberList: UiObjectDefinition ;
+UiArrayMemberList: UiObjectDefinition;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+ } break;
./
-UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ;
+UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition;
/.
-case $rule_number: {
- AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
- sym(1).UiArrayMemberList, sym(3).UiObjectMember);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-UiObjectInitializer: T_LBRACE T_RBRACE ;
+UiObjectInitializer: T_LBRACE T_RBRACE;
/.
-case $rule_number: {
- AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ;
+UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE;
/.
-case $rule_number: {
- AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-UiObjectDefinition: UiQualifiedId UiObjectInitializer ;
+UiObjectDefinition: UiQualifiedId UiObjectInitializer;
/.
-case $rule_number: {
- AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
- sym(2).UiObjectInitializer);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId, sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: UiObjectDefinition ;
+UiObjectMember: UiObjectDefinition;
-UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+UiObjectMember: UiQualifiedId T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET;
/.
-case $rule_number: {
- AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
- sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
- node->colonToken = loc(2);
- node->lbracketToken = loc(3);
- node->rbracketToken = loc(5);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(sym(1).UiQualifiedId, sym(5).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(4);
+ node->rbracketToken = loc(6);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+UiObjectMember: UiQualifiedId T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
/.
-case $rule_number: {
- AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
- sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(1).UiQualifiedId, sym(4).UiQualifiedId, sym(5).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ;
+UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer;
/.
-case $rule_number: {
- AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
- sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
- node->colonToken = loc(2);
- node->hasOnToken = true;
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+ } break;
./
-UiScriptStatement: Block ;
-UiScriptStatement: EmptyStatement ;
-UiScriptStatement: ExpressionStatement ;
-UiScriptStatement: IfStatement ;
-UiScriptStatement: WithStatement ;
-UiScriptStatement: SwitchStatement ;
-UiScriptStatement: TryStatement ;
-UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ;
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE;
/.
-case $rule_number:
-{
- AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
- sym(1).UiQualifiedId, sym(3).Statement);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
+ l->lbraceToken = loc(1);
+ l->rbraceToken = loc(4);
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ sym(1).Node = node;
+ } break;
./
-UiPropertyType: T_VAR ;
-/.
-case $rule_number: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-./
-UiPropertyType: T_RESERVED_WORD ;
+UiScriptStatement: ExpressionStatementLookahead T_FORCE_DECLARATION ExpressionStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead T_FORCE_BLOCK Block;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead T_FORCE_BLOCK UiObjectLiteral;
/.
-case $rule_number: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(3).Node;
+ } break;
./
-UiPropertyType: T_IDENTIFIER ;
-/.
-case $rule_number: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-./
-UiPropertyType: UiPropertyType T_DOT T_IDENTIFIER ;
+UiScriptStatement: ExpressionStatementLookahead EmptyStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead ExpressionStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead IfStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead WithStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead SwitchStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+UiScriptStatement: ExpressionStatementLookahead TryStatement;
/.
-case $rule_number: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(sym(1).UiQualifiedId, stringRef(3));
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ } break;
./
-UiParameterListOpt: ;
+UiObjectMember: UiQualifiedId T_COLON UiScriptStatement;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+case $rule_number:
+{
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-UiParameterListOpt: UiParameterList ;
+UiPropertyType: T_VAR;
/.
-case $rule_number: {
- sym(1).Node = sym(1).UiParameterList->finish ();
-} break;
+ case $rule_number: {
+ AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UiParameterList: UiPropertyType JsIdentifier ;
+UiPropertyType: T_RESERVED_WORD;
/.
-case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2));
- node->propertyTypeToken = loc(1);
- node->identifierToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ;
+UiPropertyType: T_IDENTIFIER;
/.
-case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4));
- node->propertyTypeToken = loc(3);
- node->commaToken = loc(2);
- node->identifierToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } 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 ;
+UiPropertyType: UiPropertyType T_DOT T_IDENTIFIER;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
- node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(2);
- node->parameters = sym(4).UiParameterList;
- node->semicolonToken = loc(6);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(sym(1).UiQualifiedId, stringRef(3));
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ;
+UiParameterListOpt: ;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
- node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+UiParameterListOpt: UiParameterList;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).UiParameterList->finish();
+ } break;
./
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+UiParameterList: UiPropertyType QmlIdentifier;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4);
- sym(1).Node = node;
-} break;
-./
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2));
+ node->propertyTypeToken = loc(1);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5);
- sym(1).Node = node;
-} break;
-./
-
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
-UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+ case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4));
+ node->propertyTypeToken = loc(3);
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+ } 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;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->typeModifier = stringRef(3);
- node->propertyToken = loc(2);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(7);
- node->semicolonToken = loc(8);
- sym(1).Node = node;
-} break;
-./
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+ } break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } 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;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+ } break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+ } break;
+./
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
-/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3),
- sym(5).Statement);
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+ } 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;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->typeModifier = stringRef(3);
+ node->propertyToken = loc(2);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(7);
+ node->semicolonToken = loc(8);
+ sym(1).Node = node;
+ } break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+ } break;
+./
+
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4),
- sym(6).Statement);
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4),
- sym(6).Statement);
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
- sym(1).Node = node;
-} break;
-./
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
-/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
- propertyName->identifierToken = loc(6);
- propertyName->next = 0;
-
- AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
- propertyName, sym(9).UiArrayMemberList->finish());
- binding->colonToken = loc(7);
- binding->lbracketToken = loc(8);
- binding->rbracketToken = loc(10);
-
- node->binding = binding;
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
- sym(1).Node = node;
-} break;
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4); // insert a fake ';' before ':'
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
- propertyName->identifierToken = loc(3);
- propertyName->next = 0;
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
- AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
- propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
- binding->colonToken = loc(4);
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer);
+ binding->colonToken = loc(4);
- node->binding = binding;
+ node->binding = binding;
- sym(1).Node = node;
-} break;
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
/.
-case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5); // insert a fake ';' before ':'
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5); // insert a fake ';' before ':'
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4));
- propertyName->identifierToken = loc(4);
- propertyName->next = 0;
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4));
+ propertyName->identifierToken = loc(4);
+ propertyName->next = 0;
- AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
- propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer);
- binding->colonToken = loc(5);
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(7).UiQualifiedId, sym(8).UiObjectInitializer);
+ binding->colonToken = loc(5);
- node->binding = binding;
+ node->binding = binding;
- sym(1).Node = node;
-} break;
+ sym(1).Node = node;
+ } break;
./
-UiObjectMember: FunctionDeclaration ;
+UiObjectMember: FunctionDeclaration;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+ } break;
./
-UiObjectMember: VariableStatement ;
+UiObjectMember: VariableStatement;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+ } break;
+./
+
+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")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+ } break;
./
UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE;
/.
-case $rule_number: {
- AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
- enumDeclaration->enumToken = loc(1);
- enumDeclaration->rbraceToken = loc(5);
- sym(1).Node = enumDeclaration;
- break;
-}
+ case $rule_number: {
+ AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
+ enumDeclaration->enumToken = loc(1);
+ enumDeclaration->rbraceToken = loc(5);
+ sym(1).Node = enumDeclaration;
+ break;
+ }
./
EnumMemberList: T_IDENTIFIER;
/.
-case $rule_number: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1));
- node->memberToken = loc(1);
- sym(1).Node = node;
- break;
-}
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1));
+ node->memberToken = loc(1);
+ sym(1).Node = node;
+ break;
+ }
./
EnumMemberList: T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
/.
-case $rule_number: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), sym(3).dval);
- node->memberToken = loc(1);
- node->valueToken = loc(3);
- sym(1).Node = node;
- break;
-}
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), sym(3).dval);
+ node->memberToken = loc(1);
+ node->valueToken = loc(3);
+ sym(1).Node = node;
+ break;
+ }
./
EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER;
/.
-case $rule_number: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3));
- node->memberToken = loc(3);
- sym(1).Node = node;
- break;
-}
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3));
+ node->memberToken = loc(3);
+ sym(1).Node = node;
+ break;
+ }
./
EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
/.
-case $rule_number: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), sym(5).dval);
- node->memberToken = loc(3);
- node->valueToken = loc(5);
- sym(1).Node = node;
- break;
-}
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), sym(5).dval);
+ node->memberToken = loc(3);
+ node->valueToken = loc(5);
+ sym(1).Node = node;
+ break;
+ }
./
-JsIdentifier: T_IDENTIFIER;
+QmlIdentifier: T_IDENTIFIER;
+QmlIdentifier: T_PROPERTY;
+QmlIdentifier: T_SIGNAL;
+QmlIdentifier: T_READONLY;
+QmlIdentifier: T_ON;
+QmlIdentifier: T_GET;
+QmlIdentifier: T_SET;
+QmlIdentifier: T_FROM;
+QmlIdentifier: T_OF;
-JsIdentifier: T_PROPERTY ;
-JsIdentifier: T_SIGNAL ;
-JsIdentifier: T_READONLY ;
-JsIdentifier: T_ON ;
-JsIdentifier: T_GET ;
-JsIdentifier: T_SET ;
+JsIdentifier: T_IDENTIFIER;
+JsIdentifier: T_PROPERTY;
+JsIdentifier: T_SIGNAL;
+JsIdentifier: T_READONLY;
+JsIdentifier: T_ON;
+JsIdentifier: T_GET;
+JsIdentifier: T_SET;
+JsIdentifier: T_FROM;
+JsIdentifier: T_STATIC;
+JsIdentifier: T_OF;
+
+IdentifierReference: JsIdentifier;
+BindingIdentifier: IdentifierReference;
--------------------------------------------------------------------------------------------------------
-- Expressions
--------------------------------------------------------------------------------------------------------
-PrimaryExpression: T_THIS ;
+PrimaryExpression: T_THIS;
/.
-case $rule_number: {
- AST::ThisExpression *node = new (pool) AST::ThisExpression();
- node->thisToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ThisExpression *node = new (pool) AST::ThisExpression();
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PrimaryExpression: JsIdentifier ;
+PrimaryExpression: IdentifierReference;
/.
-case $rule_number: {
- AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PrimaryExpression: T_NULL ;
+PrimaryExpression: Literal;
+PrimaryExpression: ArrayLiteral;
+PrimaryExpression: ObjectLiteral;
+PrimaryExpression: FunctionExpression;
+PrimaryExpression: ClassExpression;
+PrimaryExpression: GeneratorExpression;
+PrimaryExpression: RegularExpressionLiteral;
+PrimaryExpression: TemplateLiteral;
+
+PrimaryExpression: CoverParenthesizedExpressionAndArrowParameterList;
/.
-case $rule_number: {
- AST::NullExpression *node = new (pool) AST::NullExpression();
- node->nullToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ if (coverExpressionType != CE_ParenthesizedExpression) {
+ syntaxError(coverExpressionErrorLocation, "Expected token ')'.");
+ return false;
+ }
+ } break;
./
-PrimaryExpression: T_TRUE ;
+-- Parsing of the CoverParenthesizedExpressionAndArrowParameterList is restricted to the one rule below when this is parsed as a primary expression
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_RPAREN;
/.
-case $rule_number: {
- AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
- node->trueToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+ coverExpressionType = CE_ParenthesizedExpression;
+ } break;
./
-PrimaryExpression: T_FALSE ;
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN T_RPAREN;
/.
-case $rule_number: {
- AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
- node->falseToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ coverExpressionErrorLocation = loc(2);
+ coverExpressionType = CE_FormalParameterList;
+ } break;
./
-PrimaryExpression: T_NUMERIC_LITERAL ;
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN BindingRestElement T_RPAREN;
/.
-case $rule_number: {
- AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = (new (pool) AST::FormalParameterList(nullptr, sym(2).PatternElement))->finish();
+ sym(1).Node = node;
+ coverExpressionErrorLocation = loc(2);
+ coverExpressionType = CE_FormalParameterList;
+ } break;
./
-PrimaryExpression: T_MULTILINE_STRING_LITERAL ;
-/.case $rule_number:./
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_COMMA BindingRestElementOpt T_RPAREN;
+/.
+ case $rule_number: {
+ AST::FormalParameterList *list = sym(2).Expression->reparseAsFormalParameterList(pool);
+ if (!list) {
+ syntaxError(loc(1), "Invalid Arrow parameter list.");
+ return false;
+ }
+ if (sym(4).Node) {
+ list = new (pool) AST::FormalParameterList(list, sym(4).PatternElement);
+ }
+ coverExpressionErrorLocation = loc(4);
+ coverExpressionType = CE_FormalParameterList;
+ sym(1).Node = list->finish();
+ } break;
+./
-PrimaryExpression: T_STRING_LITERAL ;
+Literal: T_NULL;
/.
-case $rule_number: {
- AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NullExpression *node = new (pool) AST::NullExpression();
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+Literal: T_TRUE;
+/.
+ case $rule_number: {
+ AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+Literal: T_FALSE;
+/.
+ case $rule_number: {
+ AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+Literal: T_NUMERIC_LITERAL;
+/.
+ case $rule_number: {
+ AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PrimaryExpression: T_DIVIDE_ ;
+Literal: T_MULTILINE_STRING_LITERAL;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+Literal: T_STRING_LITERAL;
+/.
+ case $rule_number: {
+ AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+RegularExpressionLiteral: T_DIVIDE_;
/:
#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number
:/
/.
-case $rule_number: {
- bool rx = lexer->scanRegExp(Lexer::NoPrefix);
- if (!rx) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
- return false; // ### remove me
- }
-
- loc(1).length = lexer->tokenLength();
- yylloc = loc(1); // adjust the location of the current token
-
- AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
- driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
+{
+ Lexer::RegExpBodyPrefix prefix;
+ case $rule_number:
+ prefix = Lexer::NoPrefix;
+ goto scan_regexp;
./
-PrimaryExpression: T_DIVIDE_EQ ;
+RegularExpressionLiteral: T_DIVIDE_EQ;
/:
#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number
:/
/.
-case $rule_number: {
- bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
- if (!rx) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
- return false;
- }
+ case $rule_number:
+ prefix = Lexer::EqualPrefix;
+ goto scan_regexp;
- loc(1).length = lexer->tokenLength();
- yylloc = loc(1); // adjust the location of the current token
+ scan_regexp: {
+ bool rx = lexer->scanRegExp(prefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
- AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
- driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+ } break;
+}
./
-PrimaryExpression: T_LBRACKET T_RBRACKET ;
+
+ArrayLiteral: T_LBRACKET ElisionOpt T_RBRACKET;
/.
-case $rule_number: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElementList *list = nullptr;
+ if (sym(2).Elision)
+ list = (new (pool) AST::PatternElementList(sym(2).Elision, nullptr))->finish();
+ AST::ArrayPattern *node = new (pool) AST::ArrayPattern(list);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-PrimaryExpression: T_LBRACKET Elision T_RBRACKET ;
+ArrayLiteral: T_LBRACKET ElementList T_RBRACKET;
/.
-case $rule_number: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ArrayPattern *node = new (pool) AST::ArrayPattern(sym(2).PatternElementList->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ;
+ArrayLiteral: T_LBRACKET ElementList T_COMMA ElisionOpt T_RBRACKET;
/.
-case $rule_number: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ auto *list = sym(2).PatternElementList;
+ if (sym(4).Elision) {
+ AST::PatternElementList *l = new (pool) AST::PatternElementList(sym(4).Elision, nullptr);
+ list = list->append(l);
+ }
+ AST::ArrayPattern *node = new (pool) AST::ArrayPattern(list->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+ Q_ASSERT(node->isValidArrayLiteral());
+ } break;
./
-PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ;
+ElementList: AssignmentExpression_In;
/.
-case $rule_number: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
- (AST::Elision *) 0);
- node->lbracketToken = loc(1);
- node->commaToken = loc(3);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *e = new (pool) AST::PatternElement(sym(1).Expression);
+ sym(1).Node = new (pool) AST::PatternElementList(nullptr, e);
+ } break;
./
-PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ;
+ElementList: Elision AssignmentExpression_In;
/.
-case $rule_number: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
- sym(4).Elision->finish());
- node->lbracketToken = loc(1);
- node->commaToken = loc(3);
- node->rbracketToken = loc(5);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *e = new (pool) AST::PatternElement(sym(2).Expression);
+ sym(1).Node = new (pool) AST::PatternElementList(sym(1).Elision->finish(), e);
+ } break;
./
--- PrimaryExpression: T_LBRACE T_RBRACE ;
--- /.
--- case $rule_number: {
--- sym(1).Node = new (pool) AST::ObjectLiteral();
--- } break;
--- ./
+ElementList: ElisionOpt SpreadElement;
+/.
+ case $rule_number: {
+ AST::PatternElementList *node = new (pool) AST::PatternElementList(sym(1).Elision, sym(2).PatternElement);
+ sym(1).Node = node;
+ } break;
+./
-PrimaryExpression: T_LBRACE PropertyAssignmentListOpt T_RBRACE ;
+ElementList: ElementList T_COMMA ElisionOpt AssignmentExpression_In;
/.
-case $rule_number: {
- AST::ObjectLiteral *node = 0;
- if (sym(2).Node)
- node = new (pool) AST::ObjectLiteral(
- sym(2).PropertyAssignmentList->finish ());
- else
- node = new (pool) AST::ObjectLiteral();
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *e = new (pool) AST::PatternElement(sym(4).Expression);
+ AST::PatternElementList *node = new (pool) AST::PatternElementList(sym(3).Elision, e);
+ sym(1).Node = sym(1).PatternElementList->append(node);
+ } break;
./
-PrimaryExpression: T_LBRACE PropertyAssignmentList T_COMMA T_RBRACE ;
+ElementList: ElementList T_COMMA ElisionOpt SpreadElement;
/.
-case $rule_number: {
- AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
- sym(2).PropertyAssignmentList->finish ());
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElementList *node = new (pool) AST::PatternElementList(sym(3).Elision, sym(4).PatternElement);
+ sym(1).Node = sym(1).PatternElementList->append(node);
+ } break;
./
-PrimaryExpression: T_LPAREN Expression T_RPAREN ;
+Elision: T_COMMA;
/.
-case $rule_number: {
- AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
- node->lparenToken = loc(1);
- node->rparenToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision();
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
+Elision: Elision T_COMMA;
+/.
+ case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-UiQualifiedId: MemberExpression ;
+ElisionOpt: ;
/.
-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")));
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
+./
- sym(1).Expression = mem->base;
- }
+ElisionOpt: Elision;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(1).Elision->finish();
+ } break;
+./
- if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
- sym(1).UiQualifiedId = qualifiedId;
- } else {
- sym(1).UiQualifiedId = 0;
+SpreadElement: T_ELLIPSIS AssignmentExpression;
+/.
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(sym(2).Expression, AST::PatternElement::SpreadElement);
+ sym(1).Node = node;
+ } break;
+./
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id")));
+ObjectLiteral: T_LBRACE T_RBRACE;
+/.
+ case $rule_number: {
+ AST::ObjectPattern *node = new (pool) AST::ObjectPattern();
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
- return false; // ### recover
- }
-} break;
+ObjectLiteral: T_LBRACE PropertyDefinitionList T_RBRACE;
+/.
+ case $rule_number: {
+ AST::ObjectPattern *node = new (pool) AST::ObjectPattern(sym(2).PatternPropertyList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-ElementList: AssignmentExpression ;
+ObjectLiteral: T_LBRACE PropertyDefinitionList T_COMMA T_RBRACE;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
-} break;
+ case $rule_number: {
+ AST::ObjectPattern *node = new (pool) AST::ObjectPattern(sym(2).PatternPropertyList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-ElementList: Elision AssignmentExpression ;
+
+UiPropertyDefinitionList: UiPropertyDefinition;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+PropertyDefinitionList: PropertyDefinition;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::PatternPropertyList(sym(1).PatternProperty);
+ } break;
./
-ElementList: ElementList T_COMMA AssignmentExpression ;
+UiPropertyDefinitionList: UiPropertyDefinitionList T_COMMA UiPropertyDefinition;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+PropertyDefinitionList: PropertyDefinitionList T_COMMA PropertyDefinition;
/.
-case $rule_number: {
- AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
- (AST::Elision *) 0, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternPropertyList *node = new (pool) AST::PatternPropertyList(sym(1).PatternPropertyList, sym(3).PatternProperty);
+ sym(1).Node = node;
+ } break;
./
-ElementList: ElementList T_COMMA Elision AssignmentExpression ;
+PropertyDefinition: IdentifierReference;
/.
-case $rule_number: {
- AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
- sym(4).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::IdentifierPropertyName *name = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ name->propertyNameToken = loc(1);
+ AST::IdentifierExpression *expr = new (pool) AST::IdentifierExpression(stringRef(1));
+ expr->identifierToken = loc(1);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(name, expr);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-Elision: T_COMMA ;
+-- Using this production should result in a syntax error when used in an ObjectLiteral
+PropertyDefinition: CoverInitializedName;
+
+CoverInitializedName: IdentifierReference Initializer_In;
/.
-case $rule_number: {
- AST::Elision *node = new (pool) AST::Elision();
- node->commaToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::IdentifierPropertyName *name = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ name->propertyNameToken = loc(1);
+ AST::IdentifierExpression *left = new (pool) AST::IdentifierExpression(stringRef(1));
+ left->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))
+ f->name = stringRef(1);
+ AST::BinaryExpression *assignment = new (pool) AST::BinaryExpression(left, QSOperator::Assign, sym(2).Expression);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(name, assignment);
+ node->colonToken = loc(1);
+ sym(1).Node = node;
+
+ } break;
./
-Elision: Elision T_COMMA ;
+UiPropertyDefinition: UiPropertyName T_COLON AssignmentExpression_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+PropertyDefinition: PropertyName T_COLON AssignmentExpression_In;
/.
-case $rule_number: {
- AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression);
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) {
+ if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName))
+ f->name = driver->newStringRef(sym(1).PropertyName->asString());
+ }
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+PropertyDefinition: MethodDefinition;
+
+PropertyName: LiteralPropertyName;
+PropertyName: ComputedPropertyName;
+
+LiteralPropertyName: IdentifierName;
+/.
+ case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyAssignment: PropertyName T_COLON AssignmentExpression ;
+UiPropertyName: T_STRING_LITERAL;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LiteralPropertyName: T_STRING_LITERAL;
/.
-case $rule_number: {
- AST::PropertyNameAndValue *node = new (pool) AST::PropertyNameAndValue(
- sym(1).PropertyName, sym(3).Expression);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyAssignment: T_GET PropertyName T_LPAREN T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+UiPropertyName: T_NUMERIC_LITERAL;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LiteralPropertyName: T_NUMERIC_LITERAL;
/.
-case $rule_number: {
- AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
- sym(2).PropertyName, sym(6).FunctionBody);
- node->getSetToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyAssignment: T_SET PropertyName T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+IdentifierName: IdentifierReference;
+IdentifierName: ReservedIdentifier;
+
+ReservedIdentifier: T_BREAK;
+ReservedIdentifier: T_CASE;
+ReservedIdentifier: T_CATCH;
+ReservedIdentifier: T_CONTINUE;
+ReservedIdentifier: T_DEFAULT;
+ReservedIdentifier: T_DELETE;
+ReservedIdentifier: T_DO;
+ReservedIdentifier: T_ELSE;
+ReservedIdentifier: T_ENUM;
+ReservedIdentifier: T_FALSE;
+ReservedIdentifier: T_FINALLY;
+ReservedIdentifier: T_FOR;
+ReservedIdentifier: T_FUNCTION;
+ReservedIdentifier: T_IF;
+ReservedIdentifier: T_IN;
+ReservedIdentifier: T_INSTANCEOF;
+ReservedIdentifier: T_NEW;
+ReservedIdentifier: T_NULL;
+ReservedIdentifier: T_RETURN;
+ReservedIdentifier: T_SWITCH;
+ReservedIdentifier: T_THIS;
+ReservedIdentifier: T_THROW;
+ReservedIdentifier: T_TRUE;
+ReservedIdentifier: T_TRY;
+ReservedIdentifier: T_TYPEOF;
+ReservedIdentifier: T_VAR;
+ReservedIdentifier: T_VOID;
+ReservedIdentifier: T_WHILE;
+ReservedIdentifier: T_CONST;
+ReservedIdentifier: T_LET;
+ReservedIdentifier: T_DEBUGGER;
+ReservedIdentifier: T_RESERVED_WORD;
+ReservedIdentifier: T_SUPER;
+ReservedIdentifier: T_WITH;
+ReservedIdentifier: T_CLASS;
+ReservedIdentifier: T_EXTENDS;
+ReservedIdentifier: T_EXPORT;
+
+ComputedPropertyName: T_LBRACKET AssignmentExpression_In T_RBRACKET;
/.
-case $rule_number: {
- AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
- sym(2).PropertyName, sym(4).FormalParameterList, sym(7).FunctionBody);
- node->getSetToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ComputedPropertyName *node = new (pool) AST::ComputedPropertyName(sym(2).Expression);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyAssignmentList: PropertyAssignment ;
+Initializer: T_EQ AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Initializer_In: T_EQ AssignmentExpression_In;
/.
case $rule_number: {
- sym(1).Node = new (pool) AST::PropertyAssignmentList(sym(1).PropertyAssignment);
+ sym(1) = sym(2);
} break;
./
-PropertyAssignmentList: PropertyAssignmentList T_COMMA PropertyAssignment ;
+
+InitializerOpt: ;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+InitializerOpt_In: ;
/.
-case $rule_number: {
- AST::PropertyAssignmentList *node = new (pool) AST::PropertyAssignmentList(
- sym(1).PropertyAssignmentList, sym(3).PropertyAssignment);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-PropertyName: JsIdentifier %prec SHIFT_THERE ;
+InitializerOpt: Initializer;
+InitializerOpt_In: Initializer_In;
+
+TemplateLiteral: T_NO_SUBSTITUTION_TEMPLATE;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+TemplateSpans: T_TEMPLATE_TAIL;
/.
-case $rule_number: {
- AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TemplateLiteral *node = new (pool) AST::TemplateLiteral(stringRef(1), nullptr);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyName: T_STRING_LITERAL ;
+TemplateSpans: T_TEMPLATE_MIDDLE Expression TemplateSpans;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+TemplateLiteral: T_TEMPLATE_HEAD Expression TemplateSpans;
/.
-case $rule_number: {
- AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TemplateLiteral *node = new (pool) AST::TemplateLiteral(stringRef(1), sym(2).Expression);
+ node->next = sym(3).Template;
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyName: T_NUMERIC_LITERAL ;
+
+MemberExpression: PrimaryExpression;
+
+Super: T_SUPER;
/.
-case $rule_number: {
- AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::SuperLiteral *node = new (pool) AST::SuperLiteral();
+ node->superToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-PropertyName: ReservedIdentifier ;
+
+MemberExpression: Super T_LBRACKET Expression_In T_RBRACKET;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+MemberExpression: MemberExpression T_LBRACKET Expression_In T_RBRACKET;
/.
-case $rule_number: {
- AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-ReservedIdentifier: T_BREAK ;
-ReservedIdentifier: T_CASE ;
-ReservedIdentifier: T_CATCH ;
-ReservedIdentifier: T_CONTINUE ;
-ReservedIdentifier: T_DEFAULT ;
-ReservedIdentifier: T_DELETE ;
-ReservedIdentifier: T_DO ;
-ReservedIdentifier: T_ELSE ;
-ReservedIdentifier: T_ENUM ;
-ReservedIdentifier: T_FALSE ;
-ReservedIdentifier: T_FINALLY ;
-ReservedIdentifier: T_FOR ;
-ReservedIdentifier: T_FUNCTION ;
-ReservedIdentifier: T_IF ;
-ReservedIdentifier: T_IN ;
-ReservedIdentifier: T_INSTANCEOF ;
-ReservedIdentifier: T_NEW ;
-ReservedIdentifier: T_NULL ;
-ReservedIdentifier: T_RETURN ;
-ReservedIdentifier: T_SWITCH ;
-ReservedIdentifier: T_THIS ;
-ReservedIdentifier: T_THROW ;
-ReservedIdentifier: T_TRUE ;
-ReservedIdentifier: T_TRY ;
-ReservedIdentifier: T_TYPEOF ;
-ReservedIdentifier: T_VAR ;
-ReservedIdentifier: T_VOID ;
-ReservedIdentifier: T_WHILE ;
-ReservedIdentifier: T_CONST ;
-ReservedIdentifier: T_LET ;
-ReservedIdentifier: T_DEBUGGER ;
-ReservedIdentifier: T_RESERVED_WORD ;
-ReservedIdentifier: T_WITH ;
-
-PropertyIdentifier: JsIdentifier ;
-PropertyIdentifier: ReservedIdentifier ;
-
-MemberExpression: PrimaryExpression ;
-MemberExpression: FunctionExpression ;
-
-MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ;
+
+-- the identifier has to be "target", catched at codegen time
+NewTarget: T_NEW T_DOT T_IDENTIFIER;
+/. case $rule_number:
+ {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken= loc(1);
+ sym(1).Node = node;
+ } Q_FALLTHROUGH();
+./
+MemberExpression: Super T_DOT IdentifierName;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+MemberExpression: MemberExpression T_DOT IdentifierName;
/.
-case $rule_number: {
- AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
- node->lbracketToken = loc(2);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-MemberExpression: MemberExpression T_DOT PropertyIdentifier ;
+MemberExpression: MetaProperty;
+
+MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN;
/.
-case $rule_number: {
- AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
- node->dotToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+ } break;
./
-MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+MetaProperty: NewTarget;
+
+
+NewExpression: MemberExpression;
+
+NewExpression: T_NEW NewExpression;
/.
-case $rule_number: {
- AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
- node->newToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-NewExpression: MemberExpression ;
-NewExpression: T_NEW NewExpression ;
+CallExpression: CallExpression TemplateLiteral;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+MemberExpression: MemberExpression TemplateLiteral;
/.
-case $rule_number: {
- AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
- node->newToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TaggedTemplate *node = new (pool) AST::TaggedTemplate(sym(1).Expression, sym(2).Template);
+ sym(1).Node = node;
+ } break;
./
-CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+CallExpression: MemberExpression T_LPAREN Arguments T_RPAREN;
/.
-case $rule_number: {
- AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+CallExpression: Super T_LPAREN Arguments T_RPAREN;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
/.
-case $rule_number: {
- AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ;
+CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
/.
-case $rule_number: {
- AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
- node->lbracketToken = loc(2);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-CallExpression: CallExpression T_DOT PropertyIdentifier ;
+CallExpression: CallExpression T_DOT IdentifierName;
/.
-case $rule_number: {
- AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
- node->dotToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-ArgumentListOpt: ;
+Arguments: ;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-ArgumentListOpt: ArgumentList ;
+Arguments: ArgumentList;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Arguments: ArgumentList T_COMMA;
/.
-case $rule_number: {
- sym(1).Node = sym(1).ArgumentList->finish();
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+ } break;
./
-ArgumentList: AssignmentExpression ;
+ArgumentList: AssignmentExpression_In;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
+ } break;
./
-ArgumentList: ArgumentList T_COMMA AssignmentExpression ;
+ArgumentList: T_ELLIPSIS AssignmentExpression_In;
/.
-case $rule_number: {
- AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(2).Expression);
+ node->isSpreadElement = true;
+ sym(1).Node = node;
+ } break;
./
-LeftHandSideExpression: NewExpression ;
-LeftHandSideExpression: CallExpression ;
-PostfixExpression: LeftHandSideExpression ;
+ArgumentList: ArgumentList T_COMMA AssignmentExpression_In;
+/.
+ case $rule_number: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ;
+ArgumentList: ArgumentList T_COMMA T_ELLIPSIS AssignmentExpression_In;
/.
-case $rule_number: {
- AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
- node->incrementToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(4).Expression);
+ node->commaToken = loc(2);
+ node->isSpreadElement = true;
+ sym(1).Node = node;
+ } break;
./
-PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ;
+LeftHandSideExpression: NewExpression;
+LeftHandSideExpression: CallExpression;
+
+UpdateExpression: LeftHandSideExpression;
+
+UpdateExpression: LeftHandSideExpression T_PLUS_PLUS;
/.
-case $rule_number: {
- AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
- node->decrementToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: PostfixExpression ;
+UpdateExpression: LeftHandSideExpression T_MINUS_MINUS;
+/.
+ case $rule_number: {
+ AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-UnaryExpression: T_DELETE UnaryExpression ;
+UpdateExpression: T_PLUS_PLUS UnaryExpression;
/.
-case $rule_number: {
- AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
- node->deleteToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_VOID UnaryExpression ;
+UpdateExpression: T_MINUS_MINUS UnaryExpression;
/.
-case $rule_number: {
- AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
- node->voidToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_TYPEOF UnaryExpression ;
+UnaryExpression: UpdateExpression;
+
+UnaryExpression: T_DELETE UnaryExpression;
/.
-case $rule_number: {
- AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
- node->typeofToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_PLUS_PLUS UnaryExpression ;
+UnaryExpression: T_VOID UnaryExpression;
/.
-case $rule_number: {
- AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
- node->incrementToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_MINUS_MINUS UnaryExpression ;
+UnaryExpression: T_TYPEOF UnaryExpression;
/.
-case $rule_number: {
- AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
- node->decrementToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_PLUS UnaryExpression ;
+UnaryExpression: T_PLUS UnaryExpression;
/.
-case $rule_number: {
- AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
- node->plusToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_MINUS UnaryExpression ;
+UnaryExpression: T_MINUS UnaryExpression;
/.
-case $rule_number: {
- AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
- node->minusToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_TILDE UnaryExpression ;
+UnaryExpression: T_TILDE UnaryExpression;
/.
-case $rule_number: {
- AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
- node->tildeToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-UnaryExpression: T_NOT UnaryExpression ;
+UnaryExpression: T_NOT UnaryExpression;
/.
-case $rule_number: {
- AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
- node->notToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-MultiplicativeExpression: UnaryExpression ;
+ExponentiationExpression: UnaryExpression;
-MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ;
+ExponentiationExpression: UpdateExpression T_STAR_STAR ExponentiationExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Mul, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Exp, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ;
+MultiplicativeExpression: ExponentiationExpression;
+
+MultiplicativeExpression: MultiplicativeExpression MultiplicativeOperator ExponentiationExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Div, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ;
+MultiplicativeOperator: T_STAR;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Mod, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::Mul;
+ } break;
./
-AdditiveExpression: MultiplicativeExpression ;
+MultiplicativeOperator: T_DIVIDE_;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::Div;
+ } break;
+./
-AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ;
+MultiplicativeOperator: T_REMAINDER;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Add, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::Mod;
+ } break;
./
-AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ;
+AdditiveExpression: MultiplicativeExpression;
+
+AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Sub, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression;
+/.
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-ShiftExpression: AdditiveExpression ;
+ShiftExpression: AdditiveExpression;
-ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ;
+ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::LShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ;
+ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::RShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ;
+ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::URShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpression: ShiftExpression ;
+RelationalExpression_In: ShiftExpression;
+RelationalExpression: ShiftExpression;
-RelationalExpression: RelationalExpression T_LT ShiftExpression ;
+RelationalExpression_In: RelationalExpression_In RelationalOperator ShiftExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+RelationalExpression: RelationalExpression RelationalOperator ShiftExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Lt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpression: RelationalExpression T_GT ShiftExpression ;
+RelationalOperator: T_LT;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Gt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::Lt;
+ } break;
+./
+RelationalOperator: T_GT;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::Gt;
+ } break;
+./
+RelationalOperator: T_LE;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::Le;
+ } break;
+./
+RelationalOperator: T_GE;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::Ge;
+ } break;
+./
+RelationalOperator: T_INSTANCEOF;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::InstanceOf;
+ } break;
./
-RelationalExpression: RelationalExpression T_LE ShiftExpression ;
+RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Le, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpression: RelationalExpression T_GE ShiftExpression ;
+EqualityExpression_In: RelationalExpression_In;
+EqualityExpression: RelationalExpression;
+
+EqualityExpression_In: EqualityExpression_In EqualityOperator RelationalExpression_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+EqualityExpression: EqualityExpression EqualityOperator RelationalExpression;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Ge, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ;
+EqualityOperator: T_EQ_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::InstanceOf, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::Equal;
+ } break;
+./
+EqualityOperator: T_NOT_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::NotEqual;
+ } break;
+./
+EqualityOperator: T_EQ_EQ_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::StrictEqual;
+ } break;
+./
+EqualityOperator: T_NOT_EQ_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::StrictNotEqual;
+ } break;
./
-RelationalExpression: RelationalExpression T_IN ShiftExpression ;
+
+BitwiseANDExpression: EqualityExpression;
+XitwiseANDExpression_In: EqualityExpression_In;
+
+BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+XitwiseANDExpression_In: XitwiseANDExpression_In T_AND EqualityExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::In, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpressionNotIn: ShiftExpression ;
-RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ;
+BitwiseXORExpression: BitwiseANDExpression;
+BitwiseXORExpression_In: XitwiseANDExpression_In;
+
+BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+BitwiseXORExpression_In: BitwiseXORExpression_In T_XOR XitwiseANDExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Lt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ;
+BitwiseORExpression: BitwiseXORExpression;
+BitwiseORExpression_In: BitwiseXORExpression_In;
+
+BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+BitwiseORExpression_In: BitwiseORExpression_In T_OR BitwiseXORExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Gt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ;
+LogicalANDExpression: BitwiseORExpression;
+LogicalANDExpression_In: BitwiseORExpression_In;
+
+LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LogicalANDExpression_In: LogicalANDExpression_In T_AND_AND BitwiseORExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Le, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ;
+LogicalORExpression: LogicalANDExpression;
+LogicalORExpression_In: LogicalANDExpression_In;
+
+LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LogicalORExpression_In: LogicalORExpression_In T_OR_OR LogicalANDExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Ge, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ;
+
+ConditionalExpression: LogicalORExpression;
+ConditionalExpression_In: LogicalORExpression_In;
+
+ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ConditionalExpression_In: LogicalORExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::InstanceOf, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-EqualityExpression: RelationalExpression ;
+AssignmentExpression: ConditionalExpression;
+AssignmentExpression_In: ConditionalExpression_In;
+
+AssignmentExpression: YieldExpression;
+AssignmentExpression_In: YieldExpression_In;
+
+AssignmentExpression: ArrowFunction;
+AssignmentExpression_In: ArrowFunction_In;
-EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ;
+AssignmentExpression: LeftHandSideExpression T_EQ AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Equal, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ // need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
+ if (AST::Pattern *p = sym(1).Expression->patternCast()) {
+ AST::SourceLocation errorLoc;
+ QString errorMsg;
+ if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) {
+ syntaxError(errorLoc, errorMsg);
+ return false;
+ }
+ }
+ // if lhs is an identifier expression and rhs is an anonymous function expression, we need to assign the name of lhs to the function
+ if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) {
+ if (auto *id = AST::cast<AST::IdentifierExpression *>(sym(1).Expression))
+ f->name = id->name;
+ }
+
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Assign, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ;
+AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::NotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ;
+AssignmentOperator: T_STAR_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMul;
+ } break;
./
-EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ;
+AssignmentOperator: T_STAR_STAR_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictNotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceExp;
+ } break;
./
-EqualityExpressionNotIn: RelationalExpressionNotIn ;
+AssignmentOperator: T_DIVIDE_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceDiv;
+ } break;
+./
-EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ;
+AssignmentOperator: T_REMAINDER_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Equal, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMod;
+ } break;
./
-EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn;
+AssignmentOperator: T_PLUS_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::NotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAdd;
+ } break;
./
-EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ;
+AssignmentOperator: T_MINUS_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceSub;
+ } break;
./
-EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ;
+AssignmentOperator: T_LT_LT_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictNotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+ } break;
./
-BitwiseANDExpression: EqualityExpression ;
+AssignmentOperator: T_GT_GT_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+ } break;
+./
-BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ;
+AssignmentOperator: T_GT_GT_GT_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitAnd, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+ } break;
./
-BitwiseANDExpressionNotIn: EqualityExpressionNotIn ;
+AssignmentOperator: T_AND_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAnd;
+ } break;
+./
-BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ;
+AssignmentOperator: T_XOR_EQ;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitAnd, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceXor;
+ } break;
+./
+
+AssignmentOperator: T_OR_EQ;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::InplaceOr;
+ } break;
./
-BitwiseXORExpression: BitwiseANDExpression ;
+Expression: AssignmentExpression;
+Expression_In: AssignmentExpression_In;
-BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ;
+Expression: Expression T_COMMA AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Expression_In: Expression_In T_COMMA AssignmentExpression_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitXor, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+ExpressionOpt: ;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ExpressionOpt_In: ;
+/.
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ;
+ExpressionOpt: Expression;
+ExpressionOpt_In: Expression_In;
+
+-- Statements
-BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ;
+Statement: ExpressionStatementLookahead T_FORCE_BLOCK BlockStatement;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitXor, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(3).Node;
+ } break;
+./
+
+Statement: ExpressionStatementLookahead VariableStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead EmptyStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead ExpressionStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead IfStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead BreakableStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead ContinueStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead BreakStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead ReturnStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead WithStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead LabelledStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead ThrowStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead TryStatement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+Statement: ExpressionStatementLookahead DebuggerStatement;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ } break;
./
-BitwiseORExpression: BitwiseXORExpression ;
+Declaration: HoistableDeclaration;
+Declaration: ClassDeclaration;
+Declaration: LexicalDeclaration_In;
+
+HoistableDeclaration: FunctionDeclaration;
+HoistableDeclaration: GeneratorDeclaration;
-BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ;
+HoistableDeclaration_Default: FunctionDeclaration_Default;
+HoistableDeclaration_Default: GeneratorDeclaration_Default;
+
+BreakableStatement: IterationStatement;
+BreakableStatement: SwitchStatement;
+
+BlockStatement: Block;
+
+Block: T_LBRACE StatementListOpt T_RBRACE;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitOr, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ;
+StatementList: StatementListItem;
-BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ;
+StatementList: StatementList StatementListItem;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitOr, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).StatementList = sym(1).StatementList->append(sym(2).StatementList);
+ } break;
./
-LogicalANDExpression: BitwiseORExpression ;
+StatementListItem: Statement;
+/.
+ case $rule_number: {
+ sym(1).StatementList = new (pool) AST::StatementList(sym(1).Statement);
+ } break;
+./
-LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ;
+StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_AUTOMATIC_SEMICOLON;
+StatementListItem: ExpressionStatementLookahead T_FORCE_DECLARATION Declaration T_SEMICOLON;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::And, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementList(sym(3).FunctionDeclaration);
+ } break;
./
-LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ;
+StatementListOpt: ExpressionStatementLookahead;
+/.
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
+./
-LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ;
+StatementListOpt: StatementList;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::And, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).StatementList->finish();
+ } break;
./
-LogicalORExpression: LogicalANDExpression ;
+LetOrConst: T_LET;
+/.
+ case $rule_number: {
+ sym(1).scope = AST::VariableScope::Let;
+ } break;
+./
+LetOrConst: T_CONST;
+/.
+ case $rule_number: {
+ sym(1).scope = AST::VariableScope::Const;
+ } break;
+./
-LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ;
+Var: T_VAR;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Or, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).scope = AST::VariableScope::Var;
+ } break;
+./
+
+LexicalDeclaration: LetOrConst BindingList;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LexicalDeclaration_In: LetOrConst BindingList_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VarDeclaration: Var VariableDeclarationList;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VarDeclaration_In: Var VariableDeclarationList_In;
+/.
+ case $rule_number: {
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(sym(1).scope));
+ node->declarationKindToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-LogicalORExpressionNotIn: LogicalANDExpressionNotIn ;
+VariableStatement: VarDeclaration_In T_AUTOMATIC_SEMICOLON;
+VariableStatement: VarDeclaration_In T_SEMICOLON;
-LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ;
+BindingList: LexicalBinding_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+BindingList_In: LexicalBinding_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclarationList: VariableDeclaration;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclarationList_In: VariableDeclaration_In;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Or, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).PatternElement);
+ } break;
./
-ConditionalExpression: LogicalORExpression ;
+BindingList: BindingList T_COMMA LexicalBinding;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+BindingList_In: BindingList_In T_COMMA LexicalBinding_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclarationList_In: VariableDeclarationList_In T_COMMA VariableDeclaration_In;
+/.
+ case $rule_number: {
+ AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).PatternElement);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ;
+LexicalBinding: BindingIdentifier InitializerOpt;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LexicalBinding_In: BindingIdentifier InitializerOpt_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclaration: BindingIdentifier InitializerOpt;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclaration_In: BindingIdentifier InitializerOpt_In;
/.
-case $rule_number: {
- AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
- sym(3).Expression, sym(5).Expression);
- node->questionToken = loc(2);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).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))
+ f->name = stringRef(1);
+ } break;
./
-ConditionalExpressionNotIn: LogicalORExpressionNotIn ;
+LexicalBinding: BindingPattern Initializer;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+LexicalBinding_In: BindingPattern Initializer_In;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclaration: BindingPattern Initializer;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+VariableDeclaration_In: BindingPattern Initializer_In;
+/.
+ case $rule_number: {
+ auto *node = new (pool) AST::PatternElement(sym(1).Pattern, sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
-ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ;
+BindingPattern: T_LBRACE ObjectBindingPattern T_RBRACE;
/.
-case $rule_number: {
- AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
- sym(3).Expression, sym(5).Expression);
- node->questionToken = loc(2);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ auto *node = new (pool) AST::ObjectPattern(sym(2).PatternPropertyList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ node->parseMode = AST::Pattern::Binding;
+ sym(1).Node = node;
+ } break;
./
-AssignmentExpression: ConditionalExpression ;
+BindingPattern: T_LBRACKET ArrayBindingPattern T_RBRACKET;
+/.
+ case $rule_number: {
+ auto *node = new (pool) AST::ArrayPattern(sym(2).PatternElementList);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ node->parseMode = AST::Pattern::Binding;
+ sym(1).Node = node;
+ } break;
+./
+
+ObjectBindingPattern: ;
+/.
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
+./
-AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ;
+ObjectBindingPattern: BindingPropertyList;
+/. case $rule_number: ./
+ObjectBindingPattern: BindingPropertyList T_COMMA;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- sym(2).ival, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).PatternPropertyList->finish();
+ } break;
+./
+
+ArrayBindingPattern: ElisionOpt BindingRestElementOpt;
+/.
+ case $rule_number: {
+ if (sym(1).Elision || sym(2).Node) {
+ auto *l = new (pool) AST::PatternElementList(sym(1).Elision, sym(2).PatternElement);
+ sym(1).Node = l->finish();
+ } else {
+ sym(1).Node = nullptr;
+ }
+ } break;
./
-AssignmentExpressionNotIn: ConditionalExpressionNotIn ;
+ArrayBindingPattern: BindingElementList;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(1).PatternElementList->finish();
+ } break;
+./
-AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ;
+ArrayBindingPattern: BindingElementList T_COMMA ElisionOpt BindingRestElementOpt;
/.
-case $rule_number: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- sym(2).ival, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ if (sym(3).Elision || sym(4).Node) {
+ auto *l = new (pool) AST::PatternElementList(sym(3).Elision, sym(4).PatternElement);
+ l = sym(1).PatternElementList->append(l);
+ sym(1).Node = l;
+ }
+ sym(1).Node = sym(1).PatternElementList->finish();
+ } break;
./
-AssignmentOperator: T_EQ ;
+BindingPropertyList: BindingProperty;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::Assign;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::PatternPropertyList(sym(1).PatternProperty);
+ } break;
./
-AssignmentOperator: T_STAR_EQ ;
+BindingPropertyList: BindingPropertyList T_COMMA BindingProperty;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceMul;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::PatternPropertyList(sym(1).PatternPropertyList, sym(3).PatternProperty);
+ } break;
./
-AssignmentOperator: T_DIVIDE_EQ ;
+BindingElementList: BindingElisionElement;
+
+BindingElementList: BindingElementList T_COMMA BindingElisionElement;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceDiv;
-} break;
+ case $rule_number: {
+ sym(1).PatternElementList = sym(1).PatternElementList->append(sym(3).PatternElementList);
+ } break;
./
-AssignmentOperator: T_REMAINDER_EQ ;
+BindingElisionElement: ElisionOpt BindingElement;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceMod;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::PatternElementList(sym(1).Elision, sym(2).PatternElement);
+ } break;
./
-AssignmentOperator: T_PLUS_EQ ;
+
+BindingProperty: BindingIdentifier InitializerOpt_In;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceAdd;
-} break;
+ case $rule_number: {
+ AST::StringLiteralPropertyName *name = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ name->propertyNameToken = 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))
+ f->name = stringRef(1);
+ sym(1).Node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression);
+ } break;
./
-AssignmentOperator: T_MINUS_EQ ;
+BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceSub;
-} break;
+ case $rule_number: {
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_LT_LT_EQ ;
+BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceLeftShift;
-} break;
+ case $rule_number: {
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Pattern, sym(4).Expression);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_GT_GT_EQ ;
+BindingElement: BindingIdentifier InitializerOpt_In;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceRightShift;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).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))
+ f->name = stringRef(1);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_GT_GT_GT_EQ ;
+BindingElement: BindingPattern InitializerOpt_In;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceURightShift;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(sym(1).Pattern, sym(2).Expression);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_AND_EQ ;
+BindingRestElement: T_ELLIPSIS BindingIdentifier;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceAnd;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), nullptr, AST::PatternElement::RestElement);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_XOR_EQ ;
+BindingRestElement: T_ELLIPSIS BindingPattern;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceXor;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr, AST::PatternElement::RestElement);
+ sym(1).Node = node;
+ } break;
./
-AssignmentOperator: T_OR_EQ ;
+BindingRestElementOpt: ;
/.
-case $rule_number: {
- sym(1).ival = QSOperator::InplaceOr;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-Expression: AssignmentExpression ;
+BindingRestElementOpt: BindingRestElement;
+
-Expression: Expression T_COMMA AssignmentExpression ;
+EmptyStatement: T_SEMICOLON;
/.
-case $rule_number: {
- AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-ExpressionOpt: ;
+-- Spec says it should have a "[lookahead ∉ { {, function, class, let [ }]" before the Expression statement.
+-- This is implemented with the rule below that is run before any statement and inserts a T_EXPRESSION_STATEMENT_OK
+-- token if it's ok to parse as an expression statement.
+ExpressionStatementLookahead: ;
+/:
+#define J_SCRIPT_EXPRESSIONSTATEMENTLOOKAHEAD_RULE $rule_number
+:/
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ int token = lookaheadToken(lexer);
+ if (token == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ else if (token == T_FUNCTION || token == T_CLASS || token == T_LET || token == T_CONST)
+ pushToken(T_FORCE_DECLARATION);
+ } break;
./
-ExpressionOpt: Expression ;
+ExpressionStatement: Expression_In T_AUTOMATIC_SEMICOLON;
+ExpressionStatement: Expression_In T_SEMICOLON;
+/.
+ case $rule_number: {
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-ExpressionNotIn: AssignmentExpressionNotIn ;
+IfStatement: T_IF T_LPAREN Expression_In T_RPAREN Statement T_ELSE Statement;
+/.
+ case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(6);
+ sym(1).Node = node;
+ } break;
+./
-ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
+IfStatement: T_IF T_LPAREN Expression_In T_RPAREN Statement;
/.
-case $rule_number: {
- AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-ExpressionNotInOpt: ;
+
+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;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+ } break;
./
-ExpressionNotInOpt: ExpressionNotIn ;
+IterationStatement: T_WHILE T_LPAREN Expression_In T_RPAREN Statement;
+/.
+ case $rule_number: {
+ AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
+./
-Statement: Block ;
-Statement: VariableStatement ;
-Statement: EmptyStatement ;
-Statement: ExpressionStatement ;
-Statement: IfStatement ;
-Statement: IterationStatement ;
-Statement: ContinueStatement ;
-Statement: BreakStatement ;
-Statement: ReturnStatement ;
-Statement: WithStatement ;
-Statement: LabelledStatement ;
-Statement: SwitchStatement ;
-Statement: ThrowStatement ;
-Statement: TryStatement ;
-Statement: DebuggerStatement ;
+IterationStatement: T_FOR T_LPAREN ExpressionOpt T_SEMICOLON ExpressionOpt_In T_SEMICOLON ExpressionOpt_In T_RPAREN Statement; -- [lookahead != { let [ }]
+/.
+ case $rule_number: {
+ AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+ } break;
+./
+IterationStatement: T_FOR T_LPAREN VarDeclaration T_SEMICOLON ExpressionOpt_In T_SEMICOLON ExpressionOpt_In T_RPAREN Statement;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+IterationStatement: T_FOR T_LPAREN LexicalDeclaration T_SEMICOLON ExpressionOpt_In T_SEMICOLON ExpressionOpt_In T_RPAREN Statement;
+/.
+ case $rule_number: {
+ // ### get rid of the static_cast!
+ AST::ForStatement *node = new (pool) AST::ForStatement(
+ static_cast<AST::VariableStatement *>(sym(3).Node)->declarations, sym(5).Expression,
+ sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+ } break;
+./
-Block: T_LBRACE StatementListOpt T_RBRACE ;
+InOrOf: T_IN;
/.
-case $rule_number: {
- AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).forEachType = AST::ForEachType::In;
+ } break;
./
-StatementList: Statement ;
+InOrOf: T_OF;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
-} break;
+ case $rule_number: {
+ sym(1).forEachType = AST::ForEachType::Of;
+ } break;
./
-StatementList: StatementList Statement ;
+IterationStatement: T_FOR T_LPAREN LeftHandSideExpression InOrOf Expression_In T_RPAREN Statement;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
-} break;
+ case $rule_number: {
+ // need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
+ if (AST::Pattern *p = sym(3).Expression->patternCast()) {
+ AST::SourceLocation errorLoc;
+ QString errorMsg;
+ if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) {
+ syntaxError(errorLoc, errorMsg);
+ return false;
+ }
+ }
+ AST::ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression, sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inOfToken = loc(4);
+ node->rparenToken = loc(6);
+ node->type = sym(4).forEachType;
+ sym(1).Node = node;
+ } break;
./
-StatementListOpt: ;
+IterationStatement: T_FOR T_LPAREN ForDeclaration InOrOf Expression_In T_RPAREN Statement;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ AST::ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).PatternElement, sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inOfToken = loc(4);
+ node->rparenToken = loc(6);
+ node->type = sym(4).forEachType;
+ sym(1).Node = node;
+ } break;
./
-StatementListOpt: StatementList ;
+ForDeclaration: LetOrConst BindingIdentifier;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ForDeclaration: Var BindingIdentifier;
/.
-case $rule_number: {
- sym(1).Node = sym(1).StatementList->finish ();
-} break;
+ case $rule_number: {
+ auto *node = new (pool) AST::PatternElement(stringRef(2), nullptr);
+ node->identifierToken = loc(2);
+ node->scope = sym(1).scope;
+ sym(1).Node = node;
+ } break;
./
-VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
+ForDeclaration: LetOrConst BindingPattern;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ForDeclaration: Var BindingPattern;
/.
-case $rule_number: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- if (sym(1).ival == T_LET)
- s = AST::VariableDeclaration::BlockScope;
- else if (sym(1).ival == T_CONST)
- s = AST::VariableDeclaration::ReadOnlyBlockScope;
-
- AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
- node->declarationKindToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ auto *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr);
+ node->scope = sym(1).scope;
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationKind: T_LET ;
+ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON;
+ContinueStatement: T_CONTINUE T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).ival = T_LET;
-} break;
+ case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationKind: T_CONST ;
+ContinueStatement: T_CONTINUE IdentifierReference T_AUTOMATIC_SEMICOLON;
+ContinueStatement: T_CONTINUE IdentifierReference T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).ival = T_CONST;
-} break;
+ case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationKind: T_VAR ;
+BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON;
+BreakStatement: T_BREAK T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).ival = T_VAR;
-} break;
+ case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationList: VariableDeclaration ;
+BreakStatement: T_BREAK IdentifierReference T_AUTOMATIC_SEMICOLON;
+BreakStatement: T_BREAK IdentifierReference T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
-} break;
+ case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ;
+ReturnStatement: T_RETURN ExpressionOpt_In T_AUTOMATIC_SEMICOLON;
+ReturnStatement: T_RETURN ExpressionOpt_In T_SEMICOLON;
/.
-case $rule_number: {
- AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
- sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ if (!functionNestingLevel) {
+ syntaxError(loc(1), "Return statement not allowed outside of Function declaration.");
+ return false;
+ }
+ AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationListNotIn: VariableDeclarationNotIn ;
+WithStatement: T_WITH T_LPAREN Expression_In T_RPAREN Statement;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
-} break;
+ case $rule_number: {
+ AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ;
+SwitchStatement: T_SWITCH T_LPAREN Expression_In T_RPAREN CaseBlock;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
-} break;
+ case $rule_number: {
+ AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclaration: JsIdentifier InitialiserOpt ;
+CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE;
/.
-case $rule_number: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
+CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE;
/.
-case $rule_number: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+ } break;
./
-Initialiser: T_EQ AssignmentExpression ;
+CaseClauses: CaseClause;
/.
-case $rule_number: {
- // ### TODO: AST for initializer
- sym(1) = sym(2);
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
+ } break;
./
-InitialiserOpt: ;
+CaseClauses: CaseClauses CaseClause;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
+ } break;
./
-InitialiserOpt: Initialiser ;
+CaseClausesOpt: ;
+/.
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
+./
-InitialiserNotIn: T_EQ AssignmentExpressionNotIn ;
+CaseClausesOpt: CaseClauses;
/.
-case $rule_number: {
- // ### TODO: AST for initializer
- sym(1) = sym(2);
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).CaseClauses->finish();
+ } break;
./
-InitialiserNotInOpt: ;
+CaseClause: T_CASE Expression_In T_COLON StatementListOpt;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-InitialiserNotInOpt: InitialiserNotIn ;
+DefaultClause: T_DEFAULT T_COLON StatementListOpt;
+/.
+ case $rule_number: {
+ AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
-EmptyStatement: T_SEMICOLON ;
+LabelledStatement: IdentifierReference T_COLON LabelledItem;
/.
-case $rule_number: {
- AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
- node->semicolonToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-ExpressionStatement: Expression T_SEMICOLON ;
+LabelledItem: Statement;
+
+LabelledItem: ExpressionStatementLookahead T_FORCE_DECLARATION FunctionDeclaration;
/.
-case $rule_number: {
- AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ syntaxError(loc(3), "FunctionDeclarations are not allowed after a label.");
+ return false;
+ } break;
./
-IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ;
+ThrowStatement: T_THROW Expression_In T_AUTOMATIC_SEMICOLON;
+ThrowStatement: T_THROW Expression_In T_SEMICOLON;
/.
-case $rule_number: {
- AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
- node->ifToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- node->elseToken = loc(6);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+ } break;
./
-IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ;
+TryStatement: T_TRY Block Catch;
/.
-case $rule_number: {
- AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
- node->ifToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
+TryStatement: T_TRY Block Finally;
+/.
+ case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_COMPATIBILITY_SEMICOLON ; -- for JSC/V8 compatibility
-IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ;
+TryStatement: T_TRY Block Catch Finally;
/.
-case $rule_number: {
- AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
- node->doToken = loc(1);
- node->whileToken = loc(3);
- node->lparenToken = loc(4);
- node->rparenToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ;
+Catch: T_CATCH T_LPAREN CatchParameter T_RPAREN Block;
/.
-case $rule_number: {
- AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
- node->whileToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::Catch *node = new (pool) AST::Catch(sym(3).PatternElement, sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+ } break;
./
-IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+Finally: T_FINALLY Block;
/.
-case $rule_number: {
- AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
- sym(5).Expression, sym(7).Expression, sym(9).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->firstSemicolonToken = loc(4);
- node->secondSemicolonToken = loc(6);
- node->rparenToken = loc(8);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+CatchParameter: BindingIdentifier;
/.
-case $rule_number: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
- sym(8).Expression, sym(10).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->varToken = loc(3);
- node->firstSemicolonToken = loc(5);
- node->secondSemicolonToken = loc(7);
- node->rparenToken = loc(9);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1));
+ node->identifierToken = loc(1);
+ node->scope = AST::VariableScope::Let;
+ sym(1).Node = node;
+ } break;
./
-IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ;
+CatchParameter: BindingPattern;
/.
-case $rule_number: {
- AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
- sym(5).Expression, sym(7).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->inToken = loc(4);
- node->rparenToken = loc(6);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *node = new (pool) AST::PatternElement(sym(1).Pattern);
+ node->scope = AST::VariableScope::Let;
+ sym(1).Node = node;
+ } break;
./
-IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ;
+DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON; -- automatic semicolon
+DebuggerStatement: T_DEBUGGER T_SEMICOLON;
/.
-case $rule_number: {
- AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
- sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->varToken = loc(3);
- node->inToken = loc(5);
- node->rparenToken = loc(7);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-ContinueStatement: T_CONTINUE T_SEMICOLON ;
+-- tell the parser to prefer function declarations to function expressions.
+-- That is, the `Function' symbol is used to mark the start of a function
+-- declaration.
+-- This is still required for parsing QML, where MemberExpression and FunctionDeclaration would
+-- otherwise conflict.
+Function: T_FUNCTION %prec REDUCE_HERE;
+
+FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
- node->continueToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+ } break;
./
-ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ;
+
+FunctionDeclaration_Default: FunctionDeclaration;
+FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
- node->continueToken = loc(1);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(1), sym(3).FormalParameterList, sym(6).StatementList);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->lbraceToken = loc(5);
+ node->rbraceToken = loc(7);
+ sym(1).Node = node;
+ } break;
./
-BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-BreakStatement: T_BREAK T_SEMICOLON ;
+FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
- node->breakToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ 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);
+ sym(1).Node = node;
+ } break;
./
-BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ;
+FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
- node->breakToken = loc(1);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ node->functionToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->lbraceToken = loc(5);
+ node->rbraceToken = loc(7);
+ sym(1).Node = node;
+ } break;
./
-ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ;
+StrictFormalParameters: FormalParameters;
+
+FormalParameters: ;
/.
-case $rule_number: {
- AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
- node->returnToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ;
+FormalParameters: BindingRestElement;
/.
-case $rule_number: {
- AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
- node->withToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = (new (pool) AST::FormalParameterList(nullptr, sym(1).PatternElement))->finish();
+ sym(1).Node = node;
+ } break;
./
-SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ;
+FormalParameters: FormalParameterList;
+/. case $rule_number: ./
+FormalParameters: FormalParameterList T_COMMA;
/.
-case $rule_number: {
- AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
- node->switchToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ sym(1).Node = sym(1).FormalParameterList->finish();
+ } break;
./
-CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ;
+FormalParameters: FormalParameterList T_COMMA BindingRestElement;
/.
-case $rule_number: {
- AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = (new (pool) AST::FormalParameterList(sym(1).FormalParameterList, sym(3).PatternElement))->finish();
+ sym(1).Node = node;
+ } break;
./
-CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ;
+FormalParameterList: BindingElement;
/.
-case $rule_number: {
- AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(5);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(nullptr, sym(1).PatternElement);
+ sym(1).Node = node;
+ } break;
./
-CaseClauses: CaseClause ;
+
+FormalParameterList: FormalParameterList T_COMMA BindingElement;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, sym(3).PatternElement);
+ sym(1).Node = node;
+ } break;
./
-CaseClauses: CaseClauses CaseClause ;
+FormalParameter: BindingElement;
+
+FunctionLBrace: T_LBRACE;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
-} break;
+ case $rule_number: {
+ ++functionNestingLevel;
+ } break;
./
-CaseClausesOpt: ;
+FunctionRBrace: T_RBRACE;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ --functionNestingLevel;
+ } break;
./
-CaseClausesOpt: CaseClauses ;
+
+FunctionBody: StatementListOpt;
+
+ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpression; -- [lookahead ≠ {]
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpression_In; -- [lookahead ≠ {]
/.
-case $rule_number: {
- sym(1).Node = sym(1).CaseClauses->finish ();
-} break;
+ case $rule_number: {
+ AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression);
+ ret->returnToken = sym(4).Node->firstSourceLocation();
+ ret->semicolonToken = sym(4).Node->lastSourceLocation();
+ AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish();
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, statements);
+ f->isArrowFunction = true;
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
+ f->lbraceToken = sym(4).Node->firstSourceLocation();
+ f->rbraceToken = sym(4).Node->lastSourceLocation();
+ sym(1).Node = f;
+ } break;
./
-CaseClause: T_CASE Expression T_COLON StatementListOpt ;
+ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
- node->caseToken = loc(1);
- node->colonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, sym(6).StatementList);
+ f->isArrowFunction = true;
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(7);
+ sym(1).Node = f;
+ } break;
./
-DefaultClause: T_DEFAULT T_COLON StatementListOpt ;
+ArrowParameters: BindingIdentifier;
/.
-case $rule_number: {
- AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
- node->defaultToken = loc(1);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), nullptr, AST::PatternElement::Binding);
+ e->identifierToken = loc(1);
+ sym(1).FormalParameterList = (new (pool) AST::FormalParameterList(nullptr, e))->finish();
+ } break;
./
-LabelledStatement: JsIdentifier T_COLON Statement ;
+-- CoverParenthesizedExpressionAndArrowParameterList for ArrowParameters i being refined to:
+-- ArrowFormalParameters: T_LPAREN StrictFormalParameters T_RPAREN
+ArrowParameters: CoverParenthesizedExpressionAndArrowParameterList;
/.
-case $rule_number: {
- AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
- node->identifierToken = loc(1);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ if (coverExpressionType != CE_FormalParameterList) {
+ AST::NestedExpression *ne = static_cast<AST::NestedExpression *>(sym(1).Node);
+ AST::FormalParameterList *list = ne->expression->reparseAsFormalParameterList(pool);
+ if (!list) {
+ syntaxError(loc(1), "Invalid Arrow parameter list.");
+ return false;
+ }
+ sym(1).Node = list->finish();
+ }
+ } break;
./
-ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-ThrowStatement: T_THROW Expression T_SEMICOLON ;
+ConciseBodyLookahead: ;
+/:
+#define J_SCRIPT_CONCISEBODYLOOKAHEAD_RULE $rule_number
+:/
/.
-case $rule_number: {
- AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
- node->throwToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ if (lookaheadToken(lexer) == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ } break;
./
-TryStatement: T_TRY Block Catch ;
+MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/.
-case $rule_number: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(6).StatementList);
+ f->functionToken = sym(1).PropertyName->firstSourceLocation();
+ f->lparenToken = loc(2);
+ f->rparenToken = loc(4);
+ f->lbraceToken = loc(5);
+ f->rbraceToken = loc(7);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-TryStatement: T_TRY Block Finally ;
+MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
-case $rule_number: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ f->functionToken = sym(2).PropertyName->firstSourceLocation();
+ f->lparenToken = loc(3);
+ f->rparenToken = loc(5);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
+ f->isGenerator = true;
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+
+MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(6).StatementList);
+ f->functionToken = sym(2).PropertyName->firstSourceLocation();
+ f->lparenToken = loc(3);
+ f->rparenToken = loc(4);
+ f->lbraceToken = loc(5);
+ f->rbraceToken = loc(7);
+ 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;
+/.
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
+ f->functionToken = sym(2).PropertyName->firstSourceLocation();
+ f->lparenToken = loc(3);
+ f->rparenToken = loc(5);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(8);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Setter);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+ } break;
./
-TryStatement: T_TRY Block Catch Finally ;
+
+PropertySetParameterList: FormalParameter;
/.
-case $rule_number: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FormalParameterList *node = (new (pool) AST::FormalParameterList(nullptr, sym(1).PatternElement))->finish();
+ sym(1).Node = node;
+ } break;
+./
+
+GeneratorLParen: T_LPAREN;
+/.
+ case $rule_number: {
+ lexer->enterGeneratorBody();
+ } break;
./
-Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ;
+GeneratorRBrace: T_RBRACE;
/.
-case $rule_number: {
- AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
- node->catchToken = loc(1);
- node->lparenToken = loc(2);
- node->identifierToken = loc(3);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ --functionNestingLevel;
+ lexer->leaveGeneratorBody();
+ } break;
./
-Finally: T_FINALLY Block ;
+GeneratorDeclaration: Function T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
-case $rule_number: {
- AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
- node->finallyToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
+ node->isGenerator = true;
+ sym(1).Node = node;
+ } break;
+./
+
+GeneratorDeclaration_Default: GeneratorDeclaration;
+GeneratorDeclaration_Default: Function T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(1), sym(4).FormalParameterList, sym(7).StatementList);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ node->isGenerator = true;
+ sym(1).Node = node;
+ } break;
./
-DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
-DebuggerStatement: T_DEBUGGER T_SEMICOLON ;
+GeneratorExpression: T_FUNCTION T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
-case $rule_number: {
- AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
- node->debuggerToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
+ node->functionToken = loc(1);
+ if (!stringRef(3).isNull())
+ node->identifierToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->lbraceToken = loc(7);
+ node->rbraceToken = loc(9);
+ node->isGenerator = true;
+ sym(1).Node = node;
+ } break;
./
--- tell the parser to prefer function declarations to function expressions.
--- That is, the `Function' symbol is used to mark the start of a function
--- declaration.
-Function: T_FUNCTION %prec REDUCE_HERE ;
+GeneratorExpression: T_FUNCTION T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(4).FormalParameterList, sym(7).StatementList);
+ node->functionToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ node->isGenerator = true;
+ sym(1).Node = node;
+ } break;
+./
+
+GeneratorBody: FunctionBody;
-FunctionDeclaration: Function JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+YieldExpression: T_YIELD;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+YieldExpression_In: T_YIELD;
/.
-case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
- node->functionToken = loc(1);
- node->identifierToken = loc(2);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::YieldExpression *node = new (pool) AST::YieldExpression();
+ node->yieldToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-FunctionExpression: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+YieldExpression: T_YIELD T_STAR AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+YieldExpression_In: T_YIELD T_STAR AssignmentExpression_In;
/.
-case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
- 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);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::YieldExpression *node = new (pool) AST::YieldExpression(sym(3).Expression);
+ node->yieldToken = loc(1);
+ node->isYieldStar = true;
+ sym(1).Node = node;
+ } break;
./
-FunctionExpression: T_FUNCTION T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+YieldExpression: T_YIELD AssignmentExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+YieldExpression_In: T_YIELD AssignmentExpression_In;
/.
-case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
- node->functionToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::YieldExpression *node = new (pool) AST::YieldExpression(sym(2).Expression);
+ node->yieldToken = loc(1);
+ sym(1).Node = node;
+ } break;
./
-FormalParameterList: JsIdentifier ;
+
+ClassDeclaration: T_CLASS BindingIdentifier ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ClassExpression: T_CLASS BindingIdentifier ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
/.
-case $rule_number: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ClassExpression *node = new (pool) AST::ClassExpression(stringRef(2), sym(3).Expression, sym(5).ClassElementList);
+ node->classToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lbraceToken = loc(4);
+ node->rbraceToken = loc(6);
+ sym(1).Node = node;
+ } break;
./
-FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+ClassDeclaration_Default: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ClassExpression: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
/.
-case $rule_number: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
- node->commaToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
+ case $rule_number: {
+ AST::ClassExpression *node = new (pool) AST::ClassExpression(QStringRef(), sym(2).Expression, sym(4).ClassElementList);
+ node->classToken = loc(1);
+ node->lbraceToken = loc(3);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+ } break;
./
-FormalParameterListOpt: ;
+ClassDeclaration_Default: ClassDeclaration;
+
+ClassLBrace: T_LBRACE;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ lexer->setStaticIsKeyword(true);
+ } break;
./
-FormalParameterListOpt: FormalParameterList ;
+ClassRBrace: T_RBRACE;
+/. case $rule_number: ./
+ClassStaticQualifier: T_STATIC;
/.
-case $rule_number: {
- sym(1).Node = sym(1).FormalParameterList->finish ();
-} break;
+ case $rule_number: {
+ lexer->setStaticIsKeyword(false);
+ } break;
./
-FunctionBodyOpt: ;
+ClassHeritageOpt: ;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-FunctionBodyOpt: FunctionBody ;
+ClassHeritageOpt: T_EXTENDS LeftHandSideExpression;
+/.
+ case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ } break;
+./
-FunctionBody: SourceElements ;
+ClassBodyOpt: ;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-Program: Empty ;
+ClassBodyOpt: ClassElementList;
+/.
+ case $rule_number: {
+ if (sym(1).Node)
+ sym(1).Node = sym(1).ClassElementList->finish();
+ } break;
+./
+
+ClassElementList: ClassElement;
-Program: SourceElements ;
+ClassElementList: ClassElementList ClassElement;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
-} break;
+ case $rule_number: {
+ if (sym(2).Node)
+ sym(1).ClassElementList = sym(1).ClassElementList->append(sym(2).ClassElementList);
+ } break;
./
-SourceElements: SourceElement ;
+ClassElement: MethodDefinition;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
-} break;
+ case $rule_number: {
+ AST::ClassElementList *node = new (pool) AST::ClassElementList(sym(1).PatternProperty, false);
+ sym(1).Node = node;
+ } break;
./
-SourceElements: SourceElements SourceElement ;
+ClassElement: ClassStaticQualifier MethodDefinition;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
-} break;
+ case $rule_number: {
+ lexer->setStaticIsKeyword(true);
+ AST::ClassElementList *node = new (pool) AST::ClassElementList(sym(2).PatternProperty, true);
+ sym(1).Node = node;
+ } break;
./
-SourceElement: Statement ;
+ClassElement: T_SEMICOLON;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-SourceElement: FunctionDeclaration ;
+-- Scripts and Modules
+
+Script: ;
/.
-case $rule_number: {
- sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
-} break;
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ } break;
./
-PropertyAssignmentListOpt: ;
+Script: ScriptBody;
+
+ScriptBody: StatementList;
/.
-case $rule_number: {
- sym(1).Node = 0;
-} break;
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::Program(sym(1).StatementList->finish());
+ } break;
./
-PropertyAssignmentListOpt: PropertyAssignmentList ;
+Module: ModuleBodyOpt;
+/. case $rule_number: { UNIMPLEMENTED; } ./
+
+ModuleBody: ModuleItemList;
+
+ModuleBodyOpt: ;
+ModuleBodyOpt: ModuleBody;
+
+ModuleItemList: ModuleItem;
+ModuleItemList: ModuleItemList ModuleItem;
+
+ModuleItem: ImportDeclaration T_AUTOMATIC_SEMICOLON;
+ModuleItem: ImportDeclaration T_SEMICOLON;
+ModuleItem: ExportDeclaration T_AUTOMATIC_SEMICOLON;
+ModuleItem: ExportDeclaration T_SEMICOLON;
+ModuleItem: StatementListItem;
+
+ImportDeclaration: T_IMPORT ImportClause FromClause;
+ImportDeclaration: T_IMPORT ModuleSpecifier;
+
+ImportClause: ImportedDefaultBinding;
+ImportClause: NameSpaceImport;
+ImportClause: NamedImports;
+ImportClause: ImportedDefaultBinding T_COMMA NameSpaceImport;
+ImportClause: ImportedDefaultBinding T_COMMA NamedImports;
+
+ImportedDefaultBinding: ImportedBinding;
+
+NameSpaceImport: T_STAR T_AS ImportedBinding;
+
+NamedImports: T_LBRACE T_RBRACE;
+NamedImports: T_LBRACE ImportsList T_RBRACE;
+NamedImports: T_LBRACE ImportsList T_COMMA T_RBRACE;
+
+FromClause: T_FROM ModuleSpecifier;
+
+ImportsList: ImportSpecifier;
+ImportsList: ImportsList T_COMMA ImportSpecifier;
+
+ImportSpecifier: ImportedBinding;
+ImportSpecifier: IdentifierName T_AS ImportedBinding;
+
+ModuleSpecifier: T_STRING_LITERAL;
+
+ImportedBinding: BindingIdentifier;
+
+ExportDeclarationLookahead: ;
+/:
+#define J_SCRIPT_EXPORTDECLARATIONLOOKAHEAD_RULE $rule_number
+:/
+/.
+ case $rule_number: {
+ int token = lookaheadToken(lexer);
+ if (token == T_FUNCTION || token == T_CLASS)
+ pushToken(T_FORCE_DECLARATION);
+ } break;
+./
+
+ExportDeclaration: T_EXPORT T_STAR FromClause;
+ExportDeclaration: T_EXPORT ExportClause FromClause;
+ExportDeclaration: T_EXPORT ExportClause;
+ExportDeclaration: T_EXPORT VariableStatement;
+ExportDeclaration: T_EXPORT Declaration;
+ExportDeclaration: T_EXPORT T_DEFAULT ExportDeclarationLookahead T_FORCE_DECLARATION HoistableDeclaration_Default;
+ExportDeclaration: T_EXPORT T_DEFAULT ExportDeclarationLookahead T_FORCE_DECLARATION ClassDeclaration_Default;
+ExportDeclaration: T_EXPORT T_DEFAULT ExportDeclarationLookahead AssignmentExpression_In; -- [lookahead ∉ { function, class }]
+
+ExportClause: T_LBRACE T_RBRACE;
+ExportClause: T_LBRACE ExportsList T_RBRACE;
+ExportClause: T_LBRACE ExportsList T_COMMA T_RBRACE;
+
+ExportsList: ExportSpecifier;
+ExportsList: ExportsList T_COMMA ExportSpecifier;
+
+ExportSpecifier: IdentifierName;
+ExportSpecifier: IdentifierName T_AS IdentifierName;
+
+-- Old top level code
/.
+ // ------------ end of switch statement
} // switch
action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
} // if
} while (action != 0);
+#ifdef PARSER_DEBUG
+ qDebug() << "Done or error.";
+#endif
+
if (first_token == last_token) {
const int errorState = state_stack[tos];
// automatic insertion of `;'
if (yytoken != -1 && ((t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken))
|| t_action(errorState, T_COMPATIBILITY_SEMICOLON))) {
+#ifdef PARSER_DEBUG
+ qDebug() << "Inserting automatic semicolon.";
+#endif
SavedToken &tk = token_buffer[0];
tk.token = yytoken;
tk.dval = yylval;
@@ -3260,8 +4176,7 @@ PropertyAssignmentListOpt: PropertyAssignmentList ;
for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
- tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
- tk == T_FEED_JS_SOURCE_ELEMENT)
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION)
continue;
int a = t_action(errorState, tk);
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 34657a7d48..b338c5bbfe 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -45,6 +45,17 @@ QT_QML_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
+FunctionExpression *asAnonymousFunctionDefinition(Node *n)
+{
+ if (!n)
+ return nullptr;
+ FunctionExpression *f = n->asFunctionDefinition();
+ if (!f || !f->name.isNull())
+ return nullptr;
+ return f;
+}
+
+
void Node::accept(Visitor *visitor)
{
if (visitor->preVisit(this)) {
@@ -79,11 +90,62 @@ UiObjectMember *Node::uiObjectMemberCast()
return nullptr;
}
+LeftHandSideExpression *Node::leftHandSideExpressionCast()
+{
+ return nullptr;
+}
+
+Pattern *Node::patternCast()
+{
+ return nullptr;
+}
+
+FunctionExpression *Node::asFunctionDefinition()
+{
+ return nullptr;
+}
+
ExpressionNode *ExpressionNode::expressionCast()
{
return this;
}
+FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *pool)
+{
+ AST::ExpressionNode *expr = this;
+ AST::FormalParameterList *f = nullptr;
+ if (AST::Expression *commaExpr = AST::cast<AST::Expression *>(expr)) {
+ f = commaExpr->left->reparseAsFormalParameterList(pool);
+ if (!f)
+ return nullptr;
+
+ expr = commaExpr->right;
+ }
+
+ AST::ExpressionNode *rhs = nullptr;
+ if (AST::BinaryExpression *assign = AST::cast<AST::BinaryExpression *>(expr)) {
+ if (assign->op != QSOperator::Assign)
+ return nullptr;
+ expr = assign->left;
+ rhs = assign->right;
+ }
+ AST::PatternElement *binding = nullptr;
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
+ binding = new (pool) AST::PatternElement(idExpr->name, rhs);
+ binding->identifierToken = idExpr->identifierToken;
+ } else if (AST::Pattern *p = expr->patternCast()) {
+ SourceLocation loc;
+ QString s;
+ if (!p->convertLiteralToAssignmentPattern(pool, &loc, &s))
+ return nullptr;
+ binding = new (pool) AST::PatternElement(p, rhs);
+ binding->identifierToken = p->firstSourceLocation();
+ }
+ if (!binding)
+ return nullptr;
+ return new (pool) AST::FormalParameterList(f, binding);
+}
+
BinaryExpression *BinaryExpression::binaryExpressionCast()
{
return this;
@@ -107,6 +169,11 @@ void NestedExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+FunctionExpression *NestedExpression::asFunctionDefinition()
+{
+ return expression->asFunctionDefinition();
+}
+
void ThisExpression::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -147,7 +214,7 @@ void FalseLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void StringLiteral::accept0(Visitor *visitor)
+void SuperLiteral::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -155,7 +222,8 @@ void StringLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NumericLiteral::accept0(Visitor *visitor)
+
+void StringLiteral::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -163,81 +231,229 @@ void NumericLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void RegExpLiteral::accept0(Visitor *visitor)
+void TemplateLiteral::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
+ if (next)
+ accept(next, visitor);
}
visitor->endVisit(this);
}
-void ArrayLiteral::accept0(Visitor *visitor)
+void NumericLiteral::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(elements, visitor);
- accept(elision, visitor);
}
visitor->endVisit(this);
}
-void ObjectLiteral::accept0(Visitor *visitor)
+void RegExpLiteral::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(properties, visitor);
}
visitor->endVisit(this);
}
-void ElementList::accept0(Visitor *visitor)
+void ArrayPattern::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- for (ElementList *it = this; it; it = it->next) {
- accept(it->elision, visitor);
- accept(it->expression, visitor);
- }
- }
+ if (visitor->visit(this))
+ accept(elements, visitor);
visitor->endVisit(this);
}
-void Elision::accept0(Visitor *visitor)
+bool ArrayPattern::isValidArrayLiteral(SourceLocation *errorLocation) const {
+ for (PatternElementList *it = elements; it != nullptr; it = it->next) {
+ PatternElement *e = it->element;
+ if (e && e->bindingTarget != nullptr) {
+ if (errorLocation)
+ *errorLocation = e->firstSourceLocation();
+ return false;
+ }
+ }
+ return true;
+}
+
+void ObjectPattern::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- // ###
+ accept(properties, visitor);
}
visitor->endVisit(this);
}
-void PropertyNameAndValue::accept0(Visitor *visitor)
-{
- if (visitor->visit(this)) {
- accept(name, visitor);
- accept(value, visitor);
+/*
+ This is the grammar for AssignmentPattern that we need to convert the literal to:
+
+ AssignmentPattern:
+ ObjectAssignmentPattern
+ ArrayAssignmentPattern
+ ArrayAssignmentPattern:
+ [ ElisionOpt AssignmentRestElementOpt ]
+ [ AssignmentElementList ]
+ [ AssignmentElementList , ElisionOpt AssignmentRestElementOpt ]
+ AssignmentElementList:
+ AssignmentElisionElement
+ AssignmentElementList , AssignmentElisionElement
+ AssignmentElisionElement:
+ ElisionOpt AssignmentElement
+ AssignmentRestElement:
+ ... DestructuringAssignmentTarget
+
+ ObjectAssignmentPattern:
+ {}
+ { AssignmentPropertyList }
+ { AssignmentPropertyList, }
+ AssignmentPropertyList:
+ AssignmentProperty
+ AssignmentPropertyList , AssignmentProperty
+ AssignmentProperty:
+ IdentifierReference InitializerOpt_In
+ PropertyName:
+ AssignmentElement
+
+ AssignmentElement:
+ DestructuringAssignmentTarget InitializerOpt_In
+ DestructuringAssignmentTarget:
+ LeftHandSideExpression
+
+ It was originally parsed with the following grammar:
+
+ArrayLiteral:
+ [ ElisionOpt ]
+ [ ElementList ]
+ [ ElementList , ElisionOpt ]
+ElementList:
+ ElisionOpt AssignmentExpression_In
+ ElisionOpt SpreadElement
+ ElementList , ElisionOpt AssignmentExpression_In
+ ElementList , Elisionopt SpreadElement
+SpreadElement:
+ ... AssignmentExpression_In
+ObjectLiteral:
+ {}
+ { PropertyDefinitionList }
+ { PropertyDefinitionList , }
+PropertyDefinitionList:
+ PropertyDefinition
+ PropertyDefinitionList , PropertyDefinition
+PropertyDefinition:
+ IdentifierReference
+ CoverInitializedName
+ PropertyName : AssignmentExpression_In
+ MethodDefinition
+PropertyName:
+ LiteralPropertyName
+ ComputedPropertyName
+
+*/
+bool ArrayPattern::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ if (parseMode == Binding)
+ return true;
+ for (auto *it = elements; it; it = it->next) {
+ if (!it->element)
+ continue;
+ if (it->element->type == PatternElement::SpreadElement && it->next) {
+ *errorLocation = it->element->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("'...' can only appear as last element in a destructuring list.");
+ return false;
+ }
+ if (!it->element->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
}
+ parseMode = Binding;
+ return true;
+}
- visitor->endVisit(this);
+bool ObjectPattern::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ if (parseMode == Binding)
+ return true;
+ for (auto *it = properties; it; it = it->next) {
+ if (!it->property->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
+ }
+ parseMode = Binding;
+ return true;
}
-void PropertyGetterSetter::accept0(Visitor *visitor)
+bool PatternElement::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
{
- if (visitor->visit(this)) {
- accept(name, visitor);
- accept(formals, visitor);
- accept(functionBody, visitor);
+ Q_ASSERT(type == Literal || type == SpreadElement);
+ Q_ASSERT(bindingIdentifier.isNull());
+ Q_ASSERT(bindingTarget == nullptr);
+ Q_ASSERT(bindingTarget == nullptr);
+ Q_ASSERT(initializer);
+ ExpressionNode *init = initializer;
+
+ initializer = nullptr;
+ LeftHandSideExpression *lhs = init->leftHandSideExpressionCast();
+ if (type == SpreadElement) {
+ if (!lhs) {
+ *errorLocation = init->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Invalid lhs expression after '...' in destructuring expression.");
+ return false;
+ }
+ } else {
+ type = PatternElement::Binding;
+
+ if (BinaryExpression *b = init->binaryExpressionCast()) {
+ if (b->op != QSOperator::Assign) {
+ *errorLocation = b->operatorToken;
+ *errorMessage = QString::fromLatin1("Invalid assignment operation in destructuring expression");
+ return false;
+ }
+ lhs = b->left->leftHandSideExpressionCast();
+ initializer = b->right;
+ Q_ASSERT(lhs);
+ } else {
+ lhs = init->leftHandSideExpressionCast();
+ }
+ if (!lhs) {
+ *errorLocation = init->firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Destructuring target is not a left hand side expression.");
+ return false;
+ }
}
- visitor->endVisit(this);
+ if (auto *i = cast<IdentifierExpression *>(lhs)) {
+ bindingIdentifier = i->name.toString();
+ identifierToken = i->identifierToken;
+ return true;
+ }
+
+ bindingTarget = lhs;
+ if (auto *p = lhs->patternCast()) {
+ if (!p->convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage))
+ return false;
+ }
+ return true;
+}
+
+bool PatternProperty::convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage)
+{
+ Q_ASSERT(type != SpreadElement);
+ if (type == Binding)
+ return true;
+ if (type == Getter || type == Setter) {
+ *errorLocation = firstSourceLocation();
+ *errorMessage = QString::fromLatin1("Invalid getter/setter in destructuring expression.");
+ return false;
+ }
+ Q_ASSERT(type == Literal);
+ return PatternElement::convertLiteralToAssignmentPattern(pool, errorLocation, errorMessage);
}
-void PropertyAssignmentList::accept0(Visitor *visitor)
+
+void Elision::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- for (PropertyAssignmentList *it = this; it; it = it->next) {
- accept(it->assignment, visitor);
- }
+ // ###
}
visitor->endVisit(this);
@@ -496,15 +712,6 @@ void VariableDeclarationList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void VariableDeclaration::accept0(Visitor *visitor)
-{
- if (visitor->visit(this)) {
- accept(expression, visitor);
- }
-
- visitor->endVisit(this);
-}
-
void EmptyStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -557,17 +764,6 @@ void ForStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(initialiser, visitor);
- accept(condition, visitor);
- accept(expression, visitor);
- accept(statement, visitor);
- }
-
- visitor->endVisit(this);
-}
-
-void LocalForStatement::accept0(Visitor *visitor)
-{
- if (visitor->visit(this)) {
accept(declarations, visitor);
accept(condition, visitor);
accept(expression, visitor);
@@ -580,7 +776,7 @@ void LocalForStatement::accept0(Visitor *visitor)
void ForEachStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(initialiser, visitor);
+ accept(lhs, visitor);
accept(expression, visitor);
accept(statement, visitor);
}
@@ -588,18 +784,15 @@ void ForEachStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void LocalForEachStatement::accept0(Visitor *visitor)
+void ContinueStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(declaration, visitor);
- accept(expression, visitor);
- accept(statement, visitor);
}
visitor->endVisit(this);
}
-void ContinueStatement::accept0(Visitor *visitor)
+void BreakStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -607,15 +800,16 @@ void ContinueStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void BreakStatement::accept0(Visitor *visitor)
+void ReturnStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
+ accept(expression, visitor);
}
visitor->endVisit(this);
}
-void ReturnStatement::accept0(Visitor *visitor)
+void YieldExpression::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -624,6 +818,7 @@ void ReturnStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+
void WithStatement::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
@@ -717,6 +912,7 @@ void TryStatement::accept0(Visitor *visitor)
void Catch::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
+ accept(patternElement, visitor);
accept(statement, visitor);
}
@@ -752,57 +948,69 @@ void FunctionExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FormalParameterList::accept0(Visitor *visitor)
+FunctionExpression *FunctionExpression::asFunctionDefinition()
{
- if (visitor->visit(this)) {
- // ###
- }
-
- visitor->endVisit(this);
+ return this;
}
-void FunctionBody::accept0(Visitor *visitor)
+QStringList FormalParameterList::formals() const
{
- if (visitor->visit(this)) {
- accept(elements, visitor);
+ QStringList formals;
+ int i = 0;
+ for (const FormalParameterList *it = this; it; it = it->next) {
+ if (it->element) {
+ QString name = it->element->bindingIdentifier;
+ 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 += name;
+ }
+ ++i;
}
-
- visitor->endVisit(this);
+ return formals;
}
-void Program::accept0(Visitor *visitor)
+QStringList FormalParameterList::boundNames() const
{
- if (visitor->visit(this)) {
- accept(elements, visitor);
+ QStringList names;
+ for (const FormalParameterList *it = this; it; it = it->next) {
+ if (it->element)
+ it->element->boundNames(&names);
}
-
- visitor->endVisit(this);
+ return names;
}
-void SourceElements::accept0(Visitor *visitor)
+void FormalParameterList::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- for (SourceElements *it = this; it; it = it->next) {
- accept(it->element, visitor);
- }
+ accept(element, visitor);
+ if (next)
+ accept(next, visitor);
}
visitor->endVisit(this);
}
-void FunctionSourceElement::accept0(Visitor *visitor)
+FormalParameterList *FormalParameterList::finish()
{
- if (visitor->visit(this)) {
- accept(declaration, visitor);
- }
+ FormalParameterList *front = next;
+ next = nullptr;
- visitor->endVisit(this);
+ int i = 0;
+ for (const FormalParameterList *it = this; it; it = it->next) {
+ if (it->element && it->element->bindingIdentifier.isEmpty())
+ it->element->bindingIdentifier = QLatin1String("arg#") + QString::number(i);
+ ++i;
+ }
+ return front;
}
-void StatementSourceElement::accept0(Visitor *visitor)
+void Program::accept0(Visitor *visitor)
{
if (visitor->visit(this)) {
- accept(statement, visitor);
+ accept(statements, visitor);
}
visitor->endVisit(this);
@@ -984,6 +1192,138 @@ void UiEnumMemberList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+void TaggedTemplate::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(templateLiteral, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PatternElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(bindingTarget, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PatternElement::boundNames(QStringList *names)
+{
+ if (bindingTarget) {
+ if (PatternElementList *e = elementList())
+ e->boundNames(names);
+ else if (PatternPropertyList *p = propertyList())
+ p->boundNames(names);
+ } else {
+ names->append(bindingIdentifier);
+ }
+}
+
+void PatternElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elision, visitor);
+ accept(element, visitor);
+ if (next)
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PatternElementList::boundNames(QStringList *names)
+{
+ for (PatternElementList *it = this; it; it = it->next) {
+ if (it->element)
+ it->element->boundNames(names);
+ }
+}
+
+void PatternProperty::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(name, visitor);
+ accept(bindingTarget, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PatternProperty::boundNames(QStringList *names)
+{
+ PatternElement::boundNames(names);
+}
+
+void PatternPropertyList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(property, visitor);
+ if (next)
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PatternPropertyList::boundNames(QStringList *names)
+{
+ for (PatternPropertyList *it = this; it; it = it->next)
+ it->property->boundNames(names);
+}
+
+void ComputedPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ClassExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(heritage, visitor);
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ClassElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(property, visitor);
+ if (next)
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+ClassElementList *ClassElementList::finish()
+{
+ ClassElementList *front = next;
+ next = nullptr;
+ return front;
+}
+
+Pattern *Pattern::patternCast()
+{
+ return this;
+}
+
+LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast()
+{
+ return this;
+}
+
} } // namespace QQmlJS::AST
QT_QML_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index ed3c83badf..66a4e357e9 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -77,6 +77,8 @@ enum Op {
Div,
InplaceDiv,
Equal,
+ Exp,
+ InplaceExp,
Ge,
Gt,
In,
@@ -110,6 +112,13 @@ namespace QQmlJS {
namespace AST {
+enum class VariableScope {
+ NoScope,
+ Var,
+ Let,
+ Const
+};
+
template <typename T1, typename T2>
T1 cast(T2 *ast)
{
@@ -119,6 +128,8 @@ T1 cast(T2 *ast)
return 0;
}
+FunctionExpression *asAnonymousFunctionDefinition(AST::Node *n);
+
class QML_PARSER_EXPORT Node: public Managed
{
public:
@@ -126,7 +137,7 @@ public:
Kind_Undefined,
Kind_ArgumentList,
- Kind_ArrayLiteral,
+ Kind_ArrayPattern,
Kind_ArrayMemberExpression,
Kind_BinaryExpression,
Kind_Block,
@@ -148,6 +159,7 @@ public:
Kind_Expression,
Kind_ExpressionStatement,
Kind_FalseLiteral,
+ Kind_SuperLiteral,
Kind_FieldMemberExpression,
Kind_Finally,
Kind_ForEachStatement,
@@ -156,38 +168,37 @@ public:
Kind_FunctionBody,
Kind_FunctionDeclaration,
Kind_FunctionExpression,
- Kind_FunctionSourceElement,
+ Kind_ClassExpression,
Kind_IdentifierExpression,
Kind_IdentifierPropertyName,
+ Kind_ComputedPropertyName,
Kind_IfStatement,
Kind_LabelledStatement,
- Kind_LocalForEachStatement,
- Kind_LocalForStatement,
Kind_NewExpression,
Kind_NewMemberExpression,
Kind_NotExpression,
Kind_NullExpression,
+ Kind_YieldExpression,
Kind_NumericLiteral,
Kind_NumericLiteralPropertyName,
- Kind_ObjectLiteral,
+ Kind_ObjectPattern,
Kind_PostDecrementExpression,
Kind_PostIncrementExpression,
Kind_PreDecrementExpression,
Kind_PreIncrementExpression,
Kind_Program,
- Kind_PropertyAssignmentList,
+ Kind_PropertyDefinitionList,
Kind_PropertyGetterSetter,
Kind_PropertyName,
Kind_PropertyNameAndValue,
Kind_RegExpLiteral,
Kind_ReturnStatement,
- Kind_SourceElement,
- Kind_SourceElements,
Kind_StatementList,
- Kind_StatementSourceElement,
Kind_StringLiteral,
Kind_StringLiteralPropertyName,
Kind_SwitchStatement,
+ Kind_TemplateLiteral,
+ Kind_TaggedTemplate,
Kind_ThisExpression,
Kind_ThrowStatement,
Kind_TildeExpression,
@@ -203,6 +214,12 @@ public:
Kind_WhileStatement,
Kind_WithStatement,
Kind_NestedExpression,
+ Kind_ClassElementList,
+ Kind_PatternElement,
+ Kind_PatternElementList,
+ Kind_PatternProperty,
+ Kind_PatternPropertyList,
+
Kind_UiArrayBinding,
Kind_UiImport,
@@ -235,6 +252,10 @@ public:
virtual BinaryExpression *binaryExpressionCast();
virtual Statement *statementCast();
virtual UiObjectMember *uiObjectMemberCast();
+ virtual LeftHandSideExpression *leftHandSideExpressionCast();
+ virtual Pattern *patternCast();
+ // implements the IsFunctionDefinition rules in the spec
+ virtual FunctionExpression *asFunctionDefinition();
void accept(Visitor *visitor);
static void accept(Node *node, Visitor *visitor);
@@ -256,6 +277,14 @@ public:
ExpressionNode() {}
ExpressionNode *expressionCast() override;
+
+ AST::FormalParameterList *reparseAsFormalParameterList(MemoryPool *pool);
+
+};
+
+class QML_PARSER_EXPORT LeftHandSideExpression : public ExpressionNode
+{
+ LeftHandSideExpression *leftHandSideExpressionCast() override;
};
class QML_PARSER_EXPORT Statement: public Node
@@ -266,7 +295,7 @@ public:
Statement *statementCast() override;
};
-class QML_PARSER_EXPORT NestedExpression: public ExpressionNode
+class QML_PARSER_EXPORT NestedExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(NestedExpression)
@@ -283,13 +312,16 @@ public:
SourceLocation lastSourceLocation() const override
{ return rparenToken; }
+ FunctionExpression *asFunctionDefinition() override;
+
+
// attributes
ExpressionNode *expression;
SourceLocation lparenToken;
SourceLocation rparenToken;
};
-class QML_PARSER_EXPORT ThisExpression: public ExpressionNode
+class QML_PARSER_EXPORT ThisExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(ThisExpression)
@@ -308,7 +340,7 @@ public:
SourceLocation thisToken;
};
-class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode
+class QML_PARSER_EXPORT IdentifierExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(IdentifierExpression)
@@ -329,7 +361,7 @@ public:
SourceLocation identifierToken;
};
-class QML_PARSER_EXPORT NullExpression: public ExpressionNode
+class QML_PARSER_EXPORT NullExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(NullExpression)
@@ -348,7 +380,7 @@ public:
SourceLocation nullToken;
};
-class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode
+class QML_PARSER_EXPORT TrueLiteral: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(TrueLiteral)
@@ -367,7 +399,7 @@ public:
SourceLocation trueToken;
};
-class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode
+class QML_PARSER_EXPORT FalseLiteral: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(FalseLiteral)
@@ -386,7 +418,27 @@ public:
SourceLocation falseToken;
};
-class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode
+class QML_PARSER_EXPORT SuperLiteral : public LeftHandSideExpression
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SuperLiteral)
+
+ SuperLiteral() { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return superToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return superToken; }
+
+// attributes
+ SourceLocation superToken;
+};
+
+
+class QML_PARSER_EXPORT NumericLiteral: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(NumericLiteral)
@@ -407,7 +459,7 @@ public:
SourceLocation literalToken;
};
-class QML_PARSER_EXPORT StringLiteral: public ExpressionNode
+class QML_PARSER_EXPORT StringLiteral: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(StringLiteral)
@@ -428,7 +480,30 @@ public:
SourceLocation literalToken;
};
-class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode
+class QML_PARSER_EXPORT TemplateLiteral : public LeftHandSideExpression
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TemplateLiteral)
+
+ TemplateLiteral(const QStringRef &str, ExpressionNode *e)
+ : value(str), expression(e), next(nullptr)
+ { kind = K; }
+
+ SourceLocation firstSourceLocation() const override
+ { return literalToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() : (expression ? expression->lastSourceLocation() : literalToken); }
+
+ void accept0(Visitor *visitor) override;
+
+ QStringRef value;
+ ExpressionNode *expression;
+ TemplateLiteral *next;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT RegExpLiteral: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(RegExpLiteral)
@@ -450,22 +525,26 @@ public:
SourceLocation literalToken;
};
-class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode
+class QML_PARSER_EXPORT Pattern : public LeftHandSideExpression
{
public:
- QQMLJS_DECLARE_AST_NODE(ArrayLiteral)
-
- ArrayLiteral(Elision *e):
- elements (nullptr), elision (e)
- { kind = K; }
+ enum ParseMode {
+ Literal,
+ Binding
+ };
+ Pattern *patternCast() override;
+ virtual bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) = 0;
+ ParseMode parseMode = Literal;
+};
- ArrayLiteral(ElementList *elts):
- elements (elts), elision (nullptr)
- { kind = K; }
+class QML_PARSER_EXPORT ArrayPattern : public Pattern
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArrayPattern)
- ArrayLiteral(ElementList *elts, Elision *e):
- elements (elts), elision (e)
- { kind = K; }
+ ArrayPattern(PatternElementList *elts)
+ : elements(elts)
+ { kind = K; }
void accept0(Visitor *visitor) override;
@@ -475,24 +554,28 @@ public:
SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
+ bool isValidArrayLiteral(SourceLocation *errorLocation = nullptr) const;
+
+ bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
+
// attributes
- ElementList *elements;
- Elision *elision;
+ PatternElementList *elements = nullptr;
SourceLocation lbracketToken;
SourceLocation commaToken;
SourceLocation rbracketToken;
};
-class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode
+class QML_PARSER_EXPORT ObjectPattern : public Pattern
{
public:
- QQMLJS_DECLARE_AST_NODE(ObjectLiteral)
+ QQMLJS_DECLARE_AST_NODE(ObjectPattern)
- ObjectLiteral()
+ ObjectPattern()
{ kind = K; }
- ObjectLiteral(PropertyAssignmentList *plist):
- properties (plist) { kind = K; }
+ ObjectPattern(PatternPropertyList *plist)
+ : properties(plist)
+ { kind = K; }
void accept0(Visitor *visitor) override;
@@ -502,8 +585,10 @@ public:
SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
+ bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
+
// attributes
- PropertyAssignmentList *properties = nullptr;
+ PatternPropertyList *properties = nullptr;
SourceLocation lbraceToken;
SourceLocation rbraceToken;
};
@@ -543,53 +628,6 @@ public:
SourceLocation commaToken;
};
-class QML_PARSER_EXPORT ElementList: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(ElementList)
-
- ElementList(Elision *e, ExpressionNode *expr):
- elision (e), expression (expr), next (this)
- { kind = K; }
-
- ElementList(ElementList *previous, Elision *e, ExpressionNode *expr):
- elision (e), expression (expr)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
- }
-
- inline ElementList *finish ()
- {
- ElementList *front = next;
- next = nullptr;
- return front;
- }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- {
- if (elision)
- return elision->firstSourceLocation();
- return expression->firstSourceLocation();
- }
-
- SourceLocation lastSourceLocation() const override
- {
- if (next)
- return next->lastSourceLocation();
- return expression->lastSourceLocation();
- }
-
-// attributes
- Elision *elision;
- ExpressionNode *expression;
- ElementList *next;
- SourceLocation commaToken;
-};
-
class QML_PARSER_EXPORT PropertyName: public Node
{
public:
@@ -609,116 +647,184 @@ public:
SourceLocation propertyNameToken;
};
-class QML_PARSER_EXPORT PropertyAssignment: public Node
+class QML_PARSER_EXPORT PatternElement : public Node
{
public:
- PropertyAssignment(PropertyName *n)
- : name(n)
- {}
+ QQMLJS_DECLARE_AST_NODE(PatternElement)
+
+ enum Type {
+ // object literal types
+ Literal,
+ Getter,
+ Setter,
+
+ // used by both bindings and literals
+ SpreadElement,
+ RestElement = SpreadElement,
+
+ // binding types
+ Binding,
+ };
+
+ PatternElement(ExpressionNode *i = nullptr, Type t = Literal)
+ : initializer(i), type(t)
+ { kind = K; }
+
+ PatternElement(const QStringRef &n, ExpressionNode *i = nullptr, Type t = Binding)
+ : bindingIdentifier(n.toString()), initializer(i), type(t)
+ {
+ Q_ASSERT(t >= RestElement);
+ kind = K;
+ }
+
+ PatternElement(Pattern *pattern, ExpressionNode *i = nullptr, Type t = Binding)
+ : bindingTarget(pattern), initializer(i), type(t)
+ {
+ Q_ASSERT(t >= RestElement);
+ kind = K;
+ }
+
+ void accept0(Visitor *visitor) override;
+ virtual bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage);
+
+ SourceLocation firstSourceLocation() const override
+ { return identifierToken.isValid() ? identifierToken : (bindingTarget ? bindingTarget->firstSourceLocation() : initializer->firstSourceLocation()); }
+
+ SourceLocation lastSourceLocation() const override
+ { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : identifierToken); }
+
+ ExpressionNode *destructuringTarget() const { return bindingTarget; }
+ Pattern *destructuringPattern() const { return bindingTarget ? bindingTarget->patternCast() : nullptr; }
+ PatternElementList *elementList() const { ArrayPattern *a = cast<ArrayPattern *>(bindingTarget); return a ? a->elements : nullptr; }
+ PatternPropertyList *propertyList() const { ObjectPattern *o = cast<ObjectPattern *>(bindingTarget); return o ? o->properties : nullptr; }
+
+ bool isVariableDeclaration() const { return scope != VariableScope::NoScope; }
+ bool isLexicallyScoped() const { return scope == VariableScope::Let || scope == VariableScope::Const; }
+
+ virtual void boundNames(QStringList *names);
+
// attributes
- PropertyName *name;
+ SourceLocation identifierToken;
+ QString bindingIdentifier;
+ ExpressionNode *bindingTarget = nullptr;
+ ExpressionNode *initializer = nullptr;
+ Type type = Literal;
+ // when used in a VariableDeclarationList
+ VariableScope scope = VariableScope::NoScope;
};
-class QML_PARSER_EXPORT PropertyAssignmentList: public Node
+class QML_PARSER_EXPORT PatternElementList : public Node
{
public:
- QQMLJS_DECLARE_AST_NODE(PropertyAssignmentList)
+ QQMLJS_DECLARE_AST_NODE(PatternElementList)
- PropertyAssignmentList(PropertyAssignment *assignment)
- : assignment(assignment)
- , next(this)
+ PatternElementList(Elision *elision, PatternElement *element)
+ : elision(elision), element(element), next(this)
{ kind = K; }
- PropertyAssignmentList(PropertyAssignmentList *previous, PropertyAssignment *assignment)
- : assignment(assignment)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
+ PatternElementList *append(PatternElementList *n) {
+ n->next = next;
+ next = n;
+ return n;
}
- inline PropertyAssignmentList *finish ()
+ inline PatternElementList *finish ()
{
- PropertyAssignmentList *front = next;
- next = nullptr;
+ PatternElementList *front = next;
+ next = 0;
return front;
}
void accept0(Visitor *visitor) override;
+ void boundNames(QStringList *names);
+
SourceLocation firstSourceLocation() const override
- { return assignment->firstSourceLocation(); }
+ { return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : assignment->lastSourceLocation(); }
+ { return next ? next->lastSourceLocation() : (element ? element->lastSourceLocation() : elision->lastSourceLocation()); }
-// attributes
- PropertyAssignment *assignment;
- PropertyAssignmentList *next;
- SourceLocation commaToken;
+ Elision *elision = nullptr;
+ PatternElement *element = nullptr;
+ PatternElementList *next;
};
-class QML_PARSER_EXPORT PropertyNameAndValue: public PropertyAssignment
+class QML_PARSER_EXPORT PatternProperty : public PatternElement
{
public:
- QQMLJS_DECLARE_AST_NODE(PropertyNameAndValue)
+ QQMLJS_DECLARE_AST_NODE(PatternProperty)
+
+ PatternProperty(PropertyName *name, ExpressionNode *i = nullptr, Type t = Literal)
+ : PatternElement(i, t), name(name)
+ { kind = K; }
+
+ PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr)
+ : PatternElement(n, i), name(name)
+ { kind = K; }
- PropertyNameAndValue(PropertyName *n, ExpressionNode *v)
- : PropertyAssignment(n), value(v)
+ PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr)
+ : PatternElement(pattern, i), name(name)
{ kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return name->firstSourceLocation(); }
-
SourceLocation lastSourceLocation() const override
- { return value->lastSourceLocation(); }
+ {
+ SourceLocation loc = PatternElement::lastSourceLocation();
+ return loc.isValid() ? loc : name->lastSourceLocation();
+ }
+
+ void boundNames(QStringList *names) override;
+ bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override;
// attributes
+ PropertyName *name;
SourceLocation colonToken;
- ExpressionNode *value;
- SourceLocation commaToken;
};
-class QML_PARSER_EXPORT PropertyGetterSetter: public PropertyAssignment
+
+class QML_PARSER_EXPORT PatternPropertyList : public Node
{
public:
- QQMLJS_DECLARE_AST_NODE(PropertyGetterSetter)
+ QQMLJS_DECLARE_AST_NODE(PatternPropertyList)
- enum Type {
- Getter,
- Setter
- };
-
- PropertyGetterSetter(PropertyName *n, FunctionBody *b)
- : PropertyAssignment(n), type(Getter), formals(nullptr), functionBody (b)
+ PatternPropertyList(PatternProperty *property)
+ : property(property), next(this)
{ kind = K; }
- PropertyGetterSetter(PropertyName *n, FormalParameterList *f, FunctionBody *b)
- : PropertyAssignment(n), type(Setter), formals(f), functionBody (b)
- { kind = K; }
+ PatternPropertyList(PatternPropertyList *previous, PatternProperty *property)
+ : property(property), next(this)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
void accept0(Visitor *visitor) override;
+ void boundNames(QStringList *names);
+
+ inline PatternPropertyList *finish ()
+ {
+ PatternPropertyList *front = next;
+ next = 0;
+ return front;
+ }
+
SourceLocation firstSourceLocation() const override
- { return getSetToken; }
+ { return property->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return rbraceToken; }
+ { return next ? next->lastSourceLocation() : property->lastSourceLocation(); }
-// attributes
- Type type;
- SourceLocation getSetToken;
- SourceLocation lparenToken;
- FormalParameterList *formals;
- SourceLocation rparenToken;
- SourceLocation lbraceToken;
- FunctionBody *functionBody;
- SourceLocation rbraceToken;
+ PatternProperty *property;
+ PatternPropertyList *next;
};
-class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
+class QML_PARSER_EXPORT IdentifierPropertyName : public PropertyName
{
public:
QQMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
@@ -766,7 +872,31 @@ public:
double id;
};
-class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode
+class QML_PARSER_EXPORT ComputedPropertyName : public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ComputedPropertyName)
+
+ ComputedPropertyName(ExpressionNode *expression)
+ : expression(expression)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ QString asString() const override { return QString(); }
+
+ SourceLocation firstSourceLocation() const override
+ { return expression->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+};
+
+
+class QML_PARSER_EXPORT ArrayMemberExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(ArrayMemberExpression)
@@ -790,7 +920,7 @@ public:
SourceLocation rbracketToken;
};
-class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode
+class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(FieldMemberExpression)
@@ -814,7 +944,29 @@ public:
SourceLocation identifierToken;
};
-class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode
+class QML_PARSER_EXPORT TaggedTemplate : public LeftHandSideExpression
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TaggedTemplate)
+
+ TaggedTemplate(ExpressionNode *b, TemplateLiteral *t)
+ : base (b), templateLiteral(t)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return base->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return templateLiteral->lastSourceLocation(); }
+
+ // attributes
+ ExpressionNode *base;
+ TemplateLiteral *templateLiteral;
+};
+
+class QML_PARSER_EXPORT NewMemberExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(NewMemberExpression)
@@ -839,7 +991,7 @@ public:
SourceLocation rparenToken;
};
-class QML_PARSER_EXPORT NewExpression: public ExpressionNode
+class QML_PARSER_EXPORT NewExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(NewExpression)
@@ -860,7 +1012,7 @@ public:
SourceLocation newToken;
};
-class QML_PARSER_EXPORT CallExpression: public ExpressionNode
+class QML_PARSER_EXPORT CallExpression: public LeftHandSideExpression
{
public:
QQMLJS_DECLARE_AST_NODE(CallExpression)
@@ -924,6 +1076,7 @@ public:
ExpressionNode *expression;
ArgumentList *next;
SourceLocation commaToken;
+ bool isSpreadElement = false;
};
class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode
@@ -1257,16 +1410,15 @@ class QML_PARSER_EXPORT StatementList: public Node
public:
QQMLJS_DECLARE_AST_NODE(StatementList)
- StatementList(Statement *stmt):
- statement (stmt), next (this)
- { kind = K; }
+ // ### This should be a Statement, but FunctionDeclaration currently doesn't inherit it.
+ StatementList(Node *stmt)
+ : statement(stmt), next (this)
+ { kind = K; }
- StatementList(StatementList *previous, Statement *stmt):
- statement (stmt)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
+ StatementList *append(StatementList *n) {
+ n->next = next;
+ next = n;
+ return n;
}
void accept0(Visitor *visitor) override;
@@ -1285,76 +1437,21 @@ public:
}
// attributes
- Statement *statement;
+ Node *statement = nullptr;
StatementList *next;
};
-class QML_PARSER_EXPORT VariableStatement: public Statement
-{
-public:
- QQMLJS_DECLARE_AST_NODE(VariableStatement)
-
- VariableStatement(VariableDeclarationList *vlist):
- declarations (vlist)
- { kind = K; }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return declarationKindToken; }
-
- SourceLocation lastSourceLocation() const override
- { return semicolonToken; }
-
-// attributes
- VariableDeclarationList *declarations;
- SourceLocation declarationKindToken;
- SourceLocation semicolonToken;
-};
-
-class QML_PARSER_EXPORT VariableDeclaration: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(VariableDeclaration)
-
- enum VariableScope {
- FunctionScope,
- BlockScope, // let
- ReadOnlyBlockScope // const
- };
-
- VariableDeclaration(const QStringRef &n, ExpressionNode *e, VariableScope s):
- name (n), expression (e), scope(s)
- { kind = K; }
-
- bool isLexicallyScoped() const { return scope != FunctionScope; }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return identifierToken; }
-
- SourceLocation lastSourceLocation() const override
- { return expression ? expression->lastSourceLocation() : identifierToken; }
-
-// attributes
- QStringRef name;
- ExpressionNode *expression;
- SourceLocation identifierToken;
- VariableScope scope;
-};
-
class QML_PARSER_EXPORT VariableDeclarationList: public Node
{
public:
QQMLJS_DECLARE_AST_NODE(VariableDeclarationList)
- VariableDeclarationList(VariableDeclaration *decl):
- declaration (decl), next (this)
- { kind = K; }
+ VariableDeclarationList(PatternElement *decl)
+ : declaration(decl), next(this)
+ { kind = K; }
- VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl):
- declaration (decl)
+ VariableDeclarationList(VariableDeclarationList *previous, PatternElement *decl)
+ : declaration(decl)
{
kind = K;
next = previous->next;
@@ -1373,7 +1470,7 @@ public:
return declaration->lastSourceLocation();
}
- inline VariableDeclarationList *finish(VariableDeclaration::VariableScope s)
+ inline VariableDeclarationList *finish(VariableScope s)
{
VariableDeclarationList *front = next;
next = nullptr;
@@ -1385,11 +1482,33 @@ public:
}
// attributes
- VariableDeclaration *declaration;
+ PatternElement *declaration;
VariableDeclarationList *next;
SourceLocation commaToken;
};
+class QML_PARSER_EXPORT VariableStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableStatement)
+
+ VariableStatement(VariableDeclarationList *vlist):
+ declarations (vlist)
+ { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return declarationKindToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return declarations->lastSourceLocation(); }
+
+// attributes
+ VariableDeclarationList *declarations;
+ SourceLocation declarationKindToken;
+};
+
class QML_PARSER_EXPORT EmptyStatement: public Statement
{
public:
@@ -1423,7 +1542,7 @@ public:
{ return expression->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return semicolonToken; }
+ { return expression->lastSourceLocation(); }
// attributes
ExpressionNode *expression;
@@ -1523,35 +1642,11 @@ public:
initialiser (i), condition (c), expression (e), statement (stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return forToken; }
-
- SourceLocation lastSourceLocation() const override
- { return statement->lastSourceLocation(); }
-
-// attributes
- ExpressionNode *initialiser;
- ExpressionNode *condition;
- ExpressionNode *expression;
- Statement *statement;
- SourceLocation forToken;
- SourceLocation lparenToken;
- SourceLocation firstSemicolonToken;
- SourceLocation secondSemicolonToken;
- SourceLocation rparenToken;
-};
-
-class QML_PARSER_EXPORT LocalForStatement: public Statement
-{
-public:
- QQMLJS_DECLARE_AST_NODE(LocalForStatement)
-
- LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ ForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
declarations (vlist), condition (c), expression (e), statement (stmt)
{ kind = K; }
+
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
@@ -1561,26 +1656,34 @@ public:
{ return statement->lastSourceLocation(); }
// attributes
- VariableDeclarationList *declarations;
+ ExpressionNode *initialiser = nullptr;
+ VariableDeclarationList *declarations = nullptr;
ExpressionNode *condition;
ExpressionNode *expression;
Statement *statement;
SourceLocation forToken;
SourceLocation lparenToken;
- SourceLocation varToken;
SourceLocation firstSemicolonToken;
SourceLocation secondSemicolonToken;
SourceLocation rparenToken;
};
+enum class ForEachType {
+ In,
+ Of
+};
+
class QML_PARSER_EXPORT ForEachStatement: public Statement
{
public:
QQMLJS_DECLARE_AST_NODE(ForEachStatement)
- ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt):
- initialiser (i), expression (e), statement (stmt)
- { kind = K; }
+ ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt)
+ : lhs(i), expression(e), statement(stmt)
+ { kind = K; }
+ ForEachStatement(PatternElement *v, ExpressionNode *e, Statement *stmt)
+ : lhs(v), expression(e), statement(stmt)
+ { kind = K; }
void accept0(Visitor *visitor) override;
@@ -1590,42 +1693,19 @@ public:
SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
-// attributes
- ExpressionNode *initialiser;
- ExpressionNode *expression;
- Statement *statement;
- SourceLocation forToken;
- SourceLocation lparenToken;
- SourceLocation inToken;
- SourceLocation rparenToken;
-};
-
-class QML_PARSER_EXPORT LocalForEachStatement: public Statement
-{
-public:
- QQMLJS_DECLARE_AST_NODE(LocalForEachStatement)
-
- LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt):
- declaration (v), expression (e), statement (stmt)
- { kind = K; }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return forToken; }
-
- SourceLocation lastSourceLocation() const override
- { return statement->lastSourceLocation(); }
+ PatternElement *declaration() const {
+ return AST::cast<PatternElement *>(lhs);
+ }
// attributes
- VariableDeclaration *declaration;
+ Node *lhs;
ExpressionNode *expression;
Statement *statement;
SourceLocation forToken;
SourceLocation lparenToken;
- SourceLocation varToken;
- SourceLocation inToken;
+ SourceLocation inOfToken;
SourceLocation rparenToken;
+ ForEachType type;
};
class QML_PARSER_EXPORT ContinueStatement: public Statement
@@ -1696,6 +1776,28 @@ public:
SourceLocation semicolonToken;
};
+class QML_PARSER_EXPORT YieldExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(YieldExpression)
+
+ YieldExpression(ExpressionNode *e = nullptr):
+ expression (e) { kind = K; }
+
+ void accept0(Visitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return yieldToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return expression ? expression->lastSourceLocation() : yieldToken; }
+
+// attributes
+ ExpressionNode *expression;
+ bool isYieldStar = false;
+ SourceLocation yieldToken;
+};
+
class QML_PARSER_EXPORT WithStatement: public Statement
{
public:
@@ -1906,9 +2008,9 @@ class QML_PARSER_EXPORT Catch: public Node
public:
QQMLJS_DECLARE_AST_NODE(Catch)
- Catch(const QStringRef &n, Block *stmt):
- name (n), statement (stmt)
- { kind = K; }
+ Catch(PatternElement *p, Block *stmt)
+ : patternElement(p), statement(stmt)
+ { kind = K; }
void accept0(Visitor *visitor) override;
@@ -1919,7 +2021,7 @@ public:
{ return statement->lastSourceLocation(); }
// attributes
- QStringRef name;
+ PatternElement *patternElement;
Block *statement;
SourceLocation catchToken;
SourceLocation lparenToken;
@@ -1993,7 +2095,7 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public:
QQMLJS_DECLARE_AST_NODE(FunctionExpression)
- FunctionExpression(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b):
name (n), formals (f), body (b)
{ kind = K; }
@@ -2005,10 +2107,15 @@ public:
SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
+ FunctionExpression *asFunctionDefinition() override;
+
+
// attributes
QStringRef name;
+ bool isArrowFunction = false;
+ bool isGenerator = false;
FormalParameterList *formals;
- FunctionBody *body;
+ StatementList *body;
SourceLocation functionToken;
SourceLocation identifierToken;
SourceLocation lparenToken;
@@ -2022,7 +2129,7 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public:
QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
- FunctionDeclaration(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b):
FunctionExpression(n, f, b)
{ kind = K; }
@@ -2034,65 +2141,68 @@ class QML_PARSER_EXPORT FormalParameterList: public Node
public:
QQMLJS_DECLARE_AST_NODE(FormalParameterList)
- FormalParameterList(const QStringRef &n):
- name (n), next (this)
- { kind = K; }
-
- FormalParameterList(FormalParameterList *previous, const QStringRef &n):
- name (n)
+ FormalParameterList(FormalParameterList *previous, PatternElement *e)
+ : element(e)
{
kind = K;
- next = previous->next;
- previous->next = this;
+ if (previous) {
+ next = previous->next;
+ previous->next = this;
+ } else {
+ next = this;
+ }
}
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return identifierToken; }
-
- SourceLocation lastSourceLocation() const override
- { return next ? next->lastSourceLocation() : identifierToken; }
+ FormalParameterList *append(FormalParameterList *n) {
+ n->next = next;
+ next = n;
+ return n;
+ }
- inline FormalParameterList *finish ()
+ bool isSimpleParameterList()
{
- FormalParameterList *front = next;
- next = nullptr;
- return front;
+ AST::FormalParameterList *formals = this;
+ while (formals) {
+ PatternElement *e = formals->element;
+ if (e && e->type == PatternElement::RestElement)
+ return false;
+ if (e && (e->initializer || e->bindingTarget))
+ return false;
+ formals = formals->next;
+ }
+ return true;
}
-// attributes
- QStringRef name;
- FormalParameterList *next;
- SourceLocation commaToken;
- SourceLocation identifierToken;
-};
-
-class QML_PARSER_EXPORT SourceElement: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(SourceElement)
-
- inline SourceElement()
- { kind = K; }
-};
+ int length()
+ {
+ // the length property of Function objects
+ int l = 0;
+ AST::FormalParameterList *formals = this;
+ while (formals) {
+ PatternElement *e = formals->element;
+ if (!e || e->initializer)
+ break;
+ if (e->type == PatternElement::RestElement)
+ break;
+ ++l;
+ formals = formals->next;
+ }
+ return l;
+ }
-class QML_PARSER_EXPORT SourceElements: public Node
-{
-public:
- QQMLJS_DECLARE_AST_NODE(SourceElements)
+ bool containsName(const QString &name) const {
+ for (const FormalParameterList *it = this; it; it = it->next) {
+ PatternElement *b = it->element;
+ // ### handle binding patterns
+ if (b && b->bindingIdentifier == name)
+ return true;
+ }
+ return false;
+ }
- SourceElements(SourceElement *elt):
- element (elt), next (this)
- { kind = K; }
+ QStringList formals() const;
- SourceElements(SourceElements *previous, SourceElement *elt):
- element (elt)
- {
- kind = K;
- next = previous->next;
- previous->next = this;
- }
+ QStringList boundNames() const;
void accept0(Visitor *visitor) override;
@@ -2102,100 +2212,96 @@ public:
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
- inline SourceElements *finish ()
- {
- SourceElements *front = next;
- next = nullptr;
- return front;
- }
+ FormalParameterList *finish();
// attributes
- SourceElement *element;
- SourceElements *next;
+ PatternElement *element = nullptr;
+ FormalParameterList *next;
};
-class QML_PARSER_EXPORT FunctionBody: public Node
+class QML_PARSER_EXPORT ClassExpression : public ExpressionNode
{
public:
- QQMLJS_DECLARE_AST_NODE(FunctionBody)
+ QQMLJS_DECLARE_AST_NODE(ClassExpression)
- FunctionBody(SourceElements *elts):
- elements (elts)
+ ClassExpression(const QStringRef &n, ExpressionNode *heritage, ClassElementList *elements)
+ : name(n), heritage(heritage), elements(elements)
{ kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
- { return elements ? elements->firstSourceLocation() : SourceLocation(); }
+ { return classToken; }
SourceLocation lastSourceLocation() const override
- { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+ { return rbraceToken; }
// attributes
- SourceElements *elements;
+ QStringRef name;
+ ExpressionNode *heritage;
+ ClassElementList *elements;
+ SourceLocation classToken;
+ SourceLocation identifierToken;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
};
-class QML_PARSER_EXPORT Program: public Node
+class QML_PARSER_EXPORT ClassElementList : public Node
{
public:
- QQMLJS_DECLARE_AST_NODE(Program)
-
- Program(SourceElements *elts):
- elements (elts)
- { kind = K; }
-
- void accept0(Visitor *visitor) override;
-
- SourceLocation firstSourceLocation() const override
- { return elements ? elements->firstSourceLocation() : SourceLocation(); }
-
- SourceLocation lastSourceLocation() const override
- { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+ QQMLJS_DECLARE_AST_NODE(ClassElementList)
-// attributes
- SourceElements *elements;
-};
-
-class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement
-{
-public:
- QQMLJS_DECLARE_AST_NODE(FunctionSourceElement)
+ ClassElementList(PatternProperty *property, bool isStatic)
+ : isStatic(isStatic), property(property)
+ {
+ kind = K;
+ next = this;
+ }
- FunctionSourceElement(FunctionDeclaration *f):
- declaration (f)
- { kind = K; }
+ ClassElementList *append(ClassElementList *n) {
+ n->next = next;
+ next = n;
+ return n;
+ }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
- { return declaration->firstSourceLocation(); }
+ { return property->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return declaration->lastSourceLocation(); }
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return property->lastSourceLocation();
+ }
-// attributes
- FunctionDeclaration *declaration;
+ ClassElementList *finish();
+
+ bool isStatic;
+ ClassElementList *next;
+ PatternProperty *property;
};
-class QML_PARSER_EXPORT StatementSourceElement: public SourceElement
+class QML_PARSER_EXPORT Program: public Node
{
public:
- QQMLJS_DECLARE_AST_NODE(StatementSourceElement)
+ QQMLJS_DECLARE_AST_NODE(Program)
- StatementSourceElement(Statement *stmt):
- statement (stmt)
- { kind = K; }
+ Program(StatementList *statements)
+ : statements(statements)
+ { kind = K; }
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
- { return statement->firstSourceLocation(); }
+ { return statements ? statements->firstSourceLocation() : SourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return statement->lastSourceLocation(); }
+ { return statements ? statements->lastSourceLocation() : SourceLocation(); }
// attributes
- Statement *statement;
+ StatementList *statements;
};
class QML_PARSER_EXPORT DebuggerStatement: public Statement
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 140a757e51..196d23a9c4 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -89,22 +89,27 @@ class IdentifierExpression;
class NullExpression;
class TrueLiteral;
class FalseLiteral;
+class SuperLiteral;
class NumericLiteral;
class StringLiteral;
+class TemplateLiteral;
class RegExpLiteral;
-class ArrayLiteral;
-class ObjectLiteral;
-class ElementList;
+class Pattern;
+class ArrayPattern;
+class ObjectPattern;
+class PatternElement;
+class PatternElementList;
+class PatternProperty;
+class PatternPropertyList;
class Elision;
-class PropertyAssignmentList;
-class PropertyGetterSetter;
-class PropertyNameAndValue;
class PropertyName;
class IdentifierPropertyName;
class StringLiteralPropertyName;
class NumericLiteralPropertyName;
+class ComputedPropertyName;
class ArrayMemberExpression;
class FieldMemberExpression;
+class TaggedTemplate;
class NewMemberExpression;
class NewExpression;
class CallExpression;
@@ -123,20 +128,19 @@ class NotExpression;
class BinaryExpression;
class ConditionalExpression;
class Expression; // ### rename
+class YieldExpression;
class Block;
+class LeftHandSideExpression;
class StatementList;
class VariableStatement;
class VariableDeclarationList;
-class VariableDeclaration;
class EmptyStatement;
class ExpressionStatement;
class IfStatement;
class DoWhileStatement;
class WhileStatement;
class ForStatement;
-class LocalForStatement;
class ForEachStatement;
-class LocalForEachStatement;
class ContinueStatement;
class BreakStatement;
class ReturnStatement;
@@ -154,14 +158,11 @@ class Finally;
class FunctionDeclaration;
class FunctionExpression;
class FormalParameterList;
-class FunctionBody;
class Program;
-class SourceElements;
-class SourceElement;
-class FunctionSourceElement;
-class StatementSourceElement;
class DebuggerStatement;
class NestedExpression;
+class ClassExpression;
+class ClassElementList;
// ui elements
class UiProgram;
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 13218f0e98..5fbdf4adff 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -122,35 +122,41 @@ public:
virtual bool visit(FalseLiteral *) { return true; }
virtual void endVisit(FalseLiteral *) {}
+ virtual bool visit(SuperLiteral *) { return true; }
+ virtual void endVisit(SuperLiteral *) {}
+
virtual bool visit(StringLiteral *) { return true; }
virtual void endVisit(StringLiteral *) {}
+ virtual bool visit(TemplateLiteral *) { return true; }
+ virtual void endVisit(TemplateLiteral *) {}
+
virtual bool visit(NumericLiteral *) { return true; }
virtual void endVisit(NumericLiteral *) {}
virtual bool visit(RegExpLiteral *) { return true; }
virtual void endVisit(RegExpLiteral *) {}
- virtual bool visit(ArrayLiteral *) { return true; }
- virtual void endVisit(ArrayLiteral *) {}
+ virtual bool visit(ArrayPattern *) { return true; }
+ virtual void endVisit(ArrayPattern *) {}
- virtual bool visit(ObjectLiteral *) { return true; }
- virtual void endVisit(ObjectLiteral *) {}
+ virtual bool visit(ObjectPattern *) { return true; }
+ virtual void endVisit(ObjectPattern *) {}
- virtual bool visit(ElementList *) { return true; }
- virtual void endVisit(ElementList *) {}
+ virtual bool visit(PatternElementList *) { return true; }
+ virtual void endVisit(PatternElementList *) {}
- virtual bool visit(Elision *) { return true; }
- virtual void endVisit(Elision *) {}
+ virtual bool visit(PatternPropertyList *) { return true; }
+ virtual void endVisit(PatternPropertyList *) {}
- virtual bool visit(PropertyAssignmentList *) { return true; }
- virtual void endVisit(PropertyAssignmentList *) {}
+ virtual bool visit(PatternElement *) { return true; }
+ virtual void endVisit(PatternElement *) {}
- virtual bool visit(PropertyNameAndValue *) { return true; }
- virtual void endVisit(PropertyNameAndValue *) {}
+ virtual bool visit(PatternProperty *) { return true; }
+ virtual void endVisit(PatternProperty *) {}
- virtual bool visit(PropertyGetterSetter *) { return true; }
- virtual void endVisit(PropertyGetterSetter *) {}
+ virtual bool visit(Elision *) { return true; }
+ virtual void endVisit(Elision *) {}
virtual bool visit(NestedExpression *) { return true; }
virtual void endVisit(NestedExpression *) {}
@@ -164,12 +170,18 @@ public:
virtual bool visit(NumericLiteralPropertyName *) { return true; }
virtual void endVisit(NumericLiteralPropertyName *) {}
+ virtual bool visit(ComputedPropertyName *) { return true; }
+ virtual void endVisit(ComputedPropertyName *) {}
+
virtual bool visit(ArrayMemberExpression *) { return true; }
virtual void endVisit(ArrayMemberExpression *) {}
virtual bool visit(FieldMemberExpression *) { return true; }
virtual void endVisit(FieldMemberExpression *) {}
+ virtual bool visit(TaggedTemplate *) { return true; }
+ virtual void endVisit(TaggedTemplate *) {}
+
virtual bool visit(NewMemberExpression *) { return true; }
virtual void endVisit(NewMemberExpression *) {}
@@ -236,9 +248,6 @@ public:
virtual bool visit(VariableDeclarationList *) { return true; }
virtual void endVisit(VariableDeclarationList *) {}
- virtual bool visit(VariableDeclaration *) { return true; }
- virtual void endVisit(VariableDeclaration *) {}
-
virtual bool visit(EmptyStatement *) { return true; }
virtual void endVisit(EmptyStatement *) {}
@@ -257,15 +266,9 @@ public:
virtual bool visit(ForStatement *) { return true; }
virtual void endVisit(ForStatement *) {}
- virtual bool visit(LocalForStatement *) { return true; }
- virtual void endVisit(LocalForStatement *) {}
-
virtual bool visit(ForEachStatement *) { return true; }
virtual void endVisit(ForEachStatement *) {}
- virtual bool visit(LocalForEachStatement *) { return true; }
- virtual void endVisit(LocalForEachStatement *) {}
-
virtual bool visit(ContinueStatement *) { return true; }
virtual void endVisit(ContinueStatement *) {}
@@ -275,6 +278,9 @@ public:
virtual bool visit(ReturnStatement *) { return true; }
virtual void endVisit(ReturnStatement *) {}
+ virtual bool visit(YieldExpression *) { return true; }
+ virtual void endVisit(YieldExpression *) {}
+
virtual bool visit(WithStatement *) { return true; }
virtual void endVisit(WithStatement *) {}
@@ -317,21 +323,15 @@ public:
virtual bool visit(FormalParameterList *) { return true; }
virtual void endVisit(FormalParameterList *) {}
- virtual bool visit(FunctionBody *) { return true; }
- virtual void endVisit(FunctionBody *) {}
+ virtual bool visit(ClassExpression *) { return true; }
+ virtual void endVisit(ClassExpression *) {}
+
+ virtual bool visit(ClassElementList *) { return true; }
+ virtual void endVisit(ClassElementList *) {}
virtual bool visit(Program *) { return true; }
virtual void endVisit(Program *) {}
- virtual bool visit(SourceElements *) { return true; }
- virtual void endVisit(SourceElements *) {}
-
- virtual bool visit(FunctionSourceElement *) { return true; }
- virtual void endVisit(FunctionSourceElement *) {}
-
- virtual bool visit(StatementSourceElement *) { return true; }
- virtual void endVisit(StatementSourceElement *) {}
-
virtual bool visit(DebuggerStatement *) { return true; }
virtual void endVisit(DebuggerStatement *) {}
};
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
index b4f0debf85..97ce6ebea3 100644
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ b/src/qml/parser/qqmljsengine_p.cpp
@@ -112,13 +112,6 @@ double integerFromString(const char *buf, int size, int radix)
return result;
}
-double integerFromString(const QString &str, int radix)
-{
- QByteArray ba = QStringRef(&str).trimmed().toLatin1();
- return integerFromString(ba.constData(), ba.size(), radix);
-}
-
-
Engine::Engine()
: _lexer(nullptr), _directives(nullptr)
{ }
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index af26bac0ff..1de907d296 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -63,9 +63,35 @@ QT_QML_BEGIN_NAMESPACE
namespace QQmlJS {
class Lexer;
-class Directives;
class MemoryPool;
+class QML_PARSER_EXPORT Directives {
+public:
+ virtual ~Directives() {}
+
+ virtual void pragmaLibrary()
+ {
+ }
+
+ virtual void importFile(const QString &jsfile, const QString &module, int line, int column)
+ {
+ Q_UNUSED(jsfile);
+ Q_UNUSED(module);
+ Q_UNUSED(line);
+ Q_UNUSED(column);
+ }
+
+ virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column)
+ {
+ Q_UNUSED(uri);
+ Q_UNUSED(version);
+ Q_UNUSED(module);
+ Q_UNUSED(line);
+ Q_UNUSED(column);
+ }
+};
+
+
class QML_PARSER_EXPORT DiagnosticMessage
{
public:
diff --git a/src/qml/parser/qqmljsgrammar.cpp b/src/qml/parser/qqmljsgrammar.cpp
deleted file mode 100644
index 2aaeb385e3..0000000000
--- a/src/qml/parser/qqmljsgrammar.cpp
+++ /dev/null
@@ -1,1167 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part 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$
-**
-****************************************************************************/
-
-// This file was generated by qlalr - DO NOT EDIT!
-#include "qqmljsgrammar_p.h"
-
-QT_BEGIN_NAMESPACE
-
-const char *const QQmlJSGrammar::spell [] = {
- "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue",
- "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
- "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
- "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
- "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
- "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
- ")", ";", nullptr, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
- "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
- "^=", "null", "true", "false", "const", "let", "debugger", "reserved word", "multiline string literal", "comment",
- nullptr, "enum", "public", "import", "pragma", "as", "on", "get", "set", nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
-};
-
-const short QQmlJSGrammar::lhs [] = {
- 108, 108, 108, 108, 108, 108, 109, 115, 115, 118,
- 118, 118, 118, 121, 123, 119, 119, 120, 120, 120,
- 120, 120, 120, 120, 120, 124, 125, 117, 116, 128,
- 128, 129, 129, 130, 130, 127, 113, 113, 113, 113,
- 132, 132, 132, 132, 132, 132, 132, 113, 140, 140,
- 140, 140, 141, 141, 142, 142, 113, 113, 113, 113,
- 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
- 113, 113, 113, 113, 113, 113, 113, 145, 145, 145,
- 145, 126, 126, 126, 126, 126, 126, 126, 146, 146,
- 146, 146, 146, 146, 146, 146, 146, 146, 146, 146,
- 146, 146, 146, 146, 146, 146, 131, 148, 148, 148,
- 148, 147, 147, 152, 152, 152, 150, 150, 153, 153,
- 153, 153, 156, 156, 156, 156, 156, 156, 156, 156,
- 156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
- 156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
- 156, 156, 156, 156, 156, 157, 157, 122, 122, 122,
- 122, 122, 160, 160, 161, 161, 161, 161, 159, 159,
- 162, 162, 163, 163, 164, 164, 164, 165, 165, 165,
- 165, 165, 165, 165, 165, 165, 165, 166, 166, 166,
- 166, 167, 167, 167, 168, 168, 168, 168, 169, 169,
- 169, 169, 169, 169, 169, 170, 170, 170, 170, 170,
- 170, 171, 171, 171, 171, 171, 172, 172, 172, 172,
- 172, 173, 173, 174, 174, 175, 175, 176, 176, 177,
- 177, 178, 178, 179, 179, 180, 180, 181, 181, 182,
- 182, 183, 183, 184, 184, 151, 151, 185, 185, 186,
- 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 111, 111, 187, 187, 188, 188, 189, 189, 110,
- 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
- 110, 110, 110, 110, 133, 198, 198, 197, 197, 144,
- 144, 199, 199, 199, 200, 200, 202, 202, 201, 203,
- 206, 204, 204, 207, 205, 205, 134, 135, 135, 136,
- 136, 190, 190, 190, 190, 190, 190, 190, 190, 191,
- 191, 191, 191, 192, 192, 192, 192, 193, 193, 137,
- 138, 208, 208, 211, 211, 209, 209, 212, 210, 194,
- 195, 195, 139, 139, 139, 213, 214, 196, 196, 215,
- 143, 158, 158, 216, 216, 155, 155, 154, 154, 217,
- 114, 114, 218, 218, 112, 112, 149, 149, 219
-};
-
-const short QQmlJSGrammar::rhs [] = {
- 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
- 1, 2, 2, 1, 1, 2, 2, 2, 2, 3,
- 3, 5, 5, 4, 4, 2, 2, 0, 1, 1,
- 2, 1, 3, 2, 3, 2, 1, 5, 4, 4,
- 1, 1, 1, 1, 1, 1, 1, 3, 1, 1,
- 1, 3, 0, 1, 2, 4, 6, 6, 3, 3,
- 7, 7, 4, 4, 5, 5, 8, 8, 5, 6,
- 6, 10, 6, 7, 1, 1, 5, 1, 3, 3,
- 5, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 3, 4, 5, 3, 4, 3, 1, 1, 2, 3,
- 4, 1, 2, 3, 7, 8, 1, 3, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
- 3, 5, 1, 2, 4, 4, 4, 3, 0, 1,
- 1, 3, 1, 1, 1, 2, 2, 1, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 1, 3, 3,
- 3, 1, 3, 3, 1, 3, 3, 3, 1, 3,
- 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
- 3, 1, 3, 3, 3, 3, 1, 3, 3, 3,
- 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
- 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
- 3, 1, 5, 1, 5, 1, 3, 1, 3, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 3, 0, 1, 1, 3, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 3, 1, 2, 0, 1, 3,
- 3, 1, 1, 1, 1, 3, 1, 3, 2, 2,
- 2, 0, 1, 2, 0, 1, 1, 2, 2, 7,
- 5, 7, 7, 7, 5, 9, 10, 7, 8, 2,
- 2, 3, 3, 2, 2, 3, 3, 3, 3, 5,
- 5, 3, 5, 1, 2, 0, 1, 4, 3, 3,
- 3, 3, 3, 3, 4, 5, 2, 2, 2, 1,
- 8, 8, 7, 1, 3, 0, 1, 0, 1, 1,
- 1, 1, 1, 2, 1, 1, 0, 1, 2
-};
-
-const short QQmlJSGrammar::action_default [] = {
- 0, 0, 28, 0, 0, 0, 28, 0, 195, 262,
- 226, 234, 230, 174, 246, 222, 3, 159, 90, 175,
- 238, 242, 163, 192, 173, 178, 158, 212, 199, 0,
- 97, 98, 93, 0, 87, 82, 367, 0, 0, 0,
- 0, 95, 0, 0, 91, 94, 86, 0, 0, 83,
- 85, 88, 84, 96, 89, 0, 92, 0, 0, 188,
- 0, 0, 175, 194, 177, 176, 0, 0, 0, 190,
- 191, 189, 193, 0, 223, 0, 0, 0, 0, 213,
- 0, 0, 0, 0, 0, 0, 203, 0, 0, 0,
- 197, 198, 196, 201, 205, 204, 202, 200, 215, 214,
- 216, 0, 231, 0, 227, 0, 0, 169, 156, 168,
- 157, 123, 124, 125, 151, 126, 153, 127, 128, 129,
- 130, 131, 132, 133, 134, 135, 136, 137, 138, 152,
- 139, 140, 154, 141, 142, 143, 144, 145, 146, 147,
- 148, 149, 150, 155, 0, 0, 167, 263, 170, 0,
- 171, 0, 172, 166, 0, 259, 252, 250, 257, 258,
- 256, 255, 261, 254, 253, 251, 260, 247, 0, 235,
- 0, 0, 239, 0, 0, 243, 0, 0, 169, 161,
- 0, 160, 0, 165, 179, 0, 356, 356, 357, 0,
- 354, 0, 355, 0, 358, 270, 277, 276, 284, 272,
- 0, 273, 0, 359, 0, 366, 274, 275, 90, 280,
- 278, 363, 360, 365, 281, 0, 293, 0, 0, 0,
- 0, 350, 0, 367, 292, 264, 307, 0, 0, 0,
- 294, 0, 0, 282, 283, 0, 271, 279, 308, 309,
- 0, 356, 0, 0, 358, 0, 351, 352, 0, 340,
- 364, 0, 324, 325, 326, 327, 0, 320, 321, 322,
- 323, 348, 349, 0, 0, 0, 0, 0, 312, 313,
- 314, 268, 266, 228, 236, 232, 248, 224, 269, 0,
- 175, 240, 244, 217, 206, 0, 0, 225, 0, 0,
- 0, 0, 218, 0, 0, 0, 0, 0, 210, 208,
- 211, 209, 207, 220, 219, 221, 0, 233, 0, 229,
- 0, 267, 175, 0, 249, 264, 265, 0, 264, 0,
- 0, 316, 0, 0, 0, 318, 0, 237, 0, 0,
- 241, 0, 0, 245, 305, 0, 297, 306, 300, 0,
- 304, 0, 264, 298, 0, 264, 0, 0, 317, 0,
- 0, 0, 319, 0, 0, 0, 311, 0, 310, 90,
- 117, 368, 0, 0, 122, 286, 289, 0, 123, 293,
- 126, 153, 128, 129, 93, 134, 135, 87, 136, 292,
- 139, 91, 94, 264, 88, 96, 142, 89, 144, 92,
- 146, 147, 294, 149, 150, 155, 0, 119, 118, 121,
- 105, 120, 104, 0, 114, 287, 285, 0, 0, 0,
- 358, 0, 115, 163, 164, 169, 0, 162, 0, 328,
- 329, 0, 356, 0, 0, 358, 0, 116, 0, 0,
- 0, 331, 336, 334, 337, 0, 0, 335, 336, 0,
- 332, 0, 333, 288, 339, 0, 288, 338, 0, 341,
- 342, 0, 288, 343, 344, 0, 0, 345, 0, 0,
- 0, 346, 347, 181, 180, 0, 0, 0, 315, 0,
- 0, 0, 330, 302, 295, 0, 303, 299, 0, 301,
- 290, 0, 291, 296, 0, 0, 358, 0, 353, 108,
- 0, 0, 112, 99, 0, 101, 110, 0, 102, 111,
- 113, 103, 109, 100, 0, 106, 185, 183, 187, 184,
- 182, 186, 361, 6, 362, 4, 2, 75, 107, 0,
- 0, 0, 83, 85, 84, 37, 5, 0, 76, 0,
- 51, 50, 49, 0, 0, 51, 0, 0, 0, 52,
- 0, 67, 68, 0, 65, 0, 66, 41, 42, 43,
- 44, 46, 47, 71, 45, 0, 0, 0, 78, 0,
- 77, 80, 0, 81, 0, 79, 0, 51, 0, 0,
- 0, 0, 0, 61, 0, 62, 0, 0, 32, 0,
- 0, 72, 33, 0, 36, 34, 30, 0, 35, 31,
- 0, 63, 0, 64, 163, 0, 69, 73, 0, 0,
- 0, 0, 163, 288, 0, 70, 90, 123, 293, 126,
- 153, 128, 129, 93, 134, 135, 136, 292, 139, 91,
- 94, 264, 96, 142, 89, 144, 92, 146, 147, 294,
- 149, 150, 155, 74, 0, 59, 53, 60, 54, 0,
- 0, 0, 0, 56, 0, 57, 58, 55, 0, 0,
- 0, 0, 48, 0, 38, 39, 0, 40, 8, 0,
- 0, 9, 0, 11, 0, 10, 0, 1, 27, 15,
- 14, 26, 13, 12, 29, 7, 0, 18, 0, 19,
- 0, 24, 25, 0, 20, 21, 0, 22, 23, 16,
- 17, 369
-};
-
-const short QQmlJSGrammar::goto_default [] = {
- 7, 667, 213, 200, 211, 526, 513, 662, 675, 512,
- 661, 665, 663, 671, 22, 668, 666, 664, 18, 525,
- 587, 577, 584, 579, 553, 195, 199, 201, 206, 237,
- 214, 234, 568, 639, 638, 205, 236, 557, 26, 491,
- 490, 362, 361, 9, 360, 363, 204, 484, 364, 109,
- 17, 149, 24, 13, 148, 19, 25, 59, 23, 8,
- 28, 27, 283, 15, 277, 10, 273, 12, 275, 11,
- 274, 20, 281, 21, 282, 14, 276, 272, 313, 418,
- 278, 279, 207, 197, 196, 210, 209, 233, 198, 367,
- 366, 235, 475, 474, 335, 336, 477, 338, 476, 337,
- 431, 435, 438, 434, 433, 453, 454, 202, 188, 203,
- 212, 0
-};
-
-const short QQmlJSGrammar::action_index [] = {
- 350, 1528, 3041, 3041, 2937, 1235, 115, 105, 239, -108,
- 102, 93, 95, 205, -108, 422, 110, -108, -108, 727,
- 92, 118, 265, 256, -108, -108, -108, 507, 247, 1528,
- -108, -108, -108, 665, -108, -108, 2729, 1826, 1528, 1528,
- 1528, -108, 1041, 1528, -108, -108, -108, 1528, 1528, -108,
- -108, -108, -108, -108, -108, 1528, -108, 1528, 1528, -108,
- 1528, 1528, 174, 221, -108, -108, 1528, 1528, 1528, -108,
- -108, -108, 177, 1528, 422, 1528, 1528, 1528, 1528, 411,
- 1528, 1528, 1528, 1528, 1528, 1528, 211, 1528, 1528, 1528,
- 142, 148, 154, 217, 223, 226, 227, 231, 507, 385,
- 395, 1528, 57, 1528, 83, 2521, 1528, 1528, -108, -108,
- -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
- -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
- -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
- -108, -108, -108, -108, 179, 1528, -108, -108, 77, 36,
- -108, 1528, -108, -108, 1528, -108, -108, -108, -108, -108,
- -108, -108, -108, -108, -108, -108, -108, -108, 1528, 56,
- 1528, 1528, 80, 74, 1528, -108, 2521, 1528, 1528, -108,
- 125, -108, 55, -108, -108, 53, 410, 418, 72, 52,
- -108, 392, -108, 46, 3041, -108, -108, -108, -108, -108,
- 273, -108, 396, -108, 44, -108, -108, -108, 76, -108,
- -108, -108, 3041, -108, -108, 744, -108, 589, 98, 2937,
- 91, 90, 88, 3249, -108, 1528, -108, 86, 1528, 81,
- -108, 75, 73, -108, -108, 586, -108, -108, -108, -108,
- 71, 491, 69, 65, 3041, 64, -108, -108, 2937, -108,
- -108, 139, -108, -108, -108, -108, 134, -108, -108, -108,
- -108, -108, -108, 63, 66, 1528, 147, 264, -108, -108,
- -108, 1726, -108, 87, 68, 70, -108, 334, 82, 78,
- 796, 89, 121, 349, 318, 469, 1528, 330, 1528, 1528,
- 1528, 1528, 359, 1528, 1528, 1528, 1528, 1528, 284, 289,
- 303, 306, 313, 365, 369, 375, 1528, 58, 1528, 85,
- 1528, -108, 849, 1528, -108, 1528, 79, 59, 1528, 61,
- 2937, -108, 1528, 146, 2937, -108, 1528, 62, 1528, 1528,
- 106, 99, 1528, -108, 96, 176, 171, -108, -108, 1528,
- -108, 407, 1528, -108, 97, 1528, -52, 2937, -108, 1528,
- 120, 2937, -108, 1528, 123, 2937, 101, 2937, -108, 116,
- -108, 84, 45, 0, -108, -108, 2937, -39, 641, -3,
- 652, 156, 1528, 2937, -7, -11, 567, 2625, -21, 5,
- 945, 2, 94, 1629, 2625, -1, -26, 6, 1528, 10,
- -15, 1528, 14, 1528, -25, -12, 2833, -108, -108, -108,
- -108, -108, -108, 1528, -108, -108, -108, -14, -58, -13,
- 3041, -36, -108, 287, -108, 1528, -46, -108, 153, -108,
- -108, -31, 586, -57, -32, 3041, 11, -108, 1528, 168,
- 29, -108, 47, -108, 48, 169, 1528, -108, 49, 50,
- -108, 9, -108, 2937, -108, 136, 2937, -108, 275, -108,
- -108, 126, 2937, 35, -108, 33, 37, -108, 466, -4,
- 38, -108, -108, -108, -108, 1528, 130, 2937, -108, 1528,
- 117, 2937, -108, 34, -108, 296, -108, -108, 1528, -108,
- -108, 404, -108, -108, 12, 40, 3041, 13, -108, -108,
- 155, 1926, -108, -108, 2026, -108, -108, 2126, -108, -108,
- -108, -108, -108, -108, 144, -108, -108, -108, -108, -108,
- -108, -108, -108, -108, 3041, -108, -108, -108, 132, -27,
- 15, 1137, 218, -23, 17, -108, -108, 196, -108, 242,
- 8, -108, -108, 579, 237, -108, 127, 18, 415, -108,
- 103, -108, -108, 236, -108, 2223, -108, -108, -108, -108,
- -108, -108, -108, -108, -108, 27, 21, 137, 31, 20,
- -108, 23, -5, -108, -9, -108, 332, -10, 571, 201,
- 195, 586, 225, -108, 7, -108, 1137, 165, -108, 4,
- 1137, -108, -108, 1333, -108, -108, -108, 1431, -108, -108,
- 184, -108, 2223, -108, 331, 3, -108, -108, 202, 531,
- 26, 2417, 327, 3145, 1, -108, 25, 629, 24, 649,
- 124, 1528, 2937, 22, -6, 514, -8, 19, 1041, 16,
- 94, 1629, 28, 42, 67, 1528, 60, 43, 1528, 54,
- 1528, 41, 39, -108, 234, -108, 228, -108, 51, -2,
- 564, 233, 575, -108, 100, -108, -108, -108, 2320, 1137,
- 1826, 32, -108, 122, -108, -108, 30, -108, -108, 1137,
- 1137, 104, 903, -108, 308, -108, 108, -108, -108, 133,
- 119, -108, -108, -108, -108, -108, 451, -108, 164, -108,
- 161, -108, -108, 458, -108, -108, 151, -108, -108, -108,
- -108, -108,
-
- -112, 18, 86, 97, 69, 316, 7, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -64,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, 66,
- -112, -112, -112, -17, -112, -112, -10, -36, 3, 90,
- 95, -112, 149, 74, -112, -112, -112, 67, 13, -112,
- -112, -112, -112, -112, -112, 178, -112, 181, 185, -112,
- 189, 190, -112, -112, -112, -112, 198, 208, 212, -112,
- -112, -112, -112, 209, -112, 201, 164, 111, 113, -112,
- 116, 130, 131, 132, 134, 142, -112, 118, 124, 144,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, 154, -112, 155, -112, 268, 28, -8, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, 42, -112, -112, -112, -112,
- -112, 47, -112, -112, 50, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, 159, -112,
- 158, 56, -112, -112, 57, -112, 362, 60, 157, -112,
- -112, -112, -112, -112, -112, -112, 20, 151, -112, -112,
- -112, 25, -112, -112, 30, -112, -112, -112, -112, -112,
- -112, -112, 31, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, 233, -112, -112, 34, -112, 35, -112, 225,
- -112, 36, -112, 216, -112, 55, -112, -112, 53, 39,
- -112, -112, -112, -112, -112, 19, -112, -112, -112, -112,
- -112, 94, -112, -112, 92, -112, -112, -112, 117, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, 33, -112, -112, -112, -112,
- -112, 88, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, 51, 220, -112, 227, 235,
- 236, 244, -112, 21, 17, 102, 91, 89, -112, -112,
- -112, -112, -112, -112, -112, -112, 211, -112, 247, -112,
- 257, -112, -112, 264, -112, 75, -112, -112, 103, -112,
- 112, -112, 29, -112, 73, -112, 263, -112, 255, 254,
- -112, -112, 245, -112, -112, -112, -112, -112, -112, 248,
- -112, 65, 105, -112, -112, 99, -112, 162, -112, 37,
- -112, 115, -112, 44, -112, 135, -112, 137, -112, -112,
- -112, -112, -112, -112, -112, -112, 138, -112, 24, -112,
- 26, -112, 104, 140, -112, -112, 32, 64, -112, -112,
- 174, -112, -112, 48, 87, -112, -112, -112, 54, -112,
- 40, 71, -112, 150, -112, -112, 197, -112, -112, -112,
- -112, -112, -112, 12, -112, -112, -112, -112, -112, -112,
- 206, -112, -112, -112, -112, 207, -112, -112, -112, -112,
- -112, -112, 231, -112, -112, 239, -112, -112, 43, -112,
- -112, -112, -112, -112, -59, -112, 38, -112, -62, -112,
- -112, -112, -112, 258, -112, -112, 259, -112, -112, -112,
- -112, -112, 163, -72, -112, -112, 41, -112, 62, -112,
- 61, -112, -112, -112, -112, 59, -112, 193, -112, 58,
- -112, 204, -112, -112, -112, -112, -112, -112, 52, -112,
- -112, 175, -112, -112, -112, -112, 186, -112, -112, -112,
- -112, 49, -112, -112, 173, -112, -112, 45, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, 213, -112, -112, -112, -112, -112,
- -112, 46, -112, -112, -112, -112, -112, -112, -112, 27,
- -112, -112, -112, -18, -9, -112, -112, -112, 15, -112,
- -112, -112, -112, -112, -112, 331, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -112, -112, 11, -6,
- -112, 10, -112, -112, -112, -112, 156, -112, -112, -112,
- 240, -112, -112, 330, -112, -112, -112, 332, -112, -112,
- -112, -112, 376, -112, -112, 8, -112, -112, -7, 76,
- -112, 358, -112, 228, 5, -112, -112, 6, -112, 4,
- -112, 79, 221, -112, -112, 2, -112, -112, 174, -112,
- -112, 16, -112, -112, -112, 14, -112, -16, 70, -112,
- 63, -112, -112, -112, -112, -112, -30, -112, -112, -112,
- -15, -28, -13, -112, -112, -112, -112, -112, 460, 93,
- 307, -12, -112, -112, -112, -112, -11, -112, -112, -2,
- -1, 85, 84, -112, -112, -112, -112, -112, -112, -112,
- -112, -112, -112, -112, -112, -112, -3, -112, -112, -112,
- -112, -112, -112, 0, -112, -112, -112, -112, -112, -112,
- -112, -112
-};
-
-const short QQmlJSGrammar::action_info [] = {
- -132, 425, 409, 424, -151, 422, -120, 403, 347, -140,
- 428, 465, -152, -143, 417, 353, 406, -145, 452, 412,
- 410, -148, 408, -140, 469, 271, -152, 569, 353, -132,
- 271, -151, 248, 601, 583, -120, 583, 583, 565, 529,
- 562, 576, 563, 598, 555, 534, 634, 539, 564, 561,
- 558, 478, 436, 436, 436, 456, 460, 443, 644, 641,
- 556, -148, 432, 583, 442, 583, 427, -145, 488, 458,
- 452, 452, 485, 486, -143, 469, 452, 465, 428, 194,
- 191, 174, 168, 248, 73, 151, 286, 145, 286, 187,
- 310, 326, 396, 0, 168, 0, 153, 0, 244, 247,
- 402, -121, 265, 73, 101, 691, 332, 241, 326, 469,
- 306, 465, 193, 339, 452, 183, 306, 357, 145, 246,
- 318, 320, 428, 248, 353, 145, 186, 271, 145, 243,
- 580, 145, 455, 145, 176, 0, 103, 308, 145, 315,
- 264, 101, 537, 446, 145, 559, 456, 176, 176, 308,
- 0, 538, 145, 177, 145, 145, 0, 0, 345, 262,
- 261, 646, 645, 494, 542, 541, 177, 177, 170, 690,
- 689, 328, 171, 580, 103, 329, 145, 471, 654, 439,
- 351, 181, 60, 355, 341, 262, 261, 145, 60, 66,
- 467, 592, 560, 61, 60, 260, 259, 659, 660, 61,
- 255, 254, 349, 648, 505, 61, 324, 267, 659, 660,
- 537, 495, 688, 687, 420, 419, 64, 262, 261, 571,
- 105, 581, 682, 681, 440, 685, 684, 65, 430, 583,
- 535, 535, 574, 66, 67, 146, 87, 342, 88, 106,
- 68, 107, 87, 545, 88, 593, 591, 567, 87, 89,
- 88, 87, 87, 88, 88, 89, 87, 535, 88, 683,
- 0, 89, 535, 0, 89, 89, 535, 0, 66, 89,
- 636, 530, 87, 0, 88, 0, 532, 532, 67, 60,
- 176, 145, 0, 145, 68, 89, 575, 573, 531, 531,
- 61, 0, 649, 532, 0, 637, 635, 546, 544, 177,
- 0, 178, 176, 532, 481, 531, 0, 0, 532, 87,
- 0, 88, 532, 67, 87, 531, 88, 532, 0, 68,
- 531, 177, 89, 415, 531, 270, 268, 89, 87, 531,
- 88, 87, 0, 88, 239, 238, 450, 449, 87, 0,
- 88, 89, 176, 87, 89, 88, 176, 176, 288, 289,
- 0, 89, 288, 289, 269, 678, 89, 482, 480, 0,
- -107, 177, 0, 178, -107, 177, 177, 178, 415, 679,
- 677, 0, 293, 294, 0, 290, 291, 0, 0, 290,
- 291, 295, 293, 294, 296, 0, 297, 0, 293, 294,
- 0, 295, 293, 294, 296, 0, 297, 295, 293, 294,
- 296, 295, 297, 676, 296, 0, 297, 295, 80, 81,
- 296, 0, 297, 0, 0, 0, 82, 83, 80, 81,
- 84, 35, 85, 0, 0, 35, 82, 83, 0, 0,
- 84, 0, 85, 35, 80, 81, 35, 0, 0, 35,
- 75, 76, 82, 83, 35, 0, 84, 35, 85, 0,
- 6, 5, 4, 1, 3, 2, 0, 0, 49, 52,
- 50, 0, 49, 52, 50, 0, 0, 77, 78, 0,
- 49, 52, 50, 49, 52, 50, 49, 52, 50, 0,
- 35, 49, 52, 50, 49, 52, 50, 35, 46, 34,
- 51, 0, 46, 34, 51, 35, 0, 0, 35, 0,
- 46, 34, 51, 46, 34, 51, 46, 34, 51, 0,
- 0, 46, 34, 51, 46, 34, 51, 49, 52, 50,
- 35, 0, 0, 0, 49, 52, 50, 0, 0, 0,
- 80, 81, 49, 52, 50, 49, 52, 50, 82, 83,
- 0, 0, 84, 35, 85, 0, 537, 46, 34, 51,
- 186, 0, 0, 0, 46, 34, 51, 49, 52, 50,
- 35, 0, 46, 34, 51, 46, 34, 51, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 537,
- 49, 52, 50, 0, 0, 0, 537, 46, 34, 51,
- 537, 0, 0, 35, 537, 0, 35, 49, 52, 50,
- 35, 0, 0, 186, 35, 0, 0, 0, 35, 0,
- 46, 34, 51, 0, 0, 35, 0, 0, 35, 0,
- 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
- 49, 52, 50, 49, 52, 50, 0, 49, 52, 50,
- 0, 49, 52, 50, 0, 49, 52, 50, 0, 0,
- 258, 257, 49, 52, 50, 49, 52, 50, 35, 0,
- 46, 34, 51, 46, 34, 51, 0, 46, 34, 51,
- 35, 46, 34, 51, 0, 46, 34, 51, 35, 0,
- 0, 35, 46, 34, 51, 46, 34, 51, 0, 0,
- 253, 252, 0, 0, 35, 49, 52, 50, 0, 0,
- 0, 186, 253, 252, 0, 0, 0, 49, 52, 50,
- 258, 257, 0, 258, 257, 49, 52, 50, 49, 52,
- 50, 0, 0, 0, 0, 46, 34, 51, 0, 0,
- 155, 49, 52, 50, 0, 0, 0, 46, 34, 51,
- 156, 0, 0, 0, 157, 46, 34, 51, 46, 34,
- 51, 0, 0, 158, 0, 159, 0, 0, 0, 0,
- 0, 46, 34, 51, 0, 0, 160, 0, 161, 64,
- 0, 0, 0, 35, 0, 0, 162, 0, 0, 163,
- 65, 0, 0, 0, 0, 164, 0, 0, 0, 0,
- 0, 165, 0, 0, 0, 0, 0, 0, 0, 155,
- 0, 0, 0, 0, 0, 253, 252, 166, 0, 156,
- 49, 52, 50, 157, 0, 0, 0, 0, 0, 0,
- 0, 0, 158, 0, 159, 0, 0, 322, 0, 0,
- 0, 0, 0, 0, 0, 160, 0, 161, 64, 0,
- 46, 34, 51, 0, 0, 162, 0, 0, 163, 65,
- 0, 0, 155, 0, 164, 0, 0, 0, 0, 0,
- 165, 0, 156, 0, 0, 0, 157, 0, 0, 0,
- 0, 0, 0, 0, 0, 158, 166, 159, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 160, 0,
- 161, 64, 0, 0, 0, 0, 0, 0, 162, 0,
- 0, 163, 65, 0, 0, 0, 0, 164, 0, 0,
- 0, 0, 0, 165, 0, 30, 31, 0, 0, 0,
- 0, 0, 0, 0, 0, 33, 0, 0, 0, 166,
- 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
- 0, 0, 0, 0, 0, 0, 521, 0, 0, 0,
- 45, 0, 0, 0, 0, 0, 0, 30, 31, 0,
- 0, 0, 0, 0, 0, 0, 0, 33, 53, 49,
- 52, 50, 0, 54, 35, 0, 0, 0, 36, 37,
- 0, 38, 0, 0, 44, 56, 32, 0, 42, 0,
- 0, 41, 45, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 53, 49, 52, 50, 0, 54, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 44, 56, 32, 0,
- 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
- 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
- 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
- 0, 0, 0, 0, 42, 0, 0, 0, 45, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 53, 49, 52, 50,
- 0, 54, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 44, 56, 32, 0, 0, 0, 0, 41,
- 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
- 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
- 0, 0, 0, 0, 0, 0, 35, 0, 0, 0,
- 36, 37, 0, 38, 0, 0, 0, 0, 0, 0,
- 521, 0, 0, 0, 45, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 53, 49, 52, 50, 0, 54, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 44, 56,
- 32, 0, 0, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 519, 0, 30, 31, 0,
- 0, 0, 0, 0, 0, 0, 0, 221, 0, 0,
- 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
- 0, 38, 0, 0, 0, 0, 0, 0, 521, 0,
- 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 53, 522, 524, 523, 0, 54, 0, 0, 0, 0,
- 230, 0, 0, 0, 0, 0, 44, 56, 32, 216,
- 224, 0, 0, 41, 0, 0, 520, 0, 0, 0,
- 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 519, 0, 30, 31, 0, 0, 0,
- 0, 0, 0, 0, 0, 221, 0, 0, 0, 0,
- 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
- 0, 0, 0, 0, 0, 0, 521, 0, 0, 0,
- 45, 0, 0, 0, 0, 0, 0, 0, 585, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 53, 522,
- 524, 523, 0, 54, 0, 0, 0, 0, 230, 0,
- 0, 0, 0, 0, 44, 56, 32, 216, 224, 0,
- 0, 41, 0, 0, 520, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 519, 0, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 221, 0, 0, 0, 0, 0, 0,
- 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
- 0, 0, 0, 0, 521, 0, 0, 0, 45, 0,
- 0, 0, 0, 0, 0, 0, 588, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 53, 522, 524, 523,
- 0, 54, 0, 0, 0, 0, 230, 0, 0, 0,
- 0, 0, 44, 56, 32, 216, 224, 0, 0, 41,
- 0, 0, 520, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
- 0, 36, 37, 0, 38, 0, 0, 0, 39, 0,
- 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
- 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
- 55, 0, 57, 0, 58, 0, 0, 0, 0, 44,
- 56, 32, 0, 0, 0, 0, 41, 0, 0, 0,
- 0, 0, 0, 0, 46, 34, 51, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, -141, 0, 0, 0,
- 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
- 0, 33, 0, 0, 0, 0, 0, 0, 35, 0,
- 0, 0, 36, 37, 0, 38, 0, 0, 0, 39,
- 0, 40, 42, 43, 0, 0, 45, 0, 0, 0,
- 47, 0, 48, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 53, 49, 52, 50, 0, 54,
- 0, 55, 0, 57, 0, 58, 0, 0, 0, 0,
- 44, 56, 32, 0, 0, 0, 0, 41, 0, 0,
- 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
- 57, 285, 58, 0, 0, 0, 0, 44, 56, 32,
- 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 492, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 493, 0, 0, 0, 0, 0, 0, 0,
- 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
- 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
- 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 500, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 503, 0, 0, 0, 0, 0, 0, 0,
- 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
- 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
- 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 492, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 498, 0, 0, 0, 0, 0, 0, 0,
- 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
- 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
- 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 500, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 501, 0, 0, 0, 0, 0, 0, 0,
- 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
- 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
- 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 29, 30, 31, 0, 0, 0,
- 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 35, 222, 0, 0, 223, 37, 0, 38,
- 0, 0, 0, 39, 0, 40, 42, 43, 0, 0,
- 45, 0, 0, 0, 47, 0, 48, 0, 0, 0,
- 0, 0, 0, 0, 226, 0, 0, 0, 53, 49,
- 52, 50, 227, 54, 0, 55, 229, 57, 0, 58,
- 0, 232, 0, 0, 44, 56, 32, 0, 0, 0,
- 0, 41, 0, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 29, 30, 31, 0, 0, 0, 0, 0, 0,
- 0, 0, 33, 0, 0, 0, 0, 0, 0, 35,
- 222, 0, 0, 603, 650, 0, 38, 0, 0, 0,
- 39, 0, 40, 42, 43, 0, 0, 45, 0, 0,
- 0, 47, 0, 48, 0, 0, 0, 0, 0, 0,
- 0, 226, 0, 0, 0, 53, 49, 52, 50, 227,
- 54, 0, 55, 229, 57, 0, 58, 0, 232, 0,
- 0, 44, 56, 32, 0, 0, 0, 0, 41, 0,
- 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 29, 30,
- 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
- 0, 0, 0, 0, 0, 0, 35, 222, 0, 0,
- 603, 37, 0, 38, 0, 0, 0, 39, 0, 40,
- 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
- 48, 0, 0, 0, 0, 0, 0, 0, 226, 0,
- 0, 0, 53, 49, 52, 50, 227, 54, 0, 55,
- 229, 57, 0, 58, 0, 232, 0, 0, 44, 56,
- 32, 0, 0, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 111, 112, 113, 0, 0,
- 115, 117, 118, 0, 0, 119, 0, 120, 0, 0,
- 0, 123, 124, 125, 0, 0, 0, 0, 0, 0,
- 35, 126, 127, 128, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 130, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 133, 0, 0, 0, 0, 0, 0, 49, 52, 50,
- 134, 135, 136, 0, 138, 139, 140, 141, 142, 143,
- 0, 0, 131, 137, 122, 114, 129, 116, 132, 0,
- 0, 0, 121, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 111,
- 112, 113, 0, 0, 115, 117, 118, 0, 0, 119,
- 0, 120, 0, 0, 0, 123, 124, 125, 0, 0,
- 0, 0, 0, 0, 35, 126, 127, 128, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 130, 0,
- 0, 0, 399, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 133, 0, 0, 0, 0, 0,
- 401, 49, 52, 50, 134, 135, 136, 0, 138, 139,
- 140, 141, 142, 143, 0, 0, 131, 137, 122, 114,
- 129, 116, 132, 0, 0, 0, 121, 0, 0, 0,
- 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 111, 112, 113, 0, 0, 115, 117,
- 118, 0, 0, 119, 0, 120, 0, 0, 0, 123,
- 124, 125, 0, 0, 0, 0, 0, 0, 35, 126,
- 127, 128, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 130, 0, 0, 0, 399, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 133, 0,
- 0, 0, 0, 0, 401, 49, 52, 50, 134, 135,
- 136, 0, 138, 139, 140, 141, 142, 143, 0, 0,
- 131, 137, 122, 114, 129, 116, 132, 0, 0, 0,
- 121, 0, 0, 0, 0, 46, 377, 384, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 111, 112, 113,
- 0, 0, 115, 117, 118, 0, 0, 119, 0, 120,
- 0, 0, 0, 123, 124, 125, 0, 0, 0, 0,
- 0, 0, 35, 126, 127, 128, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 130, 0, 0, 0,
- 399, 0, 0, 0, 0, 0, 0, 0, 400, 0,
- 0, 0, 133, 0, 0, 0, 0, 0, 401, 49,
- 52, 50, 134, 135, 136, 0, 138, 139, 140, 141,
- 142, 143, 0, 0, 131, 137, 122, 114, 129, 116,
- 132, 0, 0, 0, 121, 0, 0, 0, 0, 46,
- 377, 384, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 215, 0, 0, 0, 0, 217, 0, 29, 30,
- 31, 219, 0, 0, 0, 0, 0, 0, 220, 33,
- 0, 0, 0, 0, 0, 0, 35, 222, 0, 0,
- 223, 37, 0, 38, 0, 0, 0, 39, 0, 40,
- 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
- 48, 0, 0, 0, 0, 0, 225, 0, 226, 0,
- 0, 0, 53, 49, 52, 50, 227, 54, 228, 55,
- 229, 57, 230, 58, 231, 232, 0, 0, 44, 56,
- 32, 216, 224, 218, 0, 41, 0, 0, 0, 0,
- 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 215, 0, 0, 0, 0,
- 217, 0, 29, 30, 31, 219, 0, 0, 0, 0,
- 0, 0, 220, 221, 0, 0, 0, 0, 0, 0,
- 35, 222, 0, 0, 223, 37, 0, 38, 0, 0,
- 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
- 0, 0, 47, 0, 48, 0, 0, 0, 0, 0,
- 225, 0, 226, 0, 0, 0, 53, 49, 52, 50,
- 227, 54, 228, 55, 229, 57, 230, 58, 231, 232,
- 0, 0, 44, 56, 32, 216, 224, 218, 0, 41,
- 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 607,
- 112, 113, 0, 0, 609, 117, 611, 30, 31, 612,
- 0, 120, 0, 0, 0, 123, 614, 615, 0, 0,
- 0, 0, 0, 0, 35, 616, 127, 128, 223, 37,
- 0, 38, 0, 0, 0, 39, 0, 40, 618, 43,
- 0, 0, 620, 0, 0, 0, 47, 0, 48, 0,
- 0, 0, 0, 0, 621, 0, 226, 0, 0, 0,
- 622, 49, 52, 50, 623, 624, 625, 55, 627, 628,
- 629, 630, 631, 632, 0, 0, 619, 626, 613, 608,
- 617, 610, 132, 41, 0, 0, 121, 0, 0, 0,
- 0, 46, 377, 384, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 368, 112, 113, 0, 0, 370, 117,
- 372, 30, 31, 373, 0, 120, 0, 0, 0, 123,
- 375, 376, 0, 0, 0, 0, 0, 0, 35, 378,
- 127, 128, 223, 37, 0, 38, 0, 0, 0, 39,
- 0, 40, 380, 43, 0, 0, 382, 0, 0, 0,
- 47, 0, 48, 0, -288, 0, 0, 0, 383, 0,
- 226, 0, 0, 0, 385, 49, 52, 50, 386, 387,
- 388, 55, 390, 391, 392, 393, 394, 395, 0, 0,
- 381, 389, 374, 369, 379, 371, 132, 41, 0, 0,
- 121, 0, 0, 0, 0, 46, 377, 384, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
-
- 543, 185, 640, 647, 642, 643, 504, 489, 397, 451,
- 655, 657, 669, 670, 154, 680, 658, 448, 686, 316,
- 185, 16, 256, 536, 251, 599, 570, 633, 572, 590,
- 597, 144, 323, 540, 457, 150, 266, 473, 190, 441,
- 350, 445, 251, 192, 256, 437, 429, 354, 208, 240,
- 185, 316, 251, 256, 185, 404, 448, 448, 316, 533,
- 566, 470, 466, 180, 451, 451, 462, 0, 62, 334,
- 510, 516, 62, 0, 0, 325, 62, 299, 316, 0,
- 459, 298, 397, 334, 0, 147, 461, 208, 499, 0,
- 152, 208, 502, 167, 600, 479, 673, 672, 518, 173,
- 175, 515, 316, 674, 208, 397, 316, 518, 316, 407,
- 208, 0, 190, 0, 321, 208, 656, 352, 62, 249,
- 464, 62, 62, 184, 509, 62, 62, 463, 463, 62,
- 208, 508, 421, 208, 62, 208, 184, 356, 245, 358,
- 405, 242, 263, 280, 62, 62, 62, 506, 284, 302,
- 62, 301, 507, 208, 317, 208, 208, 62, 208, 62,
- 343, 184, 300, 413, 348, 365, 62, 0, 62, 190,
- 518, 62, 99, 62, 100, 578, 86, 90, 346, 62,
- 208, 208, 319, 91, 344, 62, 62, 62, 413, 62,
- 93, 94, 95, 473, 96, 468, 514, 62, 189, 62,
- 150, 414, 97, 92, 208, 62, 472, 464, 182, 62,
- 62, 208, 497, 62, 62, 397, 496, 250, 365, 62,
- 104, 102, 208, 263, 208, 98, 414, 263, 169, 172,
- 365, 208, 487, 62, 359, 511, 62, 250, 463, 208,
- 62, 398, 464, 208, 62, 62, 606, 63, 72, 190,
- 150, 208, 411, 62, 518, 69, 62, 208, 416, 582,
- 365, 365, 79, 62, 62, 70, 62, 62, 483, 71,
- 0, 284, 74, 0, 0, 62, 208, 208, 423, 307,
- 284, 0, 62, 0, 287, 426, 108, 284, 0, 292,
- 62, 62, 0, 0, 0, 284, 284, 303, 304, 62,
- 312, 0, 62, 312, 284, 284, 305, 284, 284, 312,
- 62, 0, 312, 309, 284, 284, 110, 284, 62, 312,
- 0, 594, 333, 284, 284, 340, 578, 330, 653, 0,
- 518, 331, 0, 327, 311, 586, 0, 589, 0, 527,
- 0, 314, 0, 0, 518, 0, 518, 444, 447, 0,
- 489, 517, 528, 527, 0, 527, 547, 548, 549, 550,
- 554, 551, 552, 0, 0, 517, 528, 517, 528, 0,
- 0, 0, 602, 0, 0, 0, 0, 0, 0, 0,
- 108, 604, 605, 547, 548, 549, 550, 554, 551, 552,
- 594, 0, 0, 0, 0, 0, 0, 0, 0, 595,
- 596, 547, 548, 549, 550, 554, 551, 552, 0, 0,
- 110, 179, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 602, 0, 0, 0, 0, 0,
- 0, 0, 0, 651, 652, 547, 548, 549, 550, 554,
- 551, 552, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0
-};
-
-const short QQmlJSGrammar::action_check [] = {
- 7, 33, 60, 60, 7, 36, 7, 7, 60, 7,
- 36, 36, 7, 7, 60, 36, 55, 7, 33, 55,
- 33, 7, 36, 7, 36, 36, 7, 37, 36, 7,
- 36, 7, 7, 7, 33, 7, 33, 33, 47, 66,
- 17, 34, 47, 66, 29, 37, 29, 29, 17, 29,
- 29, 17, 5, 5, 5, 20, 60, 7, 60, 8,
- 33, 7, 33, 33, 55, 33, 55, 7, 55, 36,
- 33, 33, 60, 33, 7, 36, 33, 36, 36, 33,
- 8, 7, 2, 7, 1, 8, 1, 8, 1, 36,
- 8, 2, 8, -1, 2, -1, 60, -1, 33, 55,
- 55, 7, 36, 1, 48, 0, 7, 36, 2, 36,
- 48, 36, 60, 17, 33, 60, 48, 16, 8, 55,
- 61, 60, 36, 7, 36, 8, 36, 36, 8, 60,
- 8, 8, 6, 8, 15, -1, 79, 79, 8, 61,
- 77, 48, 15, 7, 8, 8, 20, 15, 15, 79,
- -1, 24, 8, 34, 8, 8, -1, -1, 61, 61,
- 62, 61, 62, 8, 61, 62, 34, 34, 50, 61,
- 62, 50, 54, 8, 79, 54, 8, 60, 56, 10,
- 60, 56, 40, 60, 8, 61, 62, 8, 40, 12,
- 60, 7, 55, 51, 40, 61, 62, 93, 94, 51,
- 61, 62, 31, 7, 60, 51, 60, 60, 93, 94,
- 15, 56, 61, 62, 61, 62, 42, 61, 62, 24,
- 15, 56, 61, 62, 55, 61, 62, 53, 60, 33,
- 29, 29, 7, 12, 57, 56, 25, 61, 27, 34,
- 63, 36, 25, 7, 27, 61, 62, 29, 25, 38,
- 27, 25, 25, 27, 27, 38, 25, 29, 27, 95,
- -1, 38, 29, -1, 38, 38, 29, -1, 12, 38,
- 36, 29, 25, -1, 27, -1, 75, 75, 57, 40,
- 15, 8, -1, 8, 63, 38, 61, 62, 87, 87,
- 51, -1, 96, 75, -1, 61, 62, 61, 62, 34,
- -1, 36, 15, 75, 8, 87, -1, -1, 75, 25,
- -1, 27, 75, 57, 25, 87, 27, 75, -1, 63,
- 87, 34, 38, 36, 87, 61, 62, 38, 25, 87,
- 27, 25, -1, 27, 61, 62, 61, 62, 25, -1,
- 27, 38, 15, 25, 38, 27, 15, 15, 18, 19,
- -1, 38, 18, 19, 90, 47, 38, 61, 62, -1,
- 33, 34, -1, 36, 33, 34, 34, 36, 36, 61,
- 62, -1, 23, 24, -1, 45, 46, -1, -1, 45,
- 46, 32, 23, 24, 35, -1, 37, -1, 23, 24,
- -1, 32, 23, 24, 35, -1, 37, 32, 23, 24,
- 35, 32, 37, 95, 35, -1, 37, 32, 23, 24,
- 35, -1, 37, -1, -1, -1, 31, 32, 23, 24,
- 35, 29, 37, -1, -1, 29, 31, 32, -1, -1,
- 35, -1, 37, 29, 23, 24, 29, -1, -1, 29,
- 18, 19, 31, 32, 29, -1, 35, 29, 37, -1,
- 100, 101, 102, 103, 104, 105, -1, -1, 66, 67,
- 68, -1, 66, 67, 68, -1, -1, 45, 46, -1,
- 66, 67, 68, 66, 67, 68, 66, 67, 68, -1,
- 29, 66, 67, 68, 66, 67, 68, 29, 96, 97,
- 98, -1, 96, 97, 98, 29, -1, -1, 29, -1,
- 96, 97, 98, 96, 97, 98, 96, 97, 98, -1,
- -1, 96, 97, 98, 96, 97, 98, 66, 67, 68,
- 29, -1, -1, -1, 66, 67, 68, -1, -1, -1,
- 23, 24, 66, 67, 68, 66, 67, 68, 31, 32,
- -1, -1, 35, 29, 37, -1, 15, 96, 97, 98,
- 36, -1, -1, -1, 96, 97, 98, 66, 67, 68,
- 29, -1, 96, 97, 98, 96, 97, 98, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 15,
- 66, 67, 68, -1, -1, -1, 15, 96, 97, 98,
- 15, -1, -1, 29, 15, -1, 29, 66, 67, 68,
- 29, -1, -1, 36, 29, -1, -1, -1, 29, -1,
- 96, 97, 98, -1, -1, 29, -1, -1, 29, -1,
- -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
- 66, 67, 68, 66, 67, 68, -1, 66, 67, 68,
- -1, 66, 67, 68, -1, 66, 67, 68, -1, -1,
- 61, 62, 66, 67, 68, 66, 67, 68, 29, -1,
- 96, 97, 98, 96, 97, 98, -1, 96, 97, 98,
- 29, 96, 97, 98, -1, 96, 97, 98, 29, -1,
- -1, 29, 96, 97, 98, 96, 97, 98, -1, -1,
- 61, 62, -1, -1, 29, 66, 67, 68, -1, -1,
- -1, 36, 61, 62, -1, -1, -1, 66, 67, 68,
- 61, 62, -1, 61, 62, 66, 67, 68, 66, 67,
- 68, -1, -1, -1, -1, 96, 97, 98, -1, -1,
- 3, 66, 67, 68, -1, -1, -1, 96, 97, 98,
- 13, -1, -1, -1, 17, 96, 97, 98, 96, 97,
- 98, -1, -1, 26, -1, 28, -1, -1, -1, -1,
- -1, 96, 97, 98, -1, -1, 39, -1, 41, 42,
- -1, -1, -1, 29, -1, -1, 49, -1, -1, 52,
- 53, -1, -1, -1, -1, 58, -1, -1, -1, -1,
- -1, 64, -1, -1, -1, -1, -1, -1, -1, 3,
- -1, -1, -1, -1, -1, 61, 62, 80, -1, 13,
- 66, 67, 68, 17, -1, -1, -1, -1, -1, -1,
- -1, -1, 26, -1, 28, -1, -1, 31, -1, -1,
- -1, -1, -1, -1, -1, 39, -1, 41, 42, -1,
- 96, 97, 98, -1, -1, 49, -1, -1, 52, 53,
- -1, -1, 3, -1, 58, -1, -1, -1, -1, -1,
- 64, -1, 13, -1, -1, -1, 17, -1, -1, -1,
- -1, -1, -1, -1, -1, 26, 80, 28, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 39, -1,
- 41, 42, -1, -1, -1, -1, -1, -1, 49, -1,
- -1, 52, 53, -1, -1, -1, -1, 58, -1, -1,
- -1, -1, -1, 64, -1, 12, 13, -1, -1, -1,
- -1, -1, -1, -1, -1, 22, -1, -1, -1, 80,
- -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
- -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
- 47, -1, -1, -1, -1, -1, -1, 12, 13, -1,
- -1, -1, -1, -1, -1, -1, -1, 22, 65, 66,
- 67, 68, -1, 70, 29, -1, -1, -1, 33, 34,
- -1, 36, -1, -1, 81, 82, 83, -1, 43, -1,
- -1, 88, 47, -1, -1, -1, -1, -1, -1, 96,
- 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, -1, 88, -1, -1, -1, -1, -1, -1,
- -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
- -1, 70, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
- -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 12,
- 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
- -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
- 33, 34, -1, 36, -1, -1, -1, -1, -1, -1,
- 43, -1, -1, -1, 47, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 65, 66, 67, 68, -1, 70, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, -1, -1, 88, -1, -1, -1, -1,
- -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 10, -1, 12, 13, -1,
- -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
- -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
- -1, 36, -1, -1, -1, -1, -1, -1, 43, -1,
- -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, -1, -1, -1,
- 75, -1, -1, -1, -1, -1, 81, 82, 83, 84,
- 85, -1, -1, 88, -1, -1, 91, -1, -1, -1,
- -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 10, -1, 12, 13, -1, -1, -1,
- -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
- -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
- -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
- 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
- 67, 68, -1, 70, -1, -1, -1, -1, 75, -1,
- -1, -1, -1, -1, 81, 82, 83, 84, 85, -1,
- -1, 88, -1, -1, 91, -1, -1, -1, -1, 96,
- 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 10, -1, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
- -1, -1, -1, -1, -1, -1, 55, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
- -1, 70, -1, -1, -1, -1, 75, -1, -1, -1,
- -1, -1, 81, 82, 83, 84, 85, -1, -1, 88,
- -1, -1, 91, -1, -1, -1, -1, 96, 97, 98,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 11,
- 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
- 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
- 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
- -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, -1, 88, -1, -1, -1,
- -1, -1, -1, -1, 96, 97, 98, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 7, -1, -1, -1,
- 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
- -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
- -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
- -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
- 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
- -1, 72, -1, 74, -1, 76, -1, -1, -1, -1,
- 81, 82, 83, -1, -1, -1, -1, 88, -1, -1,
- -1, -1, -1, -1, -1, 96, 97, 98, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
- 74, 75, 76, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
- -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
- 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
- -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
- 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
- -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
- 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
- -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
- -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
- 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
- -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
- -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 11, 12, 13, -1, -1, -1,
- -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
- -1, -1, 29, 30, -1, -1, 33, 34, -1, 36,
- -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
- 47, -1, -1, -1, 51, -1, 53, -1, -1, -1,
- -1, -1, -1, -1, 61, -1, -1, -1, 65, 66,
- 67, 68, 69, 70, -1, 72, 73, 74, -1, 76,
- -1, 78, -1, -1, 81, 82, 83, -1, -1, -1,
- -1, 88, -1, -1, -1, -1, -1, -1, -1, 96,
- 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 11, 12, 13, -1, -1, -1, -1, -1, -1,
- -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
- 30, -1, -1, 33, 34, -1, 36, -1, -1, -1,
- 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
- -1, 51, -1, 53, -1, -1, -1, -1, -1, -1,
- -1, 61, -1, -1, -1, 65, 66, 67, 68, 69,
- 70, -1, 72, 73, 74, -1, 76, -1, 78, -1,
- -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
- -1, -1, -1, -1, -1, -1, 96, 97, 98, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 11, 12,
- 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
- -1, -1, -1, -1, -1, -1, 29, 30, -1, -1,
- 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
- 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
- 53, -1, -1, -1, -1, -1, -1, -1, 61, -1,
- -1, -1, 65, 66, 67, 68, 69, 70, -1, 72,
- 73, 74, -1, 76, -1, 78, -1, -1, 81, 82,
- 83, -1, -1, -1, -1, 88, -1, -1, -1, -1,
- -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 4, 5, 6, -1, -1,
- 9, 10, 11, -1, -1, 14, -1, 16, -1, -1,
- -1, 20, 21, 22, -1, -1, -1, -1, -1, -1,
- 29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 43, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 59, -1, -1, -1, -1, -1, -1, 66, 67, 68,
- 69, 70, 71, -1, 73, 74, 75, 76, 77, 78,
- -1, -1, 81, 82, 83, 84, 85, 86, 87, -1,
- -1, -1, 91, -1, -1, -1, -1, 96, 97, 98,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
- 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
- -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
- -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
- -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 59, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, 69, 70, 71, -1, 73, 74,
- 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
- 85, 86, 87, -1, -1, -1, 91, -1, -1, -1,
- -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 4, 5, 6, -1, -1, 9, 10,
- 11, -1, -1, 14, -1, 16, -1, -1, -1, 20,
- 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
- 31, 32, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 59, -1,
- -1, -1, -1, -1, 65, 66, 67, 68, 69, 70,
- 71, -1, 73, 74, 75, 76, 77, 78, -1, -1,
- 81, 82, 83, 84, 85, 86, 87, -1, -1, -1,
- 91, -1, -1, -1, -1, 96, 97, 98, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
- -1, -1, 9, 10, 11, -1, -1, 14, -1, 16,
- -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
- -1, -1, 29, 30, 31, 32, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
- 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
- -1, -1, 59, -1, -1, -1, -1, -1, 65, 66,
- 67, 68, 69, 70, 71, -1, 73, 74, 75, 76,
- 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
- 87, -1, -1, -1, 91, -1, -1, -1, -1, 96,
- 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 4, -1, -1, -1, -1, 9, -1, 11, 12,
- 13, 14, -1, -1, -1, -1, -1, -1, 21, 22,
- -1, -1, -1, -1, -1, -1, 29, 30, -1, -1,
- 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
- 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
- 53, -1, -1, -1, -1, -1, 59, -1, 61, -1,
- -1, -1, 65, 66, 67, 68, 69, 70, 71, 72,
- 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
- 83, 84, 85, 86, -1, 88, -1, -1, -1, -1,
- -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 4, -1, -1, -1, -1,
- 9, -1, 11, 12, 13, 14, -1, -1, -1, -1,
- -1, -1, 21, 22, -1, -1, -1, -1, -1, -1,
- 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
- 59, -1, 61, -1, -1, -1, 65, 66, 67, 68,
- 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- -1, -1, 81, 82, 83, 84, 85, 86, -1, 88,
- -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
- 5, 6, -1, -1, 9, 10, 11, 12, 13, 14,
- -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
- -1, -1, -1, -1, 29, 30, 31, 32, 33, 34,
- -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
- -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
- -1, -1, -1, -1, 59, -1, 61, -1, -1, -1,
- 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
- 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
- 85, 86, 87, 88, -1, -1, 91, -1, -1, -1,
- -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 4, 5, 6, -1, -1, 9, 10,
- 11, 12, 13, 14, -1, 16, -1, -1, -1, 20,
- 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
- 31, 32, 33, 34, -1, 36, -1, -1, -1, 40,
- -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
- 51, -1, 53, -1, 55, -1, -1, -1, 59, -1,
- 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
- 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
- 81, 82, 83, 84, 85, 86, 87, 88, -1, -1,
- 91, -1, -1, -1, -1, 96, 97, 98, -1, -1,
- -1, -1, -1, -1, -1, -1, -1,
-
- 18, 18, 32, 18, 32, 18, 3, 43, 18, 25,
- 22, 22, 14, 14, 78, 18, 9, 3, 18, 3,
- 18, 3, 18, 32, 18, 32, 32, 22, 18, 18,
- 22, 3, 3, 18, 106, 43, 3, 18, 18, 101,
- 3, 3, 18, 18, 18, 104, 3, 3, 18, 18,
- 18, 3, 18, 18, 18, 43, 3, 3, 3, 32,
- 14, 3, 3, 3, 25, 25, 25, -1, 55, 18,
- 57, 2, 55, -1, -1, 2, 55, 60, 3, -1,
- 18, 60, 18, 18, -1, 43, 25, 18, 43, -1,
- 43, 18, 43, 43, 18, 43, 11, 12, 14, 43,
- 43, 4, 3, 19, 18, 18, 3, 14, 3, 45,
- 18, -1, 18, -1, 2, 18, 23, 2, 55, 2,
- 57, 55, 55, 57, 57, 55, 55, 57, 57, 55,
- 18, 57, 45, 18, 55, 18, 57, 2, 46, 2,
- 2, 47, 2, 55, 55, 55, 55, 57, 60, 60,
- 55, 60, 57, 18, 79, 18, 18, 55, 18, 55,
- 95, 57, 60, 14, 2, 2, 55, -1, 55, 18,
- 14, 55, 61, 55, 61, 19, 60, 59, 79, 55,
- 18, 18, 79, 59, 79, 55, 55, 55, 14, 55,
- 60, 60, 60, 18, 60, 2, 110, 55, 47, 55,
- 43, 52, 60, 59, 18, 55, 2, 57, 51, 55,
- 55, 18, 39, 55, 55, 18, 43, 4, 2, 55,
- 65, 67, 18, 2, 18, 61, 52, 2, 69, 71,
- 2, 18, 46, 55, 18, 57, 55, 4, 57, 18,
- 55, 44, 57, 18, 55, 55, 18, 58, 58, 18,
- 43, 18, 46, 55, 14, 57, 55, 18, 51, 19,
- 2, 2, 61, 55, 55, 57, 55, 55, 93, 57,
- -1, 60, 63, -1, -1, 55, 18, 18, 47, 68,
- 60, -1, 55, -1, 64, 46, 18, 60, -1, 62,
- 55, 55, -1, -1, -1, 60, 60, 62, 62, 55,
- 55, -1, 55, 55, 60, 60, 62, 60, 60, 55,
- 55, -1, 55, 66, 60, 60, 48, 60, 55, 55,
- -1, 14, 77, 60, 60, 77, 19, 72, 21, -1,
- 14, 77, -1, 70, 77, 5, -1, 5, -1, 23,
- -1, 77, -1, -1, 14, -1, 14, 89, 89, -1,
- 43, 35, 36, 23, -1, 23, 25, 26, 27, 28,
- 29, 30, 31, -1, -1, 35, 36, 35, 36, -1,
- -1, -1, 14, -1, -1, -1, -1, -1, -1, -1,
- 18, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 14, -1, -1, -1, -1, -1, -1, -1, -1, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, -1, -1,
- 48, 49, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 14, -1, -1, -1, -1, -1,
- -1, -1, -1, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1
-};
-
-QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsgrammar_p.h b/src/qml/parser/qqmljsgrammar_p.h
deleted file mode 100644
index 9d028f2191..0000000000
--- a/src/qml/parser/qqmljsgrammar_p.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part 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$
-**
-****************************************************************************/
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-// This file was generated by qlalr - DO NOT EDIT!
-#ifndef QQMLJSGRAMMAR_P_H
-#define QQMLJSGRAMMAR_P_H
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlJSGrammar
-{
-public:
- enum VariousConstants {
- EOF_SYMBOL = 0,
- REDUCE_HERE = 107,
- SHIFT_THERE = 106,
- T_AND = 1,
- T_AND_AND = 2,
- T_AND_EQ = 3,
- T_AS = 95,
- T_AUTOMATIC_SEMICOLON = 62,
- T_BREAK = 4,
- T_CASE = 5,
- T_CATCH = 6,
- T_COLON = 7,
- T_COMMA = 8,
- T_COMMENT = 89,
- T_COMPATIBILITY_SEMICOLON = 90,
- T_CONST = 84,
- T_CONTINUE = 9,
- T_DEBUGGER = 86,
- T_DEFAULT = 10,
- T_DELETE = 11,
- T_DIVIDE_ = 12,
- T_DIVIDE_EQ = 13,
- T_DO = 14,
- T_DOT = 15,
- T_ELSE = 16,
- T_ENUM = 91,
- T_EQ = 17,
- T_EQ_EQ = 18,
- T_EQ_EQ_EQ = 19,
- T_ERROR = 99,
- T_FALSE = 83,
- T_FEED_JS_EXPRESSION = 103,
- T_FEED_JS_PROGRAM = 105,
- T_FEED_JS_SOURCE_ELEMENT = 104,
- T_FEED_JS_STATEMENT = 102,
- T_FEED_UI_OBJECT_MEMBER = 101,
- T_FEED_UI_PROGRAM = 100,
- T_FINALLY = 20,
- T_FOR = 21,
- T_FUNCTION = 22,
- T_GE = 23,
- T_GET = 97,
- T_GT = 24,
- T_GT_GT = 25,
- T_GT_GT_EQ = 26,
- T_GT_GT_GT = 27,
- T_GT_GT_GT_EQ = 28,
- T_IDENTIFIER = 29,
- T_IF = 30,
- T_IMPORT = 93,
- T_IN = 31,
- T_INSTANCEOF = 32,
- T_LBRACE = 33,
- T_LBRACKET = 34,
- T_LE = 35,
- T_LET = 85,
- T_LPAREN = 36,
- T_LT = 37,
- T_LT_LT = 38,
- T_LT_LT_EQ = 39,
- T_MINUS = 40,
- T_MINUS_EQ = 41,
- T_MINUS_MINUS = 42,
- T_MULTILINE_STRING_LITERAL = 88,
- T_NEW = 43,
- T_NOT = 44,
- T_NOT_EQ = 45,
- T_NOT_EQ_EQ = 46,
- T_NULL = 81,
- T_NUMERIC_LITERAL = 47,
- T_ON = 96,
- T_OR = 48,
- T_OR_EQ = 49,
- T_OR_OR = 50,
- T_PLUS = 51,
- T_PLUS_EQ = 52,
- T_PLUS_PLUS = 53,
- T_PRAGMA = 94,
- T_PROPERTY = 66,
- T_PUBLIC = 92,
- T_QUESTION = 54,
- T_RBRACE = 55,
- T_RBRACKET = 56,
- T_READONLY = 68,
- T_REMAINDER = 57,
- T_REMAINDER_EQ = 58,
- T_RESERVED_WORD = 87,
- T_RETURN = 59,
- T_RPAREN = 60,
- T_SEMICOLON = 61,
- T_SET = 98,
- T_SIGNAL = 67,
- T_STAR = 63,
- T_STAR_EQ = 64,
- T_STRING_LITERAL = 65,
- T_SWITCH = 69,
- T_THIS = 70,
- T_THROW = 71,
- T_TILDE = 72,
- T_TRUE = 82,
- T_TRY = 73,
- T_TYPEOF = 74,
- T_VAR = 75,
- T_VOID = 76,
- T_WHILE = 77,
- T_WITH = 78,
- T_XOR = 79,
- T_XOR_EQ = 80,
-
- ACCEPT_STATE = 691,
- RULE_COUNT = 369,
- STATE_COUNT = 692,
- TERMINAL_COUNT = 108,
- NON_TERMINAL_COUNT = 112,
-
- GOTO_INDEX_OFFSET = 692,
- GOTO_INFO_OFFSET = 3357,
- GOTO_CHECK_OFFSET = 3357
- };
-
- static const char *const spell[];
- static const short lhs[];
- static const short rhs[];
- static const short goto_default[];
- static const short action_default[];
- static const short action_index[];
- static const short action_info[];
- static const short action_check[];
-
- static inline int nt_action (int state, int nt)
- {
- const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
- if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
- return goto_default [nt];
-
- return action_info [GOTO_INFO_OFFSET + yyn];
- }
-
- static inline int t_action (int state, int token)
- {
- const int yyn = action_index [state] + token;
-
- if (yyn < 0 || action_check [yyn] != token)
- return - action_default [state];
-
- return action_info [yyn];
- }
-};
-
-
-QT_END_NAMESPACE
-#endif // QQMLJSGRAMMAR_P_H
-
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 20daf545a9..40094ecdf8 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -57,10 +57,10 @@ QT_QML_BEGIN_NAMESPACE
namespace QQmlJS {
-static inline int classify2(const QChar *s, bool qmlMode) {
+static inline int classify2(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'a') {
if (s[1].unicode() == 's') {
- return qmlMode ? Lexer::T_AS : Lexer::T_IDENTIFIER;
+ return (parseModeFlags & Lexer::QmlMode) ? Lexer::T_AS : Lexer::T_IDENTIFIER;
}
}
else if (s[0].unicode() == 'd') {
@@ -76,15 +76,18 @@ static inline int classify2(const QChar *s, bool qmlMode) {
return Lexer::T_IN;
}
}
- else if (qmlMode && s[0].unicode() == 'o') {
+ else if (s[0].unicode() == 'o') {
if (s[1].unicode() == 'n') {
- return qmlMode ? Lexer::T_ON : Lexer::T_IDENTIFIER;
+ return (parseModeFlags & Lexer::QmlMode) ? Lexer::T_ON : Lexer::T_IDENTIFIER;
+ }
+ else if (s[1].unicode() == 'f') {
+ return Lexer::T_OF;
}
}
return Lexer::T_IDENTIFIER;
}
-static inline int classify3(const QChar *s, bool qmlMode) {
+static inline int classify3(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'f') {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 'r') {
@@ -102,7 +105,7 @@ static inline int classify3(const QChar *s, bool qmlMode) {
else if (s[0].unicode() == 'i') {
if (s[1].unicode() == 'n') {
if (s[2].unicode() == 't') {
- return qmlMode ? int(Lexer::T_INT) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_INT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -144,12 +147,12 @@ static inline int classify3(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify4(const QChar *s, bool qmlMode) {
+static inline int classify4(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'b') {
if (s[1].unicode() == 'y') {
if (s[2].unicode() == 't') {
if (s[3].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_BYTE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_BYTE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -165,7 +168,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
else if (s[1].unicode() == 'h') {
if (s[2].unicode() == 'a') {
if (s[3].unicode() == 'r') {
- return qmlMode ? int(Lexer::T_CHAR) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_CHAR) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -181,7 +184,16 @@ static inline int classify4(const QChar *s, bool qmlMode) {
else if (s[1].unicode() == 'n') {
if (s[2].unicode() == 'u') {
if (s[3].unicode() == 'm') {
- return qmlMode ? int(Lexer::T_ENUM) : int(Lexer::T_RESERVED_WORD);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_ENUM) : int(Lexer::T_RESERVED_WORD);
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'm') {
+ return int(Lexer::T_FROM);
}
}
}
@@ -190,7 +202,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 't') {
if (s[3].unicode() == 'o') {
- return qmlMode ? int(Lexer::T_GOTO) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_GOTO) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -199,7 +211,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 'g') {
- return qmlMode ? int(Lexer::T_LONG) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_LONG) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -250,7 +262,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify5(const QChar *s, bool qmlMode) {
+static inline int classify5(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'b') {
if (s[1].unicode() == 'r') {
if (s[2].unicode() == 'e') {
@@ -305,7 +317,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 'a') {
if (s[4].unicode() == 'l') {
- return qmlMode ? int(Lexer::T_FINAL) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_FINAL) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -314,7 +326,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'o') {
if (s[3].unicode() == 'a') {
if (s[4].unicode() == 't') {
- return qmlMode ? int(Lexer::T_FLOAT) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_FLOAT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -325,7 +337,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'o') {
if (s[3].unicode() == 'r') {
if (s[4].unicode() == 't') {
- return qmlMode ? int(Lexer::T_SHORT) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_SHORT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -334,7 +346,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'p') {
if (s[3].unicode() == 'e') {
if (s[4].unicode() == 'r') {
- return qmlMode ? int(Lexer::T_SUPER) : int(Lexer::T_RESERVED_WORD);
+ return int(Lexer::T_SUPER);
}
}
}
@@ -362,10 +374,21 @@ static inline int classify5(const QChar *s, bool qmlMode) {
}
}
}
+ else if (s[0].unicode() == 'y') {
+ if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'e') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'd') {
+ return (parseModeFlags & Lexer::YieldIsKeyword) ? Lexer::T_YIELD : Lexer::T_IDENTIFIER;
+ }
+ }
+ }
+ }
+ }
return Lexer::T_IDENTIFIER;
}
-static inline int classify6(const QChar *s, bool qmlMode) {
+static inline int classify6(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'd') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 'l') {
@@ -383,7 +406,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'b') {
if (s[4].unicode() == 'l') {
if (s[5].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_DOUBLE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_DOUBLE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -409,7 +432,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'o') {
if (s[4].unicode() == 'r') {
if (s[5].unicode() == 't') {
- return qmlMode ? int(Lexer::T_IMPORT) : int(Lexer::T_RESERVED_WORD);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_IMPORT) : int(Lexer::T_RESERVED_WORD);
}
}
}
@@ -422,7 +445,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'i') {
if (s[4].unicode() == 'v') {
if (s[5].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_NATIVE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_NATIVE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -435,7 +458,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'l') {
if (s[4].unicode() == 'i') {
if (s[5].unicode() == 'c') {
- return qmlMode ? Lexer::T_PUBLIC : Lexer::T_IDENTIFIER;
+ return (parseModeFlags & Lexer::QmlMode) ? Lexer::T_PUBLIC : Lexer::T_IDENTIFIER;
}
}
}
@@ -446,7 +469,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'g') {
if (s[4].unicode() == 'm') {
if (s[5].unicode() == 'a') {
- return qmlMode ? Lexer::T_PRAGMA : Lexer::T_IDENTIFIER;
+ return (parseModeFlags & Lexer::QmlMode) ? Lexer::T_PRAGMA : Lexer::T_IDENTIFIER;
}
}
}
@@ -467,7 +490,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
}
}
else if (s[0].unicode() == 's') {
- if (qmlMode && s[1].unicode() == 'i') {
+ if ((parseModeFlags & Lexer::QmlMode) && s[1].unicode() == 'i') {
if (s[2].unicode() == 'g') {
if (s[3].unicode() == 'n') {
if (s[4].unicode() == 'a') {
@@ -483,7 +506,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 't') {
if (s[4].unicode() == 'i') {
if (s[5].unicode() == 'c') {
- return qmlMode ? int(Lexer::T_STATIC) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::StaticIsKeyword) ? int(Lexer::T_STATIC) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -507,7 +530,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
if (s[3].unicode() == 'o') {
if (s[4].unicode() == 'w') {
if (s[5].unicode() == 's') {
- return qmlMode ? int(Lexer::T_THROWS) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_THROWS) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -528,7 +551,7 @@ static inline int classify6(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify7(const QChar *s, bool qmlMode) {
+static inline int classify7(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'b') {
if (s[1].unicode() == 'o') {
if (s[2].unicode() == 'o') {
@@ -536,7 +559,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'e') {
if (s[5].unicode() == 'a') {
if (s[6].unicode() == 'n') {
- return qmlMode ? int(Lexer::T_BOOLEAN) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_BOOLEAN) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -596,7 +619,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'a') {
if (s[5].unicode() == 'g') {
if (s[6].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_PACKAGE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_PACKAGE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -609,7 +632,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
if (s[4].unicode() == 'a') {
if (s[5].unicode() == 't') {
if (s[6].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_PRIVATE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_PRIVATE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -620,7 +643,7 @@ static inline int classify7(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify8(const QChar *s, bool qmlMode) {
+static inline int classify8(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'a') {
if (s[1].unicode() == 'b') {
if (s[2].unicode() == 's') {
@@ -629,7 +652,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
if (s[5].unicode() == 'a') {
if (s[6].unicode() == 'c') {
if (s[7].unicode() == 't') {
- return qmlMode ? int(Lexer::T_ABSTRACT) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_ABSTRACT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -689,7 +712,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
}
}
}
- else if (qmlMode && s[0].unicode() == 'p') {
+ else if ((parseModeFlags & Lexer::QmlMode) && s[0].unicode() == 'p') {
if (s[1].unicode() == 'r') {
if (s[2].unicode() == 'o') {
if (s[3].unicode() == 'p') {
@@ -706,7 +729,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
}
}
}
- else if (qmlMode && s[0].unicode() == 'r') {
+ else if ((parseModeFlags & Lexer::QmlMode) && s[0].unicode() == 'r') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 'a') {
if (s[3].unicode() == 'd') {
@@ -731,7 +754,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
if (s[5].unicode() == 'i') {
if (s[6].unicode() == 'l') {
if (s[7].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_VOLATILE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_VOLATILE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -743,7 +766,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify9(const QChar *s, bool qmlMode) {
+static inline int classify9(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'i') {
if (s[1].unicode() == 'n') {
if (s[2].unicode() == 't') {
@@ -753,7 +776,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 'a') {
if (s[7].unicode() == 'c') {
if (s[8].unicode() == 'e') {
- return qmlMode ? int(Lexer::T_INTERFACE) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_INTERFACE) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -772,7 +795,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 't') {
if (s[7].unicode() == 'e') {
if (s[8].unicode() == 'd') {
- return qmlMode ? int(Lexer::T_PROTECTED) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_PROTECTED) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -791,7 +814,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
if (s[6].unicode() == 'e') {
if (s[7].unicode() == 'n') {
if (s[8].unicode() == 't') {
- return qmlMode ? int(Lexer::T_TRANSIENT) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_TRANSIENT) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -804,7 +827,7 @@ static inline int classify9(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify10(const QChar *s, bool qmlMode) {
+static inline int classify10(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 'i') {
if (s[1].unicode() == 'm') {
if (s[2].unicode() == 'p') {
@@ -815,7 +838,7 @@ static inline int classify10(const QChar *s, bool qmlMode) {
if (s[7].unicode() == 'n') {
if (s[8].unicode() == 't') {
if (s[9].unicode() == 's') {
- return qmlMode ? int(Lexer::T_IMPLEMENTS) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_IMPLEMENTS) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -848,7 +871,7 @@ static inline int classify10(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-static inline int classify12(const QChar *s, bool qmlMode) {
+static inline int classify12(const QChar *s, int parseModeFlags) {
if (s[0].unicode() == 's') {
if (s[1].unicode() == 'y') {
if (s[2].unicode() == 'n') {
@@ -861,7 +884,7 @@ static inline int classify12(const QChar *s, bool qmlMode) {
if (s[9].unicode() == 'z') {
if (s[10].unicode() == 'e') {
if (s[11].unicode() == 'd') {
- return qmlMode ? int(Lexer::T_SYNCHRONIZED) : int(Lexer::T_IDENTIFIER);
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_SYNCHRONIZED) : int(Lexer::T_IDENTIFIER);
}
}
}
@@ -877,18 +900,18 @@ static inline int classify12(const QChar *s, bool qmlMode) {
return Lexer::T_IDENTIFIER;
}
-int Lexer::classify(const QChar *s, int n, bool qmlMode) {
+int Lexer::classify(const QChar *s, int n, int parseModeFlags) {
switch (n) {
- case 2: return classify2(s, qmlMode);
- case 3: return classify3(s, qmlMode);
- case 4: return classify4(s, qmlMode);
- case 5: return classify5(s, qmlMode);
- case 6: return classify6(s, qmlMode);
- case 7: return classify7(s, qmlMode);
- case 8: return classify8(s, qmlMode);
- case 9: return classify9(s, qmlMode);
- case 10: return classify10(s, qmlMode);
- case 12: return classify12(s, qmlMode);
+ case 2: return classify2(s, parseModeFlags);
+ case 3: return classify3(s, parseModeFlags);
+ case 4: return classify4(s, parseModeFlags);
+ case 5: return classify5(s, parseModeFlags);
+ case 6: return classify6(s, parseModeFlags);
+ case 7: return classify7(s, parseModeFlags);
+ case 8: return classify8(s, parseModeFlags);
+ case 9: return classify9(s, parseModeFlags);
+ case 10: return classify10(s, parseModeFlags);
+ case 12: return classify12(s, parseModeFlags);
default: return Lexer::T_IDENTIFIER;
} // switch
}
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index aab9025a08..ae016076b8 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -77,22 +77,15 @@ static inline QChar convertHex(QChar c1, QChar c2)
return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
}
-static inline QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
-{
- return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
- (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
-}
-
Lexer::Lexer(Engine *engine)
: _engine(engine)
, _codePtr(nullptr)
, _endPtr(nullptr)
- , _lastLinePtr(nullptr)
- , _tokenLinePtr(nullptr)
, _tokenStartPtr(nullptr)
, _char(QLatin1Char('\n'))
, _errorCode(NoError)
, _currentLineNumber(0)
+ , _currentColumnNumber(0)
, _tokenValue(0)
, _parenthesesState(IgnoreParentheses)
, _parenthesesCount(0)
@@ -101,6 +94,7 @@ Lexer::Lexer(Engine *engine)
, _tokenKind(0)
, _tokenLength(0)
, _tokenLine(0)
+ , _tokenColumn(0)
, _validTokenText(false)
, _prohibitAutomaticSemicolon(false)
, _restrictedKeyword(false)
@@ -137,14 +131,13 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_codePtr = code.unicode();
_endPtr = _codePtr + code.length();
- _lastLinePtr = _codePtr;
- _tokenLinePtr = _codePtr;
_tokenStartPtr = _codePtr;
_char = QLatin1Char('\n');
_errorCode = NoError;
_currentLineNumber = lineno;
+ _currentColumnNumber = 0;
_tokenValue = 0;
// parentheses state
@@ -156,6 +149,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_patternFlags = 0;
_tokenLength = 0;
_tokenLine = lineno;
+ _tokenColumn = 0;
_validTokenText = false;
_prohibitAutomaticSemicolon = false;
@@ -172,9 +166,10 @@ void Lexer::scanChar()
if (sequenceLength == 2)
_char = *_codePtr++;
- if (unsigned sequenceLength = isLineTerminatorSequence()) {
- _lastLinePtr = _codePtr + sequenceLength - 1; // points to the first character after the newline
+ ++_currentColumnNumber;
+ if (isLineTerminator()) {
++_currentLineNumber;
+ _currentColumnNumber = 0;
}
}
@@ -222,12 +217,32 @@ inline bool isBinop(int tok)
return false;
}
}
+
+int hexDigit(QChar c)
+{
+ if (c >= QLatin1Char('0') && c <= QLatin1Char('9'))
+ return c.unicode() - '0';
+ if (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
+ return c.unicode() - 'a' + 10;
+ if (c >= QLatin1Char('A') && c <= QLatin1Char('F'))
+ return c.unicode() - 'A' + 10;
+ return -1;
+}
+
+int octalDigit(QChar c)
+{
+ if (c >= QLatin1Char('0') && c <= QLatin1Char('7'))
+ return c.unicode() - '0';
+ return -1;
+}
+
} // anonymous namespace
int Lexer::lex()
{
const int previousTokenKind = _tokenKind;
+ again:
_tokenSpell = QStringRef();
_tokenKind = scanToken();
_tokenLength = _codePtr - _tokenStartPtr - 1;
@@ -239,6 +254,9 @@ int Lexer::lex()
// update the flags
switch (_tokenKind) {
case T_LBRACE:
+ if (_bracesCount > 0)
+ ++_bracesCount;
+ Q_FALLTHROUGH();
case T_SEMICOLON:
case T_QUESTION:
case T_COLON:
@@ -266,9 +284,15 @@ int Lexer::lex()
case T_CONTINUE:
case T_BREAK:
case T_RETURN:
+ case T_YIELD:
case T_THROW:
_restrictedKeyword = true;
break;
+ case T_RBRACE:
+ if (_bracesCount > 0)
+ --_bracesCount;
+ if (_bracesCount == 0)
+ goto again;
} // switch
// update the parentheses state
@@ -295,39 +319,57 @@ int Lexer::lex()
return _tokenKind;
}
-bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
-{
- if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]))
- return true;
-
- return false;
-}
-
-QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
+uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{
- if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) {
- scanChar(); // skip u
+ Q_ASSERT(_char == QLatin1Char('u'));
+ scanChar(); // skip u
+ if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
+ uint codePoint = 0;
+ for (int i = 0; i < 4; ++i) {
+ int digit = hexDigit(_char);
+ if (digit < 0)
+ goto error;
+ codePoint *= 16;
+ codePoint += digit;
+ scanChar();
+ }
- const QChar c1 = _char;
- scanChar();
+ *ok = true;
+ return codePoint;
+ } else if (_codePtr < _endPtr && _char == QLatin1Char('{')) {
+ scanChar(); // skip '{'
+ uint codePoint = 0;
+ if (!isHexDigit(_char))
+ // need at least one hex digit
+ goto error;
- const QChar c2 = _char;
- scanChar();
+ while (_codePtr <= _endPtr) {
+ int digit = hexDigit(_char);
+ if (digit < 0)
+ break;
+ codePoint *= 16;
+ codePoint += digit;
+ if (codePoint > 0x10ffff)
+ goto error;
+ scanChar();
+ }
- const QChar c3 = _char;
- scanChar();
+ if (_char != QLatin1Char('}'))
+ goto error;
- const QChar c4 = _char;
- scanChar();
+ scanChar(); // skip '}'
- if (ok)
- *ok = true;
- return convertUnicode(c1, c2, c3, c4);
+ *ok = true;
+ return codePoint;
}
+ error:
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+
*ok = false;
- return QChar();
+ return 0;
}
QChar Lexer::decodeHexEscapeCharacter(bool *ok)
@@ -351,15 +393,15 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
return QChar();
}
-static inline bool isIdentifierStart(QChar ch)
+static inline bool isIdentifierStart(uint ch)
{
// fast path for ascii
- if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
- (ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
ch == '$' || ch == '_')
return true;
- switch (ch.category()) {
+ switch (QChar::category(ch)) {
case QChar::Number_Letter:
case QChar::Letter_Uppercase:
case QChar::Letter_Lowercase:
@@ -373,17 +415,17 @@ static inline bool isIdentifierStart(QChar ch)
return false;
}
-static bool isIdentifierPart(QChar ch)
+static bool isIdentifierPart(uint ch)
{
// fast path for ascii
- if ((ch.unicode() >= 'a' && ch.unicode() <= 'z') ||
- (ch.unicode() >= 'A' && ch.unicode() <= 'Z') ||
- (ch.unicode() >= '0' && ch.unicode() <= '9') ||
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
ch == '$' || ch == '_' ||
- ch.unicode() == 0x200c /* ZWNJ */ || ch.unicode() == 0x200d /* ZWJ */)
+ ch == 0x200c /* ZWNJ */ || ch == 0x200d /* ZWJ */)
return true;
- switch (ch.category()) {
+ switch (QChar::category(ch)) {
case QChar::Mark_NonSpacing:
case QChar::Mark_SpacingCombining:
@@ -412,19 +454,23 @@ int Lexer::scanToken()
return tk;
}
+ if (_bracesCount == 0) {
+ // we're inside a Template string
+ return scanString(TemplateContinuation);
+ }
+
+
_terminator = false;
again:
_validTokenText = false;
- _tokenLinePtr = _lastLinePtr;
while (_char.isSpace()) {
- if (unsigned sequenceLength = isLineTerminatorSequence()) {
- _tokenLinePtr = _codePtr + sequenceLength - 1;
-
+ if (isLineTerminator()) {
if (_restrictedKeyword) {
// automatic semicolon insertion
_tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
_tokenStartPtr = _codePtr - 1;
return T_SEMICOLON;
} else {
@@ -438,6 +484,7 @@ again:
_tokenStartPtr = _codePtr - 1;
_tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
if (_codePtr > _endPtr)
return EOF_SYMBOL;
@@ -501,6 +548,9 @@ again:
return T_EQ_EQ_EQ;
}
return T_EQ_EQ;
+ } else if (_char == QLatin1Char('>')) {
+ scanChar();
+ return T_ARROW;
}
return T_EQ;
@@ -557,50 +607,18 @@ again:
return T_DIVIDE_;
case '.':
- if (_char.isDigit()) {
- QVarLengthArray<char,32> chars;
-
- chars.append(ch.unicode()); // append the `.'
-
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ if (isDecimalDigit(_char.unicode()))
+ return scanNumber(ch);
+ if (_char == QLatin1Char('.')) {
+ scanChar();
+ if (_char == QLatin1Char('.')) {
scanChar();
- }
-
- if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
- _codePtr[1].isDigit())) {
-
- chars.append(_char.unicode());
- scanChar(); // consume `e'
-
- if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
- chars.append(_char.unicode());
- scanChar(); // consume the sign
- }
-
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar();
- }
- }
- }
-
- chars.append('\0');
-
- const char *begin = chars.constData();
- const char *end = nullptr;
- bool ok = false;
-
- _tokenValue = qstrtod(begin, &end, &ok);
-
- if (end - begin != chars.size() - 1) {
- _errorCode = IllegalExponentIndicator;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ return T_ELLIPSIS;
+ } else {
+ _errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
return T_ERROR;
}
-
- return T_NUMERIC_LITERAL;
}
return T_DOT;
@@ -611,7 +629,7 @@ again:
} else if (_char == QLatin1Char('-')) {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
_stackToken = T_MINUS_MINUS;
return T_SEMICOLON;
}
@@ -629,7 +647,7 @@ again:
} else if (_char == QLatin1Char('+')) {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
_stackToken = T_PLUS_PLUS;
return T_SEMICOLON;
}
@@ -642,6 +660,13 @@ again:
if (_char == QLatin1Char('=')) {
scanChar();
return T_STAR_EQ;
+ } else if (_char == QLatin1Char('*')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_STAR_STAR_EQ;
+ }
+ return T_STAR_STAR;
}
return T_STAR;
@@ -676,141 +701,12 @@ again:
}
return T_NOT;
+ case '`':
+ _outerTemplateBraceCount.push(_bracesCount);
+ Q_FALLTHROUGH();
case '\'':
- case '"': {
- const QChar quote = ch;
- bool multilineStringLiteral = false;
-
- const QChar *startCode = _codePtr;
-
- if (_engine) {
- while (_codePtr <= _endPtr) {
- if (isLineTerminator()) {
- if (qmlMode())
- break;
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Stray newline in string literal");
- return T_ERROR;
- } else if (_char == QLatin1Char('\\')) {
- break;
- } else if (_char == quote) {
- _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
- scanChar();
-
- return T_STRING_LITERAL;
- }
- scanChar();
- }
- }
-
- _validTokenText = true;
- _tokenText.resize(0);
- startCode--;
- while (startCode != _codePtr - 1)
- _tokenText += *startCode++;
-
- while (_codePtr <= _endPtr) {
- if (unsigned sequenceLength = isLineTerminatorSequence()) {
- multilineStringLiteral = true;
- _tokenText += _char;
- if (sequenceLength == 2)
- _tokenText += *_codePtr;
- scanChar();
- } else if (_char == quote) {
- scanChar();
-
- if (_engine)
- _tokenSpell = _engine->newStringRef(_tokenText);
-
- return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
- } else if (_char == QLatin1Char('\\')) {
- scanChar();
- if (_codePtr > _endPtr) {
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
- return T_ERROR;
- }
-
- QChar u;
-
- switch (_char.unicode()) {
- // unicode escape sequence
- case 'u': {
- bool ok = false;
- u = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
- return T_ERROR;
- }
- } break;
-
- // hex escape sequence
- case 'x': {
- bool ok = false;
- u = decodeHexEscapeCharacter(&ok);
- if (!ok) {
- _errorCode = IllegalHexadecimalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal hexadecimal escape sequence");
- return T_ERROR;
- }
- } break;
-
- // single character escape sequence
- case '\\': u = QLatin1Char('\\'); scanChar(); break;
- case '\'': u = QLatin1Char('\''); scanChar(); break;
- case '\"': u = QLatin1Char('\"'); scanChar(); break;
- case 'b': u = QLatin1Char('\b'); scanChar(); break;
- case 'f': u = QLatin1Char('\f'); scanChar(); break;
- case 'n': u = QLatin1Char('\n'); scanChar(); break;
- case 'r': u = QLatin1Char('\r'); scanChar(); break;
- case 't': u = QLatin1Char('\t'); scanChar(); break;
- case 'v': u = QLatin1Char('\v'); scanChar(); break;
-
- case '0':
- if (! _codePtr->isDigit()) {
- scanChar();
- u = QLatin1Char('\0');
- break;
- }
- Q_FALLTHROUGH();
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Octal escape sequences are not allowed");
- return T_ERROR;
-
- case '\r':
- case '\n':
- case 0x2028u:
- case 0x2029u:
- scanChar();
- continue;
-
- default:
- // non escape character
- u = _char;
- scanChar();
- }
-
- _tokenText += u;
- } else {
- _tokenText += _char;
- scanChar();
- }
- }
-
- _errorCode = UnclosedStringLiteral;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
- return T_ERROR;
- }
+ case '"':
+ return scanString(ScanStringMode(ch.unicode()));
case '0':
case '1':
case '2':
@@ -824,28 +720,36 @@ again:
return scanNumber(ch);
default: {
- QChar c = ch;
+ uint c = ch.unicode();
bool identifierWithEscapeChars = false;
- if (c == QLatin1Char('\\') && _char == QLatin1Char('u')) {
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
+ c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ scanChar();
+ } else if (c == '\\' && _char == QLatin1Char('u')) {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ if (!ok)
return T_ERROR;
- }
}
if (isIdentifierStart(c)) {
if (identifierWithEscapeChars) {
_tokenText.resize(0);
- _tokenText += c;
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
_validTokenText = true;
}
- while (true) {
- c = _char;
- if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
- if (! identifierWithEscapeChars) {
+ while (_codePtr <= _endPtr) {
+ c = _char.unicode();
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
+ scanChar();
+ c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
+ if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
_tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
@@ -855,38 +759,52 @@ again:
scanChar(); // skip '\\'
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
- if (! ok) {
- _errorCode = IllegalUnicodeEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
+ if (!ok)
return T_ERROR;
- }
- if (isIdentifierPart(c))
- _tokenText += c;
- continue;
- } else if (isIdentifierPart(c)) {
- if (identifierWithEscapeChars)
- _tokenText += c;
- scanChar();
+ if (!isIdentifierPart(c))
+ break;
+
+ if (identifierWithEscapeChars) {
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
+ }
continue;
}
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ if (!isIdentifierPart(c))
+ break;
- int kind = T_IDENTIFIER;
+ if (identifierWithEscapeChars) {
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
+ }
+ }
+ scanChar();
+ }
+
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
- if (! identifierWithEscapeChars)
- kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
+ int kind = T_IDENTIFIER;
- if (_engine) {
- if (kind == T_IDENTIFIER && identifierWithEscapeChars)
- _tokenSpell = _engine->newStringRef(_tokenText);
- else
- _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
- }
+ if (!identifierWithEscapeChars)
+ kind = classify(_tokenStartPtr, _tokenLength, parseModeFlags());
- return kind;
+ if (_engine) {
+ if (kind == T_IDENTIFIER && identifierWithEscapeChars)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+ else
+ _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
}
+
+ return kind;
}
}
@@ -896,93 +814,278 @@ again:
return T_ERROR;
}
-int Lexer::scanNumber(QChar ch)
+int Lexer::scanString(ScanStringMode mode)
{
- if (ch != QLatin1Char('0')) {
- QVarLengthArray<char, 64> buf;
- buf += ch.toLatin1();
-
- QChar n = _char;
- const QChar *code = _codePtr;
- while (n.isDigit()) {
- buf += n.toLatin1();
- n = *code++;
- }
+ QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
+ bool multilineStringLiteral = false;
- if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
- if (code != _codePtr) {
- _codePtr = code - 1;
+ const QChar *startCode = _codePtr;
+
+ if (_engine) {
+ while (_codePtr <= _endPtr) {
+ if (isLineTerminator() && quote != QLatin1Char('`')) {
+ if (qmlMode())
+ break;
+ _errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Stray newline in string literal");
+ return T_ERROR;
+ } else if (_char == QLatin1Char('\\')) {
+ break;
+ } else if (_char == '$' && quote == QLatin1Char('`')) {
+ break;
+ } else if (_char == quote) {
+ _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
scanChar();
+
+ if (quote == QLatin1Char('`'))
+ _bracesCount = _outerTemplateBraceCount.pop();
+
+ if (mode == TemplateHead)
+ return T_NO_SUBSTITUTION_TEMPLATE;
+ else if (mode == TemplateContinuation)
+ return T_TEMPLATE_TAIL;
+ else
+ return T_STRING_LITERAL;
}
- buf.append('\0');
- _tokenValue = strtod(buf.constData(), nullptr);
- return T_NUMERIC_LITERAL;
+ scanChar();
}
- } else if (_char.isDigit() && !qmlMode()) {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
- return T_ERROR;
}
- QVarLengthArray<char,32> chars;
- chars.append(ch.unicode());
+ _validTokenText = true;
+ _tokenText.resize(0);
+ startCode--;
+ while (startCode != _codePtr - 1)
+ _tokenText += *startCode++;
+
+ while (_codePtr <= _endPtr) {
+ if (unsigned sequenceLength = isLineTerminatorSequence()) {
+ multilineStringLiteral = true;
+ _tokenText += _char;
+ if (sequenceLength == 2)
+ _tokenText += *_codePtr;
+ scanChar();
+ } else if (_char == mode) {
+ scanChar();
- if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
- ch = _char; // remember the x or X to use it in the error message below.
+ if (_engine)
+ _tokenSpell = _engine->newStringRef(_tokenText);
- // parse hex integer literal
- chars.append(_char.unicode());
- scanChar(); // consume `x'
+ if (quote == QLatin1Char('`'))
+ _bracesCount = _outerTemplateBraceCount.pop();
- while (isHexDigit(_char)) {
- chars.append(_char.unicode());
+ if (mode == TemplateContinuation)
+ return T_TEMPLATE_TAIL;
+ else if (mode == TemplateHead)
+ return T_NO_SUBSTITUTION_TEMPLATE;
+
+ return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
+ } else if (quote == QLatin1Char('`') && _char == QLatin1Char('$') && *_codePtr == '{') {
+ scanChar();
+ scanChar();
+ _bracesCount = 1;
+ if (_engine)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+
+ return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE);
+ } else if (_char == QLatin1Char('\\')) {
+ scanChar();
+ if (_codePtr > _endPtr) {
+ _errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
+ return T_ERROR;
+ }
+
+ QChar u;
+
+ switch (_char.unicode()) {
+ // unicode escape sequence
+ case 'u': {
+ bool ok = false;
+ uint codePoint = decodeUnicodeEscapeCharacter(&ok);
+ if (!ok)
+ return T_ERROR;
+ if (QChar::requiresSurrogates(codePoint)) {
+ // need to use a surrogate pair
+ _tokenText += QChar(QChar::highSurrogate(codePoint));
+ u = QChar::lowSurrogate(codePoint);
+ } else {
+ u = codePoint;
+ }
+ } break;
+
+ // hex escape sequence
+ case 'x': {
+ bool ok = false;
+ u = decodeHexEscapeCharacter(&ok);
+ if (!ok) {
+ _errorCode = IllegalHexadecimalEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal hexadecimal escape sequence");
+ return T_ERROR;
+ }
+ } break;
+
+ // single character escape sequence
+ case '\\': u = QLatin1Char('\\'); scanChar(); break;
+ case '\'': u = QLatin1Char('\''); scanChar(); break;
+ case '\"': u = QLatin1Char('\"'); scanChar(); break;
+ case 'b': u = QLatin1Char('\b'); scanChar(); break;
+ case 'f': u = QLatin1Char('\f'); scanChar(); break;
+ case 'n': u = QLatin1Char('\n'); scanChar(); break;
+ case 'r': u = QLatin1Char('\r'); scanChar(); break;
+ case 't': u = QLatin1Char('\t'); scanChar(); break;
+ case 'v': u = QLatin1Char('\v'); scanChar(); break;
+
+ case '0':
+ if (! _codePtr->isDigit()) {
+ scanChar();
+ u = QLatin1Char('\0');
+ break;
+ }
+ Q_FALLTHROUGH();
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ _errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Octal escape sequences are not allowed");
+ return T_ERROR;
+
+ case '\r':
+ case '\n':
+ case 0x2028u:
+ case 0x2029u:
+ scanChar();
+ continue;
+
+ default:
+ // non escape character
+ u = _char;
+ scanChar();
+ }
+
+ _tokenText += u;
+ } else {
+ _tokenText += _char;
scanChar();
}
+ }
- if (chars.size() < 3) {
- _errorCode = IllegalHexNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ _errorCode = UnclosedStringLiteral;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
+ return T_ERROR;
+}
+
+int Lexer::scanNumber(QChar ch)
+{
+ if (ch == QLatin1Char('0')) {
+ if (_char == QLatin1Char('x') || _char == QLatin1Char('X')) {
+ ch = _char; // remember the x or X to use it in the error message below.
+
+ // parse hex integer literal
+ scanChar(); // consume 'x'
+
+ if (!isHexDigit(_char)) {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
+
+ double d = 0.;
+ while (1) {
+ int digit = ::hexDigit(_char);
+ if (digit < 0)
+ break;
+ d *= 16;
+ d += digit;
+ scanChar();
+ }
+
+ _tokenValue = d;
+ return T_NUMERIC_LITERAL;
+ } else if (_char == QLatin1Char('o') || _char == QLatin1Char('O')) {
+ ch = _char; // remember the o or O to use it in the error message below.
+
+ // parse octal integer literal
+ scanChar(); // consume 'o'
+
+ if (!isOctalDigit(_char.unicode())) {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
+
+ double d = 0.;
+ while (1) {
+ int digit = ::octalDigit(_char);
+ if (digit < 0)
+ break;
+ d *= 8;
+ d += digit;
+ scanChar();
+ }
+
+ _tokenValue = d;
+ return T_NUMERIC_LITERAL;
+ } else if (_char == QLatin1Char('b') || _char == QLatin1Char('B')) {
+ ch = _char; // remember the b or B to use it in the error message below.
+
+ // parse binary integer literal
+ scanChar(); // consume 'b'
+
+ if (_char.unicode() != '0' && _char.unicode() != '1') {
+ _errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch);
+ return T_ERROR;
+ }
+
+ double d = 0.;
+ while (1) {
+ int digit = 0;
+ if (_char.unicode() == '1')
+ digit = 1;
+ else if (_char.unicode() != '0')
+ break;
+ d *= 2;
+ d += digit;
+ scanChar();
+ }
+
+ _tokenValue = d;
+ return T_NUMERIC_LITERAL;
+ } else if (_char.isDigit() && !qmlMode()) {
+ _errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
return T_ERROR;
}
-
- _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
- return T_NUMERIC_LITERAL;
}
// decimal integer literal
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar(); // consume the digit
- }
-
- if (_char == QLatin1Char('.')) {
- chars.append(_char.unicode());
- scanChar(); // consume `.'
+ QVarLengthArray<char,32> chars;
+ chars.append(ch.unicode());
+ if (ch != QLatin1Char('.')) {
while (_char.isDigit()) {
chars.append(_char.unicode());
- scanChar();
+ scanChar(); // consume the digit
}
- if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
- _codePtr[1].isDigit())) {
-
- chars.append(_char.unicode());
- scanChar(); // consume `e'
+ if (_char == QLatin1Char('.')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume `.'
+ }
+ }
- if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
- chars.append(_char.unicode());
- scanChar(); // consume the sign
- }
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
- while (_char.isDigit()) {
- chars.append(_char.unicode());
- scanChar();
- }
- }
- }
- } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
_codePtr[1].isDigit())) {
@@ -1001,12 +1104,6 @@ int Lexer::scanNumber(QChar ch)
}
}
- if (chars.length() == 1) {
- // if we ended up with a single digit, then it was a '0'
- _tokenValue = 0;
- return T_NUMERIC_LITERAL;
- }
-
chars.append('\0');
const char *begin = chars.constData();
@@ -1174,16 +1271,6 @@ bool Lexer::isOctalDigit(ushort c)
return (c >= '0' && c <= '7');
}
-int Lexer::tokenEndLine() const
-{
- return _currentLineNumber;
-}
-
-int Lexer::tokenEndColumn() const
-{
- return _codePtr - _lastLinePtr;
-}
-
QString Lexer::tokenText() const
{
if (_validTokenText)
@@ -1256,6 +1343,7 @@ static const int uriTokens[] = {
QQmlJSGrammar::T_FUNCTION,
QQmlJSGrammar::T_IF,
QQmlJSGrammar::T_IN,
+ QQmlJSGrammar::T_OF,
QQmlJSGrammar::T_INSTANCEOF,
QQmlJSGrammar::T_NEW,
QQmlJSGrammar::T_NULL,
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index 11d8081713..a6ac8cb354 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -51,10 +51,11 @@
// We mean it.
//
-#include "qqmljsglobal_p.h"
-#include "qqmljsgrammar_p.h"
+#include <private/qqmljsglobal_p.h>
+#include <private/qqmljsgrammar_p.h>
#include <QtCore/qstring.h>
+#include <QtCore/qstack.h>
QT_QML_BEGIN_NAMESPACE
@@ -62,32 +63,7 @@ namespace QQmlJS {
class Engine;
class DiagnosticMessage;
-
-class QML_PARSER_EXPORT Directives {
-public:
- virtual ~Directives() {}
-
- virtual void pragmaLibrary()
- {
- }
-
- virtual void importFile(const QString &jsfile, const QString &module, int line, int column)
- {
- Q_UNUSED(jsfile);
- Q_UNUSED(module);
- Q_UNUSED(line);
- Q_UNUSED(column);
- }
-
- virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column)
- {
- Q_UNUSED(uri);
- Q_UNUSED(version);
- Q_UNUSED(module);
- Q_UNUSED(line);
- Q_UNUSED(column);
- }
-};
+class Directives;
class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar
{
@@ -97,10 +73,7 @@ public:
T_BOOLEAN = T_RESERVED_WORD,
T_BYTE = T_RESERVED_WORD,
T_CHAR = T_RESERVED_WORD,
- T_CLASS = T_RESERVED_WORD,
T_DOUBLE = T_RESERVED_WORD,
- T_EXPORT = T_RESERVED_WORD,
- T_EXTENDS = T_RESERVED_WORD,
T_FINAL = T_RESERVED_WORD,
T_FLOAT = T_RESERVED_WORD,
T_GOTO = T_RESERVED_WORD,
@@ -113,8 +86,6 @@ public:
T_PRIVATE = T_RESERVED_WORD,
T_PROTECTED = T_RESERVED_WORD,
T_SHORT = T_RESERVED_WORD,
- T_STATIC = T_RESERVED_WORD,
- T_SUPER = T_RESERVED_WORD,
T_SYNCHRONIZED = T_RESERVED_WORD,
T_THROWS = T_RESERVED_WORD,
T_TRANSIENT = T_RESERVED_WORD,
@@ -124,7 +95,7 @@ public:
enum Error {
NoError,
IllegalCharacter,
- IllegalHexNumber,
+ IllegalNumber,
UnclosedStringLiteral,
IllegalEscapeSequence,
IllegalUnicodeEscapeSequence,
@@ -145,10 +116,29 @@ public:
RegExp_Multiline = 0x04
};
+ enum ParseModeFlags {
+ QmlMode = 0x1,
+ YieldIsKeyword = 0x2,
+ StaticIsKeyword = 0x4
+ };
+
public:
Lexer(Engine *engine);
+ int parseModeFlags() const {
+ int flags = 0;
+ if (qmlMode())
+ flags |= QmlMode|StaticIsKeyword;
+ if (yieldIsKeyWord())
+ flags |= YieldIsKeyword;
+ if (_staticIsKeyword)
+ flags |= StaticIsKeyword;
+ return flags;
+ }
+
bool qmlMode() const;
+ bool yieldIsKeyWord() const { return _generatorLevel != 0; }
+ void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
QString code() const;
void setCode(const QString &code, int lineno, bool qmlMode = true);
@@ -166,10 +156,7 @@ public:
int tokenLength() const { return _tokenLength; }
int tokenStartLine() const { return _tokenLine; }
- int tokenStartColumn() const { return _tokenStartPtr - _tokenLinePtr + 1; }
-
- int tokenEndLine() const;
- int tokenEndColumn() const;
+ int tokenStartColumn() const { return _tokenColumn; }
inline QStringRef tokenSpell() const { return _tokenSpell; }
double tokenValue() const { return _tokenValue; }
@@ -188,13 +175,23 @@ public:
BalancedParentheses
};
+ void enterGeneratorBody() { ++_generatorLevel; }
+ void leaveGeneratorBody() { --_generatorLevel; }
+
protected:
- int classify(const QChar *s, int n, bool qmlMode);
+ static int classify(const QChar *s, int n, int parseModeFlags);
private:
inline void scanChar();
int scanToken();
int scanNumber(QChar ch);
+ enum ScanStringMode {
+ SingleQuote = '\'',
+ DoubleQuote = '"',
+ TemplateHead = '`',
+ TemplateContinuation = 0
+ };
+ int scanString(ScanStringMode mode);
bool isLineTerminator() const;
unsigned isLineTerminatorSequence() const;
@@ -202,10 +199,9 @@ private:
static bool isDecimalDigit(ushort c);
static bool isHexDigit(QChar c);
static bool isOctalDigit(ushort c);
- static bool isUnicodeEscapeSequence(const QChar *chars);
void syncProhibitAutomaticSemicolon();
- QChar decodeUnicodeEscapeCharacter(bool *ok);
+ uint decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
private:
@@ -218,26 +214,30 @@ private:
const QChar *_codePtr;
const QChar *_endPtr;
- const QChar *_lastLinePtr;
- const QChar *_tokenLinePtr;
const QChar *_tokenStartPtr;
QChar _char;
Error _errorCode;
int _currentLineNumber;
+ int _currentColumnNumber;
double _tokenValue;
// parentheses state
ParenthesesState _parenthesesState;
int _parenthesesCount;
+ // template string stack
+ QStack<int> _outerTemplateBraceCount;
+ int _bracesCount = -1;
+
int _stackToken;
int _patternFlags;
int _tokenKind;
int _tokenLength;
int _tokenLine;
+ int _tokenColumn;
bool _validTokenText;
bool _prohibitAutomaticSemicolon;
@@ -246,6 +246,8 @@ private:
bool _followsClosingBrace;
bool _delimited;
bool _qmlMode;
+ int _generatorLevel = 0;
+ bool _staticIsKeyword = false;
};
} // end of namespace QQmlJS
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h
index ef443d96bc..58768fd805 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/parser/qqmljsmemorypool_p.h
@@ -153,12 +153,10 @@ private:
class QML_PARSER_EXPORT Managed
{
- Managed(const Managed &other);
- void operator = (const Managed &other);
-
+ Q_DISABLE_COPY(Managed)
public:
- Managed() {}
- ~Managed() {}
+ Managed() = default;
+ ~Managed() = default;
void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); }
void operator delete(void *) {}
diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp
deleted file mode 100644
index 24b04b02f9..0000000000
--- a/src/qml/parser/qqmljsparser.cpp
+++ /dev/null
@@ -1,2010 +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 "qqmljsengine_p.h"
-#include "qqmljslexer_p.h"
-#include "qqmljsast_p.h"
-#include "qqmljsmemorypool_p.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qcoreapplication.h>
-
-#include <string.h>
-
-
-
-#include "qqmljsparser_p.h"
-
-#include <QtCore/qvarlengtharray.h>
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is automatically generated from qqmljs.g.
-// Changes should be made to that file, not here. Any change to this file will
-// be lost!
-//
-// To regenerate this file, run:
-// qlalr --no-debug --no-lines --qt qqmljs.g
-//
-
-using namespace QQmlJS;
-
-QT_QML_BEGIN_NAMESPACE
-
-void Parser::reallocateStack()
-{
- if (! stack_size)
- stack_size = 128;
- else
- stack_size <<= 1;
-
- sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
- state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
- location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
- string_stack = reinterpret_cast<QStringRef*> (realloc(static_cast<void *>(string_stack), stack_size * sizeof(QStringRef)));
-}
-
-Parser::Parser(Engine *engine):
- driver(engine),
- pool(engine->pool()),
- tos(0),
- stack_size(0),
- sym_stack(nullptr),
- state_stack(nullptr),
- location_stack(nullptr),
- string_stack(nullptr),
- program(nullptr),
- yylval(0),
- first_token(nullptr),
- last_token(nullptr)
-{
-}
-
-Parser::~Parser()
-{
- if (stack_size) {
- free(sym_stack);
- free(state_stack);
- free(location_stack);
- free(string_stack);
- }
-}
-
-static inline AST::SourceLocation location(Lexer *lexer)
-{
- AST::SourceLocation loc;
- loc.offset = lexer->tokenOffset();
- loc.length = lexer->tokenLength();
- loc.startLine = lexer->tokenStartLine();
- loc.startColumn = lexer->tokenStartColumn();
- return loc;
-}
-
-AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
-{
- QVarLengthArray<QStringRef, 4> nameIds;
- QVarLengthArray<AST::SourceLocation, 4> locations;
-
- AST::ExpressionNode *it = expr;
- while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
- nameIds.append(m->name);
- locations.append(m->identifierToken);
- it = m->base;
- }
-
- if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
- AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name);
- q->identifierToken = idExpr->identifierToken;
-
- AST::UiQualifiedId *currentId = q;
- for (int i = nameIds.size() - 1; i != -1; --i) {
- currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
- currentId->identifierToken = locations[i];
- }
-
- return currentId->finish();
- }
-
- return nullptr;
-}
-
-AST::UiQualifiedPragmaId *Parser::reparseAsQualifiedPragmaId(AST::ExpressionNode *expr)
-{
- if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
- AST::UiQualifiedPragmaId *q = new (pool) AST::UiQualifiedPragmaId(idExpr->name);
- q->identifierToken = idExpr->identifierToken;
-
- return q->finish();
- }
-
- return nullptr;
-}
-
-
-bool Parser::parse(int startToken)
-{
- Lexer *lexer = driver->lexer();
- bool hadErrors = false;
- int yytoken = -1;
- int action = 0;
-
- token_buffer[0].token = startToken;
- first_token = &token_buffer[0];
- if (startToken == T_FEED_JS_PROGRAM && !lexer->qmlMode()) {
- Directives ignoreDirectives;
- Directives *directives = driver->directives();
- if (!directives)
- directives = &ignoreDirectives;
- DiagnosticMessage error;
- if (!lexer->scanDirectives(directives, &error)) {
- diagnostic_messages.append(error);
- return false;
- }
- token_buffer[1].token = lexer->tokenKind();
- token_buffer[1].dval = lexer->tokenValue();
- token_buffer[1].loc = location(lexer);
- token_buffer[1].spell = lexer->tokenSpell();
- last_token = &token_buffer[2];
- } else {
- last_token = &token_buffer[1];
- }
-
- tos = -1;
- program = nullptr;
-
- do {
- if (++tos == stack_size)
- reallocateStack();
-
- state_stack[tos] = action;
-
- _Lcheck_token:
- if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
- yyprevlloc = yylloc;
-
- if (first_token == last_token) {
- yytoken = lexer->lex();
- yylval = lexer->tokenValue();
- yytokenspell = lexer->tokenSpell();
- yylloc = location(lexer);
- } else {
- yytoken = first_token->token;
- yylval = first_token->dval;
- yytokenspell = first_token->spell;
- yylloc = first_token->loc;
- ++first_token;
- }
- }
-
- action = t_action(action, yytoken);
- if (action > 0) {
- if (action != ACCEPT_STATE) {
- yytoken = -1;
- sym(1).dval = yylval;
- stringRef(1) = yytokenspell;
- loc(1) = yylloc;
- } else {
- --tos;
- return ! hadErrors;
- }
- } else if (action < 0) {
- const int r = -action - 1;
- tos -= rhs[r];
-
- switch (r) {
-
-case 0: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 1: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 2: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 3: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 4: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 5: {
- sym(1).Node = sym(2).Node;
- program = sym(1).Node;
-} break;
-
-case 6: {
- sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiHeaderItemList,
- sym(2).UiObjectMemberList->finish());
-} break;
-
-case 8: {
- sym(1).Node = sym(1).UiHeaderItemList->finish();
-} break;
-
-case 9: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiPragma);
-} break;
-
-case 10: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiImport);
-} break;
-
-case 11: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiPragma);
-} break;
-
-case 12: {
- sym(1).Node = new (pool) AST::UiHeaderItemList(sym(1).UiHeaderItemList, sym(2).UiImport);
-} break;
-
-case 16: {
- sym(1).UiPragma->semicolonToken = loc(2);
-} break;
-
-case 18: {
- sym(1).UiImport->semicolonToken = loc(2);
-} break;
-
-case 20: {
- sym(1).UiImport->versionToken = loc(2);
- sym(1).UiImport->semicolonToken = loc(3);
-} break;
-
-case 22: {
- sym(1).UiImport->versionToken = loc(2);
- sym(1).UiImport->asToken = loc(3);
- sym(1).UiImport->importIdToken = loc(4);
- sym(1).UiImport->importId = stringRef(4);
- sym(1).UiImport->semicolonToken = loc(5);
-} break;
-
-case 24: {
- sym(1).UiImport->asToken = loc(2);
- sym(1).UiImport->importIdToken = loc(3);
- sym(1).UiImport->importId = stringRef(3);
- sym(1).UiImport->semicolonToken = loc(4);
-} break;
-
-case 25: {
- AST::UiPragma *node = nullptr;
-
- if (AST::UiQualifiedPragmaId *qualifiedId = reparseAsQualifiedPragmaId(sym(2).Expression)) {
- node = new (pool) AST::UiPragma(qualifiedId);
- }
-
- sym(1).Node = node;
-
- if (node) {
- node->pragmaToken = loc(1);
- } else {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id")));
-
- return false; // ### remove me
- }
-} break;
-
-case 26: {
- AST::UiImport *node = nullptr;
-
- if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
- node = new (pool) AST::UiImport(importIdLiteral->value);
- node->fileNameToken = loc(2);
- } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
- node = new (pool) AST::UiImport(qualifiedId);
- node->fileNameToken = loc(2);
- }
-
- sym(1).Node = node;
-
- if (node) {
- node->importToken = loc(1);
- } else {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id or a string literal")));
-
- return false; // ### remove me
- }
-} break;
-
-case 27: {
- sym(1).Node = nullptr;
-} break;
-
-case 28: {
- sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
-} break;
-
-case 29: {
- sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
-} break;
-
-case 30: {
- AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
- sym(1).UiObjectMemberList, sym(2).UiObjectMember);
- sym(1).Node = node;
-} break;
-
-case 31: {
- sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
-} break;
-
-case 32: {
- AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
- sym(1).UiArrayMemberList, sym(3).UiObjectMember);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 33: {
- AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)nullptr);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 34: {
- AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 35: {
- AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
- sym(2).UiObjectInitializer);
- sym(1).Node = node;
-} break;
-
-case 37: {
- AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
- sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
- node->colonToken = loc(2);
- node->lbracketToken = loc(3);
- node->rbracketToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 38: {
- AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
- sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 39: {
- AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
- sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
- node->colonToken = loc(2);
- node->hasOnToken = true;
- sym(1).Node = node;
-} break;
-
-case 47:
-{
- AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
- sym(1).UiQualifiedId, sym(3).Statement);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 48: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 49: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 50: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 51: {
- AST::UiQualifiedId *node = new (pool) AST::UiQualifiedId(sym(1).UiQualifiedId, stringRef(3));
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 52: {
- sym(1).Node = nullptr;
-} break;
-
-case 53: {
- sym(1).Node = sym(1).UiParameterList->finish ();
-} break;
-
-case 54: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2));
- node->propertyTypeToken = loc(1);
- node->identifierToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 55: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4));
- node->propertyTypeToken = loc(3);
- node->commaToken = loc(2);
- node->identifierToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 57: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
- node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(2);
- node->parameters = sym(4).UiParameterList;
- node->semicolonToken = loc(6);
- sym(1).Node = node;
-} break;
-
-case 59: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
- node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 61: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
-} break;
-
-case 63: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 65: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 67: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->typeModifier = stringRef(3);
- node->propertyToken = loc(2);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(7);
- node->semicolonToken = loc(8);
- sym(1).Node = node;
-} break;
-
-case 68: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3),
- sym(5).Statement);
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 69: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4),
- sym(6).Statement);
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 70: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4),
- sym(6).Statement);
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->colonToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 71: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
- propertyName->identifierToken = loc(6);
- propertyName->next = nullptr;
-
- AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
- propertyName, sym(9).UiArrayMemberList->finish());
- binding->colonToken = loc(7);
- binding->lbracketToken = loc(8);
- binding->rbracketToken = loc(10);
-
- node->binding = binding;
-
- sym(1).Node = node;
-} break;
-
-case 72: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
- propertyName->identifierToken = loc(3);
- propertyName->next = nullptr;
-
- AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
- propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
- binding->colonToken = loc(4);
-
- node->binding = binding;
-
- sym(1).Node = node;
-} break;
-
-case 73: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- node->propertyToken = loc(2);
- node->typeToken = loc(3);
- node->identifierToken = loc(4);
- node->semicolonToken = loc(5); // insert a fake ';' before ':'
-
- AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4));
- propertyName->identifierToken = loc(4);
- propertyName->next = nullptr;
-
- AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
- propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer);
- binding->colonToken = loc(5);
-
- node->binding = binding;
-
- sym(1).Node = node;
-} break;
-
-case 74: {
- sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
-} break;
-
-case 75: {
- sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
-} break;
-
-case 76: {
- AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
- enumDeclaration->enumToken = loc(1);
- enumDeclaration->rbraceToken = loc(5);
- sym(1).Node = enumDeclaration;
- break;
-}
-
-case 77: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1));
- node->memberToken = loc(1);
- sym(1).Node = node;
- break;
-}
-
-case 78: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), sym(3).dval);
- node->memberToken = loc(1);
- node->valueToken = loc(3);
- sym(1).Node = node;
- break;
-}
-
-case 79: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3));
- node->memberToken = loc(3);
- sym(1).Node = node;
- break;
-}
-
-case 80: {
- AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), sym(5).dval);
- node->memberToken = loc(3);
- node->valueToken = loc(5);
- sym(1).Node = node;
- break;
-}
-
-case 88: {
- AST::ThisExpression *node = new (pool) AST::ThisExpression();
- node->thisToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 89: {
- AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 90: {
- AST::NullExpression *node = new (pool) AST::NullExpression();
- node->nullToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 91: {
- AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
- node->trueToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 92: {
- AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
- node->falseToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 93: {
- AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
-case 94:
-case 95: {
- AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 96: {
- bool rx = lexer->scanRegExp(Lexer::NoPrefix);
- if (!rx) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
- return false; // ### remove me
- }
-
- loc(1).length = lexer->tokenLength();
- yylloc = loc(1); // adjust the location of the current token
-
- AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
- driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 97: {
- bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
- if (!rx) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
- return false;
- }
-
- loc(1).length = lexer->tokenLength();
- yylloc = loc(1); // adjust the location of the current token
-
- AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
- driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
- node->literalToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 98: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) nullptr);
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 99: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 100: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
- node->lbracketToken = loc(1);
- node->rbracketToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 101: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
- (AST::Elision *) nullptr);
- node->lbracketToken = loc(1);
- node->commaToken = loc(3);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 102: {
- AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
- sym(4).Elision->finish());
- node->lbracketToken = loc(1);
- node->commaToken = loc(3);
- node->rbracketToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 103: {
- AST::ObjectLiteral *node = nullptr;
- if (sym(2).Node)
- node = new (pool) AST::ObjectLiteral(
- sym(2).PropertyAssignmentList->finish ());
- else
- node = new (pool) AST::ObjectLiteral();
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 104: {
- AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
- sym(2).PropertyAssignmentList->finish ());
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 105: {
- AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
- node->lparenToken = loc(1);
- node->rparenToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 106: {
- if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
- QLatin1String("Ignored annotation")));
-
- sym(1).Expression = mem->base;
- }
-
- if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
- sym(1).UiQualifiedId = qualifiedId;
- } else {
- sym(1).UiQualifiedId = nullptr;
-
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
- QLatin1String("Expected a qualified name id")));
-
- return false; // ### recover
- }
-} break;
-
-case 107: {
- sym(1).Node = new (pool) AST::ElementList((AST::Elision *) nullptr, sym(1).Expression);
-} break;
-
-case 108: {
- sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
-} break;
-
-case 109: {
- AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
- (AST::Elision *) nullptr, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 110: {
- AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
- sym(4).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 111: {
- AST::Elision *node = new (pool) AST::Elision();
- node->commaToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 112: {
- AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 113: {
- AST::PropertyNameAndValue *node = new (pool) AST::PropertyNameAndValue(
- sym(1).PropertyName, sym(3).Expression);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 114: {
- AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
- sym(2).PropertyName, sym(6).FunctionBody);
- node->getSetToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
- sym(1).Node = node;
-} break;
-
-case 115: {
- AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
- sym(2).PropertyName, sym(4).FormalParameterList, sym(7).FunctionBody);
- node->getSetToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
- sym(1).Node = node;
-} break;
-
-case 116: {
- sym(1).Node = new (pool) AST::PropertyAssignmentList(sym(1).PropertyAssignment);
-} break;
-
-case 117: {
- AST::PropertyAssignmentList *node = new (pool) AST::PropertyAssignmentList(
- sym(1).PropertyAssignmentList, sym(3).PropertyAssignment);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 118: {
- AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 119: {
- AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 120: {
- AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 121: {
- AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
- node->propertyNameToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 159: {
- AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
- node->lbracketToken = loc(2);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 160: {
- AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
- node->dotToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 161: {
- AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
- node->newToken = loc(1);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 163: {
- AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
- node->newToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 164: {
- AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 165: {
- AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 166: {
- AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
- node->lbracketToken = loc(2);
- node->rbracketToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 167: {
- AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
- node->dotToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 168: {
- sym(1).Node = nullptr;
-} break;
-
-case 169: {
- sym(1).Node = sym(1).ArgumentList->finish();
-} break;
-
-case 170: {
- sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
-} break;
-
-case 171: {
- AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 175: {
- AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
- node->incrementToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 176: {
- AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
- node->decrementToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 178: {
- AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
- node->deleteToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 179: {
- AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
- node->voidToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 180: {
- AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
- node->typeofToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 181: {
- AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
- node->incrementToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 182: {
- AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
- node->decrementToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 183: {
- AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
- node->plusToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 184: {
- AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
- node->minusToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 185: {
- AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
- node->tildeToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 186: {
- AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
- node->notToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 188: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Mul, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 189: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Div, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 190: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Mod, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 192: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Add, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 193: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Sub, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 195: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::LShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 196: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::RShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 197: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::URShift, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 199: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Lt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 200: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Gt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 201: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Le, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 202: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Ge, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 203: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::InstanceOf, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 204: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::In, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 206: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Lt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 207: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Gt, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 208: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Le, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 209: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Ge, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 210: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::InstanceOf, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 212: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Equal, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 213: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::NotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 214: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 215: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictNotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 217: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Equal, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 218: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::NotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 219: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 220: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::StrictNotEqual, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 222: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitAnd, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 224: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitAnd, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 226: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitXor, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 228: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitXor, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 230: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitOr, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 232: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::BitOr, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 234: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::And, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 236: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::And, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 238: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Or, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 240: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- QSOperator::Or, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 242: {
- AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
- sym(3).Expression, sym(5).Expression);
- node->questionToken = loc(2);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 244: {
- AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
- sym(3).Expression, sym(5).Expression);
- node->questionToken = loc(2);
- node->colonToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 246: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- sym(2).ival, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 248: {
- AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
- sym(2).ival, sym(3).Expression);
- node->operatorToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 249: {
- sym(1).ival = QSOperator::Assign;
-} break;
-
-case 250: {
- sym(1).ival = QSOperator::InplaceMul;
-} break;
-
-case 251: {
- sym(1).ival = QSOperator::InplaceDiv;
-} break;
-
-case 252: {
- sym(1).ival = QSOperator::InplaceMod;
-} break;
-
-case 253: {
- sym(1).ival = QSOperator::InplaceAdd;
-} break;
-
-case 254: {
- sym(1).ival = QSOperator::InplaceSub;
-} break;
-
-case 255: {
- sym(1).ival = QSOperator::InplaceLeftShift;
-} break;
-
-case 256: {
- sym(1).ival = QSOperator::InplaceRightShift;
-} break;
-
-case 257: {
- sym(1).ival = QSOperator::InplaceURightShift;
-} break;
-
-case 258: {
- sym(1).ival = QSOperator::InplaceAnd;
-} break;
-
-case 259: {
- sym(1).ival = QSOperator::InplaceXor;
-} break;
-
-case 260: {
- sym(1).ival = QSOperator::InplaceOr;
-} break;
-
-case 262: {
- AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 263: {
- sym(1).Node = nullptr;
-} break;
-
-case 266: {
- AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 267: {
- sym(1).Node = nullptr;
-} break;
-
-case 284: {
- AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 285: {
- sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
-} break;
-
-case 286: {
- sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
-} break;
-
-case 287: {
- sym(1).Node = nullptr;
-} break;
-
-case 288: {
- sym(1).Node = sym(1).StatementList->finish ();
-} break;
-
-case 290: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- if (sym(1).ival == T_LET)
- s = AST::VariableDeclaration::BlockScope;
- else if (sym(1).ival == T_CONST)
- s = AST::VariableDeclaration::ReadOnlyBlockScope;
-
- AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
- node->declarationKindToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 291: {
- sym(1).ival = T_LET;
-} break;
-
-case 292: {
- sym(1).ival = T_CONST;
-} break;
-
-case 293: {
- sym(1).ival = T_VAR;
-} break;
-
-case 294: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
-} break;
-
-case 295: {
- AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
- sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
- node->commaToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 296: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
-} break;
-
-case 297: {
- sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
-} break;
-
-case 298: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 299: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 300: {
- // ### TODO: AST for initializer
- sym(1) = sym(2);
-} break;
-
-case 301: {
- sym(1).Node = nullptr;
-} break;
-
-case 303: {
- // ### TODO: AST for initializer
- sym(1) = sym(2);
-} break;
-
-case 304: {
- sym(1).Node = nullptr;
-} break;
-
-case 306: {
- AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
- node->semicolonToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 308: {
- AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 309: {
- AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
- node->ifToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- node->elseToken = loc(6);
- sym(1).Node = node;
-} break;
-
-case 310: {
- AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
- node->ifToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 313: {
- AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
- node->doToken = loc(1);
- node->whileToken = loc(3);
- node->lparenToken = loc(4);
- node->rparenToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
-} break;
-
-case 314: {
- AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
- node->whileToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 315: {
- AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
- sym(5).Expression, sym(7).Expression, sym(9).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->firstSemicolonToken = loc(4);
- node->secondSemicolonToken = loc(6);
- node->rparenToken = loc(8);
- sym(1).Node = node;
-} break;
-
-case 316: {
- AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
- AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
- sym(8).Expression, sym(10).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->varToken = loc(3);
- node->firstSemicolonToken = loc(5);
- node->secondSemicolonToken = loc(7);
- node->rparenToken = loc(9);
- sym(1).Node = node;
-} break;
-
-case 317: {
- AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
- sym(5).Expression, sym(7).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->inToken = loc(4);
- node->rparenToken = loc(6);
- sym(1).Node = node;
-} break;
-
-case 318: {
- AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
- sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
- node->forToken = loc(1);
- node->lparenToken = loc(2);
- node->varToken = loc(3);
- node->inToken = loc(5);
- node->rparenToken = loc(7);
- sym(1).Node = node;
-} break;
-
-case 320: {
- AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
- node->continueToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 322: {
- AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
- node->continueToken = loc(1);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 324: {
- AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
- node->breakToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 326: {
- AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
- node->breakToken = loc(1);
- node->identifierToken = loc(2);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 328: {
- AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
- node->returnToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 329: {
- AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
- node->withToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 330: {
- AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
- node->switchToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 331: {
- AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 332: {
- AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
- node->lbraceToken = loc(1);
- node->rbraceToken = loc(5);
- sym(1).Node = node;
-} break;
-
-case 333: {
- sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
-} break;
-
-case 334: {
- sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
-} break;
-
-case 335: {
- sym(1).Node = nullptr;
-} break;
-
-case 336: {
- sym(1).Node = sym(1).CaseClauses->finish ();
-} break;
-
-case 337: {
- AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
- node->caseToken = loc(1);
- node->colonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 338: {
- AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
- node->defaultToken = loc(1);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 339: {
- AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
- node->identifierToken = loc(1);
- node->colonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 341: {
- AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
- node->throwToken = loc(1);
- node->semicolonToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 342: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 343: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 344: {
- AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
- node->tryToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 345: {
- AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
- node->catchToken = loc(1);
- node->lparenToken = loc(2);
- node->identifierToken = loc(3);
- node->rparenToken = loc(4);
- sym(1).Node = node;
-} break;
-
-case 346: {
- AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
- node->finallyToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 348: {
- AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
- node->debuggerToken = loc(1);
- node->semicolonToken = loc(2);
- sym(1).Node = node;
-} break;
-
-case 350: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
- node->functionToken = loc(1);
- node->identifierToken = loc(2);
- node->lparenToken = loc(3);
- node->rparenToken = loc(5);
- node->lbraceToken = loc(6);
- node->rbraceToken = loc(8);
- sym(1).Node = node;
-} break;
-
-case 351: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
- 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);
- sym(1).Node = node;
-} break;
-
-case 352: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
- node->functionToken = loc(1);
- node->lparenToken = loc(2);
- node->rparenToken = loc(4);
- node->lbraceToken = loc(5);
- node->rbraceToken = loc(7);
- sym(1).Node = node;
-} break;
-
-case 353: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
- node->identifierToken = loc(1);
- sym(1).Node = node;
-} break;
-
-case 354: {
- AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
- node->commaToken = loc(2);
- node->identifierToken = loc(3);
- sym(1).Node = node;
-} break;
-
-case 355: {
- sym(1).Node = nullptr;
-} break;
-
-case 356: {
- sym(1).Node = sym(1).FormalParameterList->finish ();
-} break;
-
-case 357: {
- sym(1).Node = nullptr;
-} break;
-
-case 359: {
- sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
-} break;
-
-case 361: {
- sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
-} break;
-
-case 362: {
- sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
-} break;
-
-case 363: {
- sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
-} break;
-
-case 364: {
- sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
-} break;
-
-case 365: {
- sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
-} break;
-
-case 366: {
- sym(1).Node = nullptr;
-} break;
-
- } // switch
- action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
- } // if
- } while (action != 0);
-
- if (first_token == last_token) {
- const int errorState = state_stack[tos];
-
- // automatic insertion of `;'
- if (yytoken != -1 && ((t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken))
- || t_action(errorState, T_COMPATIBILITY_SEMICOLON))) {
- SavedToken &tk = token_buffer[0];
- tk.token = yytoken;
- tk.dval = yylval;
- tk.spell = yytokenspell;
- tk.loc = yylloc;
-
- yylloc = yyprevlloc;
- yylloc.offset += yylloc.length;
- yylloc.startColumn += yylloc.length;
- yylloc.length = 0;
-
- //const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'");
- //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
-
- first_token = &token_buffer[0];
- last_token = &token_buffer[1];
-
- yytoken = T_SEMICOLON;
- yylval = 0;
-
- action = errorState;
-
- goto _Lcheck_token;
- }
-
- hadErrors = true;
-
- token_buffer[0].token = yytoken;
- token_buffer[0].dval = yylval;
- token_buffer[0].spell = yytokenspell;
- token_buffer[0].loc = yylloc;
-
- token_buffer[1].token = yytoken = lexer->lex();
- token_buffer[1].dval = yylval = lexer->tokenValue();
- token_buffer[1].spell = yytokenspell = lexer->tokenSpell();
- token_buffer[1].loc = yylloc = location(lexer);
-
- if (t_action(errorState, yytoken)) {
- QString msg;
- int token = token_buffer[0].token;
- if (token < 0 || token >= TERMINAL_COUNT)
- 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));
-
- action = errorState;
- goto _Lcheck_token;
- }
-
- static int tokens[] = {
- T_PLUS,
- T_EQ,
-
- T_COMMA,
- T_COLON,
- T_SEMICOLON,
-
- T_RPAREN, T_RBRACKET, T_RBRACE,
-
- T_NUMERIC_LITERAL,
- T_IDENTIFIER,
-
- T_LPAREN, T_LBRACKET, T_LBRACE,
-
- EOF_SYMBOL
- };
-
- for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
- 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));
-
- yytoken = *tk;
- yylval = 0;
- yylloc = token_buffer[0].loc;
- yylloc.length = 0;
-
- first_token = &token_buffer[0];
- last_token = &token_buffer[2];
-
- action = errorState;
- goto _Lcheck_token;
- }
- }
-
- for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
- if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
- tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
- tk == T_FEED_JS_SOURCE_ELEMENT)
- continue;
-
- 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));
-
- yytoken = tk;
- yylval = 0;
- yylloc = token_buffer[0].loc;
- yylloc.length = 0;
-
- action = errorState;
- goto _Lcheck_token;
- }
- }
-
- const QString msg = QCoreApplication::translate("QQmlParser", "Syntax error");
- diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
- }
-
- return false;
-}
-
-QT_QML_END_NAMESPACE
-
-
diff --git a/src/qml/parser/qqmljsparser_p.h b/src/qml/parser/qqmljsparser_p.h
deleted file mode 100644
index b4aecd2f08..0000000000
--- a/src/qml/parser/qqmljsparser_p.h
+++ /dev/null
@@ -1,258 +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$
-**
-****************************************************************************/
-
-
-//
-// 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.
-//
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is automatically generated from qqmljs.g.
-// Changes should be made to that file, not here. Any change to this file will
-// be lost!
-//
-// To regenerate this file, run:
-// qlalr --no-debug --no-lines --qt qqmljs.g
-//
-
-#ifndef QQMLJSPARSER_P_H
-#define QQMLJSPARSER_P_H
-
-#include "qqmljsglobal_p.h"
-#include "qqmljsgrammar_p.h"
-#include "qqmljsast_p.h"
-#include "qqmljsengine_p.h"
-
-#include <QtCore/qlist.h>
-#include <QtCore/qstring.h>
-
-QT_QML_BEGIN_NAMESPACE
-
-namespace QQmlJS {
-
-class Engine;
-
-class QML_PARSER_EXPORT Parser: protected QQmlJSGrammar
-{
-public:
- union Value {
- int ival;
- double dval;
- AST::ArgumentList *ArgumentList;
- AST::CaseBlock *CaseBlock;
- AST::CaseClause *CaseClause;
- AST::CaseClauses *CaseClauses;
- AST::Catch *Catch;
- AST::DefaultClause *DefaultClause;
- AST::ElementList *ElementList;
- AST::Elision *Elision;
- AST::ExpressionNode *Expression;
- AST::Finally *Finally;
- AST::FormalParameterList *FormalParameterList;
- AST::FunctionBody *FunctionBody;
- AST::FunctionDeclaration *FunctionDeclaration;
- AST::Node *Node;
- AST::PropertyName *PropertyName;
- AST::PropertyAssignment *PropertyAssignment;
- AST::PropertyAssignmentList *PropertyAssignmentList;
- AST::SourceElement *SourceElement;
- AST::SourceElements *SourceElements;
- AST::Statement *Statement;
- AST::StatementList *StatementList;
- AST::Block *Block;
- AST::VariableDeclaration *VariableDeclaration;
- AST::VariableDeclarationList *VariableDeclarationList;
-
- AST::UiProgram *UiProgram;
- AST::UiHeaderItemList *UiHeaderItemList;
- AST::UiPragma *UiPragma;
- AST::UiImport *UiImport;
- AST::UiParameterList *UiParameterList;
- AST::UiPublicMember *UiPublicMember;
- AST::UiObjectDefinition *UiObjectDefinition;
- AST::UiObjectInitializer *UiObjectInitializer;
- AST::UiObjectBinding *UiObjectBinding;
- AST::UiScriptBinding *UiScriptBinding;
- AST::UiArrayBinding *UiArrayBinding;
- AST::UiObjectMember *UiObjectMember;
- AST::UiObjectMemberList *UiObjectMemberList;
- AST::UiArrayMemberList *UiArrayMemberList;
- AST::UiQualifiedId *UiQualifiedId;
- AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
- AST::UiEnumMemberList *UiEnumMemberList;
- };
-
-public:
- Parser(Engine *engine);
- ~Parser();
-
- // parse a UI program
- bool parse() { return parse(T_FEED_UI_PROGRAM); }
- bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
- bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
- bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
- bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
- bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
-
- AST::UiProgram *ast() const
- { return AST::cast<AST::UiProgram *>(program); }
-
- AST::Statement *statement() const
- {
- if (! program)
- return nullptr;
-
- return program->statementCast();
- }
-
- AST::ExpressionNode *expression() const
- {
- if (! program)
- return nullptr;
-
- return program->expressionCast();
- }
-
- AST::UiObjectMember *uiObjectMember() const
- {
- if (! program)
- return nullptr;
-
- return program->uiObjectMemberCast();
- }
-
- AST::Node *rootNode() const
- { return program; }
-
- QList<DiagnosticMessage> diagnosticMessages() const
- { return diagnostic_messages; }
-
- inline DiagnosticMessage diagnosticMessage() const
- {
- for (const DiagnosticMessage &d : diagnostic_messages) {
- if (d.kind != DiagnosticMessage::Warning)
- return d;
- }
-
- return DiagnosticMessage();
- }
-
- inline QString errorMessage() const
- { return diagnosticMessage().message; }
-
- inline int errorLineNumber() const
- { return diagnosticMessage().loc.startLine; }
-
- inline int errorColumnNumber() const
- { return diagnosticMessage().loc.startColumn; }
-
-protected:
- bool parse(int startToken);
-
- void reallocateStack();
-
- inline Value &sym(int index)
- { return sym_stack [tos + index - 1]; }
-
- inline QStringRef &stringRef(int index)
- { return string_stack [tos + index - 1]; }
-
- inline AST::SourceLocation &loc(int index)
- { return location_stack [tos + index - 1]; }
-
- AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
- AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
-
-protected:
- Engine *driver;
- MemoryPool *pool;
- int tos;
- int stack_size;
- Value *sym_stack;
- int *state_stack;
- AST::SourceLocation *location_stack;
- QStringRef *string_stack;
-
- AST::Node *program;
-
- // error recovery
- enum { TOKEN_BUFFER_SIZE = 3 };
-
- struct SavedToken {
- int token;
- double dval;
- AST::SourceLocation loc;
- QStringRef spell;
- };
-
- double yylval;
- QStringRef yytokenspell;
- AST::SourceLocation yylloc;
- AST::SourceLocation yyprevlloc;
-
- SavedToken token_buffer[TOKEN_BUFFER_SIZE];
- SavedToken *first_token;
- SavedToken *last_token;
-
- QList<DiagnosticMessage> diagnostic_messages;
-};
-
-} // end of namespace QQmlJS
-
-
-
-#define J_SCRIPT_REGEXPLITERAL_RULE1 96
-
-#define J_SCRIPT_REGEXPLITERAL_RULE2 97
-
-QT_QML_END_NAMESPACE
-
-
-
-#endif // QQMLJSPARSER_P_H
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 2137877427..940ebb3257 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -73,7 +73,7 @@ include(jsruntime/jsruntime.pri)
include(jit/jit.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
-qtConfig(animation) {
+qtConfig(qml-animation) {
include(animations/animations.pri)
}
include(types/types.pri)
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
index 91ce74bec9..71b41cd30b 100644
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ b/src/qml/qml/ftw/qflagpointer_p.h
@@ -82,6 +82,8 @@ public:
inline T *data() const;
+ inline explicit operator bool() const;
+
private:
quintptr ptr_value = 0;
@@ -230,6 +232,12 @@ T *QFlagPointer<T>::data() const
return (T *)(ptr_value & ~FlagsMask);
}
+template<typename T>
+QFlagPointer<T>::operator bool() const
+{
+ return data() != nullptr;
+}
+
template<typename T, typename T2>
QBiPointer<T, T2>::QBiPointer()
{
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
index 3cfb345b30..d32a08e0f5 100644
--- a/src/qml/qml/ftw/qqmlrefcount_p.h
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -85,19 +85,23 @@ public:
inline QQmlRefPointer();
inline QQmlRefPointer(T *, Mode m = AddRef);
inline QQmlRefPointer(const QQmlRefPointer<T> &);
+ inline QQmlRefPointer(QQmlRefPointer<T> &&);
inline ~QQmlRefPointer();
inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
+ inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o);
inline bool isNull() const { return !o; }
inline T* operator->() const { return o; }
inline T& operator*() const { return *o; }
- inline operator T*() const { return o; }
+ explicit inline operator bool() const { return o != nullptr; }
inline T* data() const { return o; }
inline QQmlRefPointer<T> &adopt(T *);
+ inline T* take() { T *res = o; o = nullptr; return res; }
+
private:
T *o;
};
@@ -156,6 +160,12 @@ QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
if (o) o->addref();
}
+template <class T>
+QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other)
+ : o(other.take())
+{
+}
+
template<class T>
QQmlRefPointer<T>::~QQmlRefPointer()
{
@@ -171,6 +181,14 @@ QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
return *this;
}
+template <class T>
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other)
+{
+ QQmlRefPointer<T> m(std::move(other));
+ qSwap(o, m.o);
+ return *this;
+}
+
/*!
Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
of the callers reference of other.
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 412dc6cba2..6d69294c17 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -20,7 +20,6 @@ SOURCES += \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlerror.cpp \
$$PWD/qqmlvaluetype.cpp \
- $$PWD/qqmlxmlhttprequest.cpp \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
$$PWD/qqmlnotifier.cpp \
@@ -31,7 +30,6 @@ SOURCES += \
$$PWD/qqmlextensionplugin.cpp \
$$PWD/qqmlimport.cpp \
$$PWD/qqmllist.cpp \
- $$PWD/qqmllocale.cpp \
$$PWD/qqmljavascriptexpression.cpp \
$$PWD/qqmlabstractbinding.cpp \
$$PWD/qqmlvaluetypeproxybinding.cpp \
@@ -85,7 +83,6 @@ HEADERS += \
$$PWD/qqmldata_p.h \
$$PWD/qqmlerror.h \
$$PWD/qqmlvaluetype_p.h \
- $$PWD/qqmlxmlhttprequest_p.h \
$$PWD/qqmlcleanup_p.h \
$$PWD/qqmlpropertycache_p.h \
$$PWD/qqmlpropertyindex_p.h \
@@ -99,7 +96,6 @@ HEADERS += \
$$PWD/qqmlimport_p.h \
$$PWD/qqmlextensionplugin.h \
$$PWD/qqmlscriptstring_p.h \
- $$PWD/qqmllocale_p.h \
$$PWD/qqmlcomponentattached_p.h \
$$PWD/qqmljavascriptexpression_p.h \
$$PWD/qqmlabstractbinding_p.h \
@@ -120,5 +116,22 @@ HEADERS += \
$$PWD/qqmldelayedcallqueue_p.h \
$$PWD/qqmlloggingcategory_p.h
+qtConfig(qml-xml-http-request) {
+ HEADERS += \
+ $$PWD/qqmlxmlhttprequest_p.h
+
+ SOURCES += \
+ $$PWD/qqmlxmlhttprequest.cpp
+
+}
+
+qtConfig(qml-locale) {
+ HEADERS += \
+ $$PWD/qqmllocale_p.h
+
+ SOURCES += \
+ $$PWD/qqmllocale.cpp
+}
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 213f23cd98..2a8e236905 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -645,6 +645,8 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i
return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type);
}
+int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QObject)
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 30a18440a8..a4b3f1f4e4 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -337,7 +337,7 @@ protected:
class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
public:
- QQmlTranslationBinding(QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Binding *binding)
+ QQmlTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
setCompilationUnit(compilationUnit);
m_binding = binding;
@@ -374,11 +374,13 @@ public:
}
}
+ bool hasDependencies() const override final { return true; }
+
private:
const QV4::CompiledData::Binding *m_binding;
};
-QQmlBinding *QQmlBinding::createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
+QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
{
QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding);
@@ -663,6 +665,11 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
return dependencies;
}
+bool QQmlBinding::hasDependencies() const
+{
+ return !permanentGuards.isEmpty() || !activeGuards.isEmpty() || translationsCaptured();
+}
+
class QObjectPointerBinding: public QQmlNonbindingBinding
{
QQmlMetaObject targetMetaObject;
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index a1295bd0ac..f192de4342 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -79,7 +79,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(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding,
+ static QQmlBinding *createTranslationBinding(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, const QV4::CompiledData::Binding *binding,
QObject *obj, QQmlContextData *ctxt);
~QQmlBinding() override;
@@ -118,6 +118,7 @@ public:
* Call this method from the UI thread.
*/
QVector<QQmlProperty> dependencies() const;
+ virtual bool hasDependencies() const;
protected:
virtual void doUpdate(const DeleteWatcher &watcher,
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 8885e69161..96f6c6aed6 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -334,7 +334,7 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
emit q->progressChanged(p);
}
-void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
+void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data)
{
url = data->finalUrl();
compilationUnit = data->compilationUnit();
@@ -343,15 +343,12 @@ void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
Q_ASSERT(data->isError());
state.errors = data->errors();
}
-
- data->release();
}
void QQmlComponentPrivate::clear()
{
if (typeData) {
typeData->unregisterCallback(this);
- typeData->release();
typeData = nullptr;
}
@@ -387,7 +384,7 @@ QQmlComponent::~QQmlComponent()
if (d->typeData) {
d->typeData->unregisterCallback(d);
- d->typeData->release();
+ d->typeData = nullptr;
}
}
@@ -580,7 +577,7 @@ void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
d->url = url;
- QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.getType(data, url);
+ QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.getType(data, url);
if (typeData->isCompleteOrError()) {
d->fromTypeData(typeData);
@@ -667,7 +664,7 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
? QQmlTypeLoader::Asynchronous
: QQmlTypeLoader::PreferSynchronous;
- QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
+ QQmlRefPointer<QQmlTypeData> data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
if (data->isCompleteOrError()) {
fromTypeData(data);
@@ -848,13 +845,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;
- if (++creationDepth.localData() >= maxCreationDepth) {
+ if (creationDepth.localData() >= maxCreationDepth) {
qWarning("QQmlComponent: Component creation is recursing - aborting");
- --creationDepth.localData();
return nullptr;
}
- Q_ASSERT(creationDepth.localData() >= 1);
- depthIncreased = true;
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
@@ -878,10 +872,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
- } else {
- Q_ASSERT(creationDepth.localData() >= 1);
- --creationDepth.localData();
- depthIncreased = false;
}
return rv;
@@ -955,14 +945,10 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
if (state.completePending) {
+ ++creationDepth.localData();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
complete(ep, &state);
- }
-
- if (depthIncreased) {
- Q_ASSERT(creationDepth.localData() >= 1);
--creationDepth.localData();
- depthIncreased = false;
}
}
@@ -1421,7 +1407,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
QQmlComponentExtension *e = componentExtension(args->v4engine());
- QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->allocObject<QV4::QmlIncubatorObject>(mode));
+ QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->allocate<QV4::QmlIncubatorObject>(mode));
QV4::ScopedObject p(scope, e->incubationProto.value());
r->setPrototype(p);
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 2a8d36f317..9b2db4bccf 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -79,7 +79,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate()
- : typeData(nullptr), progress(0.), start(-1), engine(nullptr), creationContext(nullptr), depthIncreased(false) {}
+ : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
@@ -95,11 +95,11 @@ public:
QQmlContextData *context,
QQmlContextData *forContext);
- QQmlTypeData *typeData;
+ QQmlRefPointer<QQmlTypeData> typeData;
void typeDataReady(QQmlTypeData *) override;
void typeDataProgress(QQmlTypeData *, qreal) override;
- void fromTypeData(QQmlTypeData *data);
+ void fromTypeData(const QQmlRefPointer<QQmlTypeData> &data);
QUrl url;
qreal progress;
@@ -136,7 +136,6 @@ public:
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
- bool depthIncreased;
void clear();
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 59fefde893..2468de6857 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -232,7 +232,7 @@ public:
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
QVector<DeferredData *> deferredData;
- void deferData(int objectIndex, QV4::CompiledData::CompilationUnit *, QQmlContextData *);
+ void deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &, QQmlContextData *);
void releaseDeferredData();
QV4::WeakValue jsWrapper;
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 4cca8a4d58..8c89cf0e61 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -107,6 +107,7 @@ bool QQmlDirParser::parse(const QString &source)
_components.clear();
_scripts.clear();
_designerSupported = false;
+ _className.clear();
quint16 lineNumber = 0;
bool firstLine = true;
@@ -196,7 +197,8 @@ bool QQmlDirParser::parse(const QString &source)
continue;
}
- // Ignore these. qmlimportscanner uses them.
+ _className = sections[1];
+
} else if (sections[0] == QLatin1String("internal")) {
if (sectionCount != 3) {
reportError(lineNumber, 0,
@@ -377,6 +379,11 @@ bool QQmlDirParser::designerSupported() const
return _designerSupported;
}
+QString QQmlDirParser::className() const
+{
+ return _className;
+}
+
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
{
const QString output = QStringLiteral("{%1 %2.%3}").
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index 820c40238d..d7e29813d1 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -135,6 +135,8 @@ public:
QList<TypeInfo> typeInfos() const;
#endif
+ QString className() const;
+
private:
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
void reportError(quint16 line, quint16 column, const QString &message);
@@ -150,6 +152,7 @@ private:
#ifdef QT_CREATOR
QList<TypeInfo> _typeInfos;
#endif
+ QString _className;
};
typedef QHash<QString,QQmlDirParser::Component> QQmlDirComponents;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index c6b39581a7..759d86c789 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -48,7 +48,6 @@
#include "qqmlcomponent.h"
#include "qqmlvme_p.h"
#include "qqmlstringconverters_p.h"
-#include "qqmlxmlhttprequest_p.h"
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlcomponent_p.h"
@@ -79,13 +78,17 @@
#include <private/qobject_p.h>
#include <private/qmetaobject_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <private/qqmlbind_p.h>
#include <private/qqmlconnections_p.h>
-#if QT_CONFIG(animation)
+#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)
@@ -219,7 +222,7 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3
qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections");
-#if QT_CONFIG(animation)
+#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
@@ -232,8 +235,10 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
// 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
qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package");
#if QT_CONFIG(qml_delegate_model)
@@ -250,7 +255,9 @@ void QQmlEnginePrivate::defineQtQuick2Module()
// register the QtQuick2 types which are implemented in the QtQml module.
registerQtQuick2Types("QtQuick",2,0);
+#if QT_CONFIG(qml_locale)
qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 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);
@@ -951,7 +958,9 @@ void QQmlEnginePrivate::init()
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);
@@ -1365,6 +1374,71 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
}
/*!
+ \fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
+
+ Returns the instance of a singleton type that was registered under \a qmlTypeId.
+
+ The template argument \e T may be either QJSValue or a pointer to a QObject-derived
+ type and depends on how the singleton was registered. If no instance of \e T has been
+ created yet, it is created now. If \a qmlTypeId does not represent a valid singleton
+ type, either a default constructed QJSValue or a \c nullptr is returned.
+
+ QObject* example:
+ \code
+ class MySingleton : public QObject {
+ Q_OBJECT
+ static int typeId;
+ // ...
+ };
+
+ // Register with QObject* callback
+ MySingleton::typeId = qmlRegisterSingletonType<MySingleton>(...);
+
+ // Retrieve as QObject*
+ QQmlEngine engine;
+ MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
+ \endcode
+
+ QJSValue example:
+ \code
+ // Register with QJSValue callback
+ int typeId = qmlRegisterSingletonType(...);
+
+ // Retrieve as QJSValue
+ QQmlEngine engine;
+ QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
+ \endcode
+
+ It is recommended to store the QML type id during registration, e.g. as a static member
+ in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed
+ at run-time.
+
+ \sa qmlRegisterSingletonType(), qmlTypeId()
+ \since 5.12
+*/
+template<>
+QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
+{
+ 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();
+}
+
+/*!
Refreshes all binding expressions that use strings marked for translation.
Call this function after you have installed a new translator with
@@ -1699,7 +1773,7 @@ void QQmlData::NotifyList::layout()
todo = nullptr;
}
-void QQmlData::deferData(int objectIndex, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *context)
+void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *context)
{
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = objectIndex;
@@ -2266,7 +2340,7 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache());
+ return QQmlMetaObject((*iter)->rootPropertyCache().data());
} else {
QQmlType type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type.baseMetaObject());
@@ -2278,7 +2352,7 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache());
+ return QQmlMetaObject((*iter)->rootPropertyCache().data());
} else {
QQmlType type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type.metaObject());
@@ -2290,7 +2364,7 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache();
+ return (*iter)->rootPropertyCache().data();
} else {
QQmlType type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2303,7 +2377,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVe
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache();
+ return (*iter)->rootPropertyCache().data();
} else {
QQmlType type = QQmlMetaType::qmlType(t);
locker.unlock();
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 73ad2754c8..871e6bd9b4 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -143,6 +143,9 @@ public:
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+ template<typename T>
+ T singletonInstance(int qmlTypeId);
+
public Q_SLOTS:
void retranslate();
@@ -167,6 +170,19 @@ private:
Q_DECLARE_PRIVATE(QQmlEngine)
};
+template<>
+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);
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_H
diff --git a/src/qml/qml/qqmlguard_p.h b/src/qml/qml/qqmlguard_p.h
index 808bf4c709..3ac63926a0 100644
--- a/src/qml/qml/qqmlguard_p.h
+++ b/src/qml/qml/qqmlguard_p.h
@@ -106,6 +106,34 @@ protected:
virtual void objectDestroyed(T *) {}
};
+template <typename T>
+class QQmlStrongJSQObjectReference : public QQmlGuard<T>
+{
+public:
+ void setObject(T *o, QObject *parent) {
+ T *old = this->object();
+ if (o == old)
+ return;
+
+ if (m_jsOwnership && old && old->parent() == parent)
+ QQml_setParent_noEvent(old, nullptr);
+
+ this->QQmlGuard<T>::operator=(o);
+
+ if (o && !o->parent() && !QQmlData::keepAliveDuringGarbageCollection(o)) {
+ m_jsOwnership = true;
+ QQml_setParent_noEvent(o, parent);
+ } else {
+ m_jsOwnership = false;
+ }
+ }
+
+private:
+ using QQmlGuard<T>::setObject;
+ using QQmlGuard<T>::operator=;
+ bool m_jsOwnership = false;
+};
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlGuard<QObject>)
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 005db4248e..962c92fdb0 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -735,7 +735,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
int *vmajor, int *vminor, QQmlType *type_return, QString *base,
bool *typeRecursionDetected,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction) const
+ QQmlImport::RecursionRestriction recursionRestriction,
+ QList<QQmlError> *errors) const
{
if (majversion >= 0 && minversion >= 0) {
QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
@@ -818,8 +819,19 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
};
for (uint i = 0; i < sizeof(urlsToTry) / sizeof(urlsToTry[0]); ++i) {
const QString url = urlsToTry[i];
- exists = !typeLoader->absoluteFilePath(QQmlFile::urlToLocalFileOrQrc(url)).isEmpty();
+ const QString localPath = QQmlFile::urlToLocalFileOrQrc(url);
+ exists = !typeLoader->absoluteFilePath(localPath).isEmpty();
if (exists) {
+ // don't let function.qml confuse the use of "new Function(...)" for example.
+ if (!QQml_isFileCaseCorrect(localPath)) {
+ exists = false;
+ if (errors) {
+ QQmlError caseError;
+ caseError.setDescription(QLatin1String("File name case mismatch"));
+ errors->append(caseError);
+ }
+ break;
+ }
qmlUrl = url;
break;
}
@@ -906,7 +918,7 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
for (int i=0; i<imports.count(); ++i) {
const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base,
- &typeRecursionDetected, registrationType, recursionRestriction)) {
+ &typeRecursionDetected, registrationType, recursionRestriction, errors)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
@@ -2048,7 +2060,7 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b
if (QQmlExtensionPlugin *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
// basepath should point to the directory of the module, not the plugin file itself:
- QQmlExtensionPluginPrivate::get(plugin)->baseUrl = QUrl::fromLocalFile(basePath);
+ QQmlExtensionPluginPrivate::get(plugin)->baseUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
iface->registerTypes(moduleId);
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 2437979ef8..283bd40660 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -94,7 +94,8 @@ struct QQmlImportInstance
int *vmajor, int *vminor, QQmlType* type_return,
QString *base = nullptr, bool *typeRecursionDetected = nullptr,
QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
+ QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion,
+ QList<QQmlError> *errors = nullptr) const;
};
class QQmlImportNamespace
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 93ec9421ed..9f2a96d5d9 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -93,8 +93,7 @@ void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionEngine *engine)
QQmlJavaScriptExpression::QQmlJavaScriptExpression()
- : m_error(nullptr),
- m_context(nullptr),
+ : m_context(nullptr),
m_prevExpression(nullptr),
m_nextExpression(nullptr),
m_v4Function(nullptr)
@@ -247,6 +246,9 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
g->Delete();
+ if (!watcher.wasDeleted())
+ setTranslationsCaptured(capture.translationCaptured);
+
ep->propertyCapture = lastPropertyCapture;
return result->asReturnedValue();
@@ -392,7 +394,7 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
{
if (!m_error)
m_error = new QQmlDelayedError;
- return m_error;
+ return m_error.data();
}
QV4::ReturnedValue
@@ -458,7 +460,7 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
setCompilationUnit(m_v4Function->compilationUnit);
}
-void QQmlJavaScriptExpression::setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit)
+void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
{
m_compilationUnit = compilationUnit;
}
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 01af3b89ca..de3fba0774 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -162,7 +162,7 @@ protected:
}
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
- void setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit);
+ void setCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
// We store some flag bits in the following flag pointers.
// activeGuards:flag1 - notifyOnValueChanged
@@ -171,13 +171,17 @@ protected:
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards;
+ void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); }
+ bool translationsCaptured() const { return m_error.flag(); }
+
private:
friend class QQmlContextData;
friend class QQmlPropertyCapture;
friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
friend class QQmlTranslationBinding;
- QQmlDelayedError *m_error;
+ // m_error:flag1 translationsCapturedDuringEvaluation
+ QFlagPointer<QQmlDelayedError> m_error;
QQmlContextData *m_context;
QQmlJavaScriptExpression **m_prevExpression;
@@ -208,12 +212,14 @@ public:
static void registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction);
void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce);
void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true);
+ void captureTranslation() { translationCaptured = true; }
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
QQmlJavaScriptExpression::DeleteWatcher *watcher;
QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
QStringList *errorString;
+ bool translationCaptured = false;
};
QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
@@ -260,18 +266,17 @@ void QQmlJavaScriptExpression::setScopeObject(QObject *v)
bool QQmlJavaScriptExpression::hasError() const
{
- return m_error && m_error->isValid();
+ return !m_error.isNull() && m_error->isValid();
}
bool QQmlJavaScriptExpression::hasDelayedError() const
{
- return m_error;
+ return !m_error.isNull();
}
inline void QQmlJavaScriptExpression::clearError()
{
- if (m_error)
- delete m_error;
+ delete m_error.data();
m_error = nullptr;
}
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 3fbe3df2ab..5e30f09eec 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -74,7 +74,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, i
Scope scope(engine);
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>());
+ Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
r->d()->object = object;
r->d()->propertyType = propType;
void *args[] = { &r->d()->property(), nullptr };
@@ -86,7 +86,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProp
{
Scope scope(engine);
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>());
+ Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
r->d()->object = prop.object;
r->d()->property() = prop;
r->d()->propertyType = propType;
@@ -102,9 +102,14 @@ QVariant QmlListWrapper::toVariant() const
}
-ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QmlListWrapper::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<QmlListWrapper>());
+
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
@@ -140,7 +145,7 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has
return Primitive::undefinedValue().asReturnedValue();
}
-bool QmlListWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlListWrapper::put(Managed *m, StringOrSymbol *name, const Value &value)
{
// doesn't do anything. Should we throw?
Q_UNUSED(m);
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index e02831c8d1..4b53d91933 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -93,9 +93,9 @@ struct Q_QML_EXPORT QmlListWrapper : Object
QVariant toVariant() const;
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
};
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index b4f7092a22..c5a85dd4d3 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -350,7 +350,7 @@ ReturnedValue QQmlDateExtension::method_timeZoneUpdated(const QV4::FunctionObjec
if (argc != 0)
THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
- QV4::DatePrototype::timezoneUpdated();
+ QV4::DatePrototype::timezoneUpdated(scope.engine);
RETURN_UNDEFINED();
}
@@ -825,7 +825,7 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale)
{
QV4::Scope scope(v4);
QV4LocaleDataDeletable *d = localeV4Data(scope.engine);
- QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocObject<QQmlLocaleData>());
+ QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocate<QQmlLocaleData>());
*wrapper->d()->locale = locale;
QV4::ScopedObject p(scope, d->prototype.value());
wrapper->setPrototype(p);
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 8341b1f555..859c36e11b 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -58,6 +58,8 @@
#include <private/qqmlglobal_p.h>
#include <private/qv4object_p.h>
+QT_REQUIRE_CONFIG(qml_locale);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index d842a7795f..dd027818cd 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -264,7 +264,14 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
{
if (scriptCallback && scriptApi(e).isUndefined()) {
- setScriptApi(e, scriptCallback(e, e));
+ 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);
@@ -273,6 +280,9 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
}
// 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());
@@ -576,7 +586,7 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
Q_ASSERT(isComposite());
if (!engine || !d)
return QQmlType();
- QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return QQmlType();
QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
@@ -590,11 +600,11 @@ QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) c
Q_ASSERT(isComposite());
if (!engine)
return nullptr;
- QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return nullptr;
QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
- return compilationUnit->rootPropertyCache();
+ return compilationUnit->rootPropertyCache().data();
}
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
@@ -841,7 +851,7 @@ QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersio
{
for (int i = 0; i < propertyCaches.count(); ++i)
if (propertyCaches.at(i).minorVersion == minorVersion)
- return propertyCaches.at(i).cache;
+ return propertyCaches.at(i).cache.data();
return nullptr;
}
@@ -1853,6 +1863,23 @@ void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
p->maxMinorVersion = qMax(p->maxMinorVersion, versionMinor);
}
+//From qqml.h
+int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+ if (!module)
+ return -1;
+
+ QQmlType type = module->type(QHashedStringRef(qmlName), versionMinor);
+ if (!type.isValid())
+ return -1;
+
+ return type.index();
+}
+
bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri, int majorVersion)
{
const QQmlMetaTypeData *data = metaTypeData();
@@ -2232,19 +2259,25 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStrin
}
/*!
- Returns the type (if any) that corresponds to the QVariant::Type \a userType.
- Returns null if no type is registered.
+ Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
+ \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
+ qml type registration functions. Returns null if no type is registered.
*/
-QQmlType QQmlMetaType::qmlType(int userType)
+QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
{
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- QQmlTypePrivate *type = data->idToType.value(userType);
- if (type && type->typeId == userType)
- return QQmlType(type);
- else
- return QQmlType();
+ if (category == TypeIdCategory::MetaType) {
+ QQmlTypePrivate *type = data->idToType.value(typeId);
+ if (type && type->typeId == typeId)
+ return QQmlType(type);
+ } else if (category == TypeIdCategory::QmlType) {
+ QQmlType type = data->types.value(typeId);
+ if (type.isValid())
+ return type;
+ }
+ return QQmlType();
}
/*!
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 51bf485a3e..6df439cd7a 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -91,11 +91,16 @@ public:
static QList<QQmlType> qmlSingletonTypes();
static QList<QQmlType> qmlAllTypes();
+ enum class TypeIdCategory {
+ MetaType,
+ QmlType
+ };
+
static QQmlType qmlType(const QString &qualifiedName, int, int);
static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int);
static QQmlType qmlType(const QMetaObject *);
static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor);
- static QQmlType qmlType(int);
+ static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType);
static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false);
static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 5aaf79c9e5..f6f18ab35f 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -71,7 +71,7 @@ struct ActiveOCRestorer
};
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext,
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *creationContext,
QQmlIncubatorPrivate *incubator)
: phase(Startup)
, compilationUnit(compilationUnit)
@@ -99,7 +99,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::Compil
}
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
: phase(Startup)
, compilationUnit(compilationUnit)
, resolvedTypes(compilationUnit->resolvedTypes)
@@ -193,7 +193,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context->importedScripts.set(v4, scripts);
QV4::ScopedValue v(scope);
for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
- QQmlScriptData *s = compilationUnit->dependentScripts.at(i);
+ QQmlRefPointer<QQmlScriptData> s = compilationUnit->dependentScripts.at(i);
scripts->putIndexed(i, (v = s->scriptValueForContext(context)));
}
} else if (sharedState->creationContext) {
@@ -252,7 +252,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::
Q_ASSERT(!sharedState->allJavaScriptObjects);
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
@@ -312,7 +312,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
if (!sharedState->allJavaScriptObjects)
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
@@ -1144,9 +1144,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
isComponent = true;
- QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
+ QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compilationUnit, obj, QStringLiteral("<component>"), context->url()));
+ compilationUnit.data(), obj, QStringLiteral("<component>"), context->url()));
QQmlComponentPrivate::get(component)->creationContext = context;
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
@@ -1157,7 +1157,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlType type = typeRef->type;
if (type.isValid()) {
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compilationUnit, obj, type.qmlTypeName(), context->url()));
+ compilationUnit.data(), obj, type.qmlTypeName(), context->url()));
void *ddataMemory = nullptr;
type.create(&instance, &ddataMemory, sizeof(QQmlData));
@@ -1190,8 +1190,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
} else {
Q_ASSERT(typeRef->compilationUnit);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
- compilationUnit, obj, typeRef->compilationUnit->fileName(),
- context->url()));
+ compilationUnit.data(), obj, typeRef->compilationUnit->fileName(),
+ context->url()));
if (typeRef->compilationUnit->data->isSingleton())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
@@ -1254,7 +1254,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->typeNameCache;
+ customParser->imports = compilationUnit->typeNameCache.data();
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
@@ -1264,7 +1264,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
bindings << binding;
}
}
- customParser->applyBindings(instance, compilationUnit, bindings);
+ customParser->applyBindings(instance, compilationUnit.data(), bindings);
customParser->engine = nullptr;
customParser->imports = (QQmlTypeNameCache*)nullptr;
@@ -1280,7 +1280,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (installPropertyCache) {
if (ddata->propertyCache)
ddata->propertyCache->release();;
- ddata->propertyCache = cache;
+ ddata->propertyCache = cache.data();
ddata->propertyCache->addref();
}
@@ -1292,7 +1292,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
++sharedState->allJavaScriptObjects;
QV4::Scope valueScope(v4);
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
@@ -1344,6 +1344,11 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
+ if (!b->isValueTypeProxy()) {
+ QQmlBinding *binding = static_cast<QQmlBinding*>(b.data());
+ if (!binding->hasError() && !binding->hasDependencies())
+ b->removeFromObject();
+ }
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return nullptr;
@@ -1436,7 +1441,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
if (_ddata->propertyCache)
_ddata->propertyCache->release();
- _ddata->propertyCache = cache;
+ _ddata->propertyCache = cache.data();
_ddata->propertyCache->addref();
scopeObjectProtector = _ddata->jsWrapper.value();
} else {
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 67a5bdd827..435b213341 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -85,7 +85,7 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
+ QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
@@ -104,7 +104,7 @@ public:
QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; }
private:
- QQmlObjectCreator(QQmlContextData *contextData, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
void init(QQmlContextData *parentContext);
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index 1b44bbdda3..fc798a2c23 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -181,46 +181,75 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
class QQmlOpenMetaObjectPrivate
{
public:
- QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q)
- : q(_q), parent(nullptr), type(nullptr), cacheProperties(false) {}
+ QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, bool _autoCreate, QObject *obj)
+ : q(_q), object(obj), autoCreate(_autoCreate) {}
+
+ struct Property {
+ private:
+ QVariant m_value;
+ QPointer<QObject> qobjectTracker;
+ public:
+ bool valueSet = false;
+
+ QVariant value() const {
+ if (QMetaType::typeFlags(m_value.userType()) & QMetaType::PointerToQObject
+ && qobjectTracker.isNull())
+ return QVariant::fromValue<QObject*>(nullptr);
+ return m_value;
+ }
+ QVariant &valueRef() { return m_value; }
+ void setValue(const QVariant &v) {
+ m_value = v;
+ valueSet = true;
+ if (QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject)
+ qobjectTracker = m_value.value<QObject*>();
+ }
+ };
- inline QPair<QVariant, bool> &getDataRef(int idx) {
- while (data.count() <= idx)
- data << QPair<QVariant, bool>(QVariant(), false);
- return data[idx];
+ inline void setPropertyValue(int idx, const QVariant &value) {
+ if (data.count() <= idx)
+ data.resize(idx + 1);
+ data[idx].setValue(value);
}
- inline QVariant &getData(int idx) {
- QPair<QVariant, bool> &prop = getDataRef(idx);
- if (!prop.second) {
- prop.first = q->initialValue(idx);
- prop.second = true;
- }
- return prop.first;
+ inline Property &propertyRef(int idx) {
+ if (data.count() <= idx)
+ data.resize(idx + 1);
+ Property &prop = data[idx];
+ if (!prop.valueSet)
+ prop.setValue(q->initialValue(idx));
+ return prop;
+ }
+
+ inline QVariant propertyValue(int idx) {
+ auto &prop = propertyRef(idx);
+ return prop.value();
+ }
+
+ inline QVariant &propertyValueRef(int idx) {
+ auto &prop = propertyRef(idx);
+ return prop.valueRef();
}
- inline bool hasData(int idx) const {
+ inline bool hasProperty(int idx) const {
if (idx >= data.count())
return false;
- return data[idx].second;
+ return data[idx].valueSet;
}
- bool autoCreate;
QQmlOpenMetaObject *q;
- QAbstractDynamicMetaObject *parent;
- QList<QPair<QVariant, bool> > data;
+ QAbstractDynamicMetaObject *parent = nullptr;
+ QVector<Property> data;
QObject *object;
- QQmlOpenMetaObjectType *type;
- bool cacheProperties;
+ QQmlRefPointer<QQmlOpenMetaObjectType> type;
+ bool autoCreate;
+ bool cacheProperties = false;
};
QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this))
+: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
{
- d->autoCreate = automatic;
- d->object = obj;
-
- d->type = new QQmlOpenMetaObjectType(base ? base : obj->metaObject(), nullptr);
+ d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject(), nullptr));
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -230,13 +259,9 @@ QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base, bo
}
QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, QQmlOpenMetaObjectType *type, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this))
+: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
{
- d->autoCreate = automatic;
- d->object = obj;
-
d->type = type;
- d->type->addref();
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -250,13 +275,12 @@ QQmlOpenMetaObject::~QQmlOpenMetaObject()
if (d->parent)
delete d->parent;
d->type->d->referers.remove(this);
- d->type->release();
delete d;
}
QQmlOpenMetaObjectType *QQmlOpenMetaObject::type() const
{
- return d->type;
+ return d->type.data();
}
void QQmlOpenMetaObject::emitPropertyNotification(const QByteArray &propertyName)
@@ -276,13 +300,11 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
int propId = id - d->type->d->propertyOffset;
if (c == QMetaObject::ReadProperty) {
propertyRead(propId);
- *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId);
+ *reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
} else if (c == QMetaObject::WriteProperty) {
- if (propId >= d->data.count() || d->data.at(propId).first != *reinterpret_cast<QVariant *>(a[0])) {
+ if (propId >= d->data.count() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
- QPair<QVariant, bool> &prop = d->getDataRef(propId);
- prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
- prop.second = true;
+ d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
propertyWritten(propId);
activate(o, d->type->d->signalOffset + propId, nullptr);
}
@@ -303,14 +325,12 @@ QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
QVariant QQmlOpenMetaObject::value(int id) const
{
- return d->getData(id);
+ return d->propertyValue(id);
}
void QQmlOpenMetaObject::setValue(int id, const QVariant &value)
{
- QPair<QVariant, bool> &prop = d->getDataRef(id);
- prop.first = propertyWriteValue(id, value);
- prop.second = true;
+ d->setPropertyValue(id, propertyWriteValue(id, value));
activate(d->object, id + d->type->d->signalOffset, nullptr);
}
@@ -320,23 +340,18 @@ QVariant QQmlOpenMetaObject::value(const QByteArray &name) const
if (iter == d->type->d->names.cend())
return QVariant();
- return d->getData(*iter);
+ return d->propertyValue(*iter);
}
-QVariant &QQmlOpenMetaObject::operator[](const QByteArray &name)
+QVariant &QQmlOpenMetaObject::valueRef(const QByteArray &name)
{
QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name);
Q_ASSERT(iter != d->type->d->names.cend());
- return d->getData(*iter);
-}
-
-QVariant &QQmlOpenMetaObject::operator[](int id)
-{
- return d->getData(id);
+ return d->propertyValueRef(*iter);
}
-bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
+bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val, bool force)
{
QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(name);
@@ -348,11 +363,10 @@ bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
}
if (id >= 0) {
- QVariant &dataVal = d->getData(id);
- if (dataVal == val)
+ if (!force && d->propertyValue(id) == val)
return false;
- dataVal = val;
+ d->setPropertyValue(id, val);
activate(d->object, id + d->type->d->signalOffset, nullptr);
return true;
}
@@ -363,7 +377,7 @@ bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
// returns true if this value has been initialized by a call to either value() or setValue()
bool QQmlOpenMetaObject::hasValue(int id) const
{
- return d->hasData(id);
+ return d->hasProperty(id);
}
void QQmlOpenMetaObject::setCached(bool c)
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
index 4905190b75..168a2a6f7f 100644
--- a/src/qml/qml/qqmlopenmetaobject_p.h
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -100,11 +100,10 @@ public:
~QQmlOpenMetaObject() override;
QVariant value(const QByteArray &) const;
- bool setValue(const QByteArray &, const QVariant &);
+ bool setValue(const QByteArray &, const QVariant &, bool force = false);
QVariant value(int) const;
void setValue(int, const QVariant &);
- QVariant &operator[](const QByteArray &);
- QVariant &operator[](int);
+ QVariant &valueRef(const QByteArray &);
bool hasValue(int) const;
int count() const;
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index c4487f91a3..bc0124eeab 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -255,7 +255,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
{
if (!obj) return;
- QQmlTypeNameCache *typeNameCache = context?context->imports:nullptr;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context?context->imports:nullptr;
QObject *currentObject = obj;
QVector<QStringRef> path;
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index b78a2ddd20..0785910cec 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -979,13 +979,13 @@ public:
void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
- void set(int index, QQmlPropertyCache *replacement) {
+ void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
if (QQmlPropertyCache *oldCache = data.at(index).data()) {
- if (replacement == oldCache)
+ if (replacement.data() == oldCache)
return;
oldCache->release();
}
- data[index] = replacement;
+ data[index] = replacement.data();
replacement->addref();
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index c656fac4ff..e886198e80 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -504,11 +504,12 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
if (!blob ||
blob->status() == Error || blob->status() == Complete ||
- status() == Error || status() == Complete || m_isDone ||
- m_waitingFor.contains(blob))
+ status() == Error || status() == Complete || m_isDone)
return;
- blob->addref();
+ for (auto existingDep: qAsConst(m_waitingFor))
+ if (existingDep.data() == blob)
+ return;
m_data.setStatus(WaitingForDependencies);
@@ -691,13 +692,11 @@ void QQmlDataBlob::tryDone()
void QQmlDataBlob::cancelAllWaitingFor()
{
while (m_waitingFor.count()) {
- QQmlDataBlob *blob = m_waitingFor.takeLast();
+ QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
Q_ASSERT(blob->m_waitingOnMe.contains(this));
blob->m_waitingOnMe.removeOne(this);
-
- blob->release();
}
}
@@ -706,7 +705,8 @@ void QQmlDataBlob::notifyAllWaitingOnMe()
while (m_waitingOnMe.count()) {
QQmlDataBlob *blob = m_waitingOnMe.takeLast();
- Q_ASSERT(blob->m_waitingFor.contains(this));
+ 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);
}
@@ -714,13 +714,19 @@ void QQmlDataBlob::notifyAllWaitingOnMe()
void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
{
- Q_ASSERT(m_waitingFor.contains(blob));
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
m_inCallback = true;
- m_waitingFor.removeOne(blob);
+ 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);
@@ -728,8 +734,6 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
dependencyComplete(blob);
}
- blob->release();
-
if (!isError() && m_waitingFor.isEmpty())
allDependenciesDone();
@@ -1327,20 +1331,17 @@ QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoa
QQmlTypeLoader::Blob::~Blob()
{
- for (int ii = 0; ii < m_qmldirs.count(); ++ii)
- m_qmldirs.at(ii)->release();
}
bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors)
{
- QQmlQmldirData *data = typeLoader()->getQmldir(url);
+ QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
data->setImport(this, import);
data->setPriority(this, priority);
if (data->status() == Error) {
// This qmldir must not exist - which is not an error
- data->release();
return true;
} else if (data->status() == Complete) {
// This data is already available
@@ -1348,11 +1349,11 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData:
}
// Wait for this data to become available
- addDependency(data);
+ addDependency(data.data());
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
@@ -1378,8 +1379,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob);
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob.data());
scriptImported(blob, import->location, script.nameSpace, importQualifier);
}
@@ -1398,8 +1399,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
const QString &importQualifier = stringAt(import->qualifierIndex);
if (import->type == QV4::CompiledData::Import::ImportScript) {
QUrl scriptUrl = finalUrl().resolved(QUrl(importUri));
- QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob);
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob.data());
scriptImported(blob, import->location, importQualifier, QString());
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
@@ -1426,8 +1427,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob);
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob.data());
scriptImported(blob, import->location, script.nameSpace, importQualifier);
}
@@ -1499,14 +1500,6 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
return true;
}
-void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob)
-{
- if (blob->type() == QQmlDataBlob::QmldirFile) {
- QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
- data->release();
- }
-}
-
void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
@@ -1532,7 +1525,7 @@ bool QQmlTypeLoader::Blob::isDebugging() const
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
{
bool resolve = true;
@@ -1552,7 +1545,6 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
if (resolve) {
// This is the (current) best resolution for this import
if (!updateQmldir(data, import, errors)) {
- data->release();
return false;
}
@@ -1562,7 +1554,6 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
}
}
- data->release();
return true;
}
@@ -1664,7 +1655,7 @@ QUrl QQmlTypeLoader::normalize(const QUrl &unNormalizedUrl)
/*!
Returns a QQmlTypeData for the specified \a url. The QQmlTypeData may be cached.
*/
-QQmlTypeData *QQmlTypeLoader::getType(const QUrl &unNormalizedUrl, Mode mode)
+QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl, Mode mode)
{
Q_ASSERT(!unNormalizedUrl.isRelative() &&
(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
@@ -1707,8 +1698,6 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &unNormalizedUrl, Mode mode)
}
}
- typeData->addref();
-
return typeData;
}
@@ -1716,20 +1705,20 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &unNormalizedUrl, Mode mode)
Returns a QQmlTypeData for the given \a data with the provided base \a url. The
QQmlTypeData will not be cached.
*/
-QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url, Mode mode)
+QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url, Mode mode)
{
LockHolder<QQmlTypeLoader> holder(this);
QQmlTypeData *typeData = new QQmlTypeData(url, this);
QQmlTypeLoader::loadWithStaticData(typeData, data, mode);
- return typeData;
+ return QQmlRefPointer<QQmlTypeData>(typeData, QQmlRefPointer<QQmlTypeData>::Adopt);
}
/*!
Return a QQmlScriptBlob for \a url. The QQmlScriptData may be cached.
*/
-QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &unNormalizedUrl)
+QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(const QUrl &unNormalizedUrl)
{
Q_ASSERT(!unNormalizedUrl.isRelative() &&
(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
@@ -1754,15 +1743,13 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &unNormalizedUrl)
}
}
- scriptBlob->addref();
-
return scriptBlob;
}
/*!
Returns a QQmlQmldirData for \a url. The QQmlQmldirData may be cached.
*/
-QQmlQmldirData *QQmlTypeLoader::getQmldir(const QUrl &url)
+QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url)
{
Q_ASSERT(!url.isRelative() &&
(QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
@@ -1778,8 +1765,6 @@ QQmlQmldirData *QQmlTypeLoader::getQmldir(const QUrl &url)
QQmlTypeLoader::load(qmldirData);
}
- qmldirData->addref();
-
return qmldirData;
}
@@ -2073,17 +2058,9 @@ QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
QQmlTypeData::~QQmlTypeData()
{
- for (int ii = 0; ii < m_scripts.count(); ++ii)
- m_scripts.at(ii).script->release();
- for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
- if (QQmlTypeData *tdata = m_compositeSingletons.at(ii).typeData)
- tdata->release();
- }
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd();
- it != end; ++it) {
- if (QQmlTypeData *tdata = it->typeData)
- tdata->release();
- }
+ m_scripts.clear();
+ m_compositeSingletons.clear();
+ m_resolvedTypes.clear();
}
const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
@@ -2201,7 +2178,7 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName
{
QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches,
&pendingGroupPropertyBindings,
- engine, m_compiledData, &m_importCache);
+ engine, m_compiledData.data(), &m_importCache);
QQmlCompileError error = propertyCacheCreator.buildMetaObjects();
if (error.isSet()) {
setError(error);
@@ -2209,7 +2186,7 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName
}
}
- QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData);
+ QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData.data());
aliasCreator.appendAliasPropertiesToMetaObjects();
pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
@@ -2393,8 +2370,7 @@ void QQmlTypeData::done()
}
m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
- QQmlScriptData *scriptData = script.script->scriptData();
- scriptData->addref();
+ QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
m_compiledData->dependentScripts << scriptData;
}
}
@@ -2637,8 +2613,8 @@ void QQmlTypeData::resolveTypes()
// Add any imported scripts to our resolved set
const auto resolvedScripts = m_importCache.resolvedScripts();
for (const QQmlImports::ScriptReference &script : resolvedScripts) {
- QQmlScriptBlob *blob = typeLoader()->getScript(script.location);
- addDependency(blob);
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
+ addDependency(blob.data());
ScriptReference ref;
//ref.location = ...
@@ -2681,7 +2657,7 @@ void QQmlTypeData::resolveTypes()
// TODO: give an error message? If so, we should record and show the path of the cycle.
continue;
}
- addDependency(ref.typeData);
+ addDependency(ref.typeData.data());
ref.prefix = csRef.prefix;
m_compositeSingletons << ref;
@@ -2711,7 +2687,7 @@ void QQmlTypeData::resolveTypes()
if (ref.type.isComposite()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- addDependency(ref.typeData);
+ addDependency(ref.typeData.data());
}
ref.majorVersion = majorVersion;
ref.minorVersion = minorVersion;
@@ -2743,7 +2719,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
(*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
- m_importCache.populateCache(*typeNameCache);
+ m_importCache.populateCache(typeNameCache->data());
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2833,7 +2809,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &
return true;
}
-void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
{
ScriptReference ref;
ref.script = blob;
@@ -2959,8 +2935,6 @@ void QQmlScriptData::clear()
typeNameCache = nullptr;
}
- for (int ii = 0; ii < scripts.count(); ++ii)
- scripts.at(ii)->release();
scripts.clear();
// An addref() was made when the QQmlCleanup was added to the engine.
@@ -2968,19 +2942,15 @@ void QQmlScriptData::clear()
}
QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
-: QQmlTypeLoader::Blob(url, JavaScriptFile, loader), m_scriptData(nullptr)
+: QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
{
}
QQmlScriptBlob::~QQmlScriptBlob()
{
- if (m_scriptData) {
- m_scriptData->release();
- m_scriptData = nullptr;
- }
}
-QQmlScriptData *QQmlScriptBlob::scriptData() const
+QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
{
return m_scriptData;
}
@@ -3017,11 +2987,12 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
}
QmlIR::ScriptDirectivesCollector collector(&irUnit);
+ irUnit.jsParserEngine.setDirectives(&collector);
QList<QQmlError> errors;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(
- &irUnit.jsModule, &irUnit.jsGenerator, urlString(), finalUrlString(),
- source, &errors, &collector);
+ &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(),
+ source, &errors);
// No need to addref on unit, it's initial refcount is 1
source.clear();
if (!errors.isEmpty()) {
@@ -3095,6 +3066,7 @@ void QQmlScriptBlob::done()
}
m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
+ m_scripts.clear();
m_importCache.populateCache(m_scriptData->typeNameCache);
}
@@ -3104,7 +3076,7 @@ QString QQmlScriptBlob::stringAt(int index) const
return m_scriptData->m_precompiledScript->data->stringAt(index);
}
-void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
+void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
{
ScriptReference ref;
ref.script = blob;
@@ -3118,7 +3090,7 @@ void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledDat
void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
{
Q_ASSERT(!m_scriptData);
- m_scriptData = new QQmlScriptData();
+ m_scriptData.adopt(new QQmlScriptData());
m_scriptData->url = finalUrl();
m_scriptData->urlString = finalUrlString();
m_scriptData->m_precompiledScript = unit;
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index e75719866d..98ac4b1bc1 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -217,7 +217,7 @@ private:
QList<QQmlDataBlob *> m_waitingOnMe;
// List of QQmlDataBlob's that I am waiting for to complete.
- QList<QQmlDataBlob *> m_waitingFor;
+ QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
int m_redirectCount:30;
bool m_inCallback:1;
@@ -279,14 +279,13 @@ public:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
private:
- virtual bool qmldirDataAvailable(QQmlQmldirData *, QList<QQmlError> *);
+ virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
- virtual void scriptImported(QQmlScriptBlob *, const QV4::CompiledData::Location &, const QString &, const QString &) {}
+ virtual void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &, const QV4::CompiledData::Location &, const QString &, const QString &) {}
- void dependencyError(QQmlDataBlob *) override;
void dependencyComplete(QQmlDataBlob *) override;
protected:
@@ -296,7 +295,7 @@ public:
QQmlImports m_importCache;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
- QList<QQmlQmldirData *> m_qmldirs;
+ QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
};
@@ -307,11 +306,11 @@ public:
static QUrl normalize(const QUrl &unNormalizedUrl);
- QQmlTypeData *getType(const QUrl &unNormalizedUrl, Mode mode = PreferSynchronous);
- QQmlTypeData *getType(const QByteArray &, const QUrl &url, Mode mode = PreferSynchronous);
+ QQmlRefPointer<QQmlTypeData> getType(const QUrl &unNormalizedUrl, Mode mode = PreferSynchronous);
+ QQmlRefPointer<QQmlTypeData> getType(const QByteArray &, const QUrl &url, Mode mode = PreferSynchronous);
- QQmlScriptBlob *getScript(const QUrl &unNormalizedUrl);
- QQmlQmldirData *getQmldir(const QUrl &);
+ QQmlRefPointer<QQmlScriptBlob> getScript(const QUrl &unNormalizedUrl);
+ QQmlRefPointer<QQmlQmldirData> getQmldir(const QUrl &);
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
@@ -424,13 +423,13 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
public:
struct TypeReference
{
- TypeReference() : majorVersion(0), minorVersion(0), typeData(nullptr), needsCreation(true) {}
+ TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
QV4::CompiledData::Location location;
QQmlType type;
int majorVersion;
int minorVersion;
- QQmlTypeData *typeData;
+ QQmlRefPointer<QQmlTypeData> typeData;
QString prefix; // used by CompositeSingleton types
QString qualifiedName() const;
bool needsCreation;
@@ -438,11 +437,9 @@ public:
struct ScriptReference
{
- ScriptReference() : script(nullptr) {}
-
QV4::CompiledData::Location location;
QString qualifier;
- QQmlScriptBlob *script;
+ QQmlRefPointer<QQmlScriptBlob> script;
};
private:
@@ -495,7 +492,7 @@ private:
bool reportErrors = true,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
- void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ 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.
@@ -541,7 +538,7 @@ public:
QUrl url;
QString urlString;
QQmlTypeNameCache *typeNameCache;
- QList<QQmlScriptBlob *> scripts;
+ QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
@@ -571,15 +568,13 @@ public:
struct ScriptReference
{
- ScriptReference() : script(nullptr) {}
-
QV4::CompiledData::Location location;
QString qualifier;
QString nameSpace;
- QQmlScriptBlob *script;
+ QQmlRefPointer<QQmlScriptBlob> script;
};
- QQmlScriptData *scriptData() const;
+ QQmlRefPointer<QQmlScriptData> scriptData() const;
protected:
void dataReceived(const SourceCodeData &) override;
@@ -589,11 +584,11 @@ protected:
QString stringAt(int index) const override;
private:
- void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ 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;
- QQmlScriptData *m_scriptData;
+ QQmlRefPointer<QQmlScriptData> m_scriptData;
};
class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index ce35e966aa..7270cffb00 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -95,12 +95,17 @@ QObject* QQmlTypeWrapper::singletonObject() const
QVariant QQmlTypeWrapper::toVariant() const
{
- QObject *qobjectSingleton = singletonObject();
- if (qobjectSingleton)
+ // Only Singleton type wrappers can be converted to a variant.
+ if (!isSingleton())
+ return QVariant();
+
+ QQmlEngine *e = engine()->qmlEngine();
+ QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
+ siinfo->init(e);
+ if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
return QVariant::fromValue<QObject*>(qobjectSingleton);
- // only QObject Singleton Type can be converted to a variant.
- return QVariant();
+ return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e));
}
@@ -111,7 +116,7 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o,
Q_ASSERT(t.isValid());
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
w->d()->mode = mode; w->d()->object = o;
w->d()->typePrivate = t.priv();
QQmlType::refHandle(w->d()->typePrivate);
@@ -120,15 +125,15 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o,
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
// namespace.
-ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace,
+ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
- w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace;
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
+ w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
t->addref();
return w.asReturnedValue();
}
@@ -162,10 +167,14 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n
return v4->throwTypeError(message);
}
-ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlTypeWrapper::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlTypeWrapper>());
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
QV4::Scope scope(v4);
@@ -232,7 +241,7 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp
value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
if (ok) {
- Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>());
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
enumWrapper->d()->typePrivate = type.priv();
QQmlType::refHandle(enumWrapper->d()->typePrivate);
enumWrapper->d()->scopeEnumIndex = value;
@@ -295,8 +304,12 @@ ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProp
}
-bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlTypeWrapper::put(Managed *m, StringOrSymbol *n, const Value &value)
{
+ if (n->isSymbol())
+ return Object::put(m, n, value);
+ String *name = static_cast<String *>(n);
+
Q_ASSERT(m->as<QQmlTypeWrapper>());
QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
@@ -337,11 +350,14 @@ bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value)
return false;
}
-PropertyAttributes QQmlTypeWrapper::query(const Managed *m, String *name)
+PropertyAttributes QQmlTypeWrapper::query(const Managed *m, StringOrSymbol *name)
{
+ if (name->isSymbol())
+ return Object::query(m, name);
+ String *n = static_cast<String *>(name);
// ### Implement more efficiently.
bool hasProperty = false;
- static_cast<Object *>(const_cast<Managed*>(m))->get(name, &hasProperty);
+ static_cast<Object *>(const_cast<Managed*>(m))->get(n, &hasProperty);
return hasProperty ? Attr_Data : Attr_Invalid;
}
@@ -385,10 +401,9 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value
if (!theirDData->compilationUnit)
return Encode(false);
- QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
+ QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
CompiledData::CompilationUnit *cu = td->compilationUnit();
myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
- td->release();
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
}
@@ -410,9 +425,13 @@ QQmlType Heap::QQmlScopedEnumWrapper::type() const
return QQmlType(typePrivate);
}
-ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 25ff7ba7c8..30bbc8d179 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -108,13 +108,13 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
- static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const QQmlImportRef *,
+ static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
- static PropertyAttributes query(const Managed *, String *name);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
+ static PropertyAttributes query(const Managed *, StringOrSymbol *name);
static bool isEqualTo(Managed *that, Managed *o);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
};
@@ -124,7 +124,7 @@ struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
V4_OBJECT2(QQmlScopedEnumWrapper, Object)
V4_NEEDS_DESTROY
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
};
}
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index ba0d305bd9..35b54c339b 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -55,7 +55,7 @@
QT_BEGIN_NAMESPACE
-class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
+class Q_AUTOTEST_EXPORT QQmlValueTypeProxyBinding : public QQmlAbstractBinding
{
public:
QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 6196a09d94..7e0cf64bed 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -186,7 +186,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocObject<QQmlValueTypeReference>());
+ Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocate<QQmlValueTypeReference>());
r->d()->object = object;
r->d()->property = property;
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
@@ -200,7 +200,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocObject<QQmlValueTypeWrapper>());
+ Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
r->d()->gadgetPtr = nullptr;
@@ -241,12 +241,16 @@ bool QQmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other)
return false;
}
-PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name)
+PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, StringOrSymbol *name)
{
+ if (name->isSymbol())
+ return Object::query(m, name);
+
+ String *n = static_cast<String *>(name);
Q_ASSERT(m->as<const QQmlValueTypeWrapper>());
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData *result = r->d()->propertyCache()->property(name, nullptr, nullptr);
+ QQmlPropertyData *result = r->d()->propertyCache()->property(n, nullptr, nullptr);
return result ? Attr_Data : Attr_Invalid;
}
@@ -355,9 +359,14 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
return Encode(b->engine()->newString(result));
}
-ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlValueTypeWrapper>());
+
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = r->engine();
@@ -413,8 +422,12 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
#undef VALUE_TYPE_ACCESSOR
}
-bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlValueTypeWrapper::put(Managed *m, StringOrSymbol *n, const Value &value)
{
+ if (n->isSymbol())
+ return Object::put(m, n, value);
+ String *name = static_cast<String *>(n);
+
Q_ASSERT(m->as<QQmlValueTypeWrapper>());
ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
Scope scope(v4);
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index f99d207d68..5a684bfb4d 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -106,10 +106,10 @@ public:
int typeId() const;
bool write(QObject *target, int propertyIndex) const;
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static bool put(Managed *m, String *name, const Value &value);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
+ static bool put(Managed *m, StringOrSymbol *name, const Value &value);
static bool isEqualTo(Managed *m, Managed *other);
- static PropertyAttributes query(const Managed *, String *name);
+ static PropertyAttributes query(const Managed *, StringOrSymbol *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static ReturnedValue method_toString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 9a94ac6258..13c5524d96 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -124,6 +124,10 @@ private:
// Used to check that a QQmlVME that is interrupted mid-execution
// is still valid. Checks all the objects and contexts have not been
// deleted.
+//
+// VME stands for Virtual Machine Execution. QML files used to
+// be compiled to a byte code data structure that a virtual machine executed
+// (for constructing the tree of QObjects and setting properties).
class QQmlVMEGuard
{
public:
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index c1d3980b58..6bc0f0aa1e 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -106,7 +106,7 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
QV4::Scope scope(v4);
QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
if (sp) {
- QV4::MemberData::Index index{ sp->d(), sp->d()->values.values + m_index };
+ QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + m_index };
index.set(v4, QV4::Primitive::nullValue());
}
}
@@ -176,7 +176,7 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
}
-QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, QQmlPropertyCache *cache)
+QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache)
: object(obj),
cache(cache),
interceptors(nullptr),
@@ -316,7 +316,7 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje
QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
QObject *obj,
- QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId)
+ const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
engine(engine),
ctxt(QQmlData::get(obj, true)->outerContext),
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 0c82686d47..dbcc9d2884 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -94,7 +94,7 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlInterceptorMetaObject : public QAbstractDynamicMetaObject
{
public:
- QQmlInterceptorMetaObject(QObject *obj, QQmlPropertyCache *cache);
+ QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache);
~QQmlInterceptorMetaObject() override;
void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor);
@@ -104,7 +104,7 @@ public:
QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o) override;
// Used by auto-tests for inspection
- QQmlPropertyCache *propertyCache() const { return cache; }
+ QQmlPropertyCache *propertyCache() const { return cache.data(); }
bool intercepts(QQmlPropertyIndex propertyIndex) const
{
@@ -146,7 +146,7 @@ class QQmlVMEMetaObjectEndpoint;
class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
- QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId);
+ QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlCompilationUnit, int qmlObjectId);
~QQmlVMEMetaObject() override;
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 567d83f3ee..41531c1df3 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -228,7 +228,7 @@ public:
static ReturnedValue create(ExecutionEngine *, NodeImpl *, const QList<NodeImpl *> &);
// JS API
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
};
@@ -250,7 +250,7 @@ public:
V4_NEEDS_DESTROY
// JS API
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
// C++ API
@@ -595,7 +595,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
Scope scope(v4);
QQmlXMLHttpRequestData *d = xhrdata(v4);
if (d->nodePrototype.isUndefined()) {
- ScopedObject p(scope, v4->memoryManager->allocObject<NodePrototype>());
+ ScopedObject p(scope, v4->memoryManager->allocate<NodePrototype>());
d->nodePrototype.set(v4, p);
v4->v8Engine->freezeObject(p);
}
@@ -606,7 +606,7 @@ ReturnedValue Node::create(ExecutionEngine *v4, NodeImpl *data)
{
Scope scope(v4);
- Scoped<Node> instance(scope, v4->memoryManager->allocObject<Node>(data));
+ Scoped<Node> instance(scope, v4->memoryManager->allocate<Node>(data));
ScopedObject p(scope);
switch (data->type) {
@@ -876,7 +876,7 @@ ReturnedValue Document::load(ExecutionEngine *v4, const QByteArray &data)
return Encode::null();
}
- ScopedObject instance(scope, v4->memoryManager->allocObject<Node>(document));
+ ScopedObject instance(scope, v4->memoryManager->allocate<Node>(document));
document->release(); // the GC should own the NodeImpl via Node now
ScopedObject p(scope);
instance->setPrototype((p = Document::prototype(v4)));
@@ -904,9 +904,14 @@ ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasPr
return Encode::undefined();
}
-ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue NamedNodeMap::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
Q_ASSERT(m->as<NamedNodeMap>());
+
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m);
QV4::ExecutionEngine *v4 = r->engine();
@@ -930,7 +935,7 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert
ReturnedValue NamedNodeMap::create(ExecutionEngine *v4, NodeImpl *data, const QList<NodeImpl *> &list)
{
- return (v4->memoryManager->allocObject<NamedNodeMap>(data, list))->asReturnedValue();
+ return (v4->memoryManager->allocate<NamedNodeMap>(data, list))->asReturnedValue();
}
ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProperty)
@@ -949,7 +954,7 @@ ReturnedValue NodeList::getIndexed(const Managed *m, uint index, bool *hasProper
return Encode::undefined();
}
-ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue NodeList::get(const Managed *m, StringOrSymbol *name, bool *hasProperty)
{
Q_ASSERT(m->as<NodeList>());
const NodeList *r = static_cast<const NodeList *>(m);
@@ -957,14 +962,14 @@ ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty)
name->makeIdentifier();
- if (name->equals(v4->id_length()))
+ if (name->identifier() == v4->id_length()->identifier())
return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue();
return Object::get(m, name, hasProperty);
}
ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data)
{
- return (v4->memoryManager->allocObject<NodeList>(data))->asReturnedValue();
+ return (v4->memoryManager->allocate<NodeList>(data))->asReturnedValue();
}
ReturnedValue Document::method_documentElement(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -1643,7 +1648,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r));
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototype(proto);
return w.asReturnedValue();
@@ -2049,7 +2054,7 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4)
{
Scope scope(v4);
- Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->allocObject<QQmlXMLHttpRequestCtor>(v4));
+ Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->allocate<QQmlXMLHttpRequestCtor>(v4));
ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest")));
v4->globalObject->defineReadonlyProperty(s, ctor);
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
index f2836d8301..7515ef8dcc 100644
--- a/src/qml/qml/qqmlxmlhttprequest_p.h
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -55,7 +55,7 @@
#include <QtCore/qglobal.h>
#include <private/qqmlglobal_p.h>
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
+QT_REQUIRE_CONFIG(qml_xml_http_request);
QT_BEGIN_NAMESPACE
@@ -64,7 +64,5 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *);
QT_END_NAMESPACE
-#endif // xmlstreamreader && qml_network
-
#endif // QQMLXMLHTTPREQUEST_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index f04bee7f19..e4fe84bf25 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -44,7 +44,9 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlstringconverters_p.h>
+#if QT_CONFIG(qml_locale)
#include <private/qqmllocale_p.h>
+#endif
#include <private/qv8engine_p.h>
#include <private/qqmldelayedcallqueue_p.h>
#include <QFileInfo>
@@ -138,7 +140,9 @@ void Heap::QtObject::init(QQmlEngine *qmlEngine)
o->defineDefaultProperty(QStringLiteral("btoa"), QV4::QtObject::method_btoa);
o->defineDefaultProperty(QStringLiteral("atob"), QV4::QtObject::method_atob);
o->defineDefaultProperty(QStringLiteral("resolvedUrl"), QV4::QtObject::method_resolvedUrl);
+#if QT_CONFIG(qml_locale)
o->defineDefaultProperty(QStringLiteral("locale"), QV4::QtObject::method_locale);
+#endif
o->defineDefaultProperty(QStringLiteral("binding"), QV4::QtObject::method_binding);
if (qmlEngine) {
@@ -193,7 +197,7 @@ ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) con
return Encode::undefined();
}
-ReturnedValue QtObject::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QtObject::get(const Managed *m, StringOrSymbol *name, bool *hasProperty)
{
bool hasProp = false;
if (hasProperty == nullptr) {
@@ -1152,7 +1156,7 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
if (!parentArg)
THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object");
- QQmlTypeData *typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
+ QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
qml.toUtf8(), url, QQmlTypeLoader::Synchronous);
Q_ASSERT(typeData->isCompleteOrError());
QQmlComponent component(engine);
@@ -1309,6 +1313,7 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
return QV4::QObjectWrapper::wrap(scope.engine, c);
}
+#if QT_CONFIG(qml_locale)
/*!
\qmlmethod Qt::locale(name)
@@ -1343,6 +1348,7 @@ ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, co
return QQmlLocale::locale(scope.engine, code);
}
+#endif
void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
{
@@ -1416,7 +1422,7 @@ ReturnedValue QtObject::method_binding(const FunctionObject *b, const Value *, c
if (!f)
THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function");
- return Encode(scope.engine->memoryManager->allocObject<QQmlBindingFunction>(f));
+ return Encode(scope.engine->memoryManager->allocate<QQmlBindingFunction>(f));
}
@@ -1551,7 +1557,7 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
if (i != start)
result.append(QLatin1Char(' '));
- if (argv[i].as<ArrayObject>())
+ if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
result += QLatin1Char('[') + argv[i].toQStringNoThrow() + QLatin1Char(']');
else
result.append(argv[i].toQStringNoThrow());
@@ -1795,7 +1801,7 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
globalObject->defineDefaultProperty(QStringLiteral("print"), QV4::ConsoleObject::method_log);
- QV4::ScopedObject console(scope, globalObject->engine()->memoryManager->allocObject<QV4::ConsoleObject>());
+ QV4::ScopedObject console(scope, globalObject->engine()->memoryManager->allocate<QV4::ConsoleObject>());
globalObject->defineDefaultProperty(QStringLiteral("console"), console);
}
@@ -1850,6 +1856,10 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
if (argc > i)
n = argv[i].toInt32();
+ if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr))
+ if (ep->propertyCapture)
+ ep->propertyCapture->captureTranslation();
+
QString result = QCoreApplication::translate(context.toUtf8().constData(),
text.toUtf8().constData(),
comment.toUtf8().constData(),
@@ -1953,6 +1963,10 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
if (argc > 2)
n = argv[2].toInt32();
+ if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr))
+ if (ep->propertyCapture)
+ ep->propertyCapture->captureTranslation();
+
QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
comment.toUtf8().constData(), n);
@@ -2033,6 +2047,10 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
if (argc > 1)
n = argv[1].toInt32();
+ if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr))
+ if (ep->propertyCapture)
+ ep->propertyCapture->captureTranslation();
+
return Encode(scope.engine->newString(qtTrId(argv[0].toQStringNoThrow().toUtf8().constData(), n)));
}
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index ee3b5f7d6e..60a2a6b87d 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -93,7 +93,7 @@ struct QtObject : Object
{
V4_OBJECT2(QtObject, Object)
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static ReturnedValue method_isQtObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
@@ -126,7 +126,9 @@ struct QtObject : Object
static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#if QT_CONFIG(qml_locale)
static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#endif
static ReturnedValue method_binding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 038a75d50a..b5e25fb6d4 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -39,14 +39,21 @@
#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>
@@ -78,6 +85,7 @@
#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>)
@@ -123,11 +131,12 @@ static void restoreJSValue(QDataStream &stream, void *data)
}
}
-QV8Engine::QV8Engine(QJSEngine *qq, QV4::ExecutionEngine *v4)
- : q(qq)
- , m_engine(nullptr)
+QV8Engine::QV8Engine(QV4::ExecutionEngine *v4)
+ : m_engine(nullptr)
, m_v4Engine(v4)
+#if QT_CONFIG(qml_xml_http_request)
, m_xmlHttpRequestData(nullptr)
+#endif
{
#ifdef Q_PROCESSOR_X86_32
if (!qCpuHasFeature(SSE2)) {
@@ -157,7 +166,7 @@ QV8Engine::~QV8Engine()
qDeleteAll(m_extensionData);
m_extensionData.clear();
-#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
+#if QT_CONFIG(qml_xml_http_request)
qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData);
m_xmlHttpRequestData = nullptr;
#endif
@@ -180,14 +189,16 @@ void QV8Engine::initializeGlobal()
QV4::Scope scope(m_v4Engine);
QV4::GlobalExtensions::init(m_v4Engine->globalObject, QJSEngine::AllExtensions);
- QV4::ScopedObject qt(scope, m_v4Engine->memoryManager->allocObject<QV4::QtObject>(m_engine));
+ 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(xmlstreamreader) && QT_CONFIG(qml_network)
+#if QT_CONFIG(qml_xml_http_request)
qt_add_domexceptions(m_v4Engine);
m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine);
#endif
@@ -196,8 +207,10 @@ void QV8Engine::initializeGlobal()
{
for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) {
- if (m_v4Engine->globalObject->internalClass()->nameMap.at(i))
- m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->string);
+ if (m_v4Engine->globalObject->internalClass()->nameMap.at(i).isValid()) {
+ QV4::Identifier id = m_v4Engine->globalObject->internalClass()->nameMap.at(i);
+ m_illegalNames.insert(id.toQString());
+ }
}
}
}
@@ -221,14 +234,14 @@ static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
if (!instanceOfObject)
return;
- QV4::InternalClass *frozen = object->internalClass()->propertiesFrozen();
+ 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))
+ if (!frozen->nameMap.at(i).isValid())
continue;
o = *object->propertyData(i);
if (o)
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index b6a378667e..d90f1827fe 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -154,10 +154,9 @@ 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(QJSEngine *q) { return q->handle(); }
static QV4::ExecutionEngine *getV4(QV8Engine *d) { return d->m_v4Engine; }
- QV8Engine(QJSEngine* qq, QV4::ExecutionEngine *v4);
+ QV8Engine(QV4::ExecutionEngine *v4);
virtual ~QV8Engine();
// This enum should be in sync with QQmlEngine::ObjectOwnership
@@ -170,10 +169,11 @@ public:
void initQmlGlobalObject();
void setEngine(QQmlEngine *engine);
QQmlEngine *engine() { return m_engine; }
- QJSEngine *publicEngine() { return q; }
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);
@@ -202,13 +202,14 @@ public:
int consoleCountHelper(const QString &file, quint16 line, quint16 column);
protected:
- QJSEngine* q;
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;
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 6e92867cf5..e02dfa5ed4 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -52,6 +52,7 @@
# endif
#else
# define QT_FEATURE_qml_debug -1
+# define QT_FEATURE_qml_sequence_object 1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 7a12813f0c..62ccf0d66c 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -93,7 +93,7 @@ struct DelegateModelGroupFunction : QV4::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->allocObject<DelegateModelGroupFunction>(scope, flag, code);
+ return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
}
static ReturnedValue call(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
@@ -200,8 +200,7 @@ QQmlDelegateModelParts::QQmlDelegateModelParts(QQmlDelegateModel *parent)
*/
QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt)
- : m_delegate(nullptr)
- , m_cacheMetaType(nullptr)
+ : m_cacheMetaType(nullptr)
, m_context(ctxt)
, m_parts(nullptr)
, m_filterGroup(QStringLiteral("items"))
@@ -214,6 +213,7 @@ QQmlDelegateModelPrivate::QQmlDelegateModelPrivate(QQmlContext *ctxt)
, m_transaction(false)
, m_incubatorCleanupScheduled(false)
, m_waitingToFetchMore(false)
+ , m_useFirstColumnOnly(true)
, m_cacheItems(nullptr)
, m_items(nullptr)
, m_persistedItems(nullptr)
@@ -228,6 +228,11 @@ QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate()
m_cacheMetaType->release();
}
+int QQmlDelegateModelPrivate::adaptorModelCount() const
+{
+ return m_useFirstColumnOnly ? m_adaptorModel.rowCount() : m_adaptorModel.count();
+}
+
void QQmlDelegateModelPrivate::requestMoreIfNecessary()
{
Q_Q(QQmlDelegateModel);
@@ -263,6 +268,7 @@ QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent)
QQmlDelegateModel::~QQmlDelegateModel()
{
Q_D(QQmlDelegateModel);
+ d->m_adaptorModel.setObject(nullptr, this);
for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) {
if (cacheItem->object) {
@@ -336,7 +342,7 @@ void QQmlDelegateModel::componentComplete()
static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
QVector<Compositor::Insert> inserts;
- d->m_count = d->m_adaptorModel.count();
+ d->m_count = d->adaptorModelCount();
d->m_compositor.append(
&d->m_adaptorModel,
0,
@@ -383,7 +389,7 @@ void QQmlDelegateModel::setModel(const QVariant &model)
}
if (d->m_complete) {
- _q_itemsInserted(0, d->m_adaptorModel.count());
+ _q_itemsInserted(0, d->adaptorModelCount());
d->requestMoreIfNecessary();
}
}
@@ -409,7 +415,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
return;
}
bool wasValid = d->m_delegate != nullptr;
- d->m_delegate = delegate;
+ d->m_delegate.setObject(delegate, this);
d->m_delegateValidated = false;
if (wasValid && d->m_complete) {
for (int i = 1; i < d->m_groupCount; ++i) {
@@ -475,7 +481,7 @@ void QQmlDelegateModel::setRootIndex(const QVariant &root)
if (d->m_adaptorModel.canFetchMore())
d->m_adaptorModel.fetchMore();
if (d->m_complete) {
- const int newCount = d->m_adaptorModel.count();
+ const int newCount = d->adaptorModelCount();
if (oldCount)
_q_itemsRemoved(0, oldCount);
if (newCount)
@@ -487,6 +493,35 @@ void QQmlDelegateModel::setRootIndex(const QVariant &root)
}
/*!
+ \qmlproperty int QtQml.Models::DelegateModel::rows
+
+ Contains the number of rows in the model. If the model
+ is a list of items, it will be equal to the number of items
+ in the list.
+
+ \since QtQml.Models 2.12
+*/
+int QQmlDelegateModel::rows() const
+{
+ Q_D(const QQmlDelegateModel);
+ return d->m_adaptorModel.rowCount();
+}
+
+/*!
+ \qmlproperty int QtQml.Models::DelegateModel::columns
+
+ Contains the number of columns in the model. If the model
+ is a list of items, it will be equal to \c 1.
+
+ \since QtQml.Models 2.12
+*/
+int QQmlDelegateModel::columns() const
+{
+ Q_D(const QQmlDelegateModel);
+ return d->m_adaptorModel.columnCount();
+}
+
+/*!
\qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index)
QAbstractItemModel provides a hierarchical tree of data, whereas
@@ -536,25 +571,24 @@ int QQmlDelegateModel::count() const
QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object)
{
- QQmlDelegateModel::ReleaseFlags stat = nullptr;
if (!object)
- return stat;
-
- if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object)) {
- if (cacheItem->releaseObject()) {
- cacheItem->destroyObject();
- emitDestroyingItem(object);
- if (cacheItem->incubationTask) {
- releaseIncubator(cacheItem->incubationTask);
- cacheItem->incubationTask = nullptr;
- }
- cacheItem->Dispose();
- stat |= QQmlInstanceModel::Destroyed;
- } else {
- stat |= QQmlDelegateModel::Referenced;
- }
+ 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;
}
- return stat;
+ cacheItem->Dispose();
+ return QQmlInstanceModel::Destroyed;
}
/*
@@ -862,6 +896,13 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa
}
}
+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);
@@ -951,10 +992,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
return nullptr;
cacheItem->groups = it->flags;
-
- m_cache.insert(it.cacheIndex, cacheItem);
- m_compositor.setFlags(it, 1, Compositor::CacheFlag);
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ addCacheItem(cacheItem, it);
}
// Bump the reference counts temporarily so neither the content data or the delegate object
@@ -1046,7 +1084,10 @@ QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index)
if (!it->inCache())
return QQmlIncubator::Null;
- return d->m_cache.at(it.cacheIndex)->incubationTask->status();
+ 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)
@@ -1510,7 +1551,7 @@ void QQmlDelegateModel::_q_modelReset()
d->m_adaptorModel.rootIndex = QModelIndex();
if (d->m_complete) {
- d->m_count = d->m_adaptorModel.count();
+ d->m_count = d->adaptorModelCount();
const QList<QQmlDelegateModelItem *> cache = d->m_cache;
for (int i = 0, c = cache.count(); i < c; ++i) {
@@ -1588,8 +1629,15 @@ void QQmlDelegateModel::_q_rowsMoved(
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);
+ if (begin.parent() != d->m_adaptorModel.rootIndex)
+ return;
+
+ int rowCount = end.row() - begin.row() + 1;
+
+ for (int col = begin.column(); col <= end.column(); ++col) {
+ int startIndex = d->m_adaptorModel.indexAt(begin.row(), col);
+ _q_itemsChanged(startIndex, rowCount, roles);
+ }
}
bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
@@ -1918,6 +1966,8 @@ QQmlDelegateModelItem::QQmlDelegateModelItem(
, scriptRef(0)
, groups(0)
, index(modelIndex)
+ , row(QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel.rowAt(modelIndex))
+ , column(QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel.columnAt(modelIndex))
{
metaType->addref();
}
@@ -1952,6 +2002,27 @@ void QQmlDelegateModelItem::Dispose()
delete this;
}
+void QQmlDelegateModelItem::setModelIndex(int idx)
+{
+ if (idx == index)
+ return;
+
+ const int prevRow = row;
+ const int prevColumn = column;
+ const QQmlAdaptorModel &adaptorModel = QQmlDelegateModelPrivate::get(metaType->model)->m_adaptorModel;
+
+ index = idx;
+ row = adaptorModel.rowAt(idx);
+ column = adaptorModel.columnAt(idx);
+
+ Q_EMIT modelIndexChanged();
+
+ if (row != prevRow)
+ emit rowChanged();
+ if (column != prevColumn)
+ emit columnChanged();
+}
+
void QQmlDelegateModelItem::destroyObject()
{
Q_ASSERT(object);
@@ -2080,22 +2151,29 @@ QQmlDelegateModelAttached::QQmlDelegateModelAttached(
, 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] = m_previousIndex[i] = incubationTask->index[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] = m_previousIndex[i] = it.index[i];
+ m_currentIndex[i] = it.index[i];
}
-
- if (!cacheItem->metaType->metaObject)
- cacheItem->metaType->initializeMetaObject();
-
- QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
- cacheItem->metaType->metaObject->addref();
}
/*!
@@ -2483,7 +2561,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
model->m_cacheMetaType->initializePrototype();
QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine;
QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QQmlDelegateModelItemObject>(cacheItem));
+ QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(cacheItem));
QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
o->setPrototype(p);
++cacheItem->scriptRef;
@@ -3194,7 +3272,10 @@ QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
if (!it->inCache())
return QQmlIncubator::Null;
- return model->m_cache.at(it.cacheIndex)->incubationTask->status();
+ if (auto incubationTask = model->m_cache.at(it.cacheIndex)->incubationTask)
+ return incubationTask->status();
+
+ return QQmlIncubator::Ready;
}
int QQmlPartsModel::indexOf(QObject *item, QObject *) const
@@ -3214,7 +3295,10 @@ void QQmlPartsModel::createdPackage(int index, QQuickPackage *package)
void QQmlPartsModel::initPackage(int index, QQuickPackage *package)
{
- emit initItem(index, package->part(m_part));
+ if (m_modelUpdatePending)
+ m_pendingPackageInitializations << index;
+ else
+ emit initItem(index, package->part(m_part));
}
void QQmlPartsModel::destroyingPackage(QQuickPackage *package)
@@ -3226,9 +3310,22 @@ void QQmlPartsModel::destroyingPackage(QQuickPackage *package)
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);
+ }
}
//============================================================================
@@ -3238,7 +3335,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object
V4_OBJECT2(QQmlDelegateModelGroupChange, QV4::Object)
static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
- return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>();
+ return e->memoryManager->allocate<QQmlDelegateModelGroupChange>();
}
static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
@@ -3275,7 +3372,7 @@ struct QQmlDelegateModelGroupChangeArray : public QV4::Object
public:
static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
{
- return engine->memoryManager->allocObject<QQmlDelegateModelGroupChangeArray>(changes);
+ return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes);
}
quint32 count() const { return d()->changes->count(); }
@@ -3306,12 +3403,13 @@ public:
return object.asReturnedValue();
}
- static QV4::ReturnedValue get(const QV4::Managed *m, QV4::String *name, bool *hasProperty)
+ static QV4::ReturnedValue get(const QV4::Managed *m, QV4::StringOrSymbol *name, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlDelegateModelGroupChangeArray>());
const QQmlDelegateModelGroupChangeArray *array = static_cast<const QQmlDelegateModelGroupChangeArray *>(m);
- if (name->equals(array->engine()->id_length())) {
+ name->makeIdentifier();
+ if (name->identifier() == array->engine()->id_length()->identifier()) {
if (hasProperty)
*hasProperty = true;
return QV4::Encode(array->count());
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index b0786cd088..232a40798c 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -88,6 +88,8 @@ class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public
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_PROPERTY(int rows READ rows NOTIFY rowsChanged REVISION 12)
+ Q_PROPERTY(int columns READ columns NOTIFY columnsChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "delegate")
Q_INTERFACES(QQmlParserStatus)
public:
@@ -107,6 +109,9 @@ public:
QVariant rootIndex() const;
void setRootIndex(const QVariant &root);
+ int rows() const;
+ int columns() const;
+
Q_INVOKABLE QVariant modelIndex(int idx) const;
Q_INVOKABLE QVariant parentModelIndex() const;
@@ -138,6 +143,8 @@ Q_SIGNALS:
void filterGroupChanged();
void defaultGroupsChanged();
void rootIndexChanged();
+ Q_REVISION(12) void rowsChanged();
+ Q_REVISION(12) void columnsChanged();
private Q_SLOTS:
void _q_itemsChanged(int index, int count, const QVector<int> &roles);
@@ -212,6 +219,7 @@ public:
QQmlDelegateModelAttached(QQmlDelegateModelItem *cacheItem, QObject *parent);
~QQmlDelegateModelAttached() {}
+ void resetCurrentIndex();
void setCacheItem(QQmlDelegateModelItem *item);
QQmlDelegateModel *model() const;
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 18980cfd7c..a0c1f6aa12 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -95,6 +95,8 @@ class QQmlDelegateModelItem : public QObject
{
Q_OBJECT
Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged)
+ Q_PROPERTY(int row MEMBER row NOTIFY rowChanged)
+ Q_PROPERTY(int column MEMBER column NOTIFY columnChanged)
Q_PROPERTY(QObject *model READ modelObject CONSTANT)
public:
QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, int modelIndex);
@@ -121,7 +123,7 @@ public:
int groupIndex(Compositor::Group group);
int modelIndex() const { return index; }
- void setModelIndex(int idx) { index = idx; Q_EMIT modelIndexChanged(); }
+ virtual void setModelIndex(int idx);
virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(v4, this); }
@@ -148,9 +150,13 @@ public:
Q_SIGNALS:
void modelIndexChanged();
+ void rowChanged();
+ void columnChanged();
protected:
void objectDestroyed(QObject *);
+ int row;
+ int column;
};
namespace QV4 {
@@ -269,6 +275,7 @@ public:
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();
@@ -295,6 +302,8 @@ public:
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);
@@ -305,7 +314,7 @@ public:
QQmlAdaptorModel m_adaptorModel;
QQmlListCompositor m_compositor;
- QQmlComponent *m_delegate;
+ QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
QQmlDelegateModelItemMetaType *m_cacheMetaType;
QPointer<QQmlContext> m_context;
QQmlDelegateModelParts *m_parts;
@@ -327,6 +336,7 @@ public:
bool m_transaction : 1;
bool m_incubatorCleanupScheduled : 1;
bool m_waitingToFetchMore : 1;
+ bool m_useFirstColumnOnly : 1;
union {
struct {
@@ -378,8 +388,10 @@ private:
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;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 830c2bef5a..0a9540bf4b 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -62,6 +62,8 @@
#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.
@@ -124,8 +126,8 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data
const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
{
- const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
- const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
+ 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;
@@ -227,6 +229,10 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV
data.value<QJSValue>().isCallable()) {
type = Role::Function;
break;
+ } else if (data.userType() == qMetaTypeId<const QV4::CompiledData::Binding*>()
+ && data.value<const QV4::CompiledData::Binding*>()->containsTranslations()) {
+ type = Role::String;
+ break;
} else {
type = Role::List;
break;
@@ -261,6 +267,75 @@ const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) const
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];
@@ -717,11 +792,11 @@ ModelNodeMetaObject *ListElement::objectCache()
return ModelNodeMetaObject::get(m_objectCache);
}
-QString *ListElement::getStringProperty(const ListLayout::Role &role)
+StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
- QString *s = reinterpret_cast<QString *>(mem);
- return s->data_ptr() ? s : nullptr;
+ StringOrTranslation *s = reinterpret_cast<StringOrTranslation *>(mem);
+ return s;
}
QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
@@ -806,9 +881,9 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
break;
case ListLayout::Role::String:
{
- QString *value = reinterpret_cast<QString *>(mem);
- if (value->data_ptr() != nullptr)
- data = *value;
+ StringOrTranslation *value = reinterpret_cast<StringOrTranslation *>(mem);
+ if (value->isSet())
+ data = value->toString(owner);
}
break;
case ListLayout::Role::Bool:
@@ -878,15 +953,13 @@ int ListElement::setStringProperty(const ListLayout::Role &role, const QString &
if (role.type == ListLayout::Role::String) {
char *mem = getPropertyMemory(role);
- QString *c = reinterpret_cast<QString *>(mem);
+ StringOrTranslation *c = reinterpret_cast<StringOrTranslation *>(mem);
bool changed;
- if (c->data_ptr() == nullptr) {
- new (mem) QString(s);
+ if (!c->isSet() || c->isTranslation())
changed = true;
- } else {
- changed = c->compare(s) != 0;
- *c = s;
- }
+ else
+ changed = c->asString().compare(s) != 0;
+ c->setString(s);
if (changed)
roleIndex = role.index;
}
@@ -1048,11 +1121,25 @@ int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValu
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) QString(s);
+ new (mem) StringOrTranslation(s);
}
void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d)
@@ -1219,9 +1306,9 @@ void ListElement::destroy(ListLayout *layout)
switch (r.type) {
case ListLayout::Role::String:
{
- QString *string = getStringProperty(r);
+ StringOrTranslation *string = getStringProperty(r);
if (string)
- string->~QString();
+ string->~StringOrTranslation();
}
break;
case ListLayout::Role::List:
@@ -1284,7 +1371,10 @@ int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant
roleIndex = setDoubleProperty(role, d.toDouble());
break;
case ListLayout::Role::String:
- roleIndex = setStringProperty(role, d.toString());
+ 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());
@@ -1446,7 +1536,7 @@ void ModelNodeMetaObject::propertyWritten(int index)
return;
QString propName = QString::fromUtf8(name(index));
- QVariant value = operator[](index);
+ const QVariant value = this->value(index);
QV4::Scope scope(m_model->engine());
QV4::ScopedValue v(scope, scope.engine->fromVariant(value));
@@ -1474,8 +1564,12 @@ void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCo
namespace QV4 {
-bool ModelObject::put(Managed *m, String *name, const Value &value)
+bool ModelObject::put(Managed *m, StringOrSymbol *n, const Value &value)
{
+ if (n->isSymbol())
+ return Object::put(m, n, value);
+ String *name = static_cast<String *>(n);
+
ModelObject *that = static_cast<ModelObject*>(m);
ExecutionEngine *eng = that->engine();
@@ -1491,8 +1585,12 @@ bool ModelObject::put(Managed *m, String *name, const Value &value)
return true;
}
-ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue ModelObject::get(const Managed *m, StringOrSymbol *n, bool *hasProperty)
{
+ if (n->isSymbol())
+ return Object::get(m, n, hasProperty);
+ String *name = static_cast<String *>(n);
+
const ModelObject *that = static_cast<const ModelObject*>(m);
const ListLayout::Role *role = that->d()->m_model->m_listModel->getExistingRole(name);
if (!role)
@@ -1809,6 +1907,7 @@ QQmlListModel::QQmlListModel(const QQmlListModel *owner, ListModel *data, QV4::E
m_listModel = data;
m_engine = engine;
+ m_compilationUnit = owner->m_compilationUnit;
}
QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agent)
@@ -1828,6 +1927,7 @@ QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agen
ListModel::sync(orig->m_listModel, m_listModel);
m_engine = nullptr;
+ m_compilationUnit = orig->m_compilationUnit;
}
QQmlListModel::~QQmlListModel()
@@ -2434,7 +2534,7 @@ QQmlV4Handle QQmlListModel::get(int index) const
QObject *object = m_listModel->getOrCreateModelObject(const_cast<QQmlListModel *>(this), index);
QQmlData *ddata = QQmlData::get(object);
if (ddata->jsWrapper.isNullOrUndefined()) {
- result = scope.engine->memoryManager->allocObject<QV4::ModelObject>(object, const_cast<QQmlListModel *>(this));
+ 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 {
@@ -2631,7 +2731,9 @@ bool QQmlListModelParser::applyProperty(QV4::CompiledData::CompilationUnit *comp
} else {
QVariant value;
- if (binding->evaluatesToString()) {
+ if (binding->containsTranslations()) {
+ value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
+ } else if (binding->evaluatesToString()) {
value = binding->valueAsString(qmlUnit);
} else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
value = binding->valueAsNumber();
@@ -2693,6 +2795,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::Compila
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
rv->m_engine = qmlEngine(rv)->handle();
+ rv->m_compilationUnit = compilationUnit;
const QV4::CompiledData::Unit *qmlUnit = compilationUnit->data;
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 0c0859dc80..56a1a95a02 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -64,6 +64,8 @@
#include <private/qv4engine_p.h>
#include <private/qpodvector_p.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
@@ -122,6 +124,7 @@ private:
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);
@@ -133,6 +136,7 @@ private:
QQmlListModelWorkerAgent *m_agent;
mutable QV4::ExecutionEngine *m_engine;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
bool m_mainThread;
bool m_primary;
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index ad5e94c909..75eeaeed0c 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -57,6 +57,8 @@
#include <private/qv4qobjectwrapper_p.h>
#include <qqml.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
@@ -142,16 +144,6 @@ protected:
private:
using QQmlOpenMetaObject::setValue;
- void setValue(const QByteArray &name, const QVariant &val, bool force)
- {
- if (force) {
- QVariant existingValue = value(name);
- if (existingValue.isValid()) {
- (*this)[name] = QVariant();
- }
- }
- setValue(name, val);
- }
void emitDirectNotifies(const int *changedRoles, int roleCount);
@@ -181,8 +173,8 @@ struct ModelObject : public QObjectWrapper {
struct ModelObject : public QObjectWrapper
{
- static bool put(Managed *m, String *name, const Value& value);
- static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static bool put(Managed *m, StringOrSymbol *name, const Value& value);
+ static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
V4_OBJECT2(ModelObject, QObjectWrapper)
@@ -252,6 +244,22 @@ private:
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
*/
@@ -287,6 +295,7 @@ private:
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);
@@ -301,7 +310,7 @@ private:
QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
ListModel *getListProperty(const ListLayout::Role &role);
- QString *getStringProperty(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);
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
index 2120f25744..ae2d4b11e0 100644
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ b/src/qml/types/qqmllistmodelworkeragent_p.h
@@ -59,6 +59,8 @@
#include <private/qv8engine_p.h>
+QT_REQUIRE_CONFIG(qml_list_model);
+
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
index e217b63c6f..d9756704d1 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qml/types/qqmlmodelsmodule.cpp
@@ -39,7 +39,9 @@
#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>
#endif
@@ -51,10 +53,13 @@ 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<QQmlDelegateModel,12>(uri, 2, 9, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
#endif
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index d597869994..0160e97a2f 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -57,6 +57,8 @@
#include <private/qtqmlglobal_p.h>
+QT_REQUIRE_CONFIG(qml_animation);
+
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 98f819337b..f8879160b2 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -37,9 +37,12 @@
**
****************************************************************************/
+#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>
@@ -201,7 +204,7 @@ private:
};
QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent)
- : QV8Engine(nullptr, new QV4::ExecutionEngine), p(parent)
+ : QV8Engine(new QV4::ExecutionEngine), p(parent)
#if QT_CONFIG(qml_network)
, accessManager(nullptr)
#endif
@@ -241,14 +244,13 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init()
QV4::Scope scope(m_v4Engine);
QV4::ExecutionContext *globalContext = scope.engine->rootContext();
- onmessage.set(scope.engine, QV4::Script(globalContext, QV4::Compiler::GlobalCode, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run()); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
+ onmessage.set(scope.engine, QV4::Script(globalContext, QV4::Compiler::ContextType::Global, QString::fromUtf8(CALL_ONMESSAGE_SCRIPT)).run()); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
Q_ASSERT(!scope.engine->hasException);
- QV4::Script createsendscript(globalContext, QV4::Compiler::GlobalCode, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
+ QV4::Script createsendscript(globalContext, QV4::Compiler::ContextType::Global, QString::fromUtf8(SEND_MESSAGE_CREATE_SCRIPT)); // do not use QStringLiteral here, MSVC2012 cannot apply this cleanly to the macro
QV4::ScopedFunctionObject createsendconstructor(scope, createsendscript.run());
Q_ASSERT(!scope.engine->hasException);
QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage")));
- QV4::ScopedValue function(scope, QV4::FunctionObject::createBuiltinFunction(globalContext, name,
- QQuickWorkerScriptEnginePrivate::method_sendMessage));
+ QV4::ScopedValue function(scope, QV4::FunctionObject::createBuiltinFunction(m_v4Engine, name, method_sendMessage, 1));
QV4::JSCallData jsCallData(scope, 1);
jsCallData->args[0] = function;
*jsCallData->thisObject = m_v4Engine->global();
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index 8bcbd6e544..5d75759281 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,8 +1,6 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
- $$PWD/qqmllistmodel.cpp \
- $$PWD/qqmllistmodelworkeragent.cpp \
$$PWD/qqmlmodelsmodule.cpp \
$$PWD/qqmlmodelindexvaluetype.cpp \
$$PWD/qqmlobjectmodel.cpp \
@@ -13,9 +11,6 @@ SOURCES += \
HEADERS += \
$$PWD/qqmlbind_p.h \
$$PWD/qqmlconnections_p.h \
- $$PWD/qqmllistmodel_p.h \
- $$PWD/qqmllistmodel_p_p.h \
- $$PWD/qqmllistmodelworkeragent_p.h \
$$PWD/qqmlmodelsmodule_p.h \
$$PWD/qqmlmodelindexvaluetype_p.h \
$$PWD/qqmlobjectmodel_p.h \
@@ -24,6 +19,17 @@ HEADERS += \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_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
@@ -33,7 +39,7 @@ qtConfig(qml-delegate-model) {
$$PWD/qqmldelegatemodel_p_p.h
}
-qtConfig(animation) {
+qtConfig(qml-animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index b4bebb9d5d..3016316e57 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -228,8 +228,8 @@ public:
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocObject<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocObject<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));
+ 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);
@@ -330,9 +330,8 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx)
{
if (index == -1) {
Q_ASSERT(idx >= 0);
- index = idx;
cachedData.clear();
- emit modelIndexChanged();
+ setModelIndex(idx);
const QMetaObject *meta = metaObject();
const int propertyCount = type->propertyRoles.count();
for (int i = 0; i < propertyCount; ++i)
@@ -400,6 +399,7 @@ class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
{
Q_OBJECT
Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
+
public:
QQmlDMAbstractItemModelData(
QQmlDelegateModelItemMetaType *metaType,
@@ -413,7 +413,7 @@ public:
{
if (index >= 0 && *type->model) {
const QAbstractItemModel * const model = type->model->aim();
- return model->hasChildren(model->index(index, 0, type->model->rootIndex));
+ return model->hasChildren(model->index(row, column, type->model->rootIndex));
} else {
return false;
}
@@ -421,13 +421,13 @@ public:
QVariant value(int role) const override
{
- return type->model->aim()->index(index, 0, type->model->rootIndex).data(role);
+ 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(index, 0, type->model->rootIndex), value, role);
+ type->model->aim()->index(row, column, type->model->rootIndex), value, role);
}
QV4::ReturnedValue get() override
@@ -438,7 +438,7 @@ public:
}
QV4::Scope scope(v4);
QV4::ScopedObject proto(scope, type->prototype.value());
- QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocObject<QQmlDelegateModelItemObject>(this));
+ QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
o->setPrototype(proto);
++scriptRef;
return o.asReturnedValue();
@@ -453,11 +453,16 @@ public:
{
}
- int count(const QQmlAdaptorModel &model) const override
+ 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 &model, QQmlDelegateModel *vdm) const override
{
QAbstractItemModel * const aim = model.aim();
@@ -485,9 +490,9 @@ public:
{
QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
if (it != roleNames.end()) {
- return model.aim()->index(index, 0, model.rootIndex).data(*it);
+ 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(index, 0, model.rootIndex)));
+ return QVariant(model.aim()->hasChildren(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex)));
} else {
return QVariant();
}
@@ -503,7 +508,7 @@ public:
QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
{
return model
- ? QVariant::fromValue(model.aim()->index(index, 0, model.rootIndex))
+ ? QVariant::fromValue(model.aim()->index(model.rowAt(index), model.columnAt(index), model.rootIndex))
: QVariant();
}
@@ -613,7 +618,7 @@ public:
{
QQmlAdaptorModelEngineData *data = engineData(v4);
QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QQmlDelegateModelItemObject>(this));
+ QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
QV4::ScopedObject p(scope, data->listItemProto.value());
o->setPrototype(p);
++scriptRef;
@@ -653,11 +658,16 @@ class VDMListDelegateDataType : public QQmlAdaptorModel::Accessors
public:
inline VDMListDelegateDataType() {}
- int count(const QQmlAdaptorModel &model) const override
+ 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")
@@ -737,11 +747,16 @@ public:
free(metaObject);
}
- int count(const QQmlAdaptorModel &model) const override
+ 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 *>())
@@ -911,7 +926,7 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
list.setList(variant, engine);
if (QObject *object = qvariant_cast<QObject *>(list.list())) {
- setObject(object);
+ setObject(object, vdm);
if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(object)) {
accessors = new VDMAbstractItemModelDataType(this);
@@ -933,14 +948,14 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
accessors = new VDMObjectDelegateDataType;
}
} else if (list.type() == QQmlListAccessor::ListProperty) {
- setObject(static_cast<const QQmlListReference *>(variant.constData())->object());
+ setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), vdm);
accessors = new VDMObjectDelegateDataType;
} else if (list.type() != QQmlListAccessor::Invalid
&& list.type() != QQmlListAccessor::Instance) { // Null QObject
- setObject(nullptr);
+ setObject(nullptr, vdm);
accessors = &qt_vdm_list_accessors;
} else {
- setObject(nullptr);
+ setObject(nullptr, vdm);
accessors = &qt_vdm_null_accessors;
}
}
@@ -958,6 +973,38 @@ 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(isValid() ? 1 : 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 row + (column * rowCount());
+}
+
void QQmlAdaptorModel::objectDestroyed(QObject *)
{
setModel(QVariant(), nullptr, nullptr);
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
index b152a886a5..3b2d180ca7 100644
--- a/src/qml/util/qqmladaptormodel_p.h
+++ b/src/qml/util/qqmladaptormodel_p.h
@@ -56,6 +56,7 @@
#include "private/qqmllistaccessor_p.h"
#include <private/qqmlguard_p.h>
+#include <private/qqmlnullablevalue_p.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
@@ -67,7 +68,7 @@ class QQmlDelegateModel;
class QQmlDelegateModelItem;
class QQmlDelegateModelItemMetaType;
-class QQmlAdaptorModel : public QQmlGuard<QObject>
+class QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
{
public:
class Accessors
@@ -75,7 +76,8 @@ public:
public:
inline Accessors() {}
virtual ~Accessors();
- virtual int count(const QQmlAdaptorModel &) const { return 0; }
+ virtual int rowCount(const QQmlAdaptorModel &) const { return 0; }
+ virtual int columnCount(const QQmlAdaptorModel &) const { return 0; }
virtual void cleanup(QQmlAdaptorModel &, QQmlDelegateModel * = nullptr) const {}
virtual QVariant value(const QQmlAdaptorModel &, int, const QString &) const {
@@ -116,11 +118,16 @@ public:
void invalidateModel(QQmlDelegateModel *vdm);
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;
inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); }
inline const QAbstractItemModel *aim() const { return static_cast<const QAbstractItemModel *>(object()); }
- inline int count() const { return qMax(0, accessors->count(*this)); }
inline QVariant value(int index, const QString &role) const {
return accessors->value(*this, index, role); }
inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) {
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 578c05086f..3f78ca6b69 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -122,7 +122,7 @@ QVariant QQmlPropertyMapMetaObject::propertyWriteValue(int index, const QVariant
void QQmlPropertyMapMetaObject::propertyWritten(int index)
{
- priv->emitChanged(priv->propertyName(index), operator[](index));
+ priv->emitChanged(priv->propertyName(index), value(index));
}
void QQmlPropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
@@ -311,7 +311,7 @@ QVariant &QQmlPropertyMap::operator[](const QString &key)
if (!d->keys.contains(key))
insert(key, QVariant());//force creation -- needed below
- return (*(d->mo))[utf8key];
+ return d->mo->valueRef(utf8key);
}
/*!
diff --git a/src/qmldebug/qqmldebugclient.cpp b/src/qmldebug/qqmldebugclient.cpp
index d412b7b267..03123cc6e0 100644
--- a/src/qmldebug/qqmldebugclient.cpp
+++ b/src/qmldebug/qqmldebugclient.cpp
@@ -117,11 +117,6 @@ QQmlDebugConnection *QQmlDebugClient::connection() const
return d->connection;
}
-void QQmlDebugClient::stateChanged(QQmlDebugClient::State state)
-{
- Q_UNUSED(state);
-}
-
void QQmlDebugClient::messageReceived(const QByteArray &message)
{
Q_UNUSED(message);
diff --git a/src/qmldebug/qqmldebugclient_p.h b/src/qmldebug/qqmldebugclient_p.h
index 723de5ee43..469b65d4a9 100644
--- a/src/qmldebug/qqmldebugclient_p.h
+++ b/src/qmldebug/qqmldebugclient_p.h
@@ -76,13 +76,14 @@ public:
QQmlDebugConnection *connection() const;
+signals:
+ void stateChanged(State state);
+
protected:
QQmlDebugClient(QQmlDebugClientPrivate &dd);
private:
friend class QQmlDebugConnection;
-
- virtual void stateChanged(State state);
virtual void messageReceived(const QByteArray &message);
};
diff --git a/src/qmldebug/qqmldebugconnection.cpp b/src/qmldebug/qqmldebugconnection.cpp
index 67bad8d812..4e087ee6db 100644
--- a/src/qmldebug/qqmldebugconnection.cpp
+++ b/src/qmldebug/qqmldebugconnection.cpp
@@ -259,7 +259,7 @@ QQmlDebugConnection::~QQmlDebugConnection()
Q_D(QQmlDebugConnection);
QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
for (; iter != d->plugins.end(); ++iter)
- iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ emit iter.value()->stateChanged(QQmlDebugClient::NotConnected);
}
int QQmlDebugConnection::currentDataStreamVersion() const
@@ -295,7 +295,7 @@ void QQmlDebugConnection::close()
QHash<QString, QQmlDebugClient*>::iterator iter = d->plugins.begin();
for (; iter != d->plugins.end(); ++iter)
- iter.value()->stateChanged(QQmlDebugClient::NotConnected);
+ emit iter.value()->stateChanged(QQmlDebugClient::NotConnected);
}
if (d->device) {
diff --git a/src/qmldebug/qqmldebugmessageclient.cpp b/src/qmldebug/qqmldebugmessageclient.cpp
index a03c1f8af2..0892404194 100644
--- a/src/qmldebug/qqmldebugmessageclient.cpp
+++ b/src/qmldebug/qqmldebugmessageclient.cpp
@@ -58,11 +58,6 @@ QQmlDebugMessageClient::QQmlDebugMessageClient(QQmlDebugConnection *client)
{
}
-void QQmlDebugMessageClient::stateChanged(State state)
-{
- emit newState(state);
-}
-
void QQmlDebugMessageClient::messageReceived(const QByteArray &data)
{
QDataStream ds(data);
diff --git a/src/qmldebug/qqmldebugmessageclient_p.h b/src/qmldebug/qqmldebugmessageclient_p.h
index 75c70044e4..a2a7f28f81 100644
--- a/src/qmldebug/qqmldebugmessageclient_p.h
+++ b/src/qmldebug/qqmldebugmessageclient_p.h
@@ -71,15 +71,10 @@ class QQmlDebugMessageClient : public QQmlDebugClient
public:
explicit QQmlDebugMessageClient(QQmlDebugConnection *client);
- virtual void stateChanged(State state) override;
virtual void messageReceived(const QByteArray &) override;
signals:
- void newState(QQmlDebugClient::State);
void message(QtMsgType, const QString &, const QQmlDebugContextInfo &);
-
-private:
- Q_DISABLE_COPY(QQmlDebugMessageClient)
};
QT_END_NAMESPACE
diff --git a/src/qmldebug/qqmlenginecontrolclient.cpp b/src/qmldebug/qqmlenginecontrolclient.cpp
index 45d672d4bc..cdc724ef2f 100644
--- a/src/qmldebug/qqmlenginecontrolclient.cpp
+++ b/src/qmldebug/qqmlenginecontrolclient.cpp
@@ -98,8 +98,8 @@ void QQmlEngineControlClient::messageReceived(const QByteArray &data)
{
Q_D(QQmlEngineControlClient);
QPacket stream(d->connection->currentDataStreamVersion(), data);
- int message;
- int id;
+ qint32 message;
+ qint32 id;
QString name;
stream >> message >> id;
@@ -150,7 +150,7 @@ void QQmlEngineControlClientPrivate::sendCommand(
{
Q_Q(QQmlEngineControlClient);
QPacket stream(connection->currentDataStreamVersion());
- stream << int(command) << engineId;
+ stream << static_cast<qint32>(command) << engineId;
q->sendMessage(stream.data());
}
diff --git a/src/qmldebug/qqmlprofilerclient.cpp b/src/qmldebug/qqmlprofilerclient.cpp
index 661b43f164..73db2ad94d 100644
--- a/src/qmldebug/qqmlprofilerclient.cpp
+++ b/src/qmldebug/qqmlprofilerclient.cpp
@@ -42,6 +42,10 @@
QT_BEGIN_NAMESPACE
+QQmlProfilerClientPrivate::~QQmlProfilerClientPrivate()
+{
+}
+
int QQmlProfilerClientPrivate::resolveType(const QQmlProfilerTypedEvent &event)
{
int typeIndex = -1;
@@ -165,6 +169,7 @@ QQmlProfilerClient::QQmlProfilerClient(QQmlDebugConnection *connection,
{
Q_D(QQmlProfilerClient);
setRequestedFeatures(features);
+ connect(this, &QQmlDebugClient::stateChanged, this, &QQmlProfilerClient::onStateChanged);
connect(d->engineControl.data(), &QQmlEngineControlClient::engineAboutToBeAdded,
this, &QQmlProfilerClient::sendRecordingStatus);
connect(d->engineControl.data(), &QQmlEngineControlClient::engineAboutToBeRemoved,
@@ -314,7 +319,7 @@ bool QQmlProfilerClientPrivate::updateFeatures(ProfileFeature feature)
return true;
}
-void QQmlProfilerClient::stateChanged(State status)
+void QQmlProfilerClient::onStateChanged(State status)
{
if (status == Enabled) {
sendRecordingStatus(-1);
diff --git a/src/qmldebug/qqmlprofilerclient_p.h b/src/qmldebug/qqmlprofilerclient_p.h
index 7b8e286f5b..89c117a8b5 100644
--- a/src/qmldebug/qqmlprofilerclient_p.h
+++ b/src/qmldebug/qqmlprofilerclient_p.h
@@ -76,7 +76,6 @@ public:
void setRecording(bool);
quint64 recordedFeatures() const;
virtual void messageReceived(const QByteArray &) override;
- virtual void stateChanged(State status) override;
void clearEvents();
void clearAll();
@@ -87,6 +86,7 @@ public:
protected:
QQmlProfilerClient(QQmlProfilerClientPrivate &dd);
+ void onStateChanged(State status);
signals:
void complete(qint64 maximumTime);
diff --git a/src/qmldebug/qqmlprofilerclient_p_p.h b/src/qmldebug/qqmlprofilerclient_p_p.h
index 994c08cafc..df73209858 100644
--- a/src/qmldebug/qqmlprofilerclient_p_p.h
+++ b/src/qmldebug/qqmlprofilerclient_p_p.h
@@ -79,7 +79,7 @@ public:
{
}
- virtual ~QQmlProfilerClientPrivate() override {}
+ virtual ~QQmlProfilerClientPrivate() override;
void sendRecordingStatus(int engineId);
bool updateFeatures(ProfileFeature feature);
@@ -112,4 +112,3 @@ public:
QT_END_NAMESPACE
#endif // QQMLPROFILERCLIENT_P_P_H
-
diff --git a/src/qmltest/qtestoptions_p.h b/src/qmltest/qtestoptions_p.h
index 68fe09f793..7be5c88590 100644
--- a/src/qmltest/qtestoptions_p.h
+++ b/src/qmltest/qtestoptions_p.h
@@ -51,7 +51,11 @@
// We mean it.
//
-#include <QtTest/qttestglobal.h>
+#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
+# include <QtTest/qtest_global.h>
+#else
+# include <QtTest/qttestglobal.h>
+#endif
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index 8b9ff4c5cd..a54b93f72b 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -215,8 +215,8 @@ public:
m_errors += component.errors();
if (component.isReady()) {
- CompilationUnit *rootCompilationUnit = QQmlComponentPrivate::get(&component)->compilationUnit;
- TestCaseEnumerationResult result = enumerateTestCases(rootCompilationUnit);
+ QQmlRefPointer<CompilationUnit> rootCompilationUnit = QQmlComponentPrivate::get(&component)->compilationUnit;
+ TestCaseEnumerationResult result = enumerateTestCases(rootCompilationUnit.data());
m_testCases = result.testCases + result.finalizedPartialTestCases();
m_errors += result.errors;
}
@@ -278,7 +278,7 @@ private:
if (!object) // Start at root of compilation unit if not enumerating a specific child
object = compilationUnit->objectAt(0);
- if (CompilationUnit *superTypeUnit = compilationUnit->resolvedTypes.value(object->inheritedTypeNameIndex)->compilationUnit) {
+ if (CompilationUnit *superTypeUnit = compilationUnit->resolvedTypes.value(object->inheritedTypeNameIndex)->compilationUnit.data()) {
// We have a non-C++ super type, which could indicate we're a subtype of a TestCase
if (testCaseType.isValid() && superTypeUnit->url() == testCaseType.sourceUrl())
result.isTestCase = true;
@@ -476,6 +476,9 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
// Register the test object
qmlRegisterSingletonType<QTestRootObject>("Qt.test.qtestroot", 1, 0, "QTestRootObject", testRootObject);
+ QSet<QString> commandLineTestFunctions = QTest::testFunctions.toSet();
+ const bool filteringTestFunctions = !commandLineTestFunctions.isEmpty();
+
// Scan through all of the "tst_*.qml" files and run each of them
// in turn with a separate QQuickView (for test isolation).
for (const QString &file : qAsConst(files)) {
@@ -508,10 +511,10 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
continue;
}
- static const QSet<QString> commandLineTestFunctions = QTest::testFunctions.toSet();
- if (!commandLineTestFunctions.isEmpty() &&
- !availableTestFunctions.toSet().intersects(commandLineTestFunctions))
+ const QSet<QString> availableTestSet = availableTestFunctions.toSet();
+ if (filteringTestFunctions && !availableTestSet.intersects(commandLineTestFunctions))
continue;
+ commandLineTestFunctions.subtract(availableTestSet);
QQuickView view(&engine, nullptr);
view.setFlags(Qt::Window | Qt::WindowSystemMenuHint
@@ -584,6 +587,14 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
QuickTestResult::setProgramName(nullptr);
delete app;
+ // Check that all test functions passed on the command line were found
+ if (!commandLineTestFunctions.isEmpty()) {
+ qWarning() << "Could not find the following test functions:";
+ for (const QString &functionName : qAsConst(commandLineTestFunctions))
+ qWarning(" %s()", qUtf8Printable(functionName));
+ return commandLineTestFunctions.count();
+ }
+
// Return the number of failures as the exit code.
return QuickTestResult::exitCode();
}
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index c4a3280cf6..3b854dfccd 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -61,6 +61,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/QUrl>
#include <QtCore/QDir>
+#include <QtCore/qregularexpression.h>
#include <QtQuick/qquickwindow.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qimagewriter.h>
@@ -625,9 +626,18 @@ void QuickTestResult::warn(const QString &message, const QUrl &location, int lin
QTestLog::warn(message.toLatin1().constData(), qtestFixUrl(location).toLatin1().constData(), line);
}
-void QuickTestResult::ignoreWarning(const QString &message)
+void QuickTestResult::ignoreWarning(const QJSValue &message)
{
- QTestLog::ignoreMessage(QtWarningMsg, message.toLatin1().constData());
+ if (message.isRegExp()) {
+ // ### we should probably handle QRegularExpression conversion engine-side
+ QRegExp re = message.toVariant().toRegExp();
+ QRegularExpression::PatternOptions opts = re.caseSensitivity() ==
+ Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption;
+ QRegularExpression re2(re.pattern(), opts);
+ QTestLog::ignoreMessage(QtWarningMsg, re2);
+ } else {
+ QTestLog::ignoreMessage(QtWarningMsg, message.toString().toLatin1());
+ }
}
void QuickTestResult::wait(int ms)
diff --git a/src/qmltest/quicktestresult_p.h b/src/qmltest/quicktestresult_p.h
index 6e7b72830e..f222cd3e87 100644
--- a/src/qmltest/quicktestresult_p.h
+++ b/src/qmltest/quicktestresult_p.h
@@ -137,7 +137,7 @@ public Q_SLOTS:
const QUrl &location, int line);
void warn(const QString &message, const QUrl &location, int line);
- void ignoreWarning(const QString &message);
+ void ignoreWarning(const QJSValue &message);
void wait(int ms);
void sleep(int ms);
diff --git a/src/quick/configure.json b/src/quick/configure.json
index ea1d49baad..ab356be557 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -15,6 +15,7 @@
"quick-flipable": "boolean",
"quick-gridview": "boolean",
"quick-listview": "boolean",
+ "quick-tableview": "boolean",
"quick-path": "boolean",
"quick-pathview": "boolean",
"quick-positioners": "boolean",
@@ -86,7 +87,7 @@
},
"quick-itemview": {
"label": "ItemView item",
- "condition": "features.quick-gridview || features.quick-listview",
+ "condition": "features.quick-gridview || features.quick-listview || features.quick-tableview",
"output": [
"privateFeature"
]
@@ -107,6 +108,14 @@
"privateFeature"
]
},
+ "quick-tableview": {
+ "label": "TableView item",
+ "purpose": "Provides the TableView item.",
+ "section": "Qt Quick",
+ "output": [
+ "privateFeature"
+ ]
+ },
"quick-particles": {
"label": "Particle support",
"purpose": "Provides a particle system.",
@@ -183,6 +192,7 @@
"quick-flipable",
"quick-gridview",
"quick-listview",
+ "quick-tableview",
"quick-path",
"quick-pathview",
"quick-positioners",
diff --git a/src/quick/designer/qqmldesignermetaobject.cpp b/src/quick/designer/qqmldesignermetaobject.cpp
index 09493c30d6..2efcdada8b 100644
--- a/src/quick/designer/qqmldesignermetaobject.cpp
+++ b/src/quick/designer/qqmldesignermetaobject.cpp
@@ -83,7 +83,7 @@ static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine)
{
QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object);
if (metaObject)
- return metaObject->cache;
+ return metaObject->cache.data();
return QQmlEnginePrivate::get(engine)->cache(object);
}
@@ -139,7 +139,7 @@ QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engi
cache->setParent(ddata->propertyCache);
cache->invalidate(engine, this);
ddata->propertyCache->release();
- ddata->propertyCache = cache;
+ ddata->propertyCache = cache.data();
ddata->propertyCache->addref();
}
diff --git a/src/quick/doc/snippets/qml/pathview/pathview.qml b/src/quick/doc/snippets/qml/pathview/pathview.qml
index 1a31f1372b..58d19b1a0c 100644
--- a/src/quick/doc/snippets/qml/pathview/pathview.qml
+++ b/src/quick/doc/snippets/qml/pathview/pathview.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -59,6 +59,7 @@ Rectangle {
id: delegate
Column {
id: wrapper
+ opacity: PathView.isCurrentItem ? 1 : 0.5
Image {
anchors.horizontalCenter: nameText.horizontalCenter
width: 64; height: 64
@@ -68,7 +69,6 @@ Rectangle {
id: nameText
text: name
font.pointSize: 16
- color: wrapper.PathView.isCurrentItem ? "red" : "black"
}
}
}
diff --git a/src/quick/handlers/handlers.pri b/src/quick/handlers/handlers.pri
index 8bd74d95da..a096643403 100644
--- a/src/quick/handlers/handlers.pri
+++ b/src/quick/handlers/handlers.pri
@@ -1,16 +1,20 @@
HEADERS += \
$$PWD/qquickdraghandler_p.h \
+ $$PWD/qquickhandlerpoint_p.h \
$$PWD/qquickhandlersmodule_p.h \
$$PWD/qquickmultipointhandler_p.h \
$$PWD/qquickpinchhandler_p.h \
$$PWD/qquickpointerdevicehandler_p.h \
+ $$PWD/qquickpointerdevicehandler_p_p.h \
$$PWD/qquickpointerhandler_p.h \
+ $$PWD/qquickpointerhandler_p_p.h \
$$PWD/qquickpointhandler_p.h \
$$PWD/qquicksinglepointhandler_p.h \
$$PWD/qquicktaphandler_p.h \
SOURCES += \
$$PWD/qquickdraghandler.cpp \
+ $$PWD/qquickhandlerpoint.cpp \
$$PWD/qquickhandlersmodule.cpp \
$$PWD/qquickmultipointhandler.cpp \
$$PWD/qquickpinchhandler.cpp \
@@ -19,4 +23,3 @@ SOURCES += \
$$PWD/qquickpointhandler.cpp \
$$PWD/qquicksinglepointhandler.cpp \
$$PWD/qquicktaphandler.cpp \
-
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
new file mode 100644
index 0000000000..4bd5d2cbfb
--- /dev/null
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickhandlerpoint_p.h"
+#include "private/qquickevents_p_p.h"
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH_TARGET)
+
+/*!
+ \qmltype HandlerPoint
+ \instantiates QQuickHandlerPoint
+ \inqmlmodule Qt.labs.handlers
+ \ingroup qtquick-handlers
+ \brief An event point.
+
+ A QML representation of a QQuickEventPoint.
+
+ It's possible to make bindings to properties of a \l SinglePointHandler's
+ current point. For example:
+
+ \snippet pointerHandlers/dragHandlerNullTarget.qml 0
+
+ The point is kept up-to-date when the DragHandler is actively responding to
+ an EventPoint; but when the point is released, or the current point is
+ being handled by a different handler, \c position.x and \c position.y are 0.
+
+ \note This is practically identical to QtQuick::EventPoint; however an
+ EventPoint is a long-lived QObject which is invalidated between gestures
+ and reused for subsequent event deliveries. Continuous bindings to its
+ properties are not possible, and an individual handler cannot rely on it
+ outside the period when that point is part of an active gesture which that
+ handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
+ This allows you to make lifetime bindings to its properties.
+
+ \sa SinglePointHandler::point
+*/
+
+QQuickHandlerPoint::QQuickHandlerPoint()
+ : m_id(0)
+ , m_rotation(0)
+ , m_pressure(0)
+{}
+
+void QQuickHandlerPoint::reset()
+{
+ m_id = 0;
+ m_uniqueId = QPointingDeviceUniqueId();
+ m_position = QPointF();
+ m_scenePosition = QPointF();
+ m_pressPosition = QPointF();
+ m_scenePressPosition = QPointF();
+ m_sceneGrabPosition = QPointF();
+ m_velocity = QVector2D();
+ m_rotation = 0;
+ m_pressure = 0;
+ m_ellipseDiameters = QSizeF();
+ m_pressedButtons = Qt::NoButton;
+ m_pressedModifiers = Qt::NoModifier;
+}
+
+void QQuickHandlerPoint::reset(const QQuickEventPoint *point)
+{
+ m_id = point->pointId();
+ const QQuickPointerEvent *event = point->pointerEvent();
+ switch (point->state()) {
+ case QQuickEventPoint::Pressed:
+ m_pressPosition = point->position();
+ m_scenePressPosition = point->scenePosition();
+ m_pressedButtons = event->buttons();
+ break;
+ case QQuickEventPoint::Released:
+ reset();
+ return;
+ default:
+ m_pressedButtons = event->buttons();
+ break;
+ }
+ m_pressedModifiers = event->modifiers();
+ if (event->asPointerTouchEvent()) {
+ const QQuickEventTouchPoint *tp = static_cast<const QQuickEventTouchPoint *>(point);
+ m_uniqueId = tp->uniqueId();
+ m_rotation = tp->rotation();
+ m_pressure = tp->pressure();
+ m_ellipseDiameters = tp->ellipseDiameters();
+ } else if (event->asPointerTabletEvent()) {
+ // TODO
+ } else {
+ m_uniqueId = event->device()->uniqueId();
+ m_rotation = 0;
+ m_pressure = event->buttons() ? 1 : 0;
+ m_ellipseDiameters = QSizeF();
+ }
+ m_position = point->position();
+ m_scenePosition = point->scenePosition();
+ if (point->state() == QQuickEventPoint::Updated)
+ m_velocity = point->velocity();
+}
+
+void QQuickHandlerPoint::reset(const QVector<QQuickEventPoint *> &points)
+{
+ if (points.isEmpty()) {
+ qWarning("reset: no points");
+ return;
+ }
+ if (points.count() == 1) {
+ reset(points.first());
+ return;
+ }
+ // all points are required to be from the same event
+ const QQuickPointerEvent *event = points.first()->pointerEvent();
+ QPointF posSum;
+ QPointF scenePosSum;
+ QVector2D velocitySum;
+ qreal pressureSum = 0;
+ QSizeF ellipseDiameterSum;
+ bool press = false;
+ const QQuickPointerTouchEvent *touchEvent = event->asPointerTouchEvent();
+ for (const QQuickEventPoint *point : qAsConst(points)) {
+ posSum += point->position();
+ scenePosSum += point->scenePosition();
+ velocitySum += point->velocity();
+ if (touchEvent) {
+ pressureSum += static_cast<const QQuickEventTouchPoint *>(point)->pressure();
+ ellipseDiameterSum += static_cast<const QQuickEventTouchPoint *>(point)->ellipseDiameters();
+ }
+ if (point->state() == QQuickEventPoint::Pressed)
+ press = true;
+ }
+ m_id = 0;
+ m_uniqueId = QPointingDeviceUniqueId();
+ m_pressedButtons = event->buttons();
+ m_pressedModifiers = event->modifiers();
+ m_position = posSum / points.size();
+ m_scenePosition = scenePosSum / points.size();
+ if (press) {
+ m_pressPosition = m_position;
+ m_scenePressPosition = m_scenePosition;
+ }
+ m_velocity = velocitySum / points.size();
+ m_rotation = 0; // averaging the rotations of all the points isn't very sensible
+ m_pressure = pressureSum / points.size();
+ m_ellipseDiameters = ellipseDiameterSum / points.size();
+}
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick::HandlerPoint::id
+ \brief The ID number of the point
+
+ During a touch gesture, from the time that the first finger is pressed
+ until the last finger is released, each touchpoint will have a unique ID
+ number. Likewise, if input from multiple devices occurs (for example
+ simultaneous mouse and touch presses), all the current event points from
+ all the devices will have unique IDs.
+
+ \note Do not assume that id numbers start at zero or that they are
+ sequential. Such an assumption is often false due to the way the underlying
+ drivers work.
+
+ \sa QTouchEvent::TouchPoint::id
+*/
+
+/*!
+ \readonly
+ \qmlproperty PointingDeviceUniqueId QtQuick::HandlerPoint::uniqueId
+ \brief The unique ID of the point, if any
+
+ This is normally empty, because touchscreens cannot uniquely identify fingers.
+
+ On some types of touchscreens, especially those using TUIO drivers,
+ it's possible to use recognizable physical tokens (fiducial objects)
+ in addition to fingers. So if this point is a touch point, and
+ uniqueId is set, it is the identifier for such an object.
+
+ On a graphics tablet, each type of stylus or other tool often has a unique
+ ID or serial number, which can be useful to respond in different ways to
+ different tools.
+
+ Interpreting the contents of this ID requires knowledge of the hardware and
+ drivers in use.
+
+ \sa QTabletEvent::uniqueId, QtQuick::TouchPoint::uniqueId, QtQuick::EventTouchPoint::uniqueId
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::position
+ \brief The position within the \c parent Item
+
+ This is the position of the event point relative to the bounds of
+ the \l {PointerHandler::parent} {parent}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
+ \brief The position within the scene
+
+ This is the position of the event point relative to the bounds of the Qt
+ Quick scene (typically the whole window).
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::pressPosition
+ \brief The pressed position within the \c parent Item
+
+ This is the position at which this point was pressed, relative to the
+ bounds of the \l {PointerHandler::parent} {parent}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::scenePressPosition
+ \brief The pressed position within the scene
+
+ This is the position at which this point was pressed, in the coordinate
+ system of the \l {Qt Quick Scene Graph}{scene graph}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty QPointF QtQuick::HandlerPoint::sceneGrabPosition
+ \brief The grabbed position within the scene
+
+ If this point has been grabbed by a Pointer Handler or an Item, it means
+ that object has taken sole responsibility for handling the movement and the
+ release if this point. In that case, this is the position at which the grab
+ occurred, in the coordinate system of the \l {Qt Quick Scene Graph}{scene graph}.
+*/
+
+/*!
+ \readonly
+ \qmlproperty enum QtQuick::HandlerPoint::pressedButtons
+ \brief Which mouse or stylus buttons are currently pressed
+
+ \sa MouseArea::pressedButtons
+*/
+
+/*!
+ \readonly
+ \qmlproperty enum QtQuick::HandlerPoint::modifiers
+ \brief Which modifier keys are currently pressed
+
+ This property holds the keyboard modifiers that were pressed at the time
+ the event occurred.
+
+ \sa MouseArea::modifiers
+*/
+
+/*!
+ \readonly
+ \qmlproperty QVector2D QtQuick::HandlerPoint::velocity
+ \brief A vector representing the average speed and direction of movement
+
+ This is a velocity vector pointing in the direction of movement, in logical
+ pixels per second. It has x and y components, at least one of which will be
+ nonzero when this point is in motion. It holds the average recent velocity:
+ how fast and in which direction the event point has been moving recently.
+
+ \sa QtQuick::EventPoint::velocity, QtQuick::TouchPoint::velocity, QTouchEvent::TouchPoint::velocity
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::HandlerPoint::rotation
+
+ This property holds the rotation angle of the stylus on a graphics tablet
+ or the contact patch of a touchpoint on a touchscreen.
+
+ It is valid only with certain tablet stylus devices and touchscreens that
+ can measure the rotation angle. Otherwise, it will be zero.
+*/
+
+/*!
+ \readonly
+ \qmlproperty qreal QtQuick::HandlerPoint::pressure
+
+ This property tells how hard the user is pressing the stylus on a graphics
+ tablet or the finger against a touchscreen, in the range from \c 0 (no
+ measurable pressure) to \c 1.0 (maximum pressure which the device can
+ measure).
+
+ It is valid only with certain tablets and touchscreens that can measure
+ pressure. Otherwise, it will be zero.
+*/
+
+/*!
+ \readonly
+ \qmlproperty size QtQuick::HandlerPoint::ellipseDiameters
+
+ This property holds the diameters of the contact patch, if the event
+ comes from a touchpoint and the device provides this information.
+
+ A touchpoint is modeled as an elliptical area where the finger is pressed
+ against the touchscreen. (In fact, it could also be modeled as a bitmap;
+ but in that case we expect an elliptical bounding estimate to be fitted to
+ the contact patch before the event is sent.) The harder the user presses,
+ the larger the contact patch; so, these diameters provide an alternate way
+ of detecting pressure, in case the device does not include a separate
+ pressure sensor. The ellipse is centered on \l scenePosition (\l position
+ in the PointerHandler's Item's local coordinates). The \l rotation property
+ provides the rotation of the ellipse, if known. It is expected that if the
+ \l rotation is zero, the \l {QSize::height}{height} is the larger dimension
+ (the major axis), because of the usual hand position, reaching upward or
+ outward across the surface.
+
+ If the contact patch is unknown, or the device is not a touchscreen,
+ these values will be zero.
+
+ \sa QtQuick::EventTouchPoint::ellipseDiameters, QtQuick::TouchPoint::ellipseDiameters, QTouchEvent::TouchPoint::ellipseDiameters
+*/
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickhandlerpoint_p.h b/src/quick/handlers/qquickhandlerpoint_p.h
new file mode 100644
index 0000000000..1dff52942a
--- /dev/null
+++ b/src/quick/handlers/qquickhandlerpoint_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKHANDLERPOINT_H
+#define QQUICKHANDLERPOINT_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 "qquickpointerdevicehandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMultiPointHandler;
+class QQuickSinglePointHandler;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickHandlerPoint {
+ Q_GADGET
+ Q_PROPERTY(int id READ id)
+ Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
+ Q_PROPERTY(QPointF position READ position)
+ Q_PROPERTY(QPointF scenePosition READ scenePosition)
+ Q_PROPERTY(QPointF pressPosition READ pressPosition)
+ Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition)
+ Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition)
+ Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons)
+ Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers)
+ Q_PROPERTY(QVector2D velocity READ velocity)
+ Q_PROPERTY(qreal rotation READ rotation)
+ Q_PROPERTY(qreal pressure READ pressure)
+ Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
+
+public:
+ QQuickHandlerPoint();
+
+ int id() const { return m_id; }
+ Qt::MouseButtons pressedButtons() const { return m_pressedButtons; }
+ Qt::KeyboardModifiers modifiers() const { return m_pressedModifiers; }
+ QPointF pressPosition() const { return m_pressPosition; }
+ QPointF scenePressPosition() const { return m_scenePressPosition; }
+ QPointF sceneGrabPosition() const { return m_sceneGrabPosition; }
+ QPointF position() const { return m_position; }
+ QPointF scenePosition() const { return m_scenePosition; }
+ QVector2D velocity() const { return m_velocity; }
+ qreal rotation() const { return m_rotation; }
+ qreal pressure() const { return m_pressure; }
+ QSizeF ellipseDiameters() const { return m_ellipseDiameters; }
+ QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
+
+ void reset();
+ void reset(const QQuickEventPoint *point);
+ void reset(const QVector<QQuickEventPoint *> &points);
+
+private:
+ int m_id;
+ QPointingDeviceUniqueId m_uniqueId;
+ Qt::MouseButtons m_pressedButtons;
+ Qt::KeyboardModifiers m_pressedModifiers;
+ QPointF m_position;
+ QPointF m_scenePosition;
+ QPointF m_pressPosition;
+ QPointF m_scenePressPosition;
+ QPointF m_sceneGrabPosition;
+ QVector2D m_velocity;
+ qreal m_rotation;
+ qreal m_pressure;
+ QSizeF m_ellipseDiameters;
+ friend class QQuickMultiPointHandler;
+ friend class QQuickSinglePointHandler;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickHandlerPoint)
+
+#endif // QQUICKHANDLERPOINT_H
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index d595b4c9b4..89733a4260 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -91,6 +91,20 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event)
return ret;
}
+void QQuickMultiPointHandler::handlePointerEventImpl(QQuickPointerEvent *event)
+{
+ QQuickPointerHandler::handlePointerEventImpl(event);
+ m_centroid.reset(m_currentPoints);
+ emit centroidChanged();
+}
+
+void QQuickMultiPointHandler::onActiveChanged()
+{
+ if (active()) {
+ m_centroid.m_sceneGrabPosition = m_centroid.m_scenePosition;
+ }
+}
+
QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event)
{
QVector<QQuickEventPoint *> ret;
@@ -207,27 +221,6 @@ bool QQuickMultiPointHandler::sameAsCurrentPoints(QQuickPointerEvent *event)
return ret;
}
-// TODO make templates for these functions somehow?
-QPointF QQuickMultiPointHandler::touchPointCentroid()
-{
- QPointF ret;
- if (Q_UNLIKELY(m_currentPoints.size() == 0))
- return ret;
- for (QQuickEventPoint *point : qAsConst(m_currentPoints))
- ret += point->scenePosition();
- return ret / m_currentPoints.size();
-}
-
-QVector2D QQuickMultiPointHandler::touchPointCentroidVelocity()
-{
- QVector2D ret;
- if (Q_UNLIKELY(m_currentPoints.size() == 0))
- return ret;
- for (QQuickEventPoint *point : qAsConst(m_currentPoints))
- ret += point->velocity();
- return ret / m_currentPoints.size();
-}
-
qreal QQuickMultiPointHandler::averageTouchPointDistance(const QPointF &ref)
{
qreal ret = 0;
diff --git a/src/quick/handlers/qquickmultipointhandler_p.h b/src/quick/handlers/qquickmultipointhandler_p.h
index 67e550d387..5a44866e67 100644
--- a/src/quick/handlers/qquickmultipointhandler_p.h
+++ b/src/quick/handlers/qquickmultipointhandler_p.h
@@ -53,6 +53,7 @@
#include "qquickitem.h"
#include "qevent.h"
+#include "qquickhandlerpoint_p.h"
#include "qquickpointerdevicehandler_p.h"
QT_BEGIN_NAMESPACE
@@ -63,6 +64,7 @@ class Q_AUTOTEST_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHand
Q_PROPERTY(int minimumPointCount READ minimumPointCount WRITE setMinimumPointCount NOTIFY minimumPointCountChanged)
Q_PROPERTY(int maximumPointCount READ maximumPointCount WRITE setMaximumPointCount NOTIFY maximumPointCountChanged)
Q_PROPERTY(qreal pointDistanceThreshold READ pointDistanceThreshold WRITE setPointDistanceThreshold NOTIFY pointDistanceThresholdChanged)
+ Q_PROPERTY(QQuickHandlerPoint centroid READ centroid NOTIFY centroidChanged)
public:
explicit QQuickMultiPointHandler(QObject *parent = nullptr, int minimumPointCount = 2);
@@ -77,10 +79,13 @@ public:
qreal pointDistanceThreshold() const { return m_pointDistanceThreshold; }
void setPointDistanceThreshold(qreal pointDistanceThreshold);
+ QQuickHandlerPoint centroid() const { return m_centroid; }
+
signals:
void minimumPointCountChanged();
void maximumPointCountChanged();
void pointDistanceThresholdChanged();
+ void centroidChanged();
protected:
struct PointData {
@@ -91,10 +96,10 @@ protected:
};
bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ void handlePointerEventImpl(QQuickPointerEvent *event) override;
+ void onActiveChanged() override;
bool sameAsCurrentPoints(QQuickPointerEvent *event);
QVector<QQuickEventPoint *> eligiblePoints(QQuickPointerEvent *event);
- QPointF touchPointCentroid();
- QVector2D touchPointCentroidVelocity();
qreal averageTouchPointDistance(const QPointF &ref);
qreal averageStartingDistance(const QPointF &ref);
qreal averageTouchPointAngle(const QPointF &ref);
@@ -106,6 +111,7 @@ protected:
protected:
QVector<QQuickEventPoint *> m_currentPoints;
+ QQuickHandlerPoint m_centroid;
int m_minimumPointCount;
int m_maximumPointCount;
qreal m_pointDistanceThreshold;
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 57d851ed59..412ad6227d 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -287,11 +287,11 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event)
void QQuickPinchHandler::onActiveChanged()
{
+ QQuickMultiPointHandler::onActiveChanged();
if (active()) {
m_startMatrix = QMatrix4x4();
- m_startCentroid = touchPointCentroid();
- m_startAngles = angles(m_startCentroid);
- m_startDistance = averageTouchPointDistance(m_startCentroid);
+ m_startAngles = angles(m_centroid.sceneGrabPosition());
+ m_startDistance = averageTouchPointDistance(m_centroid.sceneGrabPosition());
m_activeRotation = 0;
m_activeTranslation = QVector2D();
if (const QQuickItem *t = target()) {
@@ -319,6 +319,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
for (QQuickEventPoint *point : qAsConst(m_currentPoints))
qCDebug(lcPinchHandler) << point->state() << point->sceneGrabPosition() << "->" << point->scenePosition();
}
+ QQuickMultiPointHandler::handlePointerEventImpl(event);
qreal dist = 0;
#if QT_CONFIG(gestures)
@@ -328,8 +329,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
m_activeScale = 1;
m_activeRotation = 0;
m_activeTranslation = QVector2D();
- m_centroid = QPointF();
- m_centroidVelocity = QVector2D();
+ m_centroid.reset();
setActive(false);
emit updated();
return;
@@ -344,12 +344,9 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
return;
}
if (!active()) {
- m_centroid = gesture->point(0)->scenePosition();
setActive(true);
- m_startCentroid = m_centroid;
// Native gestures for 2-finger pinch do not allow dragging, so
// the centroid won't move during the gesture, and translation stays at zero
- m_centroidVelocity = QVector2D();
m_activeTranslation = QVector2D();
}
} else
@@ -374,17 +371,15 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
return;
}
// TODO check m_pinchOrigin: right now it acts like it's set to PinchCenter
- m_centroid = touchPointCentroid();
- m_centroidVelocity = touchPointCentroidVelocity();
// avoid mapping the minima and maxima, as they might have unmappable values
// such as -inf/+inf. Because of this we perform the bounding to min/max in local coords.
// 1. scale
- dist = averageTouchPointDistance(m_centroid);
+ dist = averageTouchPointDistance(m_centroid.scenePosition());
m_activeScale = dist / m_startDistance;
m_activeScale = qBound(m_minimumScale/m_startScale, m_activeScale, m_maximumScale/m_startScale);
// 2. rotate
- QVector<PointData> newAngles = angles(m_centroid);
+ QVector<PointData> newAngles = angles(m_centroid.scenePosition());
const qreal angleDelta = averageAngleDelta(m_startAngles, newAngles);
m_activeRotation += angleDelta;
m_startAngles = std::move(newAngles);
@@ -396,7 +391,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
QPointF centroidParentPos;
QRectF bounds(m_minimumX, m_minimumY, m_maximumX - m_minimumX, m_maximumY - m_minimumY);
if (target() && target()->parentItem()) {
- centroidParentPos = target()->parentItem()->mapFromScene(m_centroid);
+ centroidParentPos = target()->parentItem()->mapFromScene(m_centroid.scenePosition());
centroidParentPos = QPointF(qBound(bounds.left(), centroidParentPos.x(), bounds.right()),
qBound(bounds.top(), centroidParentPos.y(), bounds.bottom()));
}
@@ -407,9 +402,8 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
if (target() && target()->parentItem()) {
// 3. Drag/translate
- const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_startCentroid);
+ const QPointF centroidStartParentPos = target()->parentItem()->mapFromScene(m_centroid.sceneGrabPosition());
m_activeTranslation = QVector2D(centroidParentPos - centroidStartParentPos);
-
// apply rotation + scaling around the centroid - then apply translation.
QMatrix4x4 mat;
@@ -432,10 +426,10 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
// TODO some translation inadvertently happens; try to hold the chosen pinch origin in place
} else {
- m_activeTranslation = QVector2D(m_centroid - m_startCentroid);
+ m_activeTranslation = QVector2D(m_centroid.scenePosition() - m_centroid.scenePressPosition());
}
- qCDebug(lcPinchHandler) << "centroid" << m_startCentroid << "->" << m_centroid
+ qCDebug(lcPinchHandler) << "centroid" << m_centroid.scenePressPosition() << "->" << m_centroid.scenePosition()
<< ", distance" << m_startDistance << "->" << dist
<< ", startScale" << m_startScale << "->" << scale
<< ", activeRotation" << m_activeRotation
@@ -456,15 +450,6 @@ void QQuickPinchHandler::handlePointerEventImpl(QQuickPointerEvent *event)
/*!
\readonly
- \qmlproperty QVector2D QtQuick::PinchHandler::centroidVelocity
-
- The average velocity of the \l centroid: a vector representing the speed
- and direction of movement of the whole group of touchpoints, in logical
- pixels per second.
-*/
-
-/*!
- \readonly
\qmlproperty real QtQuick::PinchHandler::scale
The scale factor. It is 1.0 when the gesture begins, increases as the
diff --git a/src/quick/handlers/qquickpinchhandler_p.h b/src/quick/handlers/qquickpinchhandler_p.h
index 9a17971416..c2eedeb9e0 100644
--- a/src/quick/handlers/qquickpinchhandler_p.h
+++ b/src/quick/handlers/qquickpinchhandler_p.h
@@ -66,8 +66,6 @@ class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged)
Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged)
Q_PROPERTY(PinchOrigin pinchOrigin READ pinchOrigin WRITE setPinchOrigin NOTIFY pinchOriginChanged)
- Q_PROPERTY(QPointF centroid READ centroid NOTIFY updated)
- Q_PROPERTY(QVector2D centroidVelocity READ centroidVelocity NOTIFY updated)
Q_PROPERTY(qreal scale READ scale NOTIFY updated)
Q_PROPERTY(qreal rotation READ rotation NOTIFY updated)
Q_PROPERTY(QVector2D translation READ translation NOTIFY updated)
@@ -103,9 +101,6 @@ public:
QVector2D translation() const { return m_activeTranslation; }
qreal scale() const { return m_activeScale; }
qreal rotation() const { return m_activeRotation; }
- QPointF centroid() const { return m_centroid; }
- QVector2D centroidVelocity() const { return m_centroidVelocity; }
-
qreal minimumX() const { return m_minimumX; }
void setMinimumX(qreal minX);
qreal maximumX() const { return m_maximumX; }
@@ -137,8 +132,6 @@ private:
qreal m_activeScale;
qreal m_activeRotation;
QVector2D m_activeTranslation;
- QPointF m_centroid;
- QVector2D m_centroidVelocity;
qreal m_minimumScale;
qreal m_maximumScale;
@@ -156,7 +149,6 @@ private:
// internal
qreal m_startScale;
qreal m_startRotation;
- QPointF m_startCentroid;
qreal m_startDistance;
QPointF m_startPos;
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 06831613b6..add6513c1a 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qquickpointerdevicehandler_p.h"
+#include "qquickpointerdevicehandler_p_p.h"
#include <private/qquickitem_p.h>
#include <QMouseEvent>
#include <QDebug>
@@ -59,10 +59,12 @@ QT_BEGIN_NAMESPACE
allow filtering based on device type, pointer type, or keyboard modifiers.
*/
QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QObject *parent)
- : QQuickPointerHandler(parent)
- , m_acceptedDevices(QQuickPointerDevice::AllDevices)
- , m_acceptedPointerTypes(QQuickPointerDevice::AllPointerTypes)
- , m_acceptedModifiers(Qt::KeyboardModifierMask)
+ : QQuickPointerHandler(*(new QQuickPointerDeviceHandlerPrivate), parent)
+{
+}
+
+QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QObject *parent)
+ : QQuickPointerHandler(dd, parent)
{
}
@@ -70,6 +72,24 @@ QQuickPointerDeviceHandler::~QQuickPointerDeviceHandler()
{
}
+QQuickPointerDevice::DeviceTypes QQuickPointerDeviceHandler::acceptedDevices() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedDevices;
+}
+
+QQuickPointerDevice::PointerTypes QQuickPointerDeviceHandler::acceptedPointerTypes() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedPointerTypes;
+}
+
+Qt::KeyboardModifiers QQuickPointerDeviceHandler::acceptedModifiers() const
+{
+ Q_D(const QQuickPointerDeviceHandler);
+ return d->acceptedModifiers;
+}
+
/*!
\qmlproperty int PointerDeviceHandler::acceptedDevices
@@ -98,10 +118,11 @@ QQuickPointerDeviceHandler::~QQuickPointerDeviceHandler()
*/
void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices)
{
- if (m_acceptedDevices == acceptedDevices)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedDevices == acceptedDevices)
return;
- m_acceptedDevices = acceptedDevices;
+ d->acceptedDevices = acceptedDevices;
emit acceptedDevicesChanged();
}
@@ -136,10 +157,11 @@ void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceT
*/
void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes)
{
- if (m_acceptedPointerTypes == acceptedPointerTypes)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedPointerTypes == acceptedPointerTypes)
return;
- m_acceptedPointerTypes = acceptedPointerTypes;
+ d->acceptedPointerTypes = acceptedPointerTypes;
emit acceptedPointerTypesChanged();
}
@@ -171,26 +193,28 @@ void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::Po
*/
void QQuickPointerDeviceHandler::setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers)
{
- if (m_acceptedModifiers == acceptedModifiers)
+ Q_D(QQuickPointerDeviceHandler);
+ if (d->acceptedModifiers == acceptedModifiers)
return;
- m_acceptedModifiers = acceptedModifiers;
+ d->acceptedModifiers = acceptedModifiers;
emit acceptedModifiersChanged();
}
bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
+ Q_D(QQuickPointerDeviceHandler);
if (!QQuickPointerHandler::wantsPointerEvent(event))
return false;
qCDebug(lcPointerHandlerDispatch) << objectName()
- << "checking device type" << m_acceptedDevices
- << "pointer type" << m_acceptedPointerTypes
- << "modifiers" << m_acceptedModifiers;
- if ((event->device()->type() & m_acceptedDevices) == 0)
+ << "checking device type" << d->acceptedDevices
+ << "pointer type" << d->acceptedPointerTypes
+ << "modifiers" << d->acceptedModifiers;
+ if ((event->device()->type() & d->acceptedDevices) == 0)
return false;
- if ((event->device()->pointerType() & m_acceptedPointerTypes) == 0)
+ if ((event->device()->pointerType() & d->acceptedPointerTypes) == 0)
return false;
- if (m_acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != m_acceptedModifiers)
+ if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers)
return false;
return true;
}
diff --git a/src/quick/handlers/qquickpointerdevicehandler_p.h b/src/quick/handlers/qquickpointerdevicehandler_p.h
index 1638604ea7..cd861b2bf1 100644
--- a/src/quick/handlers/qquickpointerdevicehandler_p.h
+++ b/src/quick/handlers/qquickpointerdevicehandler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -36,6 +36,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#include "qquickpointerhandler_p.h"
#ifndef QQUICKPOINTERDEVICEHANDLER_H
#define QQUICKPOINTERDEVICEHANDLER_H
@@ -51,10 +52,10 @@
// We mean it.
//
-#include "qquickpointerhandler_p.h"
-
QT_BEGIN_NAMESPACE
+class QQuickPointerDeviceHandlerPrivate;
+
class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler
{
Q_OBJECT
@@ -66,11 +67,11 @@ public:
explicit QQuickPointerDeviceHandler(QObject *parent = nullptr);
~QQuickPointerDeviceHandler();
- QQuickPointerDevice::DeviceTypes acceptedDevices() const { return m_acceptedDevices; }
- QQuickPointerDevice::PointerTypes acceptedPointerTypes() const { return m_acceptedPointerTypes; }
- Qt::KeyboardModifiers acceptedModifiers() const { return m_acceptedModifiers; }
+ QQuickPointerDevice::DeviceTypes acceptedDevices() const;
+ QQuickPointerDevice::PointerTypes acceptedPointerTypes() const;
+ Qt::KeyboardModifiers acceptedModifiers() const;
-public slots:
+public Q_SLOTS:
void setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices);
void setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes);
void setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers);
@@ -81,12 +82,11 @@ Q_SIGNALS:
void acceptedModifiersChanged();
protected:
+ QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QObject *parent = nullptr);
+
bool wantsPointerEvent(QQuickPointerEvent *event) override;
-protected:
- QQuickPointerDevice::DeviceTypes m_acceptedDevices;
- QQuickPointerDevice::PointerTypes m_acceptedPointerTypes;
- Qt::KeyboardModifiers m_acceptedModifiers;
+ Q_DECLARE_PRIVATE(QQuickPointerDeviceHandler)
};
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerdevicehandler_p_p.h b/src/quick/handlers/qquickpointerdevicehandler_p_p.h
new file mode 100644
index 0000000000..ee6bd060d6
--- /dev/null
+++ b/src/quick/handlers/qquickpointerdevicehandler_p_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERDEVICEHANDLER_P_H
+#define QQUICKPOINTERDEVICEHANDLER_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 "qquickpointerdevicehandler_p.h"
+#include "qquickpointerhandler_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPointerDeviceHandler)
+
+public:
+ static QQuickPointerDeviceHandlerPrivate* get(QQuickPointerDeviceHandler *q) { return q->d_func(); }
+ static const QQuickPointerDeviceHandlerPrivate* get(const QQuickPointerDeviceHandler *q) { return q->d_func(); }
+
+ QQuickPointerDevice::DeviceTypes acceptedDevices = QQuickPointerDevice::AllDevices;
+ QQuickPointerDevice::PointerTypes acceptedPointerTypes = QQuickPointerDevice::AllPointerTypes;
+ Qt::KeyboardModifiers acceptedModifiers = Qt::KeyboardModifierMask;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOINTERDEVICEHANDLER_P_H
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index e5b1dc8985..a0325dd0c6 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -38,6 +38,8 @@
****************************************************************************/
#include "qquickpointerhandler_p.h"
+#include "qquickpointerhandler_p_p.h"
+#include <QtQuick/private/qquickitem_p.h>
QT_BEGIN_NAMESPACE
@@ -60,15 +62,12 @@ Q_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
*/
QQuickPointerHandler::QQuickPointerHandler(QObject *parent)
- : QObject(parent)
- , m_currentEvent(nullptr)
- , m_target(nullptr)
- , m_enabled(true)
- , m_active(false)
- , m_targetExplicitlySet(false)
- , m_hadKeepMouseGrab(false)
- , m_hadKeepTouchGrab(false)
- , m_grabPermissions(CanTakeOverFromItems | CanTakeOverFromHandlersOfDifferentType | ApprovesTakeOverByAnything)
+ : QObject(*(new QQuickPointerHandlerPrivate), parent)
+{
+}
+
+QQuickPointerHandler::QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
{
}
@@ -113,8 +112,9 @@ void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEv
setActive(false);
point->setAccepted(false);
if (auto par = parentItem()) {
- par->setKeepMouseGrab(m_hadKeepMouseGrab);
- par->setKeepTouchGrab(m_hadKeepTouchGrab);
+ Q_D(const QQuickPointerHandler);
+ par->setKeepMouseGrab(d->hadKeepMouseGrab);
+ par->setKeepTouchGrab(d->hadKeepTouchGrab);
}
break;
case QQuickEventPoint::OverrideGrabPassive:
@@ -130,7 +130,6 @@ void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEv
}
/*!
- \internal
Acquire or give up a passive grab of the given \a point, according to the \a grab state.
Unlike the exclusive grab, multiple PointerHandlers can have passive grabs
@@ -181,19 +180,20 @@ bool QQuickPointerHandler::canGrab(QQuickEventPoint *point)
*/
bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObject *proposedGrabber)
{
+ Q_D(const QQuickPointerHandler);
bool allowed = false;
if (proposedGrabber == this) {
QObject* existingGrabber = point->exclusiveGrabber();
- allowed = (existingGrabber == nullptr) || ((m_grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
+ allowed = (existingGrabber == nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
if (existingGrabber) {
if (QQuickPointerHandler *existingPhGrabber = point->grabberPointerHandler()) {
- if (!allowed && (m_grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
+ if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
existingPhGrabber->metaObject()->className() != metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & CanTakeOverFromHandlersOfSameType) &&
+ if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
existingPhGrabber->metaObject()->className() == metaObject()->className())
allowed = true;
- } else if ((m_grabPermissions & CanTakeOverFromItems)) {
+ } else if ((d->grabPermissions & CanTakeOverFromItems)) {
QQuickItem * existingItemGrabber = point->grabberItem();
if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && point->pointerEvent()->asPointerMouseEvent()) ||
(existingItemGrabber->keepTouchGrab() && point->pointerEvent()->asPointerTouchEvent())))
@@ -203,18 +203,18 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
} else {
// proposedGrabber is different: that means this instance will lose its grab
if (proposedGrabber) {
- if ((m_grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
+ if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
proposedGrabber->metaObject()->className() != metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
proposedGrabber->metaObject()->className() == metaObject()->className())
allowed = true;
- if (!allowed && (m_grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits("QQuickItem"))
+ if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits("QQuickItem"))
allowed = true;
} else {
- if (!allowed && (m_grabPermissions & ApprovesCancellation))
+ if (!allowed && (d->grabPermissions & ApprovesCancellation))
allowed = true;
}
}
@@ -236,12 +236,19 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec
which allows most takeover scenarios but avoids e.g. two PinchHandlers fighting
over the same touchpoints.
*/
+QQuickPointerHandler::GrabPermissions QQuickPointerHandler::grabPermissions() const
+{
+ Q_D(const QQuickPointerHandler);
+ return static_cast<QQuickPointerHandler::GrabPermissions>(d->grabPermissions);
+}
+
void QQuickPointerHandler::setGrabPermissions(GrabPermissions grabPermission)
{
- if (m_grabPermissions == grabPermission)
+ Q_D(QQuickPointerHandler);
+ if (d->grabPermissions == grabPermission)
return;
- m_grabPermissions = grabPermission;
+ d->grabPermissions = grabPermission;
emit grabPermissionChanged();
}
@@ -253,8 +260,13 @@ void QQuickPointerHandler::componentComplete()
{
}
+QQuickPointerEvent *QQuickPointerHandler::currentEvent()
+{
+ Q_D(const QQuickPointerHandler);
+ return d->currentEvent;
+}
+
/*!
- \internal
Acquire or give up the exclusive grab of the given \a point, according to
the \a grab state, and subject to the rules: canGrab(), and the rule not to
relinquish another handler's grab. Returns true if permission is granted,
@@ -284,7 +296,6 @@ bool QQuickPointerHandler::setExclusiveGrab(QQuickEventPoint *point, bool grab)
}
/*!
- \internal
Cancel any existing grab of the given \a point.
*/
void QQuickPointerHandler::cancelAllGrabs(QQuickEventPoint *point)
@@ -313,15 +324,28 @@ bool QQuickPointerHandler::parentContains(const QQuickEventPoint *point) const
If a PointerHandler is disabled, it will reject all events
and no signals will be emitted.
*/
+bool QQuickPointerHandler::enabled() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->enabled;
+}
+
void QQuickPointerHandler::setEnabled(bool enabled)
{
- if (m_enabled == enabled)
+ Q_D(QQuickPointerHandler);
+ if (d->enabled == enabled)
return;
- m_enabled = enabled;
+ d->enabled = enabled;
emit enabledChanged();
}
+bool QQuickPointerHandler::active() const
+{
+ Q_D(const QQuickPointerHandler);
+ return d->active;
+}
+
/*!
\qmlproperty Item QtQuick::PointerHandler::target
@@ -335,21 +359,28 @@ void QQuickPointerHandler::setEnabled(bool enabled)
*/
void QQuickPointerHandler::setTarget(QQuickItem *target)
{
- m_targetExplicitlySet = true;
- if (m_target == target)
+ Q_D(QQuickPointerHandler);
+ d->targetExplicitlySet = true;
+ if (d->target == target)
return;
- QQuickItem *oldTarget = m_target;
- m_target = target;
+ QQuickItem *oldTarget = d->target;
+ d->target = target;
onTargetChanged(oldTarget);
emit targetChanged();
}
+QQuickItem *QQuickPointerHandler::parentItem() const
+{
+ return static_cast<QQuickItem *>(QObject::parent());
+}
+
QQuickItem *QQuickPointerHandler::target() const
{
- if (!m_targetExplicitlySet)
+ Q_D(const QQuickPointerHandler);
+ if (!d->targetExplicitlySet)
return parentItem();
- return m_target;
+ return d->target;
}
void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
@@ -374,8 +405,14 @@ void QQuickPointerHandler::handlePointerEvent(QQuickPointerEvent *event)
bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
{
+ Q_D(const QQuickPointerHandler);
Q_UNUSED(event)
- return m_enabled;
+ return d->enabled;
+}
+
+bool QQuickPointerHandler::wantsEventPoint(QQuickEventPoint *point)
+{
+ return parentContains(point);
}
/*!
@@ -390,9 +427,10 @@ bool QQuickPointerHandler::wantsPointerEvent(QQuickPointerEvent *event)
*/
void QQuickPointerHandler::setActive(bool active)
{
- if (m_active != active) {
- qCDebug(lcPointerHandlerActive) << this << m_active << "->" << active;
- m_active = active;
+ Q_D(QQuickPointerHandler);
+ if (d->active != active) {
+ qCDebug(lcPointerHandlerActive) << this << d->active << "->" << active;
+ d->active = active;
onActiveChanged();
emit activeChanged();
}
@@ -400,7 +438,8 @@ void QQuickPointerHandler::setActive(bool active)
void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
{
- m_currentEvent = event;
+ Q_D(QQuickPointerHandler);
+ d->currentEvent = event;
}
/*!
@@ -430,4 +469,20 @@ void QQuickPointerHandler::handlePointerEventImpl(QQuickPointerEvent *event)
emitted when the grab is stolen by a different Pointer Handler or Item.
*/
+QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
+ : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
+ QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
+ QQuickPointerHandler::ApprovesTakeOverByAnything)
+ , enabled(true)
+ , active(false)
+ , targetExplicitlySet(false)
+ , hadKeepMouseGrab(false)
+ , hadKeepTouchGrab(false)
+{
+}
+
+QQuickPointerHandlerPrivate::~QQuickPointerHandlerPrivate()
+{
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index e2bcce8fc9..1327e6be4e 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -51,8 +51,6 @@
// We mean it.
//
-#include "qevent.h"
-
#include <QtQuick/private/qquickevents_p_p.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -60,6 +58,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcPointerHandlerDispatch)
+class QQuickPointerHandlerPrivate;
+
class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandler : public QObject, public QQmlParserStatus
{
Q_OBJECT
@@ -91,19 +91,19 @@ public:
Q_FLAG(GrabPermissions)
public:
- bool enabled() const { return m_enabled; }
+ bool enabled() const;
void setEnabled(bool enabled);
- bool active() const { return m_active; }
+ bool active() const;
QQuickItem *target() const;
void setTarget(QQuickItem *target);
- QQuickItem * parentItem() const { return static_cast<QQuickItem *>(QObject::parent()); }
+ QQuickItem * parentItem() const;
void handlePointerEvent(QQuickPointerEvent *event);
- GrabPermissions grabPermissions() const { return static_cast<GrabPermissions>(m_grabPermissions); }
+ GrabPermissions grabPermissions() const;
void setGrabPermissions(GrabPermissions grabPermissions);
Q_SIGNALS:
@@ -115,11 +115,14 @@ Q_SIGNALS:
void canceled(QQuickEventPoint *point);
protected:
+ QQuickPointerHandler(QQuickPointerHandlerPrivate &dd, QObject *parent);
+
void classBegin() override;
void componentComplete() override;
- QQuickPointerEvent *currentEvent() { return m_currentEvent; }
+ QQuickPointerEvent *currentEvent();
virtual bool wantsPointerEvent(QQuickPointerEvent *event);
+ virtual bool wantsEventPoint(QQuickEventPoint *point);
virtual void handlePointerEventImpl(QQuickPointerEvent *event);
void setActive(bool active);
virtual void onTargetChanged(QQuickItem *oldTarget) { Q_UNUSED(oldTarget); }
@@ -133,19 +136,10 @@ protected:
QPointF eventPos(const QQuickEventPoint *point) const;
bool parentContains(const QQuickEventPoint *point) const;
-private:
- QQuickPointerEvent *m_currentEvent;
- QQuickItem *m_target;
- bool m_enabled : 1;
- bool m_active : 1;
- bool m_targetExplicitlySet : 1;
- bool m_hadKeepMouseGrab : 1; // some handlers override target()->setKeepMouseGrab(); this remembers previous state
- bool m_hadKeepTouchGrab : 1; // some handlers override target()->setKeepTouchGrab(); this remembers previous state
- uint m_reserved : 19;
- uint8_t m_grabPermissions : 8;
-
friend class QQuickEventPoint;
friend class QQuickWindowPrivate;
+
+ Q_DECLARE_PRIVATE(QQuickPointerHandler)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPointerHandler::GrabPermissions)
diff --git a/src/quick/handlers/qquickpointerhandler_p_p.h b/src/quick/handlers/qquickpointerhandler_p_p.h
new file mode 100644
index 0000000000..ce50b98c57
--- /dev/null
+++ b/src/quick/handlers/qquickpointerhandler_p_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOINTERHANDLER_P_H
+#define QQUICKPOINTERHANDLER_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 "qevent.h"
+
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerHandlerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPointerHandler)
+
+public:
+ static QQuickPointerHandlerPrivate* get(QQuickPointerHandler *q) { return q->d_func(); }
+ static const QQuickPointerHandlerPrivate* get(const QQuickPointerHandler *q) { return q->d_func(); }
+
+ QQuickPointerHandlerPrivate();
+ virtual ~QQuickPointerHandlerPrivate() override;
+
+ QQuickPointerEvent *currentEvent = nullptr;
+ QQuickItem *target = nullptr;
+ uint8_t grabPermissions : 8;
+ bool enabled : 1;
+ bool active : 1;
+ bool targetExplicitlySet : 1;
+ bool hadKeepMouseGrab : 1; // some handlers override target()->setKeepMouseGrab(); this remembers previous state
+ bool hadKeepTouchGrab : 1; // some handlers override target()->setKeepTouchGrab(); this remembers previous state
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOINTERHANDLER_P_H
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index 9df20390e4..04b4214bab 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -79,16 +79,23 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
// It's expected to be an update or a release.
// If we no longer want it, cancel the grab.
int candidatePointCount = 0;
+ bool missing = true;
QQuickEventPoint *point = nullptr;
int c = event->pointCount();
for (int i = 0; i < c; ++i) {
QQuickEventPoint *p = event->point(i);
+ const bool found = (p->pointId() == m_pointInfo.m_id);
+ if (found)
+ missing = false;
if (wantsEventPoint(p)) {
++candidatePointCount;
- if (p->pointId() == m_pointInfo.m_id)
+ if (found)
point = p;
}
}
+ if (missing)
+ qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << m_pointInfo.m_id
+ << "is missing from current event, but was neither canceled nor released";
if (point) {
if (candidatePointCount == 1 || (candidatePointCount > 1 && m_ignoreAdditionalPoints)) {
point->setAccepted();
@@ -97,8 +104,6 @@ bool QQuickSinglePointHandler::wantsPointerEvent(QQuickPointerEvent *event)
point->cancelAllGrabs(this);
}
} else {
- qCWarning(DBG_TOUCH_TARGET) << this << "pointId" << hex << m_pointInfo.m_id
- << "is missing from current event, but was neither canceled nor released";
return false;
}
} else {
@@ -130,48 +135,16 @@ void QQuickSinglePointHandler::handlePointerEventImpl(QQuickPointerEvent *event)
if (!m_pointInfo.m_id || !currentPoint->isAccepted()) {
reset();
} else {
- if (event->asPointerTouchEvent()) {
- QQuickEventTouchPoint *tp = static_cast<QQuickEventTouchPoint *>(currentPoint);
- m_pointInfo.m_uniqueId = tp->uniqueId();
- m_pointInfo.m_rotation = tp->rotation();
- m_pointInfo.m_pressure = tp->pressure();
- m_pointInfo.m_ellipseDiameters = tp->ellipseDiameters();
- } else if (event->asPointerTabletEvent()) {
- // TODO
- } else {
- m_pointInfo.m_uniqueId = event->device()->uniqueId();
- m_pointInfo.m_rotation = 0;
- m_pointInfo.m_pressure = event->buttons() ? 1 : 0;
- m_pointInfo.m_ellipseDiameters = QSizeF();
- }
- m_pointInfo.m_position = currentPoint->position();
- m_pointInfo.m_scenePosition = currentPoint->scenePosition();
- if (currentPoint->state() == QQuickEventPoint::Updated)
- m_pointInfo.m_velocity = currentPoint->velocity();
+ m_pointInfo.reset(currentPoint);
handleEventPoint(currentPoint);
- switch (currentPoint->state()) {
- case QQuickEventPoint::Pressed:
- m_pointInfo.m_pressPosition = currentPoint->position();
- m_pointInfo.m_scenePressPosition = currentPoint->scenePosition();
- m_pointInfo.m_pressedButtons = event->buttons();
- break;
- case QQuickEventPoint::Released:
+ if (currentPoint->state() == QQuickEventPoint::Released) {
setExclusiveGrab(currentPoint, false);
reset();
- break;
- default:
- m_pointInfo.m_pressedButtons = event->buttons();
- break;
}
emit pointChanged();
}
}
-bool QQuickSinglePointHandler::wantsEventPoint(QQuickEventPoint *point)
-{
- return parentContains(point);
-}
-
void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabState stateChange, QQuickEventPoint *point)
{
if (grabber != this)
@@ -264,213 +237,4 @@ void QQuickSinglePointHandler::reset()
handled, this object is reset to default values (all coordinates are 0).
*/
-/*!
- \qmltype HandlerPoint
- \instantiates QQuickHandlerPoint
- \inqmlmodule Qt.labs.handlers
- \ingroup qtquick-handlers
- \brief An event point.
-
- A QML representation of a QQuickEventPoint.
-
- It's possible to make bindings to properties of a \l SinglePointHandler's
- current point. For example:
-
- \snippet pointerHandlers/dragHandlerNullTarget.qml 0
-
- The point is kept up-to-date when the DragHandler is actively responding to
- an EventPoint; but when the point is released, or the current point is
- being handled by a different handler, \c position.x and \c position.y are 0.
-
- \note This is practically identical to QtQuick::EventPoint; however an
- EventPoint is a long-lived QObject which is invalidated between gestures
- and reused for subsequent event deliveries. Continuous bindings to its
- properties are not possible, and an individual handler cannot rely on it
- outside the period when that point is part of an active gesture which that
- handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
- This allows you to make lifetime bindings to its properties.
-
- \sa SinglePointHandler::point
-*/
-
-QQuickHandlerPoint::QQuickHandlerPoint()
- : m_id(0)
- , m_rotation(0)
- , m_pressure(0)
-{}
-
-void QQuickHandlerPoint::reset()
-{
- m_id = 0;
- m_uniqueId = QPointingDeviceUniqueId();
- m_position = QPointF();
- m_scenePosition = QPointF();
- m_pressPosition = QPointF();
- m_scenePressPosition = QPointF();
- m_sceneGrabPosition = QPointF();
- m_velocity = QVector2D();
- m_rotation = 0;
- m_pressure = 0;
- m_ellipseDiameters = QSizeF();
- m_pressedButtons = Qt::NoButton;
-}
-
-/*!
- \readonly
- \qmlproperty int QtQuick::HandlerPoint::id
- \brief The ID number of the point
-
- During a touch gesture, from the time that the first finger is pressed
- until the last finger is released, each touchpoint will have a unique ID
- number. Likewise, if input from multiple devices occurs (for example
- simultaneous mouse and touch presses), all the current event points from
- all the devices will have unique IDs.
-
- \note Do not assume that id numbers start at zero or that they are
- sequential. Such an assumption is often false due to the way the underlying
- drivers work.
-
- \sa QTouchEvent::TouchPoint::id
-*/
-
-/*!
- \readonly
- \qmlproperty PointingDeviceUniqueId QtQuick::HandlerPoint::uniqueId
- \brief The unique ID of the point, if any
-
- This is normally empty, because touchscreens cannot uniquely identify fingers.
-
- On some types of touchscreens, especially those using TUIO drivers,
- it's possible to use recognizable physical tokens (fiducial objects)
- in addition to fingers. So if this point is a touch point, and
- uniqueId is set, it is the identifier for such an object.
-
- On a graphics tablet, each type of stylus or other tool often has a unique
- ID or serial number, which can be useful to respond in different ways to
- different tools.
-
- Interpreting the contents of this ID requires knowledge of the hardware and
- drivers in use.
-
- \sa QTabletEvent::uniqueId, QtQuick::TouchPoint::uniqueId, QtQuick::EventTouchPoint::uniqueId
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::position
- \brief The position within the \c parent Item
-
- This is the position of the event point relative to the bounds of
- the \l {PointerHandler::parent} {parent}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
- \brief The position within the scene
-
- This is the position of the event point relative to the bounds of the Qt
- Quick scene (typically the whole window).
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::pressPosition
- \brief The pressed position within the \c parent Item
-
- This is the position at which this point was pressed, relative to the
- bounds of the \l {PointerHandler::parent} {parent}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::scenePressPosition
- \brief The pressed position within the scene
-
- This is the position at which this point was pressed, in the coordinate
- system of the \l {Qt Quick Scene Graph}{scene graph}.
-*/
-
-/*!
- \readonly
- \qmlproperty QPointF QtQuick::HandlerPoint::sceneGrabPosition
- \brief The grabbed position within the scene
-
- If this point has been grabbed by a Pointer Handler or an Item, it means
- that object has taken sole responsibility for handling the movement and the
- release if this point. In that case, this is the position at which the grab
- occurred, in the coordinate system of the \l {Qt Quick Scene Graph}{scene graph}.
-*/
-
-/*!
- \readonly
- \qmlproperty enum QtQuick::HandlerPoint::pressedButtons
- \brief Which mouse or stylus buttons are currently pressed
-
- \sa MouseArea::pressedButtons
-*/
-
-/*!
- \readonly
- \qmlproperty QVector2D QtQuick::HandlerPoint::velocity
- \brief A vector representing the average speed and direction of movement
-
- This is a velocity vector pointing in the direction of movement, in logical
- pixels per second. It has x and y components, at least one of which will be
- nonzero when this point is in motion. It holds the average recent velocity:
- how fast and in which direction the event point has been moving recently.
-
- \sa QtQuick::EventPoint::velocity, QtQuick::TouchPoint::velocity, QTouchEvent::TouchPoint::velocity
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::HandlerPoint::rotation
-
- This property holds the rotation angle of the stylus on a graphics tablet
- or the contact patch of a touchpoint on a touchscreen.
-
- It is valid only with certain tablet stylus devices and touchscreens that
- can measure the rotation angle. Otherwise, it will be zero.
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::HandlerPoint::pressure
-
- This property tells how hard the user is pressing the stylus on a graphics
- tablet or the finger against a touchscreen, in the range from \c 0 (no
- measurable pressure) to \c 1.0 (maximum pressure which the device can
- measure).
-
- It is valid only with certain tablets and touchscreens that can measure
- pressure. Otherwise, it will be zero.
-*/
-
-/*!
- \readonly
- \qmlproperty size QtQuick::HandlerPoint::ellipseDiameters
-
- This property holds the diameters of the contact patch, if the event
- comes from a touchpoint and the device provides this information.
-
- A touchpoint is modeled as an elliptical area where the finger is pressed
- against the touchscreen. (In fact, it could also be modeled as a bitmap;
- but in that case we expect an elliptical bounding estimate to be fitted to
- the contact patch before the event is sent.) The harder the user presses,
- the larger the contact patch; so, these diameters provide an alternate way
- of detecting pressure, in case the device does not include a separate
- pressure sensor. The ellipse is centered on \l scenePosition (\l position
- in the PointerHandler's Item's local coordinates). The \l rotation property
- provides the rotation of the ellipse, if known. It is expected that if the
- \l rotation is zero, the \l {QSize::height}{height} is the larger dimension
- (the major axis), because of the usual hand position, reaching upward or
- outward across the surface.
-
- If the contact patch is unknown, or the device is not a touchscreen,
- these values will be zero.
-
- \sa QtQuick::EventTouchPoint::ellipseDiameters, QtQuick::TouchPoint::ellipseDiameters, QTouchEvent::TouchPoint::ellipseDiameters
-*/
-
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquicksinglepointhandler_p.h b/src/quick/handlers/qquicksinglepointhandler_p.h
index 7606b4f7ba..66ef1dbeb2 100644
--- a/src/quick/handlers/qquicksinglepointhandler_p.h
+++ b/src/quick/handlers/qquicksinglepointhandler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -51,60 +51,11 @@
// We mean it.
//
+#include "qquickhandlerpoint_p.h"
#include "qquickpointerdevicehandler_p.h"
QT_BEGIN_NAMESPACE
-class QQuickSinglePointHandler;
-
-class Q_QUICK_PRIVATE_EXPORT QQuickHandlerPoint {
- Q_GADGET
- Q_PROPERTY(int id READ id)
- Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
- Q_PROPERTY(QPointF position READ position)
- Q_PROPERTY(QPointF scenePosition READ scenePosition)
- Q_PROPERTY(QPointF pressPosition READ pressPosition)
- Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition)
- Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition)
- Q_PROPERTY(Qt::MouseButtons pressedButtons READ pressedButtons)
- Q_PROPERTY(QVector2D velocity READ velocity)
- Q_PROPERTY(qreal rotation READ rotation)
- Q_PROPERTY(qreal pressure READ pressure)
- Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
-
-public:
- QQuickHandlerPoint();
-
- int id() const { return m_id; }
- Qt::MouseButtons pressedButtons() const { return m_pressedButtons; }
- QPointF pressPosition() const { return m_pressPosition; }
- QPointF scenePressPosition() const { return m_scenePressPosition; }
- QPointF sceneGrabPosition() const { return m_sceneGrabPosition; }
- QPointF position() const { return m_position; }
- QPointF scenePosition() const { return m_scenePosition; }
- QVector2D velocity() const { return m_velocity; }
- qreal rotation() const { return m_rotation; }
- qreal pressure() const { return m_pressure; }
- QSizeF ellipseDiameters() const { return m_ellipseDiameters; }
- QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
-
-private:
- void reset();
- int m_id;
- QPointingDeviceUniqueId m_uniqueId;
- Qt::MouseButtons m_pressedButtons;
- QPointF m_position;
- QPointF m_scenePosition;
- QPointF m_pressPosition;
- QPointF m_scenePressPosition;
- QPointF m_sceneGrabPosition;
- QVector2D m_velocity;
- qreal m_rotation;
- qreal m_pressure;
- QSizeF m_ellipseDiameters;
- friend class QQuickSinglePointHandler;
-};
-
class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointHandler : public QQuickPointerDeviceHandler
{
Q_OBJECT
@@ -126,7 +77,6 @@ Q_SIGNALS:
protected:
bool wantsPointerEvent(QQuickPointerEvent *event) override;
- virtual bool wantsEventPoint(QQuickEventPoint *point);
void handlePointerEventImpl(QQuickPointerEvent *event) override;
virtual void handleEventPoint(QQuickEventPoint *point) = 0;
@@ -148,7 +98,6 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickHandlerPoint)
QML_DECLARE_TYPE(QQuickSinglePointHandler)
#endif // QQUICKPOINTERSINGLEHANDLER_H
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 902ff0df10..b12894e23f 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -107,7 +107,7 @@ QQuickTapHandler::~QQuickTapHandler()
{
}
-static bool dragOverThreshold(QQuickEventPoint *point)
+static bool dragOverThreshold(const QQuickEventPoint *point)
{
QPointF delta = point->scenePosition() - point->scenePressPosition();
return (QQuickWindowPrivate::dragOverThreshold(delta.x(), Qt::XAxis, point) ||
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2c115f4d3c..ef6f5fa716 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -596,7 +596,7 @@ public:
static QV4::Heap::QQuickJSContext2DPrototype *create(QV4::ExecutionEngine *engine)
{
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocObject<QQuickJSContext2DPrototype>());
+ QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocate<QQuickJSContext2DPrototype>());
o->defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0);
o->defineDefaultProperty(QStringLiteral("restore"), method_restore, 0);
@@ -954,7 +954,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
{
QV4::Scope scope(v4);
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DPixelData>());
QV4::ScopedObject p(scope, ed->pixelArrayProto.value());
pixelData->setPrototype(p);
@@ -966,7 +966,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
*pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DImageData>());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DImageData>());
imageData->d()->pixelData = pixelData.asReturnedValue();
return imageData.asReturnedValue();
}
@@ -1582,7 +1582,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(const
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QLinearGradient(x0, y0, x1, y1);
@@ -1634,7 +1634,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(const
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r1, QPointF(x0, y0), r0);
@@ -1678,7 +1678,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(cons
QQuickContext2DEngineData *ed = engineData(scope.engine);
- QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QConicalGradient(x, y, angle);
@@ -1738,7 +1738,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(const QV4::F
CHECK_CONTEXT(r)
if (argc >= 2) {
- QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>());
QColor color = scope.engine->toVariant(argv[0], qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
@@ -4399,7 +4399,7 @@ void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine)
QQuickContext2DEngineData *ed = engineData(engine);
QV4::Scope scope(engine);
- QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocObject<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocate<QQuickJSContext2D>());
QV4::ScopedObject p(scope, ed->contextPrototype.value());
wrapper->setPrototype(p);
wrapper->d()->context = this;
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 1acb3b5265..e649b5429d 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -122,9 +122,11 @@ qtConfig(quick-gridview) {
qtConfig(quick-itemview) {
HEADERS += \
+ $$PWD/qquickitemviewfxitem_p_p.h \
$$PWD/qquickitemview_p.h \
$$PWD/qquickitemview_p_p.h
SOURCES += \
+ $$PWD/qquickitemviewfxitem.cpp \
$$PWD/qquickitemview.cpp
}
@@ -142,6 +144,14 @@ qtConfig(quick-listview) {
$$PWD/qquicklistview.cpp
}
+qtConfig(quick-tableview) {
+ HEADERS += \
+ $$PWD/qquicktableview_p.h \
+ $$PWD/qquicktableview_p_p.h
+ SOURCES += \
+ $$PWD/qquicktableview.cpp
+}
+
qtConfig(quick-pathview) {
HEADERS += \
$$PWD/qquickpathview_p.h \
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 603d5a3120..18adb4e992 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -268,6 +268,16 @@ QT_BEGIN_NAMESPACE
Stops, then starts the sprite animation.
*/
+/*!
+ \qmlsignal QtQuick::AnimatedSprite::finished()
+ \since 5.12
+
+ This signal is emitted when the sprite has finished animating.
+
+ It is not emitted when running is set to \c false, nor for sprites whose
+ \l loops property is set to \c AnimatedSprite.Infinite.
+*/
+
QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) :
QQuickItem(*(new QQuickAnimatedSpritePrivate), parent)
{
@@ -806,6 +816,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
frameAt = 0;
d->m_running = false;
emit runningChanged(false);
+ emit finished();
maybeUpdate();
}
} else {
diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h
index d7e60b909c..ff59591c9f 100644
--- a/src/quick/items/qquickanimatedsprite_p.h
+++ b/src/quick/items/qquickanimatedsprite_p.h
@@ -135,6 +135,8 @@ Q_SIGNALS:
void loopsChanged(int arg);
void currentFrameChanged(int arg);
+ Q_REVISION(12) void finished();
+
public Q_SLOTS:
void start();
void stop();
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index d4aba31e28..31c56b7cb7 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -642,6 +642,11 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(const QTouchDevice *d)
return dev;
}
+const QTouchDevice *QQuickPointerDevice::qTouchDevice() const
+{
+ return g_touchDevices->key(const_cast<QQuickPointerDevice *>(this));
+}
+
QList<QQuickPointerDevice*> QQuickPointerDevice::touchDevices()
{
return g_touchDevices->values();
@@ -901,7 +906,7 @@ void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, b
if (grabber) {
grabber->onGrabChanged(grabber, GrabExclusive, this);
for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) {
- if (passiveGrabber != grabber)
+ if (!passiveGrabber.isNull() && passiveGrabber != grabber)
passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
}
}
@@ -1291,7 +1296,7 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
Qt::TouchPointState state = Qt::TouchPointStationary;
switch (ev->type()) {
case QEvent::MouseButtonPress:
- m_mousePoint->clearPassiveGrabbers();
+ m_point->clearPassiveGrabbers();
Q_FALLTHROUGH();
case QEvent::MouseButtonDblClick:
state = Qt::TouchPointPressed;
@@ -1305,13 +1310,13 @@ QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
default:
break;
}
- m_mousePoint->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ m_point->reset(state, ev->windowPos(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
return this;
}
-void QQuickPointerMouseEvent::localize(QQuickItem *target)
+void QQuickSinglePointEvent::localize(QQuickItem *target)
{
- m_mousePoint->localizePosition(target);
+ m_point->localizePosition(target);
}
QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
@@ -1412,35 +1417,54 @@ QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event)
break;
}
quint64 deviceId = QTouchDevicePrivate::get(const_cast<QTouchDevice *>(ev->device()))->id; // a bit roundabout since QTouchDevice::mTouchDeviceId is protected
- m_gesturePoint->reset(state, ev->windowPos(), deviceId << 24, ev->timestamp());
+ m_point->reset(state, ev->windowPos(), deviceId << 24, ev->timestamp());
return this;
}
-
-void QQuickPointerNativeGestureEvent::localize(QQuickItem *target)
-{
- m_gesturePoint->localizePosition(target);
-}
#endif // QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerMouseEvent::point(int i) const {
+QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
+{
if (i == 0)
- return m_mousePoint;
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const {
- if (i >= 0 && i < m_pointCount)
- return m_touchPoints.at(i);
- return nullptr;
+QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
+{
+ m_event = static_cast<QInputEvent*>(event);
+ if (!event)
+ return this;
+#if QT_CONFIG(wheelevent)
+ if (event->type() == QEvent::Wheel) {
+ auto ev = static_cast<QWheelEvent*>(event);
+ m_device = QQuickPointerDevice::genericMouseDevice();
+ m_device->eventDeliveryTargets().clear();
+ // m_button = Qt::NoButton;
+ m_pressedButtons = ev->buttons();
+ m_angleDelta = QVector2D(ev->angleDelta());
+ m_pixelDelta = QVector2D(ev->pixelDelta());
+ m_phase = ev->phase();
+ m_synthSource = ev->source();
+ m_inverted = ev->inverted();
+
+ m_point->reset(Qt::TouchPointMoved, ev->posF(), quint64(1) << 24, ev->timestamp()); // mouse has device ID 1
+ }
+#endif
+ // TODO else if (event->type() == QEvent::Scroll) ...
+ return this;
}
-#if QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerNativeGestureEvent::point(int i) const {
- if (i == 0)
- return m_gesturePoint;
+void QQuickPointerScrollEvent::localize(QQuickItem *target)
+{
+ m_point->localizePosition(target);
+}
+
+QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const
+{
+ if (i >= 0 && i < m_pointCount)
+ return m_touchPoints.at(i);
return nullptr;
}
-#endif // QT_CONFIG(gestures)
QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
: QObject(parent), m_pointId(0), m_exclusiveGrabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
@@ -1454,17 +1478,19 @@ QQuickPointerEvent *QQuickEventPoint::pointerEvent() const
return static_cast<QQuickPointerEvent *>(parent());
}
-bool QQuickPointerMouseEvent::allPointsAccepted() const {
- return m_mousePoint->isAccepted();
+bool QQuickSinglePointEvent::allPointsAccepted() const
+{
+ return m_point->isAccepted();
}
-bool QQuickPointerMouseEvent::allUpdatedPointsAccepted() const {
- return m_mousePoint->state() == QQuickEventPoint::Pressed || m_mousePoint->isAccepted();
+bool QQuickSinglePointEvent::allUpdatedPointsAccepted() const
+{
+ return m_point->state() == QQuickEventPoint::Pressed || m_point->isAccepted();
}
-bool QQuickPointerMouseEvent::allPointsGrabbed() const
+bool QQuickSinglePointEvent::allPointsGrabbed() const
{
- return m_mousePoint->exclusiveGrabber() != nullptr;
+ return m_point->exclusiveGrabber() != nullptr;
}
QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
@@ -1477,10 +1503,10 @@ QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) cons
/*!
Returns the exclusive grabber of this event, if any, in a vector.
*/
-QVector<QObject *> QQuickPointerMouseEvent::exclusiveGrabbers() const
+QVector<QObject *> QQuickSinglePointEvent::exclusiveGrabbers() const
{
QVector<QObject *> result;
- if (QObject *grabber = m_mousePoint->exclusiveGrabber())
+ if (QObject *grabber = m_point->exclusiveGrabber())
result << grabber;
return result;
}
@@ -1488,17 +1514,18 @@ QVector<QObject *> QQuickPointerMouseEvent::exclusiveGrabbers() const
/*!
Remove all passive and exclusive grabbers of this event, without notifying.
*/
-void QQuickPointerMouseEvent::clearGrabbers() const {
- m_mousePoint->setGrabberItem(nullptr);
- m_mousePoint->clearPassiveGrabbers();
+void QQuickSinglePointEvent::clearGrabbers() const
+{
+ m_point->setGrabberItem(nullptr);
+ m_point->clearPassiveGrabbers();
}
/*!
Returns whether the given \a handler is the exclusive grabber of this event.
*/
-bool QQuickPointerMouseEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
+bool QQuickSinglePointEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
{
- return m_mousePoint->exclusiveGrabber() == handler;
+ return handler && (m_point->exclusiveGrabber() == handler);
}
bool QQuickPointerMouseEvent::isPressEvent() const
@@ -1526,7 +1553,8 @@ bool QQuickPointerMouseEvent::isReleaseEvent() const
return me && me->type() == QEvent::MouseButtonRelease;
}
-bool QQuickPointerTouchEvent::allPointsAccepted() const {
+bool QQuickPointerTouchEvent::allPointsAccepted() const
+{
for (int i = 0; i < m_pointCount; ++i) {
if (!m_touchPoints.at(i)->isAccepted())
return false;
@@ -1534,7 +1562,8 @@ bool QQuickPointerTouchEvent::allPointsAccepted() const {
return true;
}
-bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const {
+bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const
+{
for (int i = 0; i < m_pointCount; ++i) {
auto point = m_touchPoints.at(i);
if (point->state() != QQuickEventPoint::Pressed && !point->isAccepted())
@@ -1571,7 +1600,8 @@ QVector<QObject *> QQuickPointerTouchEvent::exclusiveGrabbers() const
Remove all passive and exclusive grabbers of all touchpoints in this event,
without notifying.
*/
-void QQuickPointerTouchEvent::clearGrabbers() const {
+void QQuickPointerTouchEvent::clearGrabbers() const
+{
for (auto point: m_touchPoints) {
point->setGrabberItem(nullptr);
point->clearPassiveGrabbers();
@@ -1629,7 +1659,8 @@ QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() cons
If the touchpoint cannot be found, this returns nullptr.
Ownership of the event is NOT transferred to the caller.
*/
-QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const {
+QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const
+{
const QTouchEvent::TouchPoint *p = touchPointById(pointID);
if (!p)
return nullptr;
@@ -1669,33 +1700,6 @@ QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickIte
}
#if QT_CONFIG(gestures)
-/*!
- Returns the exclusive grabber of this event, if any, in a vector.
-*/
-QVector<QObject *> QQuickPointerNativeGestureEvent::exclusiveGrabbers() const
-{
- QVector<QObject *> result;
- if (QObject *grabber = m_gesturePoint->exclusiveGrabber())
- result << grabber;
- return result;
-}
-
-/*!
- Remove all passive and exclusive grabbers of this event, without notifying.
-*/
-void QQuickPointerNativeGestureEvent::clearGrabbers() const {
- m_gesturePoint->setGrabberItem(nullptr);
- m_gesturePoint->clearPassiveGrabbers();
-}
-
-/*!
- Returns whether the given \a handler is the exclusive grabber of this event.
-*/
-bool QQuickPointerNativeGestureEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
-{
- return m_gesturePoint->exclusiveGrabber() == handler;
-}
-
bool QQuickPointerNativeGestureEvent::isPressEvent() const
{
return type() == Qt::BeginNativeGesture;
@@ -1729,6 +1733,39 @@ qreal QQuickPointerNativeGestureEvent::value() const
#endif // QT_CONFIG(gestures)
/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are placed
+ on the touchpad and scrolling begins. On other devices where this
+ information is not available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isPressEvent() const
+{
+ return phase() == Qt::ScrollBegin;
+}
+
+/*!
+ Returns true when the scroll event has Qt::ScrollUpdate phase, or when the
+ phase is unknown. Some multi-touch-capable touchpads and trackpads provide
+ phase information; whereas ordinary mouse wheels and other types of
+ trackpads do not, and in such cases this is always true.
+*/
+bool QQuickPointerScrollEvent::isUpdateEvent() const
+{
+ return phase() == Qt::ScrollUpdate || phase() == Qt::NoScrollPhase;
+}
+
+/*!
+ Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
+ which provide phase information, this is true when the fingers are lifted
+ from the touchpad. On other devices where this information is not
+ available, it remains false.
+*/
+bool QQuickPointerScrollEvent::isReleaseEvent() const
+{
+ return phase() == Qt::ScrollEnd;
+}
+
+/*!
\internal
Returns a pointer to the QQuickEventPoint which has the \a pointId as
\l {QQuickEventPoint::pointId}{pointId}.
@@ -1736,13 +1773,15 @@ qreal QQuickPointerNativeGestureEvent::value() const
\fn QQuickPointerEvent::pointById(int pointId) const
*/
-QQuickEventPoint *QQuickPointerMouseEvent::pointById(int pointId) const {
- if (m_mousePoint && pointId == m_mousePoint->pointId())
- return m_mousePoint;
+QQuickEventPoint *QQuickSinglePointEvent::pointById(int pointId) const
+{
+ if (m_point && pointId == m_point->pointId())
+ return m_point;
return nullptr;
}
-QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const {
+QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const
+{
auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(),
[pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } );
if (it != m_touchPoints.constEnd())
@@ -1750,21 +1789,14 @@ QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const {
return nullptr;
}
-#if QT_CONFIG(gestures)
-QQuickEventPoint *QQuickPointerNativeGestureEvent::pointById(int pointId) const {
- if (m_gesturePoint && pointId == m_gesturePoint->pointId())
- return m_gesturePoint;
- return nullptr;
-}
-#endif
-
/*!
\internal
Returns a pointer to the original TouchPoint which has the same
\l {QTouchEvent::TouchPoint::id}{id} as \a pointId, if the original event is a
QTouchEvent, and if that point is found. Otherwise, returns nullptr.
*/
-const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const {
+const QTouchEvent::TouchPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const
+{
const QTouchEvent *ev = asTouchEvent();
if (!ev)
return nullptr;
@@ -1875,24 +1907,10 @@ QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const
return static_cast<QTouchEvent *>(m_event);
}
-#if QT_CONFIG(gestures)
-bool QQuickPointerNativeGestureEvent::allPointsAccepted() const {
- return m_gesturePoint->isAccepted();
-}
-
-bool QQuickPointerNativeGestureEvent::allUpdatedPointsAccepted() const {
- return m_gesturePoint->state() == QQuickEventPoint::Pressed || m_gesturePoint->isAccepted();
-}
-
-bool QQuickPointerNativeGestureEvent::allPointsGrabbed() const
-{
- return m_gesturePoint->exclusiveGrabber() != nullptr;
-}
-#endif // QT_CONFIG(gestures)
-
#ifndef QT_NO_DEBUG_STREAM
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *dev)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
if (!dev) {
@@ -1914,7 +1932,8 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerDevice *
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QQuickPointerEvent(";
@@ -1933,7 +1952,8 @@ Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *e
return dbg;
}
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event) {
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event)
+{
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index bb6726706d..c67c386676 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -69,6 +69,7 @@ class QQuickPointerMouseEvent;
#if QT_CONFIG(gestures)
class QQuickPointerNativeGestureEvent;
#endif
+class QQuickPointerScrollEvent;
class QQuickPointerTabletEvent;
class QQuickPointerTouchEvent;
class QQuickPointerHandler;
@@ -419,17 +420,19 @@ public: // helpers for C++ only (during event delivery)
#if QT_CONFIG(gestures)
virtual QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() { return nullptr; }
#endif
+ virtual QQuickPointerScrollEvent *asPointerScrollEvent() { return nullptr; }
virtual const QQuickPointerMouseEvent *asPointerMouseEvent() const { return nullptr; }
virtual const QQuickPointerTouchEvent *asPointerTouchEvent() const { return nullptr; }
virtual const QQuickPointerTabletEvent *asPointerTabletEvent() const { return nullptr; }
#if QT_CONFIG(gestures)
virtual const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const { return nullptr; }
#endif
+ virtual const QQuickPointerScrollEvent *asPointerScrollEvent() const { return nullptr; }
virtual bool allPointsAccepted() const = 0;
virtual bool allUpdatedPointsAccepted() const = 0;
virtual bool allPointsGrabbed() const = 0;
- bool isAccepted() { return m_event->isAccepted(); }
- void setAccepted(bool accepted) { m_event->setAccepted(accepted); }
+ bool isAccepted() { return m_event ? m_event->isAccepted() : false; }
+ void setAccepted(bool accepted) { if (m_event) m_event->setAccepted(accepted); }
QVector<QPointF> unacceptedPressedPointScenePositions() const;
virtual int pointCount() const = 0;
@@ -439,7 +442,7 @@ public: // helpers for C++ only (during event delivery)
virtual void clearGrabbers() const = 0;
virtual bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const = 0;
- ulong timestamp() const { return m_event->timestamp(); }
+ ulong timestamp() const { return m_event ? m_event->timestamp() : 0; }
protected:
QQuickPointerDevice *m_device;
@@ -450,21 +453,14 @@ protected:
Q_DISABLE_COPY(QQuickPointerEvent)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickPointerEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickSinglePointEvent : public QQuickPointerEvent
{
Q_OBJECT
public:
- QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_mousePoint(new QQuickEventPoint(this)) { }
+ QQuickSinglePointEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickPointerEvent(parent, device), m_point(new QQuickEventPoint(this)) { }
- QQuickPointerEvent *reset(QEvent *) override;
void localize(QQuickItem *target) override;
- bool isPressEvent() const override;
- bool isDoubleClickEvent() const override;
- bool isUpdateEvent() const override;
- bool isReleaseEvent() const override;
- QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
- const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
int pointCount() const override { return 1; }
QQuickEventPoint *point(int i) const override;
QQuickEventPoint *pointById(int pointId) const override;
@@ -475,10 +471,28 @@ public:
void clearGrabbers() const override;
bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
- QMouseEvent *asMouseEvent(const QPointF& localPos) const;
+protected:
+ QQuickEventPoint *m_point;
-private:
- QQuickEventPoint *m_mousePoint;
+ Q_DISABLE_COPY(QQuickSinglePointEvent)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+public:
+ QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ bool isPressEvent() const override;
+ bool isDoubleClickEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerMouseEvent *asPointerMouseEvent() override { return this; }
+ const QQuickPointerMouseEvent *asPointerMouseEvent() const override { return this; }
+
+ QMouseEvent *asMouseEvent(const QPointF& localPos) const;
Q_DISABLE_COPY(QQuickPointerMouseEvent)
};
@@ -526,7 +540,7 @@ private:
};
#if QT_CONFIG(gestures)
-class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickPointerEvent
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickSinglePointEvent
{
Q_OBJECT
Q_PROPERTY(Qt::NativeGestureType type READ type CONSTANT)
@@ -534,34 +548,65 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerNativeGestureEvent : public QQuickPoin
public:
QQuickPointerNativeGestureEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
- : QQuickPointerEvent(parent, device), m_gesturePoint(new QQuickEventPoint(this)) { }
+ : QQuickSinglePointEvent(parent, device) { }
QQuickPointerEvent *reset(QEvent *) override;
- void localize(QQuickItem *target) override;
bool isPressEvent() const override;
bool isUpdateEvent() const override;
bool isReleaseEvent() const override;
QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() override { return this; }
const QQuickPointerNativeGestureEvent *asPointerNativeGestureEvent() const override { return this; }
- int pointCount() const override { return 1; }
- QQuickEventPoint *point(int i) const override;
- QQuickEventPoint *pointById(int pointId) const override;
- bool allPointsAccepted() const override;
- bool allUpdatedPointsAccepted() const override;
- bool allPointsGrabbed() const override;
- QVector<QObject *> exclusiveGrabbers() const override;
- void clearGrabbers() const override;
- bool hasExclusiveGrabber(const QQuickPointerHandler *handler) const override;
Qt::NativeGestureType type() const;
qreal value() const;
-private:
- QQuickEventPoint *m_gesturePoint;
-
Q_DISABLE_COPY(QQuickPointerNativeGestureEvent)
};
#endif // QT_CONFIG(gestures)
+class Q_QUICK_PRIVATE_EXPORT QQuickPointerScrollEvent : public QQuickSinglePointEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector2D angleDelta READ angleDelta CONSTANT)
+ Q_PROPERTY(QVector2D pixelDelta READ pixelDelta CONSTANT)
+ Q_PROPERTY(bool hasAngleDelta READ hasAngleDelta CONSTANT)
+ Q_PROPERTY(bool hasPixelDelta READ hasPixelDelta CONSTANT)
+ Q_PROPERTY(bool inverted READ isInverted CONSTANT)
+
+public:
+ QQuickPointerScrollEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr)
+ : QQuickSinglePointEvent(parent, device) { }
+
+ QQuickPointerEvent *reset(QEvent *) override;
+ void localize(QQuickItem *target) override;
+ bool isPressEvent() const override;
+ bool isUpdateEvent() const override;
+ bool isReleaseEvent() const override;
+ QQuickPointerScrollEvent *asPointerScrollEvent() override { return this; }
+ const QQuickPointerScrollEvent *asPointerScrollEvent() const override { return this; }
+ QVector2D angleDelta() const { return m_angleDelta; }
+ QVector2D pixelDelta() const { return m_pixelDelta; }
+ bool hasAngleDelta() const { return !angleDelta().isNull(); }
+ bool hasPixelDelta() const { return !pixelDelta().isNull(); }
+ bool isInverted() const { return m_inverted; }
+ Qt::ScrollPhase phase() const { return m_phase; }
+
+private:
+ // TODO add QQuickPointerDevice source() whenever QInputEvent is extended to have a source device
+ // then maybe Qt::MouseEventSource synthSource() will be obsolete... that's why it's not public now
+ Qt::MouseEventSource synthSource() const { return m_synthSource; }
+
+private:
+ QVector2D m_angleDelta;
+ QVector2D m_pixelDelta;
+ Qt::ScrollPhase m_phase = Qt::NoScrollPhase;
+ Qt::MouseEventSource m_synthSource = Qt::MouseEventNotSynthesized;
+ bool m_inverted = false;
+
+ friend class QQuickWindowPrivate;
+
+ Q_DISABLE_COPY(QQuickPointerScrollEvent)
+};
+
// ### Qt 6: move this to qtbase, replace QTouchDevice and the enums in QTabletEvent
class Q_QUICK_PRIVATE_EXPORT QQuickPointerDevice : public QObject
@@ -627,6 +672,7 @@ public:
int buttonCount() const { return m_buttonCount; }
QString name() const { return m_name; }
QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; }
+ const QTouchDevice *qTouchDevice() const;
static QQuickPointerDevice *touchDevice(const QTouchDevice *d);
static QList<QQuickPointerDevice *> touchDevices();
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 9be8b7f2b9..01413385d9 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -8680,7 +8680,7 @@ void QV4::Heap::QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkS
quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine)
{
- return (engine->memoryManager->allocObject<QQuickItemWrapper>(q_func()))->asReturnedValue();
+ return (engine->memoryManager->allocate<QQuickItemWrapper>(q_func()))->asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 51a91e1f7a..96927dd37a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -422,6 +422,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickAnimatedImage, 11>(uri, 2, 11,"AnimatedImage");
#endif
qmlRegisterType<QQuickItem, 11>(uri, 2, 11,"Item");
+
+ qmlRegisterType<QQuickAnimatedSprite, 12>("QtQuick", 2, 12, "AnimatedSprite");
+ qmlRegisterType<QQuickGradient, 12>(uri, 2, 12, "Gradient");
}
static void initResources()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index f2e055e874..4e4881ce19 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qquickitemview_p_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQml/QQmlInfo>
#include "qplatformdefs.h"
@@ -52,117 +53,14 @@ Q_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
#endif
FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemViewAttached *attached)
- : item(i)
+ : QQuickItemViewFxItem(i, own, QQuickItemViewPrivate::get(v))
, view(v)
- , transitionableItem(nullptr)
, attached(attached)
- , ownItem(own)
- , releaseAfterTransition(false)
- , trackGeom(false)
{
if (attached) // can be null for default components (see createComponentItem)
attached->setView(view);
}
-FxViewItem::~FxViewItem()
-{
- delete transitionableItem;
- if (ownItem && item) {
- trackGeometry(false);
- item->setParentItem(nullptr);
- item->deleteLater();
- item = nullptr;
- }
-}
-
-qreal FxViewItem::itemX() const
-{
- return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
-}
-
-qreal FxViewItem::itemY() const
-{
- return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
-}
-
-void FxViewItem::moveTo(const QPointF &pos, bool immediate)
-{
- if (transitionableItem)
- transitionableItem->moveTo(pos, immediate);
- else if (item)
- item->setPosition(pos);
-}
-
-void FxViewItem::setVisible(bool visible)
-{
- if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
- return;
- if (item)
- QQuickItemPrivate::get(item)->setCulled(!visible);
-}
-
-void FxViewItem::trackGeometry(bool track)
-{
- if (track) {
- if (!trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = true;
- }
- } else {
- if (trackGeom) {
- if (item) {
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
- }
- trackGeom = false;
- }
- }
-}
-
-QQuickItemViewTransitioner::TransitionType FxViewItem::scheduledTransitionType() const
-{
- return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
-}
-
-bool FxViewItem::transitionScheduledOrRunning() const
-{
- return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
-}
-
-bool FxViewItem::transitionRunning() const
-{
- return transitionableItem ? transitionableItem->transitionRunning() : false;
-}
-
-bool FxViewItem::isPendingRemoval() const
-{
- return transitionableItem ? transitionableItem->isPendingRemoval() : false;
-}
-
-void FxViewItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
-{
- if (!transitioner)
- return;
- if (!transitionableItem)
- transitionableItem = new QQuickItemViewTransitionableItem(item);
- transitioner->transitionNextReposition(transitionableItem, type, asTarget);
-}
-
-bool FxViewItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
-{
- return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
-}
-
-void FxViewItem::startTransition(QQuickItemViewTransitioner *transitioner)
-{
- if (transitionableItem)
- transitionableItem->startTransition(transitioner, index);
-}
-
-
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
: active(false)
{
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index e250cf0ccb..ea5b5df9c6 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -56,6 +56,7 @@
QT_REQUIRE_CONFIG(quick_itemview);
#include "qquickitemview_p.h"
+#include "qquickitemviewfxitem_p_p.h"
#include "qquickitemviewtransition_p.h"
#include "qquickflickable_p_p.h"
#include <QtQml/private/qqmlobjectmodel_p.h>
@@ -65,47 +66,13 @@ QT_REQUIRE_CONFIG(quick_itemview);
QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT FxViewItem
+class Q_AUTOTEST_EXPORT FxViewItem : public QQuickItemViewFxItem
{
public:
FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached);
- virtual ~FxViewItem();
-
- qreal itemX() const;
- qreal itemY() const;
- inline qreal itemWidth() const { return item ? item->width() : 0; }
- inline qreal itemHeight() const { return item ? item->height() : 0; }
-
- void moveTo(const QPointF &pos, bool immediate);
- void setVisible(bool visible);
- void trackGeometry(bool track);
-
- QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
- bool transitionScheduledOrRunning() const;
- bool transitionRunning() const;
- bool isPendingRemoval() const;
-
- void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
- bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
- void startTransition(QQuickItemViewTransitioner *transitioner);
-
- // these are positions and sizes along the current direction of scrolling/flicking
- virtual qreal position() const = 0;
- virtual qreal endPosition() const = 0;
- virtual qreal size() const = 0;
- virtual qreal sectionSize() const = 0;
-
- virtual bool contains(qreal x, qreal y) const = 0;
- QPointer<QQuickItem> item;
QQuickItemView *view;
- QQuickItemViewTransitionableItem *transitionableItem;
QQuickItemViewAttached *attached;
- int index;
- bool ownItem;
- bool releaseAfterTransition;
- bool trackGeom;
};
diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp
new file mode 100644
index 0000000000..f9c65967ea
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemviewfxitem_p_p.h"
+#include "qquickitem_p.h"
+#include "qquickitemview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener* changeListener)
+ : item(item)
+ , ownItem(ownItem)
+ , changeListener(changeListener)
+ , transitionableItem(nullptr)
+ , releaseAfterTransition(false)
+ , trackGeom(false)
+{
+}
+
+QQuickItemViewFxItem::~QQuickItemViewFxItem()
+{
+ delete transitionableItem;
+ if (ownItem && item) {
+ trackGeometry(false);
+ item->setParentItem(0);
+ item->deleteLater();
+ }
+}
+
+qreal QQuickItemViewFxItem::itemX() const
+{
+ return transitionableItem ? transitionableItem->itemX() : (item ? item->x() : 0);
+}
+
+qreal QQuickItemViewFxItem::itemY() const
+{
+ return transitionableItem ? transitionableItem->itemY() : (item ? item->y() : 0);
+}
+
+void QQuickItemViewFxItem::moveTo(const QPointF &pos, bool immediate)
+{
+ if (transitionableItem)
+ transitionableItem->moveTo(pos, immediate);
+ else if (item)
+ item->setPosition(pos);
+}
+
+void QQuickItemViewFxItem::setVisible(bool visible)
+{
+ if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
+ return;
+ if (item)
+ QQuickItemPrivate::get(item)->setCulled(!visible);
+}
+
+void QQuickItemViewFxItem::trackGeometry(bool track)
+{
+ if (track) {
+ if (!trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = true;
+ }
+ } else {
+ if (trackGeom) {
+ if (item) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(changeListener, QQuickItemPrivate::Geometry);
+ }
+ trackGeom = false;
+ }
+ }
+}
+
+QRectF QQuickItemViewFxItem::geometry() const
+{
+ return QRectF(item->position(), item->size());
+}
+
+void QQuickItemViewFxItem::setGeometry(const QRectF &geometry)
+{
+ item->setPosition(geometry.topLeft());
+ item->setSize(geometry.size());
+}
+
+QQuickItemViewTransitioner::TransitionType QQuickItemViewFxItem::scheduledTransitionType() const
+{
+ return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
+}
+
+bool QQuickItemViewFxItem::transitionScheduledOrRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
+}
+
+bool QQuickItemViewFxItem::transitionRunning() const
+{
+ return transitionableItem ? transitionableItem->transitionRunning() : false;
+}
+
+bool QQuickItemViewFxItem::isPendingRemoval() const
+{
+ return transitionableItem ? transitionableItem->isPendingRemoval() : false;
+}
+
+void QQuickItemViewFxItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
+{
+ if (!transitioner)
+ return;
+ if (!transitionableItem)
+ transitionableItem = new QQuickItemViewTransitionableItem(item);
+ transitioner->transitionNextReposition(transitionableItem, type, asTarget);
+}
+
+bool QQuickItemViewFxItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
+{
+ return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
+}
+
+void QQuickItemViewFxItem::startTransition(QQuickItemViewTransitioner *transitioner)
+{
+ if (transitionableItem)
+ transitionableItem->startTransition(transitioner, index);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h
new file mode 100644
index 0000000000..48ffe248bc
--- /dev/null
+++ b/src/quick/items/qquickitemviewfxitem_p_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFXVIEWITEM_P_P_H
+#define QQUICKFXVIEWITEM_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 <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+
+QT_REQUIRE_CONFIG(quick_itemview);
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickItemViewFxItem
+{
+public:
+ QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuickItemChangeListener *changeListener);
+ virtual ~QQuickItemViewFxItem();
+
+ qreal itemX() const;
+ qreal itemY() const;
+ inline qreal itemWidth() const { return item ? item->width() : 0; }
+ inline qreal itemHeight() const { return item ? item->height() : 0; }
+
+ void moveTo(const QPointF &pos, bool immediate);
+ void setVisible(bool visible);
+ void trackGeometry(bool track);
+
+ QRectF geometry() const;
+ void setGeometry(const QRectF &geometry);
+
+ QQuickItemViewTransitioner::TransitionType scheduledTransitionType() const;
+ bool transitionScheduledOrRunning() const;
+ bool transitionRunning() const;
+ bool isPendingRemoval() const;
+
+ void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
+ bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
+ void startTransition(QQuickItemViewTransitioner *transitioner);
+
+ // these are positions and sizes along the current direction of scrolling/flicking
+ virtual qreal position() const = 0;
+ virtual qreal endPosition() const = 0;
+ virtual qreal size() const = 0;
+ virtual qreal sectionSize() const = 0;
+
+ virtual bool contains(qreal x, qreal y) const = 0;
+
+ int index = -1;
+ QPointer<QQuickItem> item;
+ bool ownItem;
+ QQuickItemChangeListener *changeListener;
+ QQuickItemViewTransitionableItem *transitionableItem;
+ bool releaseAfterTransition;
+ bool trackGeom;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFXVIEWITEM_P_P_H
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index ea6a63559a..0de9d6c49a 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -54,7 +54,7 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
QQuickLoaderPrivate::QQuickLoaderPrivate()
- : item(nullptr), object(nullptr), component(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
+ : item(nullptr), object(nullptr), itemContext(nullptr), incubator(nullptr), updatingSize(false),
active(true), loadingFromSource(false), asynchronous(false)
{
}
@@ -111,9 +111,8 @@ void QQuickLoaderPrivate::clear()
QObject::disconnect(component, SIGNAL(progressChanged(qreal)),
q, SIGNAL(progressChanged()));
component->deleteLater();
- component = nullptr;
+ component.setObject(nullptr, q);
}
- componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -438,7 +437,7 @@ void QQuickLoader::loadFromSource()
if (isComponentComplete()) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
d->load();
}
}
@@ -481,11 +480,7 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
- d->component = comp;
- if (comp) {
- if (QQmlData *ddata = QQmlData::get(comp))
- d->componentStrongReference = ddata->jsWrapper;
- }
+ d->component.setObject(comp, this);
d->loadingFromSource = false;
if (d->active)
@@ -828,7 +823,7 @@ void QQuickLoader::componentComplete()
if (active()) {
if (d->loadingFromSource) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
- d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
+ d->component.setObject(new QQmlComponent(qmlEngine(this), d->source, mode, this), this);
}
d->load();
}
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 7492527401..349b5c6c06 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -103,8 +103,7 @@ public:
QUrl source;
QQuickItem *item;
QObject *object;
- QQmlComponent *component;
- QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
+ QQmlStrongJSQObjectReference<QQmlComponent> component;
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index bf030b9d80..ab8203d0a8 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -219,10 +219,11 @@ void QQuickGradientStop::updateGradient()
of solid color fills or images. Consider using gradients for static items
in a user interface.
- In Qt 5.0, only vertical, linear gradients can be applied to items. If you
- need to apply different orientations of gradients, a combination of rotation
- and clipping will need to be applied to the relevant items. This can
- introduce additional performance requirements for your application.
+ Since Qt 5.12, vertical and horizontal linear gradients can be applied to items.
+ If you need to apply angled gradients, a combination of rotation and clipping
+ can be applied to the relevant items. Alternatively, consider using
+ QtQuick.Shapes::LinearGradient or QtGraphicalEffects::LinearGradient. These
+ approaches can all introduce additional performance requirements for your application.
The use of animations involving gradient stops may not give the desired
result. An alternative way to animate gradients is to use pre-generated
@@ -255,6 +256,28 @@ QQmlListProperty<QQuickGradientStop> QQuickGradient::stops()
return QQmlListProperty<QQuickGradientStop>(this, m_stops);
}
+/*!
+ \qmlproperty enumeration QtQuick::Gradient::orientation
+ \since 5.12
+
+ Set this property to define the direction of the gradient.
+ \list
+ \li Gradient.Vertical - a vertical gradient
+ \li Gradient.Horizontal - a horizontal gradient
+ \endlist
+
+ The default is Gradient.Vertical.
+*/
+void QQuickGradient::setOrientation(Orientation orientation)
+{
+ if (m_orientation == orientation)
+ return;
+
+ m_orientation = orientation;
+ emit orientationChanged();
+ emit updated();
+}
+
QGradientStops QQuickGradient::gradientStops() const
{
QGradientStops stops;
@@ -374,7 +397,7 @@ QQuickPen *QQuickRectangle::border()
The gradient to use to fill the rectangle.
- This property allows for the construction of simple vertical gradients.
+ This property allows for the construction of simple vertical or horizontal gradients.
Other gradients may be formed by adding rotation to the rectangle.
\div {class="float-left"}
@@ -510,10 +533,13 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
rectangle->setAntialiasing(antialiasing());
QGradientStops stops;
+ bool vertical = true;
if (d->gradient) {
stops = d->gradient->gradientStops();
+ vertical = d->gradient->orientation() == QQuickGradient::Vertical;
}
rectangle->setGradientStops(stops);
+ rectangle->setGradientVertical(vertical);
rectangle->update();
diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h
index c07ad835fb..ddafaafb28 100644
--- a/src/quick/items/qquickrectangle_p.h
+++ b/src/quick/items/qquickrectangle_p.h
@@ -119,24 +119,34 @@ class Q_QUICK_PRIVATE_EXPORT QQuickGradient : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QQuickGradientStop> stops READ stops)
+ Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged REVISION 12)
Q_CLASSINFO("DefaultProperty", "stops")
public:
QQuickGradient(QObject *parent=nullptr);
~QQuickGradient() override;
+ enum Orientation { Vertical = Qt::Vertical,
+ Horizontal = Qt::Horizontal };
+ Q_ENUM(Orientation)
+
QQmlListProperty<QQuickGradientStop> stops();
+ Orientation orientation() const { return m_orientation; }
+ void setOrientation(Orientation orientation);
+
QGradientStops gradientStops() const;
Q_SIGNALS:
void updated();
+ void orientationChanged();
private:
void doUpdate();
private:
QList<QQuickGradientStop *> m_stops;
+ Orientation m_orientation = Vertical;
friend class QQuickRectangle;
friend class QQuickGradientStop;
};
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 49568db552..b06b0821d2 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -187,7 +187,6 @@ void QQuickRenderControlPrivate::windowDestroyed()
{
if (window) {
rc->invalidate();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
delete QQuickWindowPrivate::get(window)->animationController;
QQuickWindowPrivate::get(window)->animationController = nullptr;
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index d7a0f1b681..23f179be1d 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -66,6 +66,7 @@ void QQuickScaleGrid::setLeft(int pos)
{
if (_left != pos) {
_left = pos;
+ emit leftBorderChanged();
emit borderChanged();
}
}
@@ -74,6 +75,7 @@ void QQuickScaleGrid::setTop(int pos)
{
if (_top != pos) {
_top = pos;
+ emit topBorderChanged();
emit borderChanged();
}
}
@@ -82,6 +84,7 @@ void QQuickScaleGrid::setRight(int pos)
{
if (_right != pos) {
_right = pos;
+ emit rightBorderChanged();
emit borderChanged();
}
}
@@ -90,6 +93,7 @@ void QQuickScaleGrid::setBottom(int pos)
{
if (_bottom != pos) {
_bottom = pos;
+ emit bottomBorderChanged();
emit borderChanged();
}
}
diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h
index 5752f61e3f..f5187a8eea 100644
--- a/src/quick/items/qquickscalegrid_p_p.h
+++ b/src/quick/items/qquickscalegrid_p_p.h
@@ -65,10 +65,10 @@ class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject
{
Q_OBJECT
- Q_PROPERTY(int left READ left WRITE setLeft NOTIFY borderChanged)
- Q_PROPERTY(int top READ top WRITE setTop NOTIFY borderChanged)
- Q_PROPERTY(int right READ right WRITE setRight NOTIFY borderChanged)
- Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY borderChanged)
+ Q_PROPERTY(int left READ left WRITE setLeft NOTIFY leftBorderChanged)
+ Q_PROPERTY(int top READ top WRITE setTop NOTIFY topBorderChanged)
+ Q_PROPERTY(int right READ right WRITE setRight NOTIFY rightBorderChanged)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomBorderChanged)
public:
QQuickScaleGrid(QObject *parent=nullptr);
@@ -90,6 +90,10 @@ public:
Q_SIGNALS:
void borderChanged();
+ void leftBorderChanged();
+ void topBorderChanged();
+ void rightBorderChanged();
+ void bottomBorderChanged();
private:
int _left;
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
new file mode 100644
index 0000000000..bcdc06a783
--- /dev/null
+++ b/src/quick/items/qquicktableview.cpp
@@ -0,0 +1,1474 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktableview_p.h"
+#include "qquicktableview_p_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
+
+#define Q_TABLEVIEW_UNREACHABLE(output) { dumpTable(); qWarning() << "output:" << output; Q_UNREACHABLE(); }
+#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT(cond || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
+
+static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
+static const int kBufferTimerInterval = 300;
+
+static QLine rectangleEdge(const QRect &rect, Qt::Edge tableEdge)
+{
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ return QLine(rect.topLeft(), rect.bottomLeft());
+ case Qt::RightEdge:
+ return QLine(rect.topRight(), rect.bottomRight());
+ case Qt::TopEdge:
+ return QLine(rect.topLeft(), rect.topRight());
+ case Qt::BottomEdge:
+ return QLine(rect.bottomLeft(), rect.bottomRight());
+ }
+ return QLine();
+}
+
+static QRect expandedRect(const QRect &rect, Qt::Edge edge, int increment)
+{
+ switch (edge) {
+ case Qt::LeftEdge:
+ return rect.adjusted(-increment, 0, 0, 0);
+ case Qt::RightEdge:
+ return rect.adjusted(0, 0, increment, 0);
+ case Qt::TopEdge:
+ return rect.adjusted(0, -increment, 0, 0);
+ case Qt::BottomEdge:
+ return rect.adjusted(0, 0, 0, increment);
+ }
+ return QRect();
+}
+
+const QPoint QQuickTableViewPrivate::kLeft = QPoint(-1, 0);
+const QPoint QQuickTableViewPrivate::kRight = QPoint(1, 0);
+const QPoint QQuickTableViewPrivate::kUp = QPoint(0, -1);
+const QPoint QQuickTableViewPrivate::kDown = QPoint(0, 1);
+
+QQuickTableViewPrivate::QQuickTableViewPrivate()
+ : QQuickFlickablePrivate()
+{
+ cacheBufferDelayTimer.setSingleShot(true);
+ QObject::connect(&cacheBufferDelayTimer, &QTimer::timeout, [=]{ loadBuffer(); });
+}
+
+QQuickTableViewPrivate::~QQuickTableViewPrivate()
+{
+ clear();
+}
+
+QString QQuickTableViewPrivate::tableLayoutToString() const
+{
+ return QString(QLatin1String("table cells: (%1,%2) -> (%3,%4), item count: %5, table rect: %6,%7 x %8,%9"))
+ .arg(loadedTable.topLeft().x()).arg(loadedTable.topLeft().y())
+ .arg(loadedTable.bottomRight().x()).arg(loadedTable.bottomRight().y())
+ .arg(loadedItems.count())
+ .arg(loadedTableOuterRect.x())
+ .arg(loadedTableOuterRect.y())
+ .arg(loadedTableOuterRect.width())
+ .arg(loadedTableOuterRect.height());
+}
+
+void QQuickTableViewPrivate::dumpTable() const
+{
+ auto listCopy = loadedItems;
+ std::stable_sort(listCopy.begin(), listCopy.end(),
+ [](const FxTableItem *lhs, const FxTableItem *rhs)
+ { return lhs->index < rhs->index; });
+
+ qWarning() << QStringLiteral("******* TABLE DUMP *******");
+ for (int i = 0; i < listCopy.count(); ++i)
+ qWarning() << static_cast<FxTableItem *>(listCopy.at(i))->cell;
+ qWarning() << tableLayoutToString();
+
+ QString filename = QStringLiteral("QQuickTableView_dumptable_capture.png");
+ if (q_func()->window()->grabWindow().save(filename))
+ qWarning() << "Window capture saved to:" << filename;
+}
+
+QQuickTableViewAttached *QQuickTableViewPrivate::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object);
+ return static_cast<QQuickTableViewAttached *>(attachedObject);
+}
+
+int QQuickTableViewPrivate::modelIndexAtCell(const QPoint &cell)
+{
+ int availableRows = tableSize.height();
+ int modelIndex = cell.y() + (cell.x() * availableRows);
+ Q_TABLEVIEW_ASSERT(modelIndex < model->count(), modelIndex << cell);
+ return modelIndex;
+}
+
+QPoint QQuickTableViewPrivate::cellAtModelIndex(int modelIndex)
+{
+ int availableRows = tableSize.height();
+ Q_TABLEVIEW_ASSERT(availableRows > 0, availableRows);
+ int column = int(modelIndex / availableRows);
+ int row = modelIndex % availableRows;
+ return QPoint(column, row);
+}
+
+void QQuickTableViewPrivate::updateContentWidth()
+{
+ Q_Q(QQuickTableView);
+
+ const qreal thresholdBeforeAdjust = 0.1;
+ int currentRightColumn = loadedTable.right();
+
+ if (currentRightColumn > contentSizeBenchMarkPoint.x()) {
+ contentSizeBenchMarkPoint.setX(currentRightColumn);
+
+ qreal currentWidth = loadedTableOuterRect.right();
+ qreal averageCellSize = currentWidth / (currentRightColumn + 1);
+ qreal averageSize = averageCellSize + cellSpacing.width();
+ qreal estimatedWith = (tableSize.width() * averageSize) - cellSpacing.width();
+
+ // loadedTableOuterRect has already been adjusted for left margin
+ currentWidth += tableMargins.right();
+ estimatedWith += tableMargins.right();
+
+ if (currentRightColumn >= tableSize.width() - 1) {
+ // We are at the last column, and can set the exact width
+ if (currentWidth != q->implicitWidth())
+ q->setContentWidth(currentWidth);
+ } else if (currentWidth >= q->implicitWidth()) {
+ // We are at the estimated width, but there are still more columns
+ q->setContentWidth(estimatedWith);
+ } else {
+ // Only set a new width if the new estimate is substantially different
+ qreal diff = 1 - (estimatedWith / q->implicitWidth());
+ if (qAbs(diff) > thresholdBeforeAdjust)
+ q->setContentWidth(estimatedWith);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::updateContentHeight()
+{
+ Q_Q(QQuickTableView);
+
+ const qreal thresholdBeforeAdjust = 0.1;
+ int currentBottomRow = loadedTable.bottom();
+
+ if (currentBottomRow > contentSizeBenchMarkPoint.y()) {
+ contentSizeBenchMarkPoint.setY(currentBottomRow);
+
+ qreal currentHeight = loadedTableOuterRect.bottom();
+ qreal averageCellSize = currentHeight / (currentBottomRow + 1);
+ qreal averageSize = averageCellSize + cellSpacing.height();
+ qreal estimatedHeight = (tableSize.height() * averageSize) - cellSpacing.height();
+
+ // loadedTableOuterRect has already been adjusted for top margin
+ currentHeight += tableMargins.bottom();
+ estimatedHeight += tableMargins.bottom();
+
+ if (currentBottomRow >= tableSize.height() - 1) {
+ // We are at the last row, and can set the exact height
+ if (currentHeight != q->implicitHeight())
+ q->setContentHeight(currentHeight);
+ } else if (currentHeight >= q->implicitHeight()) {
+ // We are at the estimated height, but there are still more rows
+ q->setContentHeight(estimatedHeight);
+ } else {
+ // Only set a new height if the new estimate is substantially different
+ qreal diff = 1 - (estimatedHeight / q->implicitHeight());
+ if (qAbs(diff) > thresholdBeforeAdjust)
+ q->setContentHeight(estimatedHeight);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::enforceFirstRowColumnAtOrigo()
+{
+ // Gaps before the first row/column can happen if rows/columns
+ // changes size while flicking e.g because of spacing changes or
+ // changes to a column maxWidth/row maxHeight. Check for this, and
+ // move the whole table rect accordingly.
+ bool layoutNeeded = false;
+ const qreal flickMargin = 50;
+
+ if (loadedTable.x() == 0 && loadedTableOuterRect.x() != tableMargins.left()) {
+ // The table is at the beginning, but not at the edge of the
+ // content view. So move the table to origo.
+ loadedTableOuterRect.moveLeft(tableMargins.left());
+ layoutNeeded = true;
+ } else if (loadedTableOuterRect.x() < 0) {
+ // The table is outside the beginning of the content view. Move
+ // the whole table inside, and make some room for flicking.
+ loadedTableOuterRect.moveLeft(tableMargins.left() + loadedTable.x() == 0 ? 0 : flickMargin);
+ layoutNeeded = true;
+ }
+
+ if (loadedTable.y() == 0 && loadedTableOuterRect.y() != tableMargins.top()) {
+ loadedTableOuterRect.moveTop(tableMargins.top());
+ layoutNeeded = true;
+ } else if (loadedTableOuterRect.y() < 0) {
+ loadedTableOuterRect.moveTop(tableMargins.top() + loadedTable.y() == 0 ? 0 : flickMargin);
+ layoutNeeded = true;
+ }
+
+ if (layoutNeeded)
+ relayoutTableItems();
+}
+
+void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
+{
+ QRectF topLeftRect = loadedTableItem(loadedTable.topLeft())->geometry();
+ QRectF bottomRightRect = loadedTableItem(loadedTable.bottomRight())->geometry();
+ loadedTableOuterRect = topLeftRect.united(bottomRightRect);
+ loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
+}
+
+void QQuickTableViewPrivate::syncLoadedTableFromLoadRequest()
+{
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::TopEdge:
+ loadedTable.setTopLeft(loadRequest.firstCell());
+ break;
+ case Qt::RightEdge:
+ case Qt::BottomEdge:
+ loadedTable.setBottomRight(loadRequest.lastCell());
+ break;
+ default:
+ loadedTable = QRect(loadRequest.firstCell(), loadRequest.lastCell());
+ }
+}
+
+FxTableItem *QQuickTableViewPrivate::itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const
+{
+ return loadedTableItem(fxTableItem->cell + direction);
+}
+
+FxTableItem *QQuickTableViewPrivate::loadedTableItem(const QPoint &cell) const
+{
+ for (int i = 0; i < loadedItems.count(); ++i) {
+ FxTableItem *item = loadedItems.at(i);
+ if (item->cell == cell)
+ return item;
+ }
+
+ Q_TABLEVIEW_UNREACHABLE(cell);
+ return nullptr;
+}
+
+FxTableItem *QQuickTableViewPrivate::createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+ Q_Q(QQuickTableView);
+
+ bool ownItem = false;
+ int modelIndex = modelIndexAtCell(cell);
+
+ QObject* object = model->object(modelIndex, incubationMode);
+ if (!object) {
+ if (model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
+ // Item is incubating. Return nullptr for now, and let the table call this
+ // function again once we get a callback to itemCreatedCallback().
+ return nullptr;
+ }
+
+ qWarning() << "TableView: failed loading index:" << modelIndex;
+ object = new QQuickItem();
+ ownItem = true;
+ }
+
+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
+ if (!item) {
+ // The model could not provide an QQuickItem for the
+ // given index, so we create a placeholder instead.
+ qWarning() << "TableView: delegate is not an item:" << modelIndex;
+ model->release(object);
+ item = new QQuickItem();
+ ownItem = true;
+ }
+
+ item->setParentItem(q->contentItem());
+
+ FxTableItem *fxTableItem = new FxTableItem(item, q, ownItem);
+ fxTableItem->setVisible(false);
+ fxTableItem->cell = cell;
+ fxTableItem->index = modelIndex;
+ return fxTableItem;
+}
+
+FxTableItem *QQuickTableViewPrivate::loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+{
+#ifdef QT_DEBUG
+ // Since TableView needs to work flawlessly when e.g incubating inside an async
+ // loader, being able to override all loading to async while debugging can be helpful.
+ static const bool forcedAsync = forcedIncubationMode == QLatin1String("async");
+ if (forcedAsync)
+ incubationMode = QQmlIncubator::Asynchronous;
+#endif
+
+ // Note that even if incubation mode is asynchronous, the item might
+ // be ready immediately since the model has a cache of items.
+ QBoolBlocker guard(blockItemCreatedCallback);
+ auto item = createFxTableItem(cell, incubationMode);
+ qCDebug(lcTableViewDelegateLifecycle) << cell << "ready?" << bool(item);
+ return item;
+}
+
+void QQuickTableViewPrivate::releaseLoadedItems() {
+ // Make a copy and clear the list of items first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ auto const tmpList = loadedItems;
+ loadedItems.clear();
+ for (FxTableItem *item : tmpList)
+ releaseItem(item);
+}
+
+void QQuickTableViewPrivate::releaseItem(FxTableItem *fxTableItem)
+{
+ if (fxTableItem->item) {
+ if (fxTableItem->ownItem)
+ delete fxTableItem->item;
+ else if (model->release(fxTableItem->item) != QQmlInstanceModel::Destroyed)
+ fxTableItem->item->setParentItem(nullptr);
+ }
+
+ delete fxTableItem;
+}
+
+void QQuickTableViewPrivate::clear()
+{
+ tableInvalid = true;
+ tableRebuilding = false;
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+
+ releaseLoadedItems();
+ loadedTable = QRect();
+ loadedTableOuterRect = QRect();
+ loadedTableInnerRect = QRect();
+ columnWidths.clear();
+ rowHeights.clear();
+ contentSizeBenchMarkPoint = QPoint(-1, -1);
+
+ updateContentWidth();
+ updateContentHeight();
+}
+
+void QQuickTableViewPrivate::unloadItem(const QPoint &cell)
+{
+ FxTableItem *item = loadedTableItem(cell);
+ loadedItems.removeOne(item);
+ releaseItem(item);
+}
+
+void QQuickTableViewPrivate::unloadItems(const QLine &items)
+{
+ qCDebug(lcTableViewDelegateLifecycle) << items;
+
+ if (items.dx()) {
+ int y = items.p1().y();
+ for (int x = items.p1().x(); x <= items.p2().x(); ++x)
+ unloadItem(QPoint(x, y));
+ } else {
+ int x = items.p1().x();
+ for (int y = items.p1().y(); y <= items.p2().y(); ++y)
+ unloadItem(QPoint(x, y));
+ }
+}
+
+bool QQuickTableViewPrivate::canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ if (loadedTable.topLeft().x() == 0)
+ return false;
+ return loadedTableOuterRect.left() > fillRect.left() + cellSpacing.width();
+ case Qt::RightEdge:
+ if (loadedTable.bottomRight().x() >= tableSize.width() - 1)
+ return false;
+ return loadedTableOuterRect.right() < fillRect.right() - cellSpacing.width();
+ case Qt::TopEdge:
+ if (loadedTable.topLeft().y() == 0)
+ return false;
+ return loadedTableOuterRect.top() > fillRect.top() + cellSpacing.height();
+ case Qt::BottomEdge:
+ if (loadedTable.bottomRight().y() >= tableSize.height() - 1)
+ return false;
+ return loadedTableOuterRect.bottom() < fillRect.bottom() - cellSpacing.height();
+ }
+
+ return false;
+}
+
+bool QQuickTableViewPrivate::canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const
+{
+ // Note: if there is only one row or column left, we cannot unload, since
+ // they are needed as anchor point for further layouting.
+ switch (tableEdge) {
+ case Qt::LeftEdge:
+ if (loadedTable.width() <= 1)
+ return false;
+ return loadedTableInnerRect.left() < fillRect.left();
+ case Qt::RightEdge:
+ if (loadedTable.width() <= 1)
+ return false;
+ return loadedTableInnerRect.right() > fillRect.right();
+ case Qt::TopEdge:
+ if (loadedTable.height() <= 1)
+ return false;
+ return loadedTableInnerRect.top() < fillRect.top();
+ case Qt::BottomEdge:
+ if (loadedTable.height() <= 1)
+ return false;
+ return loadedTableInnerRect.bottom() > fillRect.bottom();
+ }
+ Q_TABLEVIEW_UNREACHABLE(tableEdge);
+ return false;
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToLoad(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (canLoadTableEdge(edge, rect))
+ return edge;
+ }
+ return Qt::Edge(0);
+}
+
+Qt::Edge QQuickTableViewPrivate::nextEdgeToUnload(const QRectF rect)
+{
+ for (Qt::Edge edge : allTableEdges) {
+ if (canUnloadTableEdge(edge, rect))
+ return edge;
+ }
+ return Qt::Edge(0);
+}
+
+qreal QQuickTableViewPrivate::cellWidth(const QPoint& cell)
+{
+ // If a delegate item has TableView.cellWidth set, then
+ // we prefer that. Otherwise we fall back to use implicitWidth.
+ // Using an items width directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ if (auto const attached = getAttachedObject(cellItem)) {
+ if (!attached->m_cellWidth.isNull)
+ return attached->m_cellWidth;
+ }
+ return cellItem->implicitWidth();
+}
+
+qreal QQuickTableViewPrivate::cellHeight(const QPoint& cell)
+{
+ // If a delegate item has TableView.cellHeight set, then
+ // we prefer that. Otherwise we fall back to use implicitHeight.
+ // Using an items height directly is not an option, since we change
+ // it during layout (which would also cause problems when recycling items).
+ auto const cellItem = loadedTableItem(cell)->item;
+ if (auto const attached = getAttachedObject(cellItem)) {
+ if (!attached->m_cellHeight.isNull)
+ return attached->m_cellHeight;
+ }
+ return cellItem->implicitHeight();
+}
+
+void QQuickTableViewPrivate::calculateColumnWidthsAfterRebuilding()
+{
+ qreal prevColumnWidth = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ qreal columnWidth = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row)
+ columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
+
+ if (columnWidth <= 0)
+ columnWidth = kDefaultColumnWidth;
+
+ if (columnWidth == prevColumnWidth)
+ continue;
+
+ columnWidths.append({column, columnWidth});
+ prevColumnWidth = columnWidth;
+ }
+
+ if (columnWidths.isEmpty()) {
+ // Add at least one column, wo we don't need
+ // to check if the vector is empty elsewhere.
+ columnWidths.append({0, 0});
+ }
+}
+
+void QQuickTableViewPrivate::calculateRowHeightsAfterRebuilding()
+{
+ qreal prevRowHeight = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ qreal rowHeight = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column)
+ rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
+
+ if (rowHeight <= 0)
+ rowHeight = kDefaultRowHeight;
+
+ if (rowHeight == prevRowHeight)
+ continue;
+
+ rowHeights.append({row, rowHeight});
+ prevRowHeight = rowHeight;
+ }
+
+ if (rowHeights.isEmpty()) {
+ // Add at least one row, wo we don't need
+ // to check if the vector is empty elsewhere.
+ rowHeights.append({0, 0});
+ }
+}
+
+void QQuickTableViewPrivate::calculateColumnWidth(int column)
+{
+ if (column < columnWidths.last().index) {
+ // We only do the calculation once, and then stick with the size.
+ // See comments inside ColumnRowSize struct.
+ return;
+ }
+
+ qreal columnWidth = 0;
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row)
+ columnWidth = qMax(columnWidth, cellWidth(QPoint(column, row)));
+
+ if (columnWidth <= 0)
+ columnWidth = kDefaultColumnWidth;
+
+ if (columnWidth == columnWidths.last().size)
+ return;
+
+ columnWidths.append({column, columnWidth});
+}
+
+void QQuickTableViewPrivate::calculateRowHeight(int row)
+{
+ if (row < rowHeights.last().index) {
+ // We only do the calculation once, and then stick with the size.
+ // See comments inside ColumnRowSize struct.
+ return;
+ }
+
+ qreal rowHeight = 0;
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column)
+ rowHeight = qMax(rowHeight, cellHeight(QPoint(column, row)));
+
+ if (rowHeight <= 0)
+ rowHeight = kDefaultRowHeight;
+
+ if (rowHeight == rowHeights.last().size)
+ return;
+
+ rowHeights.append({row, rowHeight});
+}
+
+void QQuickTableViewPrivate::calculateEdgeSizeFromLoadRequest()
+{
+ if (tableRebuilding)
+ return;
+
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::TopEdge:
+ // Flicking left or up through "never loaded" rows/columns is currently
+ // not supported. You always need to start loading the table from the beginning.
+ return;
+ case Qt::RightEdge:
+ if (tableSize.height() > 1)
+ calculateColumnWidth(loadedTable.right());
+ break;
+ case Qt::BottomEdge:
+ if (tableSize.width() > 1)
+ calculateRowHeight(loadedTable.bottom());
+ break;
+ default:
+ Q_TABLEVIEW_UNREACHABLE("This function should not be called when loading top-left item");
+ }
+}
+
+void QQuickTableViewPrivate::calculateTableSize()
+{
+ // tableSize is the same as row and column count, and will always
+ // be the same as the number of rows and columns in the model.
+ Q_Q(QQuickTableView);
+ QSize prevTableSize = tableSize;
+
+ if (delegateModel)
+ tableSize = QSize(delegateModel->columns(), delegateModel->rows());
+ else if (model)
+ tableSize = QSize(1, model->count());
+ else
+ tableSize = QSize(0, 0);
+
+ if (prevTableSize.width() != tableSize.width())
+ emit q->columnsChanged();
+ if (prevTableSize.height() != tableSize.height())
+ emit q->rowsChanged();
+}
+
+qreal QQuickTableViewPrivate::columnWidth(int column)
+{
+ if (!columnWidths.isEmpty()) {
+ // Find the first ColumnRowSize with a column before, or at, the given column
+ auto iter = std::upper_bound(columnWidths.constBegin(), columnWidths.constEnd(),
+ ColumnRowSize{column, -1}, ColumnRowSize::lessThan);
+
+ if (iter == columnWidths.constEnd()) {
+ // If the table is not a list, return the size
+ // of the last recorded ColumnRowSize.
+ if (tableSize.height() > 1)
+ return columnWidths.last().size;
+ } else {
+ // Check if we got an explicit assignment for this column
+ if (iter->index == column)
+ return iter->size;
+
+ // If the table is not a list, return the size of
+ // ColumnRowSize element found before column. Since there
+ // is always an element stored for column 0, this is safe.
+ // Otherwise we continue, and return the size of the delegate
+ // item at the given column instead.
+ if (tableSize.height() > 1)
+ return (iter - 1)->size;
+ }
+ }
+
+ // If we have an item loaded at column, return the width of the item.
+ if (column >= loadedTable.left() && column <= loadedTable.right())
+ return cellWidth(QPoint(column, loadedTable.top()));
+
+ return -1;
+}
+
+qreal QQuickTableViewPrivate::rowHeight(int row)
+{
+ if (!rowHeights.isEmpty()) {
+ // Find the ColumnRowSize assignment before, or at, row
+ auto iter = std::lower_bound(rowHeights.constBegin(), rowHeights.constEnd(),
+ ColumnRowSize{row, -1}, ColumnRowSize::lessThan);
+
+ if (iter == rowHeights.constEnd()) {
+ // If the table is not a list, return the size
+ // of the last recorded ColumnRowSize.
+ if (tableSize.width() > 1)
+ return rowHeights.last().size;
+ } else {
+ // Check if we got an explicit assignment for this row
+ if (iter->index == row)
+ return iter->size;
+
+ // If the table is not a list, return the size of
+ // ColumnRowSize element found before row. Since there
+ // is always an element stored for row 0, this is safe.
+ // Otherwise we continue, and return the size of the delegate
+ // item at the given row instead.
+ if (tableSize.width() > 1)
+ return (iter - 1)->size;
+ }
+ }
+
+ // If we have an item loaded at row, return the height of the item.
+ if (row >= loadedTable.top() && row <= loadedTable.bottom())
+ return cellHeight(QPoint(loadedTable.left(), row));
+
+ return -1;
+}
+
+void QQuickTableViewPrivate::relayoutTable()
+{
+ relayoutTableItems();
+ columnRowPositionsInvalid = false;
+
+ syncLoadedTableRectFromLoadedTable();
+ contentSizeBenchMarkPoint = QPoint(-1, -1);
+ updateContentWidth();
+ updateContentHeight();
+}
+
+void QQuickTableViewPrivate::relayoutTableItems()
+{
+ qCDebug(lcTableViewDelegateLifecycle);
+ columnRowPositionsInvalid = false;
+
+ qreal nextColumnX = loadedTableOuterRect.x();
+ qreal nextRowY = loadedTableOuterRect.y();
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ // Adjust the geometry of all cells in the current column
+ qreal width = columnWidth(column);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveLeft(nextColumnX);
+ geometry.setWidth(width);
+ item->setGeometry(geometry);
+ }
+
+ nextColumnX += width + cellSpacing.width();
+ }
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ // Adjust the geometry of all cells in the current row
+ qreal height = rowHeight(row);
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ auto item = loadedTableItem(QPoint(column, row));
+ QRectF geometry = item->geometry();
+ geometry.moveTop(nextRowY);
+ geometry.setHeight(height);
+ item->setGeometry(geometry);
+ }
+
+ nextRowY += height + cellSpacing.height();
+ }
+
+ if (Q_UNLIKELY(lcTableViewDelegateLifecycle().isDebugEnabled())) {
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ QPoint cell = QPoint(column, row);
+ qCDebug(lcTableViewDelegateLifecycle()) << "relayout item:" << cell << loadedTableItem(cell)->geometry();
+ }
+ }
+ }
+}
+
+void QQuickTableViewPrivate::layoutVerticalEdge(Qt::Edge tableEdge)
+{
+ int column = (tableEdge == Qt::LeftEdge) ? loadedTable.left() : loadedTable.right();
+ QPoint neighbourDirection = (tableEdge == Qt::LeftEdge) ? kRight : kLeft;
+ qreal left = -1;
+
+ qreal width = columnWidth(column);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+
+ for (int row = loadedTable.top(); row <= loadedTable.bottom(); ++row) {
+ auto fxTableItem = loadedTableItem(QPoint(column, row));
+ auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection);
+
+ QRectF geometry = fxTableItem->geometry();
+ geometry.setWidth(width);
+ geometry.setHeight(neighbourItem->geometry().height());
+
+ if (left == -1) {
+ // left will be the same for all items in the
+ // column, so do the calculation once.
+ left = tableEdge == Qt::LeftEdge ?
+ neighbourItem->geometry().left() - cellSpacing.width() - geometry.width() :
+ neighbourItem->geometry().right() + cellSpacing.width();
+ }
+
+ geometry.moveLeft(left);
+ geometry.moveTop(neighbourItem->geometry().top());
+
+ fxTableItem->setGeometry(geometry);
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(column, row) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
+{
+ int row = (tableEdge == Qt::TopEdge) ? loadedTable.top() : loadedTable.bottom();
+ QPoint neighbourDirection = (tableEdge == Qt::TopEdge) ? kDown : kUp;
+ qreal top = -1;
+
+ qreal height = rowHeight(row);
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ for (int column = loadedTable.left(); column <= loadedTable.right(); ++column) {
+ auto fxTableItem = loadedTableItem(QPoint(column, row));
+ auto const neighbourItem = itemNextTo(fxTableItem, neighbourDirection);
+
+ QRectF geometry = fxTableItem->geometry();
+ geometry.setWidth(neighbourItem->geometry().width());
+ geometry.setHeight(height);
+
+ if (top == -1) {
+ // top will be the same for all items in the
+ // row, so do the calculation once.
+ top = tableEdge == Qt::TopEdge ?
+ neighbourItem->geometry().top() - cellSpacing.height() - geometry.height() :
+ neighbourItem->geometry().bottom() + cellSpacing.height();
+ }
+
+ geometry.moveTop(top);
+ geometry.moveLeft(neighbourItem->geometry().left());
+
+ fxTableItem->setGeometry(geometry);
+ fxTableItem->setVisible(true);
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "layout item:" << QPoint(column, row) << fxTableItem->geometry();
+ }
+}
+
+void QQuickTableViewPrivate::layoutTopLeftItem()
+{
+ // ###todo: support starting with other top-left items than 0,0
+ const QPoint cell = loadRequest.firstCell();
+ Q_TABLEVIEW_ASSERT(cell == QPoint(0, 0), loadRequest.toString());
+ auto topLeftItem = loadedTableItem(cell);
+ auto item = topLeftItem->item;
+
+ qreal width = cellWidth(cell);
+ qreal height = cellHeight(cell);
+ if (width <= 0)
+ width = kDefaultColumnWidth;
+ if (height <= 0)
+ height = kDefaultRowHeight;
+
+ item->setPosition(QPoint(tableMargins.left(), tableMargins.top()));
+ item->setSize(QSizeF(width, height));
+ topLeftItem->setVisible(true);
+ qCDebug(lcTableViewDelegateLifecycle) << "geometry:" << topLeftItem->geometry();
+}
+
+void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
+{
+ switch (loadRequest.edge()) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge:
+ layoutVerticalEdge(loadRequest.edge());
+ break;
+ case Qt::TopEdge:
+ case Qt::BottomEdge:
+ layoutHorizontalEdge(loadRequest.edge());
+ break;
+ default:
+ layoutTopLeftItem();
+ break;
+ }
+}
+
+void QQuickTableViewPrivate::cancelLoadRequest()
+{
+ loadRequest.markAsDone();
+ model->cancel(modelIndexAtCell(loadRequest.currentCell()));
+
+ if (tableInvalid) {
+ // No reason to rollback already loaded edge items
+ // since we anyway are about to reload all items.
+ return;
+ }
+
+ if (loadRequest.atBeginning()) {
+ // No items have yet been loaded, so nothing to unload
+ return;
+ }
+
+ QLine rollbackItems;
+ rollbackItems.setP1(loadRequest.firstCell());
+ rollbackItems.setP2(loadRequest.previousCell());
+ qCDebug(lcTableViewDelegateLifecycle()) << "rollback:" << rollbackItems << tableLayoutToString();
+ unloadItems(rollbackItems);
+}
+
+void QQuickTableViewPrivate::processLoadRequest()
+{
+ Q_TABLEVIEW_ASSERT(loadRequest.isActive(), "");
+
+ while (loadRequest.hasCurrentCell()) {
+ QPoint cell = loadRequest.currentCell();
+ FxTableItem *fxTableItem = loadFxTableItem(cell, loadRequest.incubationMode());
+
+ if (!fxTableItem) {
+ // Requested item is not yet ready. Just leave, and wait for this
+ // function to be called again when the item is ready.
+ return;
+ }
+
+ loadedItems.append(fxTableItem);
+ loadRequest.moveToNextCell();
+ }
+
+ qCDebug(lcTableViewDelegateLifecycle()) << "all items loaded!";
+
+ syncLoadedTableFromLoadRequest();
+ calculateEdgeSizeFromLoadRequest();
+ layoutTableEdgeFromLoadRequest();
+
+ syncLoadedTableRectFromLoadedTable();
+ enforceFirstRowColumnAtOrigo();
+ updateContentWidth();
+ updateContentHeight();
+
+ loadRequest.markAsDone();
+ qCDebug(lcTableViewDelegateLifecycle()) << "request completed! Table:" << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::beginRebuildTable()
+{
+ qCDebug(lcTableViewDelegateLifecycle());
+ clear();
+ tableInvalid = false;
+ tableRebuilding = true;
+ calculateTableSize();
+ loadInitialTopLeftItem();
+ loadAndUnloadVisibleEdges();
+}
+
+void QQuickTableViewPrivate::endRebuildTable()
+{
+ tableRebuilding = false;
+
+ if (loadedItems.isEmpty())
+ return;
+
+ // We don't calculate row/column sizes for lists.
+ // Instead we we use the sizes of the items directly
+ // unless for explicit row/column size assignments.
+ columnWidths.clear();
+ rowHeights.clear();
+ if (tableSize.height() > 1)
+ calculateColumnWidthsAfterRebuilding();
+ if (tableSize.width() > 1)
+ calculateRowHeightsAfterRebuilding();
+
+ relayoutTable();
+ qCDebug(lcTableViewDelegateLifecycle()) << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::loadInitialTopLeftItem()
+{
+ Q_TABLEVIEW_ASSERT(loadedItems.isEmpty(), "");
+
+ if (tableSize.isEmpty())
+ return;
+
+ if (model->count() == 0)
+ return;
+
+ // Load top-left item. After loaded, loadItemsInsideRect() will take
+ // care of filling out the rest of the table.
+ loadRequest.begin(QPoint(0, 0), QQmlIncubator::AsynchronousIfNested);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
+{
+ unloadItems(rectangleEdge(loadedTable, edge));
+ loadedTable = expandedRect(loadedTable, edge, -1);
+ syncLoadedTableRectFromLoadedTable();
+ qCDebug(lcTableViewDelegateLifecycle) << tableLayoutToString();
+}
+
+void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
+{
+ QLine cellsToLoad = rectangleEdge(expandedRect(loadedTable, edge, 1), edge);
+ loadRequest.begin(cellsToLoad, edge, incubationMode);
+ processLoadRequest();
+}
+
+void QQuickTableViewPrivate::loadAndUnloadVisibleEdges()
+{
+ // Unload table edges that have been moved outside the visible part of the
+ // table (including buffer area), and load new edges that has been moved inside.
+ // Note: an important point is that we always keep the table rectangular
+ // and without holes to reduce complexity (we never leave the table in
+ // a half-loaded state, or keep track of multiple patches).
+ // We load only one edge (row or column) at a time. This is especially
+ // important when loading into the buffer, since we need to be able to
+ // cancel the buffering quickly if the user starts to flick, and then
+ // focus all further loading on the edges that are flicked into view.
+
+ if (loadRequest.isActive()) {
+ // Don't start loading more edges while we're
+ // already waiting for another one to load.
+ return;
+ }
+
+ if (loadedItems.isEmpty()) {
+ // We need at least the top-left item to be loaded before we can
+ // start loading edges around it. Not having a top-left item at
+ // this point means that the model is empty (or no delegate).
+ return;
+ }
+
+ const QRectF unloadRect = hasBufferedItems ? bufferRect() : viewportRect;
+ bool tableModified;
+
+ do {
+ tableModified = false;
+
+ if (Qt::Edge edge = nextEdgeToUnload(unloadRect)) {
+ tableModified = true;
+ unloadEdge(edge);
+ }
+
+ if (Qt::Edge edge = nextEdgeToLoad(viewportRect)) {
+ tableModified = true;
+ loadEdge(edge, QQmlIncubator::AsynchronousIfNested);
+ if (loadRequest.isActive())
+ return;
+ }
+ } while (tableModified);
+
+}
+
+void QQuickTableViewPrivate::loadBuffer()
+{
+ // Rather than making sure to stop the timer from all locations that can
+ // violate the "buffering allowed" state, we just check that we're in the
+ // right state here before we start buffering.
+ if (cacheBuffer <= 0 || loadRequest.isActive() || loadedItems.isEmpty())
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle());
+ const QRectF loadRect = bufferRect();
+ while (Qt::Edge edge = nextEdgeToLoad(loadRect)) {
+ loadEdge(edge, QQmlIncubator::Asynchronous);
+ if (loadRequest.isActive())
+ break;
+ }
+
+ hasBufferedItems = true;
+}
+
+void QQuickTableViewPrivate::unloadBuffer()
+{
+ if (!hasBufferedItems)
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle());
+ hasBufferedItems = false;
+ cacheBufferDelayTimer.stop();
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+ while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
+ unloadEdge(edge);
+}
+
+QRectF QQuickTableViewPrivate::bufferRect()
+{
+ return viewportRect.adjusted(-cacheBuffer, -cacheBuffer, cacheBuffer, cacheBuffer);
+}
+
+void QQuickTableViewPrivate::invalidateTable() {
+ tableInvalid = true;
+ if (loadRequest.isActive())
+ cancelLoadRequest();
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::invalidateColumnRowPositions() {
+ columnRowPositionsInvalid = true;
+ q_func()->polish();
+}
+
+void QQuickTableViewPrivate::updatePolish()
+{
+ // Whenever something changes, e.g viewport moves, spacing is set to a
+ // new value, model changes etc, this function will end up being called. Here
+ // we check what needs to be done, and load/unload cells accordingly.
+ Q_Q(QQuickTableView);
+
+ if (loadRequest.isActive()) {
+ // We're currently loading items async to build a new edge in the table. We see the loading
+ // as an atomic operation, which means that we don't continue doing anything else until all
+ // items have been received and laid out. Note that updatePolish is then called once more
+ // after the loadRequest has completed to handle anything that might have occurred in-between.
+ return;
+ }
+
+ // viewportRect describes the part of the content view that is actually visible. Since a
+ // negative width/height can happen (e.g during start-up), we check for this to avoid rebuilding
+ // the table (and e.g calculate initial row/column sizes) based on a premature viewport rect.
+ viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
+ if (!viewportRect.isValid())
+ return;
+
+ if (tableInvalid) {
+ beginRebuildTable();
+ if (loadRequest.isActive())
+ return;
+ }
+
+ if (tableRebuilding)
+ endRebuildTable();
+
+ if (loadedItems.isEmpty()) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model or no delegate";
+ return;
+ }
+
+ if (columnRowPositionsInvalid)
+ relayoutTable();
+
+ if (hasBufferedItems && nextEdgeToLoad(viewportRect)) {
+ // We are about to load more edges, so trim down the table as much
+ // as possible to avoid loading cells that are outside the viewport.
+ unloadBuffer();
+ }
+
+ loadAndUnloadVisibleEdges();
+
+ if (loadRequest.isActive())
+ return;
+
+ if (cacheBuffer > 0) {
+ // When polish hasn't been called for a while (which means that the viewport
+ // rect hasn't changed), we start buffering items. We delay this operation by
+ // using a timer to increase performance (by not loading hidden items) while
+ // the user is flicking.
+ cacheBufferDelayTimer.start(kBufferTimerInterval);
+ }
+}
+
+void QQuickTableViewPrivate::createWrapperModel()
+{
+ Q_Q(QQuickTableView);
+
+ delegateModel = new QQmlDelegateModel(qmlContext(q), q);
+ if (q->isComponentComplete())
+ delegateModel->componentComplete();
+ model = delegateModel;
+}
+
+void QQuickTableViewPrivate::itemCreatedCallback(int modelIndex, QObject*)
+{
+ if (blockItemCreatedCallback)
+ return;
+
+ qCDebug(lcTableViewDelegateLifecycle) << "item done loading:"
+ << cellAtModelIndex(modelIndex);
+
+ // Since the item we waited for has finished incubating, we can
+ // continue with the load request. processLoadRequest will
+ // ask the model for the requested item once more, which will be
+ // quick since the model has cached it.
+ processLoadRequest();
+ loadAndUnloadVisibleEdges();
+ updatePolish();
+}
+
+void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
+{
+ Q_UNUSED(modelIndex);
+ auto attached = getAttachedObject(object);
+ if (!attached)
+ return;
+
+ // Even though row and column is injected directly into the context of a delegate item
+ // from QQmlDelegateModel and its model classes, they will only return which row and
+ // column an item represents in the model. This might be different from which
+ // cell an item ends up in in the Table, if a different rows/columns has been set
+ // on it (which is typically the case for list models). For those cases, Table.row
+ // and Table.column can be helpful.
+ QPoint cell = cellAtModelIndex(modelIndex);
+ attached->setTableView(q_func());
+ attached->setColumn(cell.x());
+ attached->setRow(cell.y());
+}
+
+void QQuickTableViewPrivate::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
+{
+ Q_UNUSED(changeSet);
+ Q_UNUSED(reset);
+
+ // TODO: implement fine-grained support for model changes
+ invalidateTable();
+}
+
+QQuickTableView::QQuickTableView(QQuickItem *parent)
+ : QQuickFlickable(*(new QQuickTableViewPrivate), parent)
+{
+}
+
+int QQuickTableView::rows() const
+{
+ return d_func()->tableSize.height();
+}
+
+int QQuickTableView::columns() const
+{
+ return d_func()->tableSize.width();
+}
+
+qreal QQuickTableView::rowSpacing() const
+{
+ return d_func()->cellSpacing.height();
+}
+
+void QQuickTableView::setRowSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qFuzzyCompare(d->cellSpacing.height(), spacing))
+ return;
+
+ d->cellSpacing.setHeight(spacing);
+ d->invalidateColumnRowPositions();
+ emit rowSpacingChanged();
+}
+
+qreal QQuickTableView::columnSpacing() const
+{
+ return d_func()->cellSpacing.width();
+}
+
+void QQuickTableView::setColumnSpacing(qreal spacing)
+{
+ Q_D(QQuickTableView);
+ if (qFuzzyCompare(d->cellSpacing.width(), spacing))
+ return;
+
+ d->cellSpacing.setWidth(spacing);
+ d->invalidateColumnRowPositions();
+ emit columnSpacingChanged();
+}
+
+qreal QQuickTableView::topMargin() const
+{
+ return d_func()->tableMargins.top();
+}
+
+void QQuickTableView::setTopMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.top(), margin))
+ return;
+
+ d->tableMargins.setTop(margin);
+ d->invalidateColumnRowPositions();
+ emit topMarginChanged();
+}
+
+qreal QQuickTableView::bottomMargin() const
+{
+ return d_func()->tableMargins.bottom();
+}
+
+void QQuickTableView::setBottomMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.bottom(), margin))
+ return;
+
+ d->tableMargins.setBottom(margin);
+ d->invalidateColumnRowPositions();
+ emit bottomMarginChanged();
+}
+
+qreal QQuickTableView::leftMargin() const
+{
+ return d_func()->tableMargins.left();
+}
+
+void QQuickTableView::setLeftMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.left(), margin))
+ return;
+
+ d->tableMargins.setLeft(margin);
+ d->invalidateColumnRowPositions();
+ emit leftMarginChanged();
+}
+
+qreal QQuickTableView::rightMargin() const
+{
+ return d_func()->tableMargins.right();
+}
+
+void QQuickTableView::setRightMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.right(), margin))
+ return;
+
+ d->tableMargins.setRight(margin);
+ d->invalidateColumnRowPositions();
+ emit rightMarginChanged();
+}
+
+int QQuickTableView::cacheBuffer() const
+{
+ return d_func()->cacheBuffer;
+}
+
+void QQuickTableView::setCacheBuffer(int newBuffer)
+{
+ Q_D(QQuickTableView);
+ if (d->cacheBuffer == newBuffer || newBuffer < 0)
+ return;
+
+ d->cacheBuffer = newBuffer;
+
+ if (newBuffer == 0)
+ d->unloadBuffer();
+
+ emit cacheBufferChanged();
+ polish();
+}
+
+QVariant QQuickTableView::model() const
+{
+ return d_func()->modelVariant;
+}
+
+void QQuickTableView::setModel(const QVariant &newModel)
+{
+ Q_D(QQuickTableView);
+
+ d->modelVariant = newModel;
+ QVariant effectiveModelVariant = d->modelVariant;
+ if (effectiveModelVariant.userType() == qMetaTypeId<QJSValue>())
+ effectiveModelVariant = effectiveModelVariant.value<QJSValue>().toVariant();
+
+ if (d->model) {
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::createdItem, d, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::initItem, d, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::disconnect(d->model, &QQmlInstanceModel::modelUpdated, d, &QQuickTableViewPrivate::modelUpdated);
+ }
+
+ const auto instanceModel = qobject_cast<QQmlInstanceModel *>(qvariant_cast<QObject*>(effectiveModelVariant));
+
+ if (instanceModel) {
+ if (d->delegateModel)
+ delete d->delegateModel;
+ d->model = instanceModel;
+ d->delegateModel = qmlobject_cast<QQmlDelegateModel *>(instanceModel);
+ } else {
+ if (!d->delegateModel)
+ d->createWrapperModel();
+ QQmlDelegateModelPrivate::get(d->delegateModel)->m_useFirstColumnOnly = false;
+ d->delegateModel->setModel(effectiveModelVariant);
+ }
+
+ Q_ASSERT(d->model);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::createdItem, d, &QQuickTableViewPrivate::itemCreatedCallback);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::initItem, d, &QQuickTableViewPrivate::initItemCallback);
+ QObjectPrivate::connect(d->model, &QQmlInstanceModel::modelUpdated, d, &QQuickTableViewPrivate::modelUpdated);
+
+ d->invalidateTable();
+
+ emit modelChanged();
+}
+
+QQmlComponent *QQuickTableView::delegate() const
+{
+ Q_D(const QQuickTableView);
+ if (d->delegateModel)
+ return d->delegateModel->delegate();
+
+ return nullptr;
+}
+
+void QQuickTableView::setDelegate(QQmlComponent *newDelegate)
+{
+ Q_D(QQuickTableView);
+ if (newDelegate == delegate())
+ return;
+
+ if (!d->delegateModel)
+ d->createWrapperModel();
+
+ d->delegateModel->setDelegate(newDelegate);
+ d->invalidateTable();
+
+ emit delegateChanged();
+}
+
+QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickTableViewAttached(obj);
+}
+
+void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
+ // We update the viewport rect from within updatePolish to
+ // ensure that we update when we're ready to update, and not
+ // while we're in the middle of loading/unloading edges.
+ d->updatePolish();
+}
+
+void QQuickTableView::viewportMoved(Qt::Orientations orientation)
+{
+ Q_D(QQuickTableView);
+ QQuickFlickable::viewportMoved(orientation);
+ // We update the viewport rect from within updatePolish to
+ // ensure that we update when we're ready to update, and not
+ // while we're in the middle of loading/unloading edges.
+ d->updatePolish();
+}
+
+void QQuickTableView::componentComplete()
+{
+ Q_D(QQuickTableView);
+
+ if (!d->model)
+ setModel(QVariant());
+
+ if (d->delegateModel)
+ d->delegateModel->componentComplete();
+
+ QQuickFlickable::componentComplete();
+}
+
+#include "moc_qquicktableview_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
new file mode 100644
index 0000000000..f3a589b9e4
--- /dev/null
+++ b/src/quick/items/qquicktableview_p.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABLEVIEW_P_H
+#define QQUICKTABLEVIEW_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/qpointer.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQml/private/qqmlnullablevalue_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTableViewAttached;
+class QQuickTableViewPrivate;
+class QQmlChangeSet;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int rows READ rows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns NOTIFY columnsChanged)
+ Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
+ Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+
+public:
+ QQuickTableView(QQuickItem *parent = nullptr);
+
+ int rows() const;
+ int columns() const;
+
+ qreal rowSpacing() const;
+ void setRowSpacing(qreal spacing);
+
+ qreal columnSpacing() const;
+ void setColumnSpacing(qreal spacing);
+
+ qreal topMargin() const;
+ void setTopMargin(qreal margin);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal margin);
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal margin);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal margin);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int newBuffer);
+
+ QVariant model() const;
+ void setModel(const QVariant &newModel);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *);
+
+ static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void rowsChanged();
+ void columnsChanged();
+ void rowSpacingChanged();
+ void columnSpacingChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void cacheBufferChanged();
+ void modelChanged();
+ void delegateChanged();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void viewportMoved(Qt::Orientations orientation) override;
+ void componentComplete() override;
+
+private:
+ Q_DISABLE_COPY(QQuickTableView)
+ Q_DECLARE_PRIVATE(QQuickTableView)
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableViewAttached : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickTableView *tableView READ tableView NOTIFY tableViewChanged)
+ Q_PROPERTY(qreal cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
+ Q_PROPERTY(qreal cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged)
+ Q_PROPERTY(int row READ row NOTIFY rowChanged)
+ Q_PROPERTY(int column READ column NOTIFY columnChanged)
+
+public:
+ QQuickTableViewAttached(QObject *parent)
+ : QObject(parent) {}
+
+ QQuickTableView *tableView() const { return m_tableview; }
+ void setTableView(QQuickTableView *newTableView) {
+ if (newTableView == m_tableview)
+ return;
+ m_tableview = newTableView;
+ Q_EMIT tableViewChanged();
+ }
+
+ qreal cellWidth() const { return m_cellWidth; }
+ void setCellWidth(qreal newWidth) {
+ if (newWidth == m_cellWidth)
+ return;
+ m_cellWidth = newWidth;
+ Q_EMIT cellWidthChanged();
+ }
+
+ qreal cellHeight() const { return m_cellHeight; }
+ void setCellHeight(qreal newHeight) {
+ if (newHeight == m_cellHeight)
+ return;
+ m_cellHeight = newHeight;
+ Q_EMIT cellHeightChanged();
+ }
+
+ int row() const { return m_row; }
+ void setRow(int newRow) {
+ if (newRow == m_row)
+ return;
+ m_row = newRow;
+ Q_EMIT rowChanged();
+ }
+
+ int column() const { return m_column; }
+ void setColumn(int newColumn) {
+ if (newColumn == m_column)
+ return;
+ m_column = newColumn;
+ Q_EMIT columnChanged();
+ }
+
+Q_SIGNALS:
+ void tableViewChanged();
+ void cellWidthChanged();
+ void cellHeightChanged();
+ void rowChanged();
+ void columnChanged();
+
+private:
+ QPointer<QQuickTableView> m_tableview;
+ int m_row = -1;
+ int m_column = -1;
+ QQmlNullableValue<qreal> m_cellWidth;
+ QQmlNullableValue<qreal> m_cellHeight;
+
+ friend class QQuickTableViewPrivate;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTableView)
+QML_DECLARE_TYPEINFO(QQuickTableView, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTABLEVIEW_P_H
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
new file mode 100644
index 0000000000..fa3cf95268
--- /dev/null
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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 "qquicktableview_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
+
+static const int kDefaultCacheBuffer = 300;
+static const qreal kDefaultRowHeight = 50;
+static const qreal kDefaultColumnWidth = 50;
+
+class FxTableItem;
+
+class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTableView)
+
+public:
+ class TableEdgeLoadRequest
+ {
+ // Whenever we need to load new rows or columns in the
+ // table, we fill out a TableEdgeLoadRequest.
+ // TableEdgeLoadRequest is just a struct that keeps track
+ // of which cells that needs to be loaded, and which cell
+ // the table is currently loading. The loading itself is
+ // done by QQuickTableView.
+
+ public:
+ void begin(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = Qt::Edge(0);
+ tableCells = QLine(cell, cell);
+ mode = incubationMode;
+ cellCount = 1;
+ currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
+ }
+
+ void begin(const QLine cellsToLoad, Qt::Edge edgeToLoad, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = edgeToLoad;
+ tableCells = cellsToLoad;
+ mode = incubationMode;
+ cellCount = tableCells.x2() - tableCells.x1() + tableCells.y2() - tableCells.y1() + 1;
+ currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin:" << toString();
+ }
+
+ inline void markAsDone() { active = false; }
+ inline bool isActive() { return active; }
+
+ inline QPoint firstCell() { return tableCells.p1(); }
+ inline QPoint lastCell() { return tableCells.p2(); }
+ inline QPoint currentCell() { return cellAt(currentIndex); }
+ inline QPoint previousCell() { return cellAt(currentIndex - 1); }
+
+ inline bool atBeginning() { return currentIndex == 0; }
+ inline bool hasCurrentCell() { return currentIndex < cellCount; }
+ inline void moveToNextCell() { ++currentIndex; }
+
+ inline Qt::Edge edge() { return tableEdge; }
+ inline QQmlIncubator::IncubationMode incubationMode() { return mode; }
+
+ QString toString()
+ {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "TableSectionLoadRequest(" << "edge:"
+ << tableEdge << " cells:" << tableCells << " incubation:";
+
+ switch (mode) {
+ case QQmlIncubator::Asynchronous:
+ dbg << "Asynchronous";
+ break;
+ case QQmlIncubator::AsynchronousIfNested:
+ dbg << "AsynchronousIfNested";
+ break;
+ case QQmlIncubator::Synchronous:
+ dbg << "Synchronous";
+ break;
+ }
+
+ return str;
+ }
+
+ private:
+ Qt::Edge tableEdge = Qt::Edge(0);
+ QLine tableCells;
+ int currentIndex = 0;
+ int cellCount = 0;
+ bool active = false;
+ QQmlIncubator::IncubationMode mode = QQmlIncubator::AsynchronousIfNested;
+
+ QPoint cellAt(int index)
+ {
+ int x = tableCells.p1().x() + (tableCells.dx() ? index : 0);
+ int y = tableCells.p1().y() + (tableCells.dy() ? index : 0);
+ return QPoint(x, y);
+ }
+ };
+
+ struct ColumnRowSize
+ {
+ // ColumnRowSize is a helper class for storing row heights
+ // and column widths. We calculate the average width of a column
+ // the first time it's scrolled into view based on the size of
+ // the loaded items in the new column. Since we never load more items
+ // that what fits inside the viewport (cachebuffer aside), this calculation
+ // would be different depending on which row you were at when the column
+ // was scrolling in. To avoid that a column resizes when it's scrolled
+ // in and out and in again, we store its width. But to avoid storing
+ // the width for all columns, we choose to only store the width if it
+ // differs from the column(s) to the left. The same logic applies for row heights.
+ // 'index' translates to either 'row' or 'column'.
+ int index;
+ qreal size;
+
+ static bool lessThan(const ColumnRowSize& a, const ColumnRowSize& b)
+ {
+ return a.index < b.index;
+ }
+ };
+
+public:
+ QQuickTableViewPrivate();
+ ~QQuickTableViewPrivate() override;
+
+ static inline QQuickTableViewPrivate *get(QQuickTableView *q) { return q->d_func(); }
+
+ void updatePolish() override;
+
+public:
+ QList<FxTableItem *> loadedItems;
+
+ // model, delegateModel and modelVariant all points to the same model. modelVariant
+ // is the model assigned by the user. And delegateModel is the wrapper model we create
+ // around it. But if the model is an instance model directly, we cannot wrap it, so
+ // we need a pointer for that case as well.
+ QQmlInstanceModel* model = nullptr;
+ QPointer<QQmlDelegateModel> delegateModel = nullptr;
+ QVariant modelVariant;
+
+ // loadedTable describes the table cells that are currently loaded (from top left
+ // row/column to bottom right row/column). loadedTableOuterRect describes the actual
+ // pixels that those cells cover, and is matched agains the viewport to determine when
+ // we need to fill up with more rows/columns. loadedTableInnerRect describes the pixels
+ // that the loaded table covers if you remove one row/column on each side of the table, and
+ // is used to determine rows/columns that are no longer visible and can be unloaded.
+ QRect loadedTable;
+ QRectF loadedTableOuterRect;
+ QRectF loadedTableInnerRect;
+
+ QRectF viewportRect = QRectF(0, 0, -1, -1);
+
+ QSize tableSize;
+
+ TableEdgeLoadRequest loadRequest;
+
+ QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
+ QSizeF cellSpacing;
+ QMarginsF tableMargins;
+
+ int cacheBuffer = kDefaultCacheBuffer;
+ QTimer cacheBufferDelayTimer;
+ bool hasBufferedItems = false;
+
+ bool blockItemCreatedCallback = false;
+ bool tableInvalid = false;
+ bool tableRebuilding = false;
+ bool columnRowPositionsInvalid = false;
+
+ QVector<ColumnRowSize> columnWidths;
+ QVector<ColumnRowSize> rowHeights;
+
+ const static QPoint kLeft;
+ const static QPoint kRight;
+ const static QPoint kUp;
+ const static QPoint kDown;
+
+#ifdef QT_DEBUG
+ QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
+#endif
+
+public:
+ QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+
+ int modelIndexAtCell(const QPoint &cell);
+ QPoint cellAtModelIndex(int modelIndex);
+
+ void calculateColumnWidthsAfterRebuilding();
+ void calculateRowHeightsAfterRebuilding();
+ void calculateColumnWidth(int column);
+ void calculateRowHeight(int row);
+ void calculateEdgeSizeFromLoadRequest();
+ void calculateTableSize();
+
+ qreal columnWidth(int column);
+ qreal rowHeight(int row);
+
+ void relayoutTable();
+ void relayoutTableItems();
+
+ void layoutVerticalEdge(Qt::Edge tableEdge);
+ void layoutHorizontalEdge(Qt::Edge tableEdge);
+ void layoutTopLeftItem();
+ void layoutTableEdgeFromLoadRequest();
+
+ void updateContentWidth();
+ void updateContentHeight();
+
+ void enforceFirstRowColumnAtOrigo();
+ void syncLoadedTableRectFromLoadedTable();
+ void syncLoadedTableFromLoadRequest();
+
+ bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ Qt::Edge nextEdgeToLoad(const QRectF rect);
+ Qt::Edge nextEdgeToUnload(const QRectF rect);
+
+ qreal cellWidth(const QPoint &cell);
+ qreal cellHeight(const QPoint &cell);
+
+ FxTableItem *loadedTableItem(const QPoint &cell) const;
+ FxTableItem *itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const;
+ FxTableItem *createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+ FxTableItem *loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+
+ void releaseItem(FxTableItem *fxTableItem);
+ void releaseLoadedItems();
+ void clear();
+
+ void unloadItem(const QPoint &cell);
+ void unloadItems(const QLine &items);
+
+ void loadInitialTopLeftItem();
+ void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
+ void unloadEdge(Qt::Edge edge);
+ void loadAndUnloadVisibleEdges();
+ void cancelLoadRequest();
+ void processLoadRequest();
+ void beginRebuildTable();
+ void endRebuildTable();
+
+ void loadBuffer();
+ void unloadBuffer();
+ QRectF bufferRect();
+
+ void invalidateTable();
+ void invalidateColumnRowPositions();
+
+ void createWrapperModel();
+
+ void initItemCallback(int modelIndex, QObject *item);
+ void itemCreatedCallback(int modelIndex, QObject *object);
+ void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
+
+ inline QString tableLayoutToString() const;
+ void dumpTable() const;
+};
+
+class FxTableItem : public QQuickItemViewFxItem
+{
+public:
+ FxTableItem(QQuickItem *item, QQuickTableView *table, bool own)
+ : QQuickItemViewFxItem(item, own, QQuickTableViewPrivate::get(table))
+ {
+ }
+
+ qreal position() const override { return 0; }
+ qreal endPosition() const override { return 0; }
+ qreal size() const override { return 0; }
+ qreal sectionSize() const override { return 0; }
+ bool contains(qreal, qreal) const override { return false; }
+
+ QPoint cell;
+};
+
+Q_DECLARE_TYPEINFO(QQuickTableViewPrivate::ColumnRowSize, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 76720e5c5d..3c260165f7 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -88,6 +88,7 @@ QQuickTextPrivate::QQuickTextPrivate()
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
, layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
, polishSize(false)
+ , updateSizeRecursionGuard(false)
{
implicitAntialiasing = true;
}
@@ -442,6 +443,7 @@ void QQuickTextPrivate::updateSize()
//### need to confirm cost of always setting these for richText
internalWidthUpdate = true;
+ qreal oldWidth = q->width();
qreal iWidth = -1;
if (!q->widthValid())
iWidth = size.width();
@@ -449,24 +451,35 @@ void QQuickTextPrivate::updateSize()
q->setImplicitSize(iWidth + hPadding, size.height() + vPadding);
internalWidthUpdate = false;
- if (iWidth == -1)
- q->setImplicitHeight(size.height() + vPadding);
-
- QTextBlock firstBlock = extra->doc->firstBlock();
- while (firstBlock.layout()->lineCount() == 0)
- firstBlock = firstBlock.next();
-
- QTextBlock lastBlock = extra->doc->lastBlock();
- while (lastBlock.layout()->lineCount() == 0)
- lastBlock = lastBlock.previous();
-
- if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
- QTextLine firstLine = firstBlock.layout()->lineAt(0);
- QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
- advance = QSizeF(lastLine.horizontalAdvance(),
- (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ // If the implicit width update caused a recursive change of the width,
+ // we will have skipped integral parts of the layout due to the
+ // internalWidthUpdate recursion guard. To make sure everything is up
+ // to date, we need to run a second pass over the layout when updateSize()
+ // is done.
+ if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
+ updateSizeRecursionGuard = true;
+ updateSize();
+ updateSizeRecursionGuard = false;
} else {
- advance = QSizeF();
+ if (iWidth == -1)
+ q->setImplicitHeight(size.height() + vPadding);
+
+ QTextBlock firstBlock = extra->doc->firstBlock();
+ while (firstBlock.layout()->lineCount() == 0)
+ firstBlock = firstBlock.next();
+
+ QTextBlock lastBlock = extra->doc->lastBlock();
+ while (lastBlock.layout()->lineCount() == 0)
+ lastBlock = lastBlock.previous();
+
+ if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
+ QTextLine firstLine = firstBlock.layout()->lineAt(0);
+ QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
+ advance = QSizeF(lastLine.horizontalAdvance(),
+ (lastLine.y() + lastBlock.layout()->position().y()) - (firstLine.y() + firstBlock.layout()->position().y()));
+ } else {
+ advance = QSizeF();
+ }
}
}
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index b0b1492d57..fd26d966c8 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -174,6 +174,7 @@ public:
bool needToUpdateLayout:1;
bool formatModifiesFontSize:1;
bool polishSize:1; // Workaround for problem with polish called after updateSize (QTBUG-42636)
+ bool updateSizeRecursionGuard:1;
static const QChar elideChar;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index d9db8b56b4..c80e052dad 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -88,6 +88,8 @@ Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
+Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target")
Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
@@ -256,14 +258,16 @@ void QQuickWindow::hideEvent(QHideEvent *)
void QQuickWindow::focusOutEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(false, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(false, ev->reason());
}
/*! \reimp */
void QQuickWindow::focusInEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
- d->contentItem->setFocus(true, ev->reason());
+ if (d->contentItem)
+ d->contentItem->setFocus(true, ev->reason());
d->updateFocusItemTransform();
}
@@ -1315,7 +1319,9 @@ QQuickWindow::~QQuickWindow()
#if QT_CONFIG(draganddrop)
delete d->dragGrabber; d->dragGrabber = nullptr;
#endif
- delete d->contentItem; d->contentItem = nullptr;
+ QQuickRootItem *root = d->contentItem;
+ d->contentItem = nullptr;
+ delete root;
qDeleteAll(d->pointerEventInstances);
d->pointerEventInstances.clear();
@@ -1571,6 +1577,8 @@ bool QQuickWindow::event(QEvent *e)
return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
break;
case QEvent::Enter: {
+ if (!d->contentItem)
+ return false;
QEnterEvent *enter = static_cast<QEnterEvent*>(e);
bool accepted = enter->isAccepted();
bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
@@ -1592,7 +1600,8 @@ bool QQuickWindow::event(QEvent *e)
break;
#endif
case QEvent::WindowDeactivate:
- contentItem()->windowDeactivateEvent();
+ if (d->contentItem)
+ d->contentItem->windowDeactivateEvent();
break;
case QEvent::Close: {
// TOOD Qt 6 (binary incompatible)
@@ -1617,7 +1626,7 @@ bool QQuickWindow::event(QEvent *e)
}
#if QT_CONFIG(gestures)
case QEvent::NativeGesture:
- d->deliverNativeGestureEvent(d->contentItem, static_cast<QNativeGestureEvent*>(e));
+ d->deliverSinglePointEventUntilAccepted(d->pointerEventInstance(e));
break;
#endif
case QEvent::ShortcutOverride:
@@ -1886,43 +1895,57 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
return false;
}
-#if QT_CONFIG(wheelevent)
-bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
+// Simple delivery of non-mouse, non-touch Pointer Events: visit the items and handlers
+// in the usual reverse-paint-order until propagation is stopped
+bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEvent *event)
{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QPointF p = item->mapFromScene(event->posF());
- if (!item->contains(p))
- return false;
- }
+ Q_ASSERT(event->pointCount() == 1);
+ QQuickEventPoint *point = event->point(0);
+ QVector<QQuickItem *> targetItems = pointerTargets(contentItem, point->scenePosition(), false, false);
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverWheelEvent(child, event))
- return true;
- }
-
- QPointF p = item->mapFromScene(event->posF());
-
- if (item->contains(p)) {
- QWheelEvent wheel(p, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(),
- event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted());
- wheel.setTimestamp(event->timestamp());
- wheel.accept();
- QCoreApplication::sendEvent(item, &wheel);
- if (wheel.isAccepted()) {
- event->accept();
+ for (QQuickItem *item : targetItems) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ event->localize(item);
+ // Let Pointer Handlers have the first shot
+ itemPrivate->handlePointerEvent(event);
+ if (point->isAccepted())
return true;
+ QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint());
+#if QT_CONFIG(wheelevent)
+ // Let the Item have a chance to handle it
+ if (QQuickPointerScrollEvent *pse = event->asPointerScrollEvent()) {
+ QWheelEvent wheel(point->position(), g, pse->pixelDelta().toPoint(), pse->angleDelta().toPoint(),
+ pse->buttons(), pse->modifiers(), pse->phase(),
+ pse->isInverted(), pse->synthSource());
+ wheel.setTimestamp(pse->timestamp());
+ wheel.accept();
+ QCoreApplication::sendEvent(item, &wheel);
+ if (wheel.isAccepted()) {
+ qCDebug(lcWheelTarget) << &wheel << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
}
+#endif
+#if QT_CONFIG(gestures)
+ if (QQuickPointerNativeGestureEvent *pnge = event->asPointerNativeGestureEvent()) {
+ QNativeGestureEvent nge(pnge->type(), pnge->device()->qTouchDevice(), point->position(), point->scenePosition(), g,
+ pnge->value(), 0L, 0L); // TODO can't copy things I can't access
+ nge.accept();
+ QCoreApplication::sendEvent(item, &nge);
+ if (nge.isAccepted()) {
+ qCDebug(lcGestureTarget) << &nge << "->" << item;
+ event->setAccepted(true);
+ return true;
+ }
+ }
+#endif // gestures
}
- return false;
+ return false; // it wasn't handled
}
+#if QT_CONFIG(wheelevent)
/*! \reimp */
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
@@ -1937,55 +1960,11 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
return;
event->ignore();
- d->deliverWheelEvent(d->contentItem, event);
+ d->deliverPointerEvent(d->pointerEventInstance(event));
d->lastWheelEventAccepted = event->isAccepted();
}
#endif // wheelevent
-#if QT_CONFIG(gestures)
-bool QQuickWindowPrivate::deliverNativeGestureEvent(QQuickItem *item, QNativeGestureEvent *event)
-{
- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
-
- QPointF p = item->mapFromScene(event->windowPos());
- if ((itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) && !item->contains(p))
- return false;
-
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverNativeGestureEvent(child, event))
- return true;
- }
-
- // Try the Item's pointer handlers first
- QQuickPointerEvent *pointerEvent = pointerEventInstance(event);
- pointerEvent->localize(item);
- if (itemPrivate->handlePointerEvent(pointerEvent, false)) {
- if (pointerEvent->allPointsAccepted()) {
- event->accept();
- return true;
- }
- }
-
- // If still not accepted, try direct delivery to the item
- if (item->contains(p)) {
- QNativeGestureEvent copy(event->gestureType(), event->device(), p, event->windowPos(), event->screenPos(),
- event->value(), 0L, 0L); // TODO can't copy things I can't access
- event->accept();
- item->event(&copy);
- if (copy.isAccepted()) {
- event->accept();
- return true;
- }
- }
-
- return false;
-}
-#endif // gestures
-
bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event)
{
qCDebug(DBG_TOUCH) << event;
@@ -2229,6 +2208,8 @@ QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(QQuickPointer
if (eventType == QEvent::NativeGesture && !qobject_cast<QQuickPointerNativeGestureEvent*>(e))
continue;
#endif
+ if (eventType == QEvent::Wheel && !qobject_cast<QQuickPointerScrollEvent*>(e))
+ continue;
// Otherwise we assume there's only one event type per device.
// More disambiguation tests might need to be added above if that changes later.
if (e->device() == device)
@@ -2248,7 +2229,10 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic
// QWindowSystemInterface::handleMouseEvent() does not take a device parameter:
// we assume all mouse events come from one mouse (the "core pointer").
// So when the event is a mouse event, device == QQuickPointerDevice::genericMouseDevice()
- ev = new QQuickPointerMouseEvent(q, device);
+ if (eventType == QEvent::Wheel)
+ ev = new QQuickPointerScrollEvent(q, device);
+ else
+ ev = new QQuickPointerMouseEvent(q, device);
break;
case QQuickPointerDevice::TouchPad:
case QQuickPointerDevice::TouchScreen:
@@ -2282,6 +2266,7 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) con
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
+ case QEvent::Wheel:
dev = QQuickPointerDevice::genericMouseDevice();
break;
case QEvent::TouchBegin:
@@ -2324,7 +2309,7 @@ void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event)
} else if (event->asPointerTouchEvent()) {
deliverTouchEvent(event->asPointerTouchEvent());
} else {
- Q_ASSERT(false);
+ deliverSinglePointEventUntilAccepted(event);
}
event->reset(nullptr);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index b5e3a2c1eb..eb2f4d20fa 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -152,12 +152,7 @@ public:
bool sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
bool sendFilteredPointerEvent(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent = nullptr);
bool sendFilteredPointerEventImpl(QQuickPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent);
-#if QT_CONFIG(wheelevent)
- bool deliverWheelEvent(QQuickItem *, QWheelEvent *);
-#endif
-#if QT_CONFIG(gestures)
- bool deliverNativeGestureEvent(QQuickItem *, QNativeGestureEvent *);
-#endif
+ bool deliverSinglePointEventUntilAccepted(QQuickPointerEvent *);
// entry point of events to the window
void handleTouchEvent(QTouchEvent *);
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
index d715d900ba..2e5fdbbe6b 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -77,6 +77,11 @@ QSGSoftwareRenderableNode *QSGAbstractSoftwareRenderer::renderableNode(QSGNode *
return m_nodes.value(node, nullptr);
}
+const QLinkedList<QSGSoftwareRenderableNode*> &QSGAbstractSoftwareRenderer::renderableNodes() const
+{
+ return m_renderableNodes;
+}
+
void QSGAbstractSoftwareRenderer::addNodeMapping(QSGNode *node, QSGSoftwareRenderableNode *renderableNode)
{
m_nodes.insert(node, renderableNode);
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
index f6594d931a..99204ef25e 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
@@ -88,6 +88,7 @@ protected:
QRect backgroundRect();
// only known after calling optimizeRenderList()
bool isOpaque() const { return m_isOpaque; }
+ const QLinkedList<QSGSoftwareRenderableNode*> &renderableNodes() const;
private:
void nodeAdded(QSGNode *node);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
index bf3141bc32..2c361e03e2 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode.cpp
@@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode()
: m_penWidth(0)
, m_radius(0)
+ , m_vertical(true)
, m_cornerPixmapIsDirty(true)
, m_devicePixelRatio(1)
{
@@ -186,6 +187,15 @@ void QSGSoftwareInternalRectangleNode::setGradientStops(const QGradientStops &st
markDirty(DirtyMaterial);
}
+void QSGSoftwareInternalRectangleNode::setGradientVertical(bool vertical)
+{
+ if (m_vertical != vertical) {
+ m_vertical = vertical;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
void QSGSoftwareInternalRectangleNode::setRadius(qreal radius)
{
if (m_radius != radius) {
@@ -209,7 +219,7 @@ void QSGSoftwareInternalRectangleNode::update()
}
if (!m_stops.isEmpty()) {
- QLinearGradient gradient(QPoint(0,0), QPoint(0,1));
+ QLinearGradient gradient(QPoint(0,0), QPoint(m_vertical ? 0 : 1, m_vertical ? 1 : 0));
gradient.setStops(m_stops);
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
m_brush = QBrush(gradient);
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
index 1f87424d2a..125520de26 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalrectanglenode_p.h
@@ -69,6 +69,7 @@ public:
void setPenColor(const QColor &color) override;
void setPenWidth(qreal width) override;
void setGradientStops(const QGradientStops &stops) override;
+ void setGradientVertical(bool vertical) override;
void setRadius(qreal radius) override;
void setAntialiasing(bool antialiasing) override { Q_UNUSED(antialiasing) }
void setAligned(bool aligned) override;
@@ -91,6 +92,7 @@ private:
double m_radius;
QPen m_pen;
QBrush m_brush;
+ bool m_vertical;
bool m_cornerPixmapIsDirty;
QPixmap m_cornerPixmap;
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
index 8fc87db179..b20d0a1828 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
@@ -72,7 +72,7 @@ class QSGSoftwareNinePatchNode;
class QSGSoftwareSpriteNode;
class QSGRenderNode;
-class QSGSoftwareRenderableNode
+class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderableNode
{
public:
enum NodeType {
@@ -104,6 +104,7 @@ public:
bool isOpaque() const { return m_isOpaque; }
bool isDirty() const { return m_isDirty; }
bool isDirtyRegionEmpty() const;
+ QSGNode *handle() const { return m_handle.node; }
void setTransform(const QTransform &transform);
void setClipRegion(const QRegion &clipRegion, bool hasClipRegion = true);
@@ -123,6 +124,7 @@ public:
private:
union RenderableNodeHandle {
+ QSGNode *node;
QSGSimpleRectNode *simpleRectNode;
QSGSimpleTextureNode *simpleTextureNode;
QSGSoftwareInternalImageNode *imageNode;
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 9c88b8272c..c23163a6b3 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -136,6 +136,7 @@ public:
virtual void setPenColor(const QColor &color) = 0;
virtual void setPenWidth(qreal width) = 0;
virtual void setGradientStops(const QGradientStops &stops) = 0;
+ virtual void setGradientVertical(bool vertical) = 0;
virtual void setRadius(qreal radius) = 0;
virtual void setAntialiasing(bool antialiasing) { Q_UNUSED(antialiasing) }
virtual void setAligned(bool aligned) = 0;
diff --git a/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
index df124cce35..91317ee2d7 100644
--- a/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp
@@ -68,19 +68,30 @@ namespace
{
float x, y;
Color4ub color;
- void set(float nx, float ny, Color4ub ncolor)
+
+ void set(float primary, float secondary, Color4ub ncolor, bool vertical)
{
- x = nx; y = ny; color = ncolor;
+ if (vertical) {
+ x = secondary; y = primary;
+ } else {
+ x = primary; y = secondary;
+ }
+ color = ncolor;
}
};
struct SmoothVertex : public Vertex
{
float dx, dy;
- void set(float nx, float ny, Color4ub ncolor, float ndx, float ndy)
+
+ void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
{
- Vertex::set(nx, ny, ncolor);
- dx = ndx; dy = ndy;
+ Vertex::set(primary, secondary, ncolor, vertical);
+ if (vertical) {
+ dx = dSecondary; dy = dPrimary;
+ } else {
+ dx = dPrimary; dy = dSecondary;
+ }
}
};
@@ -103,6 +114,7 @@ QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
, m_antialiasing(false)
, m_gradient_is_opaque(true)
, m_dirty_geometry(false)
+ , m_gradient_is_vertical(true)
, m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
{
setGeometry(&m_geometry);
@@ -160,6 +172,15 @@ void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops
m_dirty_geometry = true;
}
+void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
+{
+ if (vertical == m_gradient_is_vertical)
+ return;
+ m_gradient_is_vertical = vertical;
+ m_dirty_geometry = true;
+}
+
+
void QSGBasicInternalRectangleNode::setRadius(qreal radius)
{
if (radius == m_radius)
@@ -230,12 +251,15 @@ void QSGBasicInternalRectangleNode::updateGeometry()
Color4ub transparent = { 0, 0, 0, 0 };
const QGradientStops &stops = m_gradient_stops;
+ float length = (m_gradient_is_vertical ? height : width);
+ float secondaryLength = (m_gradient_is_vertical ? width : height);
+
int nextGradientStop = 0;
- float gradientPos = penWidth / height;
+ float gradientPos = penWidth / length;
while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
++nextGradientStop;
int lastGradientStop = stops.size() - 1;
- float lastGradientPos = 1.0f - penWidth / height;
+ float lastGradientPos = 1.0f - penWidth / length;
while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
--lastGradientStop;
int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
@@ -319,40 +343,46 @@ void QSGBasicInternalRectangleNode::updateGeometry()
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
- float py = 0; // previous inner y-coordinate.
- float plx = 0; // previous inner left x-coordinate.
- float prx = 0; // previous inner right x-coordinate.
+ float pp = 0; // previous inner primary coordinate.
+ float pss = 0; // previous inner secondary start coordinate.
+ float pse = 0; // previous inner secondary end coordinate.
float angle = 0.5f * float(M_PI) / segments;
float cosStep = qFastCos(angle);
float sinStep = qFastSin(angle);
+ float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
+ float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
+ float innerLength = (m_gradient_is_vertical ? innerRect.height() : innerRect.width());
+ float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
+ float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
+
for (int part = 0; part < 2; ++part) {
float c = 1 - part;
float s = part;
for (int i = 0; i <= segments; ++i) {
- float y, lx, rx;
+ float p, ss, se;
if (innerRadius > 0) {
- y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
- lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / height;
+ p = (part ? innerEnd : innerStart) - innerRadius * c; // current inner primary coordinate.
+ ss = innerSecondaryStart - innerRadius * s; // current inner secondary start coordinate.
+ se = innerSecondaryEnd + innerRadius * s; // current inner secondary end coordinate.
+ gradientPos = ((part ? innerLength : 0) + radius - innerRadius * c) / length;
} else {
- y = (part ? innerRect.bottom() + innerRadius : innerRect.top() - innerRadius); // current inner y-coordinate.
- lx = innerRect.left() - innerRadius; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() + innerRadius : -innerRadius) + radius) / height;
+ p = (part ? innerEnd + innerRadius : innerStart - innerRadius); // current inner primary coordinate.
+ ss = innerSecondaryStart - innerRadius; // current inner secondary start coordinate.
+ se = innerSecondaryEnd + innerRadius; // current inner secondary end coordinate.
+ gradientPos = ((part ? innerLength + innerRadius : -innerRadius) + radius) / length;
}
- float Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
- float lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
- float rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+ float outerEdge = (part ? innerEnd : innerStart) - outerRadius * c; // current outer primary coordinate.
+ float outerSecondaryStart = innerSecondaryStart - outerRadius * s; // current outer secondary start coordinate.
+ float outerSecondaryEnd = innerSecondaryEnd + outerRadius * s; // current outer secondary end coordinate.
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
- float gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * height;
- float t = (gy - py) / (y - py);
- float glx = plx * (1 - t) + t * lx;
- float grx = prx * (1 - t) + t * rx;
+ float gp = (innerStart - radius) + stops.at(nextGradientStop).first * length;
+ float t = (gp - pp) / (p - pp);
+ float gis = pss * (1 - t) + t * ss; // gradient inner start
+ float gie = pse * (1 - t) + t * se; // gradient inner end
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
@@ -377,23 +407,23 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(grx, gy, fillColor, width - grx - delta, dy);
- smoothVertices[index++].set(glx, gy, fillColor, delta - glx, dy);
+ float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
+ smoothVertices[index++].set(gp, gie, fillColor, dp, secondaryLength - gie - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, fillColor, dp, delta - gis, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(grx, gy, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(glx, gy, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
+ smoothVertices[index++].set(gp, gie, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
} else {
- dy = lower ? delta : -delta;
- smoothVertices[index++].set(grx, gy, transparent, delta, dy);
- smoothVertices[index++].set(glx, gy, transparent, -delta, dy);
+ dp = lower ? delta : -delta;
+ smoothVertices[index++].set(gp, gie, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, gis, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(grx, gy, fillColor);
- vertices[index++].set(glx, gy, fillColor);
+ vertices[index++].set(gp, gie, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, gis, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(grx, gy, borderColor);
- vertices[index++].set(glx, gy, borderColor);
+ vertices[index++].set(gp, gie, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, gis, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
@@ -430,41 +460,41 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
- float dy = part ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+ float dp = part ? qMin(0.0f, length - p - delta) : qMax(0.0f, delta - p);
+ smoothVertices[index++].set(p, se, fillColor, dp, secondaryLength - se - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, fillColor, dp, delta - ss, m_gradient_is_vertical);
- dy = part ? delta : -delta;
+ dp = part ? delta : -delta;
if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, transparent, delta, dy);
- smoothVertices[index++].set(lX, Y, transparent, -delta, dy);
+ smoothVertices[index++].set(p, se, borderColor, -0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, borderColor, -0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, 0.49f * penWidth * c, -0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, 0.49f * penWidth * c, 0.49f * penWidth * s, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, dp, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
- smoothVertices[index++].set(rx, y, transparent, delta, dy);
- smoothVertices[index++].set(lx, y, transparent, -delta, dy);
+ smoothVertices[index++].set(p, se, transparent, dp, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(p, ss, transparent, dp, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
+ vertices[index++].set(p, se, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(p, ss, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
+ vertices[index++].set(p, se, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(p, ss, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
- py = y;
- plx = lx;
- prx = rx;
+ pp = p;
+ pss = ss;
+ pse = se;
// Rotate
qreal tmp = c;
@@ -543,19 +573,24 @@ void QSGBasicInternalRectangleNode::updateGeometry()
quint16 *indices = g->indexDataAsUShort();
quint16 index = 0;
- float lx = innerRect.left();
- float rx = innerRect.right();
- float lX = outerRect.left();
- float rX = outerRect.right();
+ float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
+ float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
+ float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
+ float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
+
+ float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
+ float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
+ float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
+ float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
for (int part = -1; part <= 1; part += 2) {
- float y = (part == 1 ? innerRect.bottom() : innerRect.top());
- float Y = (part == 1 ? outerRect.bottom() : outerRect.top());
- gradientPos = (y - innerRect.top() + penWidth) / height;
+ float innerEdge = (part == 1 ? innerEnd : innerStart);
+ float outerEdge = (part == 1 ? outerEnd : outerStart);
+ gradientPos = (innerEdge - innerStart + penWidth) / length;
while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
// Insert vertices at gradient stops.
- float gy = (innerRect.top() - penWidth) + stops.at(nextGradientStop).first * height;
+ float gp = (innerStart - penWidth) + stops.at(nextGradientStop).first * length;
fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
@@ -580,22 +615,22 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 3;
bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(rx, gy, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, gy, fillColor, delta - lx, dy);
+ float dp = lower ? qMin(0.0f, length - gp - delta) : qMax(0.0f, delta - gp);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(rx, gy, borderColor, 0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
- smoothVertices[index++].set(lx, gy, borderColor, -0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, borderColor, (lower ? 0.49f : -0.49f) * penWidth, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, borderColor, (lower ? 0.49f : -0.49f) * penWidth, -0.49f * penWidth, m_gradient_is_vertical);
} else {
- smoothVertices[index++].set(rx, gy, transparent, delta, lower ? delta : -delta);
- smoothVertices[index++].set(lx, gy, transparent, -delta, lower ? delta : -delta);
+ smoothVertices[index++].set(gp, innerSecondaryEnd, transparent, lower ? delta : -delta, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(gp, innerSecondaryStart, transparent, lower ? delta : -delta, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, gy, fillColor);
- vertices[index++].set(lx, gy, fillColor);
+ vertices[index++].set(gp, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, gy, borderColor);
- vertices[index++].set(lx, gy, borderColor);
+ vertices[index++].set(gp, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(gp, innerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
++nextGradientStop;
@@ -632,34 +667,34 @@ void QSGBasicInternalRectangleNode::updateGeometry()
indices[innerAATail++] = index + 1;
indices[innerAATail++] = index + 3;
- float dy = part == 1 ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+ float dp = part == 1 ? qMin(0.0f, length - innerEdge - delta) : qMax(0.0f, delta - innerEdge);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, transparent, delta, delta * part);
- smoothVertices[index++].set(lX, Y, transparent, -delta, delta * part);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, 0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, borderColor, 0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, -0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, -0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
indices[--outerAAHead] = index - 2;
indices[--outerAAHead] = index - 4;
indices[outerAATail++] = index - 3;
indices[outerAATail++] = index - 1;
} else {
- smoothVertices[index++].set(rx, y, transparent, delta, delta * part);
- smoothVertices[index++].set(lx, y, transparent, -delta, delta * part);
+ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
+ smoothVertices[index++].set(innerEdge, innerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
}
} else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
+ vertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
+ vertices[index++].set(innerEdge, innerSecondaryStart, fillColor, m_gradient_is_vertical);
if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
+ vertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(innerEdge, innerSecondaryStart, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
+ vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
}
}
}
diff --git a/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
index 98e53669ce..99f26b9aed 100644
--- a/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgbasicinternalrectanglenode_p.h
@@ -66,6 +66,7 @@ public:
void setPenColor(const QColor &color) override;
void setPenWidth(qreal width) override;
void setGradientStops(const QGradientStops &stops) override;
+ void setGradientVertical(bool vertical) override;
void setRadius(qreal radius) override;
void setAntialiasing(bool antialiasing) override;
void setAligned(bool aligned) override;
@@ -90,6 +91,7 @@ protected:
uint m_antialiasing : 1;
uint m_gradient_is_opaque : 1;
uint m_dirty_geometry : 1;
+ uint m_gradient_is_vertical : 1;
QSGGeometry m_geometry;
};
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 9ee1a323e5..02be9daac0 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -234,6 +234,27 @@ QQmlProperty QQuickAbstractAnimationPrivate::createProperty(QObject *obj, const
The corresponding handler is \c onStopped.
*/
+/*!
+ \qmlsignal QtQuick::Animation::finished()
+ \since 5.12
+
+ This signal is emitted when the animation has finished naturally.
+
+ It is not emitted when \l running is set to \c false, nor for animations whose
+ \l loops property is set to \c Animation.Infinite.
+
+ In addition, it is only emitted for top-level, standalone animations. It
+ will not be emitted for animations in a Behavior or Transition, or
+ animations that are part of an animation group.
+
+ If \l alwaysRunToEnd is true, this signal will not be emitted until the
+ animation has completed its current iteration.
+
+ The corresponding handler is \c onFinished.
+
+ \sa stopped(), started(), running
+*/
+
void QQuickAbstractAnimation::setRunning(bool r)
{
Q_D(QQuickAbstractAnimation);
@@ -656,6 +677,7 @@ void QQuickAbstractAnimationPrivate::animationFinished(QAbstractAnimationJob*)
if (loopCount != 1)
animationInstance->setLoopCount(loopCount);
}
+ emit q->finished();
}
QQuickAbstractAnimation::ThreadingModel QQuickAbstractAnimation::threadingModel() const
diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h
index 2293f2597f..746cb938bd 100644
--- a/src/quick/util/qquickanimation_p.h
+++ b/src/quick/util/qquickanimation_p.h
@@ -126,6 +126,7 @@ Q_SIGNALS:
void pausedChanged(bool);
void alwaysRunToEndChanged(bool);
void loopCountChanged(int);
+ Q_REVISION(12) void finished();
public Q_SLOTS:
void restart();
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index f7c8724318..5d7664433b 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -39,8 +39,10 @@
#include "qquickimageprovider.h"
+#include "qquickimageprovider_p.h"
#include "qquickpixmapcache_p.h"
#include <QtQuick/private/qsgcontext_p.h>
+#include <private/qqmlglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -160,7 +162,10 @@ QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage
Constructs the image response
*/
QQuickImageResponse::QQuickImageResponse()
+ : QObject(*(new QQuickImageResponsePrivate))
{
+ qmlobject_connect(this, QQuickImageResponse, SIGNAL(finished()),
+ this, QQuickImageResponse, SLOT(_q_finished()));
}
/*!
diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h
index 4f8193789a..82d0501697 100644
--- a/src/quick/util/qquickimageprovider.h
+++ b/src/quick/util/qquickimageprovider.h
@@ -69,6 +69,8 @@ public:
static QQuickTextureFactory *textureFactoryForImage(const QImage &image);
};
+class QQuickImageResponsePrivate;
+
class Q_QUICK_EXPORT QQuickImageResponse : public QObject
{
Q_OBJECT
@@ -84,6 +86,10 @@ public Q_SLOTS:
Q_SIGNALS:
void finished();
+
+private:
+ Q_DECLARE_PRIVATE(QQuickImageResponse)
+ Q_PRIVATE_SLOT(d_func(), void _q_finished())
};
class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
diff --git a/src/quick/util/qquickimageprovider_p.h b/src/quick/util/qquickimageprovider_p.h
new file mode 100644
index 0000000000..b5baf79319
--- /dev/null
+++ b/src/quick/util/qquickimageprovider_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKQQUICKIMAGEPROVIDER_P_H
+#define QQUICKQQUICKIMAGEPROVIDER_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/qtquickglobal_p.h>
+#include <private/qobject_p.h>
+#include <qquickimageprovider.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickImageResponsePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickImageResponse)
+public:
+ bool finished = false;
+
+ void _q_finished() { finished = true; }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QQUICKQQUICKIMAGEPROVIDER_P_H
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 4237ec3edf..0dd2a88ca1 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -39,6 +39,7 @@
#include "qquickpixmapcache_p.h"
#include <qquickimageprovider.h>
+#include "qquickimageprovider_p.h"
#include <qqmlengine.h>
#include <private/qqmlglobal_p.h>
@@ -179,6 +180,8 @@ public:
QQuickPixmapReaderThreadObject(QQuickPixmapReader *);
void processJobs();
bool event(QEvent *e) override;
+public slots:
+ void asyncResponseFinished(QQuickImageResponse *response);
private slots:
void networkRequestDone();
void asyncResponseFinished();
@@ -613,10 +616,15 @@ void QQuickPixmapReaderThreadObject::networkRequestDone()
#endif
}
+void QQuickPixmapReaderThreadObject::asyncResponseFinished(QQuickImageResponse *response)
+{
+ reader->asyncResponseFinished(response);
+}
+
void QQuickPixmapReaderThreadObject::asyncResponseFinished()
{
QQuickImageResponse *response = static_cast<QQuickImageResponse *>(sender());
- reader->asyncResponseFinished(response);
+ asyncResponseFinished(response);
}
void QQuickPixmapReader::processJobs()
@@ -800,7 +808,14 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize);
}
- QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished()));
+ // Might be that the async provider was so quick it emitted the signal before we
+ // could connect to it.
+ if (static_cast<QQuickImageResponsePrivate*>(QObjectPrivate::get(response))->finished) {
+ QMetaObject::invokeMethod(threadObject, "asyncResponseFinished",
+ Qt::QueuedConnection, Q_ARG(QQuickImageResponse*, response));
+ } else {
+ QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished()));
+ }
asyncResponses.insert(response, runningJob);
break;
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index bd9f04e562..decc6eac31 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -116,9 +116,8 @@ void QQuickProfiler::stopProfilingImpl()
m_data.clear();
}
-void QQuickProfiler::reportDataImpl(bool trackLocations)
+void QQuickProfiler::reportDataImpl()
{
- Q_UNUSED(trackLocations);
QMutexLocker lock(&m_dataMutex);
emit dataReady(m_data);
m_data.clear();
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index d699ddf371..28b058c2e8 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -357,7 +357,7 @@ protected:
void startProfilingImpl(quint64 features);
void stopProfilingImpl();
- void reportDataImpl(bool trackLocations);
+ void reportDataImpl();
void setTimer(const QElapsedTimer &t);
};
diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp
index b953ad1c7f..3ca6440784 100644
--- a/src/quick/util/qquickstate.cpp
+++ b/src/quick/util/qquickstate.cpp
@@ -222,7 +222,7 @@ bool QQuickState::isWhenKnown() const
QQmlBinding *QQuickState::when() const
{
Q_D(const QQuickState);
- return d->when;
+ return d->when.data();
}
void QQuickState::setWhen(QQmlBinding *when)
diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h
index f1bc24c558..61472b4d06 100644
--- a/src/quick/util/qquickstate_p_p.h
+++ b/src/quick/util/qquickstate_p_p.h
@@ -203,12 +203,12 @@ class QQuickStatePrivate : public QObjectPrivate
public:
QQuickStatePrivate()
- : when(nullptr), named(false), inState(false), group(nullptr) {}
+ : named(false), inState(false), group(nullptr) {}
typedef QList<QQuickSimpleAction> SimpleActionList;
QString name;
- QQmlBinding *when;
+ QQmlBinding::Ptr when;
bool named;
struct OperationGuard : public QQmlGuard<QQuickStateOperation>
diff --git a/src/quick/util/qquicksvgparser.cpp b/src/quick/util/qquicksvgparser.cpp
index 2bf9c121d3..0687913565 100644
--- a/src/quick/util/qquicksvgparser.cpp
+++ b/src/quick/util/qquicksvgparser.cpp
@@ -280,11 +280,8 @@ bool QQuickSvgParser::parsePathDataFast(const QString &dataStr, QPainterPath &pa
++str;
QChar pathElem = *str;
++str;
- QChar endc = *end;
- *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
QVarLengthArray<qreal, 8> arg;
parseNumbersArray(str, arg);
- *const_cast<QChar *>(end) = endc;
if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
arg.append(0);//dummy
const qreal *num = arg.constData();
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index b2e5b84cf4..31d4d4c437 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -132,4 +132,7 @@ void QQuickUtilModule::defineModule()
qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
#endif
+
+ qmlRegisterUncreatableType<QQuickAbstractAnimation, 12>("QtQuick", 2, 12, "Animation",
+ QQuickAbstractAnimation::tr("Animation is an abstract class"));
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index edcb268cd9..c51f082d03 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -53,6 +53,7 @@ HEADERS += \
$$PWD/qquickfontloader_p.h \
$$PWD/qquickstyledtext_p.h \
$$PWD/qquickimageprovider.h \
+ $$PWD/qquickimageprovider_p.h \
$$PWD/qquicksvgparser_p.h \
$$PWD/qquickvaluetypes_p.h \
$$PWD/qquickanimator_p.h \
diff --git a/src/imports/shapes/qquicknvprfunctions.cpp b/src/quickshapes/qquicknvprfunctions.cpp
index 409a59be7f..409a59be7f 100644
--- a/src/imports/shapes/qquicknvprfunctions.cpp
+++ b/src/quickshapes/qquicknvprfunctions.cpp
diff --git a/src/imports/shapes/qquicknvprfunctions_p.h b/src/quickshapes/qquicknvprfunctions_p.h
index 342e92cbc3..92246cf4c8 100644
--- a/src/imports/shapes/qquicknvprfunctions_p.h
+++ b/src/quickshapes/qquicknvprfunctions_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
#include <qopengl.h>
#include <QtGui/qsurfaceformat.h>
diff --git a/src/imports/shapes/qquicknvprfunctions_p_p.h b/src/quickshapes/qquicknvprfunctions_p_p.h
index 6df20566af..3d9ca0de9f 100644
--- a/src/imports/shapes/qquicknvprfunctions_p_p.h
+++ b/src/quickshapes/qquicknvprfunctions_p_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "qquicknvprfunctions_p.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuickShapes/private/qquicknvprfunctions_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/imports/shapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 067a54736f..edfa308c4d 100644
--- a/src/imports/shapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -658,9 +658,22 @@ void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
}
}
+struct QQuickShapeResourceInitializer
+{
+ QQuickShapeResourceInitializer()
+ {
+#if defined(QT_STATIC)
+ Q_INIT_RESOURCE(qtquickshapes);
+#endif
+ }
+};
+
+Q_GLOBAL_STATIC(QQuickShapeResourceInitializer, initQQuickShapeResources)
+
QQuickShape::QQuickShape(QQuickItem *parent)
: QQuickItem(*(new QQuickShapePrivate), parent)
{
+ initQQuickShapeResources();
setFlag(ItemHasContents);
}
diff --git a/src/imports/shapes/qquickshape_p.h b/src/quickshapes/qquickshape_p.h
index 1dfeaf9228..cd242cafc3 100644
--- a/src/imports/shapes/qquickshape_p.h
+++ b/src/quickshapes/qquickshape_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "qquickitem.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuick/qquickitem.h>
#include <private/qtquickglobal_p.h>
#include <private/qquickpath_p_p.h>
@@ -62,7 +63,7 @@ QT_BEGIN_NAMESPACE
class QQuickShapePathPrivate;
class QQuickShapePrivate;
-class QQuickShapeGradient : public QQuickGradient
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeGradient : public QQuickGradient
{
Q_OBJECT
Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged)
@@ -88,7 +89,7 @@ private:
SpreadMode m_spread;
};
-class QQuickShapeLinearGradient : public QQuickShapeGradient
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeLinearGradient : public QQuickShapeGradient
{
Q_OBJECT
Q_PROPERTY(qreal x1 READ x1 WRITE setX1 NOTIFY x1Changed)
@@ -120,7 +121,7 @@ private:
QPointF m_end;
};
-class QQuickShapeRadialGradient : public QQuickShapeGradient
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeRadialGradient : public QQuickShapeGradient
{
Q_OBJECT
Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged)
@@ -167,7 +168,7 @@ private:
qreal m_focalRadius = 0;
};
-class QQuickShapeConicalGradient : public QQuickShapeGradient
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeConicalGradient : public QQuickShapeGradient
{
Q_OBJECT
Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged)
@@ -197,7 +198,7 @@ private:
qreal m_angle = 0;
};
-class QQuickShapePath : public QQuickPath
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePath : public QQuickPath
{
Q_OBJECT
@@ -296,7 +297,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged())
};
-class QQuickShape : public QQuickItem
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShape : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(RendererType rendererType READ rendererType NOTIFY rendererChanged)
diff --git a/src/imports/shapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h
index ef2775885e..bf4a47f62c 100644
--- a/src/imports/shapes/qquickshape_p_p.h
+++ b/src/quickshapes/qquickshape_p_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "qquickshape_p.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuickShapes/private/qquickshape_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QPainterPath>
#include <QColor>
@@ -122,7 +123,7 @@ struct QQuickShapeStrokeFillParams
QQuickShapeGradient *fillGradient;
};
-class QQuickShapePathPrivate : public QQuickPathPrivate
+class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePathPrivate : public QQuickPathPrivate
{
Q_DECLARE_PUBLIC(QQuickShapePath)
diff --git a/src/imports/shapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index 8a4785a83a..8a4785a83a 100644
--- a/src/imports/shapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
diff --git a/src/imports/shapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h
index 11070ae7dc..9928d7ab72 100644
--- a/src/imports/shapes/qquickshapegenericrenderer_p.h
+++ b/src/quickshapes/qquickshapegenericrenderer_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "qquickshape_p_p.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuickShapes/private/qquickshape_p_p.h>
#include <qsgnode.h>
#include <qsggeometry.h>
#include <qsgmaterial.h>
diff --git a/src/imports/shapes/qquickshapenvprrenderer.cpp b/src/quickshapes/qquickshapenvprrenderer.cpp
index 51af0d8961..51af0d8961 100644
--- a/src/imports/shapes/qquickshapenvprrenderer.cpp
+++ b/src/quickshapes/qquickshapenvprrenderer.cpp
diff --git a/src/imports/shapes/qquickshapenvprrenderer_p.h b/src/quickshapes/qquickshapenvprrenderer_p.h
index f6c9fc169e..d40eb1bce9 100644
--- a/src/imports/shapes/qquickshapenvprrenderer_p.h
+++ b/src/quickshapes/qquickshapenvprrenderer_p.h
@@ -51,8 +51,9 @@
// We mean it.
//
-#include "qquickshape_p_p.h"
-#include "qquicknvprfunctions_p.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuickShapes/private/qquickshape_p_p.h>
+#include <QtQuickShapes/private/qquicknvprfunctions_p.h>
#include <qsgrendernode.h>
#include <QColor>
#include <QVector4D>
diff --git a/src/quickshapes/qquickshapesglobal.h b/src/quickshapes/qquickshapesglobal.h
new file mode 100644
index 0000000000..eb279c5d14
--- /dev/null
+++ b/src/quickshapes/qquickshapesglobal.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQUICKSHAPESGLOBAL_H
+#define QQUICKSHAPESGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKSHAPES_LIB)
+# define Q_QUICKSHAPES_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKSHAPES_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKSHAPES_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSHAPESGLOBAL_H
+
diff --git a/src/quickshapes/qquickshapesglobal_p.h b/src/quickshapes/qquickshapesglobal_p.h
new file mode 100644
index 0000000000..2f559b45a0
--- /dev/null
+++ b/src/quickshapes/qquickshapesglobal_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSHAPESGLOBAL_P_H
+#define QQUICKSHAPESGLOBAL_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 "qquickshapesglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+#define Q_QUICKSHAPES_PRIVATE_EXPORT Q_QUICKSHAPES_EXPORT
+
+QT_END_NAMESPACE
+
+
+#endif // QQUICKSHAPESGLOBAL_P_H
diff --git a/src/imports/shapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index 0f5c3604b5..0f5c3604b5 100644
--- a/src/imports/shapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
diff --git a/src/imports/shapes/qquickshapesoftwarerenderer_p.h b/src/quickshapes/qquickshapesoftwarerenderer_p.h
index 0abc2e37b0..11e658b4b7 100644
--- a/src/imports/shapes/qquickshapesoftwarerenderer_p.h
+++ b/src/quickshapes/qquickshapesoftwarerenderer_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "qquickshape_p_p.h"
+#include <QtQuickShapes/private/qquickshapesglobal_p.h>
+#include <QtQuickShapes/private/qquickshape_p_p.h>
#include <qsgrendernode.h>
#include <QPen>
#include <QBrush>
diff --git a/src/imports/shapes/qtquickshapesplugin.qrc b/src/quickshapes/qtquickshapes.qrc
index f139861693..f139861693 100644
--- a/src/imports/shapes/qtquickshapesplugin.qrc
+++ b/src/quickshapes/qtquickshapes.qrc
diff --git a/src/quickshapes/quickshapes.pro b/src/quickshapes/quickshapes.pro
new file mode 100644
index 0000000000..5a59dec18e
--- /dev/null
+++ b/src/quickshapes/quickshapes.pro
@@ -0,0 +1,33 @@
+TARGET = QtQuickShapes
+
+QT = core gui-private qml quick-private
+
+CONFIG += simd optimize_full internal_module
+
+HEADERS += \
+ qquickshapesglobal.h \
+ qquickshapesglobal_p.h \
+ qquickshape_p.h \
+ qquickshape_p_p.h \
+ qquickshapegenericrenderer_p.h \
+ qquickshapesoftwarerenderer_p.h
+
+SOURCES += \
+ qquickshape.cpp \
+ qquickshapegenericrenderer.cpp \
+ qquickshapesoftwarerenderer.cpp
+
+qtConfig(opengl) {
+ HEADERS += \
+ qquicknvprfunctions_p.h \
+ qquicknvprfunctions_p_p.h \
+ qquickshapenvprrenderer_p.h
+
+ SOURCES += \
+ qquicknvprfunctions.cpp \
+ qquickshapenvprrenderer.cpp
+}
+
+RESOURCES += qtquickshapes.qrc
+
+load(qt_module)
diff --git a/src/imports/shapes/shaders/blit.frag b/src/quickshapes/shaders/blit.frag
index 505f0db179..505f0db179 100644
--- a/src/imports/shapes/shaders/blit.frag
+++ b/src/quickshapes/shaders/blit.frag
diff --git a/src/imports/shapes/shaders/blit.vert b/src/quickshapes/shaders/blit.vert
index f8306bd945..f8306bd945 100644
--- a/src/imports/shapes/shaders/blit.vert
+++ b/src/quickshapes/shaders/blit.vert
diff --git a/src/imports/shapes/shaders/blit_core.frag b/src/quickshapes/shaders/blit_core.frag
index 7073808fba..7073808fba 100644
--- a/src/imports/shapes/shaders/blit_core.frag
+++ b/src/quickshapes/shaders/blit_core.frag
diff --git a/src/imports/shapes/shaders/blit_core.vert b/src/quickshapes/shaders/blit_core.vert
index 5246441da3..5246441da3 100644
--- a/src/imports/shapes/shaders/blit_core.vert
+++ b/src/quickshapes/shaders/blit_core.vert
diff --git a/src/imports/shapes/shaders/conicalgradient.frag b/src/quickshapes/shaders/conicalgradient.frag
index af5fdd5ee0..af5fdd5ee0 100644
--- a/src/imports/shapes/shaders/conicalgradient.frag
+++ b/src/quickshapes/shaders/conicalgradient.frag
diff --git a/src/imports/shapes/shaders/conicalgradient.vert b/src/quickshapes/shaders/conicalgradient.vert
index 3350b0675a..3350b0675a 100644
--- a/src/imports/shapes/shaders/conicalgradient.vert
+++ b/src/quickshapes/shaders/conicalgradient.vert
diff --git a/src/imports/shapes/shaders/conicalgradient_core.frag b/src/quickshapes/shaders/conicalgradient_core.frag
index e18b80159a..e18b80159a 100644
--- a/src/imports/shapes/shaders/conicalgradient_core.frag
+++ b/src/quickshapes/shaders/conicalgradient_core.frag
diff --git a/src/imports/shapes/shaders/conicalgradient_core.vert b/src/quickshapes/shaders/conicalgradient_core.vert
index f94a56401b..f94a56401b 100644
--- a/src/imports/shapes/shaders/conicalgradient_core.vert
+++ b/src/quickshapes/shaders/conicalgradient_core.vert
diff --git a/src/imports/shapes/shaders/lineargradient.frag b/src/quickshapes/shaders/lineargradient.frag
index 7f4a739109..7f4a739109 100644
--- a/src/imports/shapes/shaders/lineargradient.frag
+++ b/src/quickshapes/shaders/lineargradient.frag
diff --git a/src/imports/shapes/shaders/lineargradient.vert b/src/quickshapes/shaders/lineargradient.vert
index eb21b8886b..eb21b8886b 100644
--- a/src/imports/shapes/shaders/lineargradient.vert
+++ b/src/quickshapes/shaders/lineargradient.vert
diff --git a/src/imports/shapes/shaders/lineargradient_core.frag b/src/quickshapes/shaders/lineargradient_core.frag
index 5908acfa67..5908acfa67 100644
--- a/src/imports/shapes/shaders/lineargradient_core.frag
+++ b/src/quickshapes/shaders/lineargradient_core.frag
diff --git a/src/imports/shapes/shaders/lineargradient_core.vert b/src/quickshapes/shaders/lineargradient_core.vert
index 60b56f38e3..60b56f38e3 100644
--- a/src/imports/shapes/shaders/lineargradient_core.vert
+++ b/src/quickshapes/shaders/lineargradient_core.vert
diff --git a/src/imports/shapes/shaders/radialgradient.frag b/src/quickshapes/shaders/radialgradient.frag
index 0f503bc0f7..0f503bc0f7 100644
--- a/src/imports/shapes/shaders/radialgradient.frag
+++ b/src/quickshapes/shaders/radialgradient.frag
diff --git a/src/imports/shapes/shaders/radialgradient.vert b/src/quickshapes/shaders/radialgradient.vert
index 3350b0675a..3350b0675a 100644
--- a/src/imports/shapes/shaders/radialgradient.vert
+++ b/src/quickshapes/shaders/radialgradient.vert
diff --git a/src/imports/shapes/shaders/radialgradient_core.frag b/src/quickshapes/shaders/radialgradient_core.frag
index 706ce53e4d..706ce53e4d 100644
--- a/src/imports/shapes/shaders/radialgradient_core.frag
+++ b/src/quickshapes/shaders/radialgradient_core.frag
diff --git a/src/imports/shapes/shaders/radialgradient_core.vert b/src/quickshapes/shaders/radialgradient_core.vert
index f94a56401b..f94a56401b 100644
--- a/src/imports/shapes/shaders/radialgradient_core.vert
+++ b/src/quickshapes/shaders/radialgradient_core.vert
diff --git a/src/src.pro b/src/src.pro
index 5177dfc743..92d79a9825 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -2,15 +2,18 @@ TEMPLATE = subdirs
CONFIG += ordered
include($$OUT_PWD/qml/qtqml-config.pri)
include($$OUT_PWD/quick/qtquick-config.pri)
-QT_FOR_CONFIG += qml quick-private
+QT_FOR_CONFIG += qml qml-private quick-private
SUBDIRS += \
qml
-qtHaveModule(gui):qtConfig(animation) {
+qtConfig(qml-animation) {
SUBDIRS += \
- quick
+ quick \
+ quickshapes
+
+ qtConfig(testlib): \
+ SUBDIRS += qmltest
- qtConfig(testlib): SUBDIRS += qmltest
qtConfig(quick-particles): \
SUBDIRS += particles
qtHaveModule(widgets): SUBDIRS += quickwidgets
@@ -18,8 +21,9 @@ qtHaveModule(gui):qtConfig(animation) {
SUBDIRS += \
plugins \
- imports \
- qmldevtools
+ imports
+
+qtConfig(qml-devtools): SUBDIRS += qmldevtools
qmldevtools.depends = qml
@@ -27,3 +31,5 @@ qtConfig(qml-network) {
QT_FOR_CONFIG += network
qtConfig(localserver):qtConfig(qml-debug): SUBDIRS += qmldebug
}
+
+DISTFILES += sync.profile configure.json
diff --git a/sync.profile b/sync.profile
index 64abbd2eb9..642942d152 100644
--- a/sync.profile
+++ b/sync.profile
@@ -1,9 +1,13 @@
%modules = ( # path to module name map
"QtQml" => "$basedir/src/qml",
"QtQuick" => "$basedir/src/quick",
+ "QtQuickShapes" => "$basedir/src/quickshapes",
"QtQuickWidgets" => "$basedir/src/quickwidgets",
"QtQuickParticles" => "$basedir/src/particles",
"QtQuickTest" => "$basedir/src/qmltest",
"QtPacketProtocol" => "$basedir/src/plugins/qmltooling/packetprotocol",
"QtQmlDebug" => "$basedir/src/qmldebug",
);
+%inject_headers = (
+ "$basedir/src/qml" => [ "^qqmljsgrammar_p.h", "^qqmljsparser_p.h" ],
+);
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index f851688b5e..d2cfd3897a 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -89,21 +89,12 @@ public:
protected:
//inherited from QQmlDebugClient
- void stateChanged(State state);
void messageReceived(const QByteArray &data);
signals:
- void enabled();
void debugOutput();
};
-void QQmlDebugMsgClient::stateChanged(State state)
-{
- if (state == Enabled) {
- emit enabled();
- }
-}
-
void QQmlDebugMsgClient::messageReceived(const QByteArray &data)
{
QPacket ds(connection()->currentDataStreamVersion(), data);
diff --git a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
index 452520cf11..ffdbf72ded 100644
--- a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
+++ b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
@@ -66,8 +66,6 @@ void tst_QQmlDebugClient::initTestCase()
QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer"));
QQmlDebugConnector::setServices(QStringList()
<< QStringLiteral("tst_QQmlDebugClient::handshake()"));
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugClient::handshake()");
diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
index 52e7f85e52..37118f4bd0 100644
--- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
+++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp
@@ -125,7 +125,7 @@ void tst_QQmlDebuggingEnabler::qmlscene()
QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
}
- QCOMPARE(m_process->state(), QLatin1String("running"));
+ QCOMPARE(m_process->state(), QProcess::Running);
if (!blockMode) {
QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(
QLatin1String("Component.onCompleted")), 15000);
@@ -172,7 +172,7 @@ void tst_QQmlDebuggingEnabler::custom()
QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
}
- QCOMPARE(m_process->state(), QLatin1String("running"));
+ QCOMPARE(m_process->state(), QProcess::Running);
if (!blockMode) {
QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(QLatin1String("QQmlEngine created")),
15000);
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
index 660afce216..b36e576320 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -254,6 +254,8 @@ public:
{
parser = jsEngine.evaluate(QLatin1String("JSON.parse"));
stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
+ QObject::connect(this, &QQmlDebugClient::stateChanged,
+ this, &QJSDebugClient::onStateChanged);
}
void connect(bool redundantRefs = false, bool namesAsObjects = false);
@@ -275,7 +277,7 @@ public:
protected:
//inherited from QQmlDebugClient
- void stateChanged(State state);
+ void onStateChanged(State state);
void messageReceived(const QByteArray &data);
signals:
@@ -663,7 +665,7 @@ void QJSDebugClient::disconnect()
sendMessage(packMessage(DISCONNECT, json.toString().toUtf8()));
}
-void QJSDebugClient::stateChanged(State state)
+void QJSDebugClient::onStateChanged(State state)
{
if (state == Enabled)
flushSendBuffer();
diff --git a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
index 5b3c0c5240..4e47c92c2a 100644
--- a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
+++ b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp
@@ -65,8 +65,6 @@ void tst_QQmlDebugLocal::initTestCase()
{
fileName = QString::fromLatin1("tst_QQmlDebugLocal%1").arg(std::time(nullptr));
QQmlDebugConnector::setPluginKey("QQmlDebugServer");
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugLocal::handshake()");
const QString waitingMsg = QString("QML Debugger: Connecting to socket %1...").arg(fileName);
diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp
index 993a1d5f63..35bd912d9b 100644
--- a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp
+++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp
@@ -118,7 +118,7 @@ void tst_QQmlDebugProcess::sessionStart()
QTimer::singleShot(delay, process.data(), wait);
QTRY_VERIFY(done);
- QVERIFY(process->state().startsWith("not running"));
+ QCOMPARE(process->state(), QProcess::NotRunning);
}
QTEST_MAIN(tst_QQmlDebugProcess)
diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
index 1daf6b581e..3557940386 100644
--- a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
@@ -75,8 +75,6 @@ void tst_QQmlDebugService::initTestCase()
QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer"));
QQmlDebugConnector::setServices(QStringList()
<< QStringLiteral("tst_QQmlDebugService"));
- QTest::ignoreMessage(QtWarningMsg,
- "QML debugger: Cannot set plugin key after loading the plugin.");
m_service = new QQmlDebugTestService("tst_QQmlDebugService", 2);
foreach (const QString &service, QQmlDebuggingEnabler::debuggerServices())
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 3cb315b355..323048f7d8 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -261,11 +261,13 @@ void tst_QQmlProfilerService::checkProcessTerminated()
QVERIFY(m_client->client);
QTRY_COMPARE(m_client->client->state(), QQmlDebugClient::NotConnected);
QVERIFY(m_process);
+ QVERIFY(m_process->exitStatus() != QProcess::CrashExit);
QTRY_COMPARE(m_process->exitStatus(), QProcess::NormalExit);
}
void tst_QQmlProfilerService::checkTraceReceived()
{
+ QVERIFY(m_process->exitStatus() != QProcess::CrashExit);
QTRY_VERIFY2(m_isComplete, "No trace received in time.");
QVector<qint64> numbers;
@@ -282,6 +284,7 @@ void tst_QQmlProfilerService::checkTraceReceived()
void tst_QQmlProfilerService::checkJsHeap()
{
+ QVERIFY(m_client);
QVERIFY2(m_client->jsHeapMessages.count() > 0, "no JavaScript heap messages received");
bool seen_alloc = false;
@@ -340,6 +343,11 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty
int expectedPosition, const QQmlProfilerEventType &expected,
quint32 checks, const QVector<qint64> &expectedNumbers)
{
+ if (!m_client) {
+ qWarning() << "No debug client available";
+ return false;
+ }
+
const QVector<QQmlProfilerEvent> *target = nullptr;
switch (type) {
case MessageListQML: target = &(m_client->qmlMessages); break;
@@ -349,6 +357,11 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty
case MessageListPixmap: target = &(m_client->pixmapMessages); break;
}
+ if (!target) {
+ qWarning() << "Invalid MessageListType" << type;
+ return false;
+ }
+
if (target->length() <= expectedPosition) {
qWarning() << "Not enough events. expected position:" << expectedPosition
<< "length:" << target->length();
@@ -629,7 +642,7 @@ void tst_QQmlProfilerService::scenegraphData()
void tst_QQmlProfilerService::profileOnExit()
{
- connect(true, "exit.qml");
+ QCOMPARE(connect(true, "exit.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
@@ -711,7 +724,7 @@ void tst_QQmlProfilerService::flushInterval()
void tst_QQmlProfilerService::translationBinding()
{
- connect(true, "qstr.qml");
+ QCOMPARE(connect(true, "qstr.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
@@ -727,12 +740,13 @@ void tst_QQmlProfilerService::translationBinding()
void tst_QQmlProfilerService::memory()
{
- connect(true, "memory.qml");
+ QCOMPARE(connect(true, "memory.qml"), ConnectSuccess);
checkProcessTerminated();
checkTraceReceived();
checkJsHeap();
+ QVERIFY(m_client);
int smallItems = 0;
for (auto message : m_client->jsHeapMessages) {
const QQmlProfilerEventType &type = m_client->types[message.typeIndex()];
@@ -757,6 +771,8 @@ void tst_QQmlProfilerService::compile()
// Flush interval so that we actually get the events before we stop recording.
connect(true, "test.qml", true, 100);
+ QVERIFY(m_client);
+
// We need to check specifically for compile events as we can otherwise stop recording after the
// StartTrace has arrived, but before it compiles anything.
QTRY_VERIFY(hasCompileEvents(m_client->types));
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index c65c592f10..a176f674e6 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -86,8 +86,7 @@ public:
QV4::Scope scope(v4);
QV4::ScopedString name(scope, v4->newString(functionName));
- QV4::ScopedContext ctx(scope, v4->rootContext());
- QV4::ScopedValue function(scope, FunctionObject::createBuiltinFunction(ctx, name, injectedFunction));
+ QV4::ScopedValue function(scope, FunctionObject::createBuiltinFunction(v4, name, injectedFunction, 0));
v4->globalObject->put(name, function);
}
@@ -220,7 +219,21 @@ public:
{
for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
m_capturedScope.append(NamedRefs());
- ScopeJob job(&collector, i, 0);
+ FrameJob frameJob(&collector, i);
+ debugger->runInEngine(&frameJob);
+ QJsonObject frameObj = frameJob.returnValue();
+ QJsonArray scopes = frameObj.value(QLatin1String("scopes")).toArray();
+ int nscopes = scopes.size();
+ int s = 0;
+ for (s = 0; s < nscopes; ++s) {
+ QJsonObject o = scopes.at(s).toObject();
+ if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext
+ break;
+ }
+ if (s == nscopes)
+ return;
+
+ ScopeJob job(&collector, i, s);
debugger->runInEngine(&job);
NamedRefs &refs = m_capturedScope.last();
QJsonObject object = job.returnValue();
@@ -482,7 +495,7 @@ void tst_qv4debugger::conditionalBreakPoint()
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 2);
+ QCOMPARE(frame0.size(), 3);
QVERIFY(frame0.contains("i"));
QCOMPARE(frame0.value("i").toInt(), 11);
}
@@ -541,7 +554,7 @@ void tst_qv4debugger::readArguments()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 4);
+ QCOMPARE(frame0.size(), 5);
QVERIFY(frame0.contains(QStringLiteral("a")));
QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number"));
QCOMPARE(frame0.value(QStringLiteral("a")).toDouble(), 1.0);
@@ -565,7 +578,7 @@ void tst_qv4debugger::readComplicatedArguments()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 1);
+ QCOMPARE(frame0.size(), 2);
QVERIFY(frame0.contains(QStringLiteral("a")));
QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number"));
QCOMPARE(frame0.value(QStringLiteral("a")).toInt(), 12);
@@ -589,7 +602,7 @@ void tst_qv4debugger::readLocals()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 4); // locals and parameters
+ QCOMPARE(frame0.size(), 5); // locals and parameters
QVERIFY(frame0.contains("c"));
QCOMPARE(frame0.type("c"), QStringLiteral("number"));
QCOMPARE(frame0.value("c").toDouble(), 3.0);
@@ -614,7 +627,7 @@ void tst_qv4debugger::readObject()
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
- QCOMPARE(frame0.size(), 2);
+ QCOMPARE(frame0.size(), 3);
QVERIFY(frame0.contains("b"));
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
QJsonObject b = frame0.rawValue("b");
@@ -679,7 +692,7 @@ void tst_qv4debugger::readContextInAllFrames()
for (int i = 0; i < 12; ++i) {
const TestAgent::NamedRefs &scope = m_debuggerAgent->m_capturedScope.at(i);
- QCOMPARE(scope.size(), 2);
+ QCOMPARE(scope.size(), 3);
QVERIFY(scope.contains("n"));
QCOMPARE(scope.type("n"), QStringLiteral("number"));
QCOMPARE(scope.value("n").toDouble(), i + 1.0);
diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp
index b118b22c64..602e533388 100644
--- a/tests/auto/qml/debugger/shared/debugutil.cpp
+++ b/tests/auto/qml/debugger/shared/debugutil.cpp
@@ -98,6 +98,9 @@ QString QQmlDebugTest::connectionStateString(const QQmlDebugConnection *connecti
QQmlDebugTestClient::QQmlDebugTestClient(const QString &s, QQmlDebugConnection *c)
: QQmlDebugClient(s, c)
{
+ connect(this, &QQmlDebugClient::stateChanged, this, [this](QQmlDebugClient::State newState) {
+ QCOMPARE(newState, state());
+ });
}
QByteArray QQmlDebugTestClient::waitForResponse()
@@ -111,31 +114,12 @@ QByteArray QQmlDebugTestClient::waitForResponse()
return lastMsg;
}
-void QQmlDebugTestClient::stateChanged(State stat)
-{
- QCOMPARE(stat, state());
- emit stateHasChanged();
-}
-
void QQmlDebugTestClient::messageReceived(const QByteArray &ba)
{
lastMsg = ba;
emit serverMessage(ba);
}
-template<typename F>
-struct Finalizer {
- F m_lambda;
- Finalizer(F &&lambda) : m_lambda(std::forward<F>(lambda)) {}
- ~Finalizer() { m_lambda(); }
-};
-
-template<typename F>
-static Finalizer<F> defer(F &&lambda)
-{
- return Finalizer<F>(std::forward<F>(lambda));
-}
-
QQmlDebugTest::ConnectResult QQmlDebugTest::connect(
const QString &executable, const QString &services, const QString &extraArgs,
bool block)
@@ -162,31 +146,27 @@ QQmlDebugTest::ConnectResult QQmlDebugTest::connect(
if (m_clients.contains(nullptr))
return ClientsFailed;
- auto allEnabled = [this]() {
- for (QQmlDebugClient *client : m_clients) {
- if (client->state() != QQmlDebugClient::Enabled)
- return false;
- }
- return true;
- };
+ ClientStateHandler stateHandler(m_clients, createOtherClients(m_connection), services.isEmpty()
+ ? QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable);
- QList<QQmlDebugClient *> others = createOtherClients(m_connection);
- auto deleter = defer([&others]() { qDeleteAll(others); });
- Q_UNUSED(deleter);
const int port = m_process->debugPort();
m_connection->connectToHost(QLatin1String("127.0.0.1"), port);
- for (int tries = 0; tries < 100 && !allEnabled(); ++tries)
- QTest::qWait(50);
- if (!allEnabled())
+
+ QEventLoop loop;
+ QTimer timer;
+ QObject::connect(&stateHandler, &ClientStateHandler::allOk, &loop, &QEventLoop::quit);
+ QObject::connect(m_connection, &QQmlDebugConnection::disconnected, &loop, &QEventLoop::quit);
+ QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+
+ timer.start(5000);
+ loop.exec();
+
+ if (!stateHandler.allEnabled())
return EnableFailed;
- const QQmlDebugClient::State expectedState = services.isEmpty() ? QQmlDebugClient::Enabled
- : QQmlDebugClient::Unavailable;
- for (QQmlDebugClient *other : others) {
- if (other->state() != expectedState)
- return RestrictFailed;
- }
+ if (!stateHandler.othersAsExpected())
+ return RestrictFailed;
return ConnectSuccess;
}
@@ -211,7 +191,7 @@ void QQmlDebugTest::cleanup()
if (QTest::currentTestFailed()) {
const QString null = QStringLiteral("null");
- qDebug() << "Process State:" << (m_process ? m_process->state() : null);
+ qDebug() << "Process State:" << (m_process ? m_process->stateString() : null);
qDebug() << "Application Output:" << (m_process ? m_process->output() : null);
qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection);
for (QQmlDebugClient *client : m_clients) {
@@ -234,3 +214,41 @@ void QQmlDebugTest::cleanup()
m_process = nullptr;
}
}
+
+ClientStateHandler::ClientStateHandler(const QList<QQmlDebugClient *> &clients,
+ const QList<QQmlDebugClient *> &others,
+ QQmlDebugClient::State expectedOthers) :
+ m_clients(clients), m_others(others), m_expectedOthers(expectedOthers)
+{
+ for (QQmlDebugClient *client : m_clients) {
+ QObject::connect(client, &QQmlDebugClient::stateChanged,
+ this, &ClientStateHandler::checkStates);
+ }
+ for (QQmlDebugClient *client : m_others) {
+ QObject::connect(client, &QQmlDebugClient::stateChanged,
+ this, &ClientStateHandler::checkStates);
+ }
+}
+
+ClientStateHandler::~ClientStateHandler()
+{
+ qDeleteAll(m_others);
+}
+
+void ClientStateHandler::checkStates()
+{
+ for (QQmlDebugClient *client : m_clients) {
+ if (client->state() != QQmlDebugClient::Enabled)
+ return;
+ }
+
+ m_allEnabled = true;
+
+ for (QQmlDebugClient *other : m_others) {
+ if (other->state() != m_expectedOthers)
+ return;
+ }
+
+ m_othersAsExpected = true;
+ emit allOk();
+}
diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h
index 94ad83bfce..cc7c9bd19d 100644
--- a/tests/auto/qml/debugger/shared/debugutil_p.h
+++ b/tests/auto/qml/debugger/shared/debugutil_p.h
@@ -88,11 +88,9 @@ public:
QByteArray waitForResponse();
signals:
- void stateHasChanged();
void serverMessage(const QByteArray &);
protected:
- virtual void stateChanged(State state);
virtual void messageReceived(const QByteArray &ba);
private:
@@ -116,4 +114,31 @@ public:
}
};
+class ClientStateHandler : public QObject
+{
+ Q_OBJECT
+public:
+ ClientStateHandler(const QList<QQmlDebugClient *> &clients,
+ const QList<QQmlDebugClient *> &others,
+ QQmlDebugClient::State expectedOthers);
+
+ ~ClientStateHandler();
+
+ bool allEnabled() const { return m_allEnabled; }
+ bool othersAsExpected() const { return m_othersAsExpected; }
+
+signals:
+ void allOk();
+
+private:
+ void checkStates();
+
+ const QList<QQmlDebugClient *> m_clients;
+ const QList<QQmlDebugClient *> m_others;
+ const QQmlDebugClient::State m_expectedOthers;
+
+ bool m_allEnabled = false;
+ bool m_othersAsExpected = false;
+};
+
#endif // DEBUGUTIL_P_H
diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
index f2b85833c9..6f74edf863 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
@@ -50,6 +50,7 @@ QQmlDebugProcess::QQmlDebugProcess(const QString &executable, QObject *parent)
this, [this]() {
m_timer.stop();
m_eventLoop.quit();
+ emit finished();
});
connect(&m_timer, &QTimer::timeout,
this, &QQmlDebugProcess::timeout);
@@ -60,7 +61,7 @@ QQmlDebugProcess::~QQmlDebugProcess()
stop();
}
-QString QQmlDebugProcess::state()
+QString QQmlDebugProcess::stateString() const
{
QString stateStr;
switch (m_process.state()) {
@@ -155,6 +156,11 @@ bool QQmlDebugProcess::waitForFinished()
return m_process.waitForFinished();
}
+QProcess::ProcessState QQmlDebugProcess::state() const
+{
+ return m_process.state();
+}
+
QProcess::ExitStatus QQmlDebugProcess::exitStatus() const
{
return m_process.exitStatus();
diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h
index fd2c89bb41..945cc58c85 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h
+++ b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h
@@ -52,7 +52,7 @@ public:
QQmlDebugProcess(const QString &executable, QObject *parent = 0);
~QQmlDebugProcess();
- QString state();
+ QString stateString() const;
void addEnvironment(const QString &environment);
@@ -61,6 +61,7 @@ public:
int debugPort() const;
bool waitForFinished();
+ QProcess::ProcessState state() const;
QProcess::ExitStatus exitStatus() const;
QString output() const;
@@ -69,6 +70,7 @@ public:
signals:
void readyReadStandardOutput();
+ void finished();
private slots:
void timeout();
diff --git a/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp b/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
index 4dce07d824..896ed608fd 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugtestservice.cpp
@@ -48,5 +48,4 @@ void QQmlDebugTestService::stateAboutToBeChanged(QQmlDebugService::State)
void QQmlDebugTestService::stateChanged(State)
{
Q_ASSERT(QThread::currentThread() != thread());
- emit stateHasChanged();
}
diff --git a/tests/auto/qml/debugger/shared/qqmldebugtestservice.h b/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
index 37b4a9f98c..9c39c0893d 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
+++ b/tests/auto/qml/debugger/shared/qqmldebugtestservice.h
@@ -38,9 +38,6 @@ class QQmlDebugTestService : public QQmlDebugService
public:
QQmlDebugTestService(const QString &s, float version = 1, QObject *parent = 0);
-signals:
- void stateHasChanged();
-
protected:
virtual void messageReceived(const QByteArray &ba);
virtual void stateAboutToBeChanged(State state);
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 589f25d174..de7a072842 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -1,177 +1,4664 @@
-# wrong tests
-# uses octal number
-15.2.3.6-2-17-1 failing
+# ----- These are tests we will not fix
-# these fail after the update to Unicode 6.3.
-# the reason is that u+180e changed type from whitespace to control
-S9.3.1_A2
-S9.3.1_A3_T1
-S9.3.1_A3_T2
-S15.1.2.2_A2_T10
-S15.1.2.3_A2_T10
-15.5.4.20-3-2
-15.5.4.20-3-3
-15.5.4.20-3-4
-15.5.4.20-3-5
-15.5.4.20-3-6
+# The tests below rely on the ES6 spec quirk that allows 'let' as an identifier. We've
+# always treated 'let' as a reserved keyword (without ever getting a bug report about it),
+# so we'll keep it that way. It also removes a huge headache in the parser.
+language/statements/for-in/let-block-with-newline.js sloppyFails
+language/statements/for-of/let-block-with-newline.js sloppyFails
+language/statements/for/let-block-with-newline.js sloppyFails
+language/statements/if/let-block-with-newline.js sloppyFails
+language/statements/labeled/let-block-with-newline.js sloppyFails
+language/statements/while/let-block-with-newline.js sloppyFails
+language/statements/with/let-block-with-newline.js sloppyFails
+language/statements/for-in/let-identifier-with-newline.js sloppyFails
+language/statements/for-of/let-identifier-with-newline.js sloppyFails
+language/statements/for/let-identifier-with-newline.js sloppyFails
+language/statements/if/let-identifier-with-newline.js sloppyFails
+language/statements/labeled/let-identifier-with-newline.js sloppyFails
+language/statements/while/let-identifier-with-newline.js sloppyFails
+language/statements/with/let-identifier-with-newline.js sloppyFails
-11.2.3-3_3 failing
-S13_A15_T4 failing
-S15.4.4.3_A1_T1 failing
-S15.4.4.3_A3_T1 failing
-S15.5.4.11_A5_T1 failing
-S15.2.4.4_A14 failing
-# Function declarations in conditionals. We allow them, because the real
-# world requires them.
-Sbp_12.5_A9_T3 failing
-Sbp_12.6.1_A13_T3 failing
-Sbp_12.6.2_A13_T3 failing
-Sbp_12.6.4_A13_T3 failing
-
-# es6: function length attributes are configurable, wasn't in es5
-S15.1.2.2_A9.2 failing
-S15.1.3.1_A5.2 failing
-S15.1.3.2_A5.2 failing
-S15.1.3.3_A5.2 failing
-S15.1.2.3_A7.2 failing
-S15.1.2.4_A2.2 failing
-S15.1.2.5_A2.2 failing
-S15.1.3.4_A5.2 failing
-15.2.3.3-4-186 failing
-S15.2.4.2_A9 failing
-S15.2.4.3_A9 failing
-S15.2.4.4_A9 failing
-S15.2.4.5_A9 failing
-S15.2.4.6_A9 failing
-S15.2.4.7_A9 failing
-15.3.3.2-1 failing
-15.4.4.2_A4.2
-S15.3.4.2_A9 failing
-S15.3.4.3_A9 failing
-S15.3.4.4_A9 failing
-15.3.4.5-15-2 failing
-S15.4.4.2_A4.2 failing
-S15.4.4.3_A4.2 failing
-S15.4.4.4_A4.2 failing
-S15.4.4.5_A6.2 failing
-S15.4.4.6_A5.2 failing
-S15.4.4.7_A6.2 failing
-S15.4.4.8_A5.2 failing
-S15.4.4.9_A5.2 failing
-S15.4.4.10_A5.2 failing
-S15.4.4.11_A7.2 failing
-S15.4.4.12_A5.2 failing
-S15.4.4.13_A5.2 failing
-S15.5.4.10_A9 failing
-S15.5.4.11_A9 failing
-S15.5.4.12_A9 failing
-S15.5.4.13_A9 failing
-S15.5.4.14_A9 failing
-S15.5.4.15_A9 failing
-S15.5.4.16_A9 failing
-S15.5.4.17_A9 failing
-S15.5.4.18_A9 failing
-S15.5.4.19_A9 failing
-S15.5.4.4_A9 failing
-S15.5.4.5_A9 failing
-S15.5.4.6_A9 failing
-S15.5.4.7_A9 failing
-S15.5.4.8_A9 failing
-S15.5.4.9_A9 failing
-S15.9.4.2_A3_T2 failing
-S15.9.4.3_A3_T2 failing
-S15.9.5.2_A3_T2 failing
-S15.9.5.3_A3_T2 failing
-S15.9.5.4_A3_T2 failing
-S15.9.5.5_A3_T2 failing
-S15.9.5.1_A3_T2 failing
-S15.9.5.10_A3_T2 failing
-S15.9.5.11_A3_T2 failing
-S15.9.5.12_A3_T2 failing
-S15.9.5.13_A3_T2 failing
-S15.9.5.14_A3_T2 failing
-S15.9.5.15_A3_T2 failing
-S15.9.5.16_A3_T2 failing
-S15.9.5.17_A3_T2 failing
-S15.9.5.18_A3_T2 failing
-S15.9.5.19_A3_T2 failing
-S15.9.5.20_A3_T2 failing
-S15.9.5.21_A3_T2 failing
-S15.9.5.22_A3_T2 failing
-S15.9.5.23_A3_T2 failing
-S15.9.5.24_A3_T2 failing
-S15.9.5.25_A3_T2 failing
-S15.9.5.26_A3_T2 failing
-S15.9.5.27_A3_T2 failing
-S15.9.5.28_A3_T2 failing
-S15.9.5.29_A3_T2 failing
-S15.9.5.30_A3_T2 failing
-S15.9.5.31_A3_T2 failing
-S15.9.5.32_A3_T2 failing
-S15.9.5.33_A3_T2 failing
-S15.9.5.34_A3_T2 failing
-S15.9.5.35_A3_T2 failing
-S15.9.5.36_A3_T2 failing
-S15.9.5.37_A3_T2 failing
-S15.9.5.38_A3_T2 failing
-S15.9.5.39_A3_T2 failing
-S15.9.5.40_A3_T2 failing
-S15.9.5.41_A3_T2 failing
-S15.9.5.42_A3_T2 failing
-S15.9.5.6_A3_T2 failing
-S15.9.5.7_A3_T2 failing
-S15.9.5.8_A3_T2 failing
-S15.9.5.9_A3_T2 failing
-S15.10.6.2_A9 failing
-S15.10.6.3_A9 failing
-S15.10.6.4_A9 failing
-
-# es6: Object.freeze(v) on a non-object returns v, no longer TypeError
-15.2.3.9-1 failing
-15.2.3.9-1-1 failing
-15.2.3.9-1-2 failing
-15.2.3.9-1-3 failing
-15.2.3.9-1-4 failing
-# es6: Object.preventExtensions(O) on a non-object, no longer TypeError
-15.2.3.10-1 failing
-15.2.3.10-1-3 failing
-15.2.3.10-1-4 failing
-# es6: Object.isSealed(O) on a non-object, no longer TypeError
-15.2.3.11-1
-# es6: Object.isFrozen(O) on a non-object, no longer TypeError
-15.2.3.12-1
-15.2.3.12-1-3
-15.2.3.12-1-4
-# es6: Object.isExtensible(O) on a non-object, no longer TypeError
-15.2.3.13-1
-15.2.3.13-1-3
-15.2.3.13-1-4
-# es6: Object.keys(O) on a non-object, no longer TypeError
-15.2.3.14-1-1
-15.2.3.14-1-2
-15.2.3.14-1-3
-15.2.3.14-1
-15.2.3.14-2
-15.2.3.14-3
-# es6: Object.getOwnPropertyDescriptor(O) on a non-object, no longer TypeError
-15.2.3.3-1
-15.2.3.3-1-3
-15.2.3.3-1-4
-# es6: Object.getPrototypeOf(O) on a non-object, no longer TypeError
-15.2.3.2-1
-15.2.3.2-1-3
-15.2.3.2-1-4
-# es6: Object.getOwnPropertyNames(O) on a non-object, no longer TypeError
-15.2.3.4-1
-15.2.3.4-1-4
-15.2.3.4-1-5
-# es6: Object.seal(O) on a non-object, no longer TypeError
-15.2.3.8-1
-15.2.3.8-1-1
-15.2.3.8-1-2
-15.2.3.8-1-3
-15.2.3.8-1-4
-
-# es6: Date.prototype is no longer a DateObject
-15.9.5.40_1 failing
+# ----- test failures that should be fixed
+built-ins/Array/from/iter-cstm-ctor-err.js fails
+built-ins/Array/from/proto-from-ctor-realm.js fails
+built-ins/Array/isArray/proxy-revoked.js fails
+built-ins/Array/isArray/proxy.js fails
+built-ins/Array/length/define-own-prop-length-overflow-realm.js fails
+built-ins/Array/of/proto-from-ctor-realm.js fails
+built-ins/Array/proto-from-ctor-realm.js fails
+built-ins/Array/prototype/Symbol.unscopables/prop-desc.js fails
+built-ins/Array/prototype/Symbol.unscopables/value.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-length-to-string-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-length-value-of-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-negative-length.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-primitive-non-number-length.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-string-length.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like-to-length-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_array-like.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_holey-sloppy-arguments.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_large-typed-array.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_length-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_non-array.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments-with-dupes.js sloppyFails
+built-ins/Array/prototype/concat/Array.prototype.concat_sloppy-arguments.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_small-typed-array.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-boolean-wrapper.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-function.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-getter-throws.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-number-wrapper.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-reg-exp.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-sparse-object.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_spreadable-string-wrapper.js fails
+built-ins/Array/prototype/concat/Array.prototype.concat_strict-arguments.js fails
+built-ins/Array/prototype/concat/S15.4.4.4_A3_T2.js fails
+built-ins/Array/prototype/concat/S15.4.4.4_A3_T3.js fails
+built-ins/Array/prototype/concat/create-ctor-non-object.js fails
+built-ins/Array/prototype/concat/create-proto-from-ctor-realm-array.js fails
+built-ins/Array/prototype/concat/create-proto-from-ctor-realm-non-array.js fails
+built-ins/Array/prototype/concat/create-proxy.js fails
+built-ins/Array/prototype/concat/create-revoked-proxy.js fails
+built-ins/Array/prototype/concat/create-species-non-ctor.js fails
+built-ins/Array/prototype/concat/create-species.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-is-array-proxy-revoked.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-proxy-revoked.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-proxy.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-val-falsey.js fails
+built-ins/Array/prototype/concat/is-concat-spreadable-val-truthy.js fails
+built-ins/Array/prototype/copyWithin/return-abrupt-from-delete-proxy-target.js fails
+built-ins/Array/prototype/copyWithin/return-abrupt-from-has-start.js fails
+built-ins/Array/prototype/every/15.4.4.16-3-29.js fails
+built-ins/Array/prototype/filter/create-ctor-non-object.js fails
+built-ins/Array/prototype/filter/create-proto-from-ctor-realm-array.js fails
+built-ins/Array/prototype/filter/create-proto-from-ctor-realm-non-array.js fails
+built-ins/Array/prototype/filter/create-proxy.js fails
+built-ins/Array/prototype/filter/create-revoked-proxy.js fails
+built-ins/Array/prototype/filter/create-species-non-ctor.js fails
+built-ins/Array/prototype/filter/create-species.js fails
+built-ins/Array/prototype/includes/get-prop.js fails
+built-ins/Array/prototype/includes/length-boundaries.js fails
+built-ins/Array/prototype/indexOf/15.4.4.14-3-28.js fails
+built-ins/Array/prototype/indexOf/15.4.4.14-3-29.js fails
+built-ins/Array/prototype/join/S15.4.4.5_A4_T3.js fails
+built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-28.js fails
+built-ins/Array/prototype/map/create-ctor-non-object.js fails
+built-ins/Array/prototype/map/create-proto-from-ctor-realm-array.js fails
+built-ins/Array/prototype/map/create-proto-from-ctor-realm-non-array.js fails
+built-ins/Array/prototype/map/create-proxy.js fails
+built-ins/Array/prototype/map/create-revoked-proxy.js fails
+built-ins/Array/prototype/map/create-species-non-ctor.js fails
+built-ins/Array/prototype/map/create-species-undef-invalid-len.js fails
+built-ins/Array/prototype/map/create-species.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A2_T2.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A3_T1.js fails
+built-ins/Array/prototype/pop/S15.4.4.6_A3_T2.js fails
+built-ins/Array/prototype/pop/clamps-to-integer-limit.js fails
+built-ins/Array/prototype/pop/length-near-integer-limit.js fails
+built-ins/Array/prototype/push/S15.4.4.7_A2_T2.js fails
+built-ins/Array/prototype/push/S15.4.4.7_A3.js fails
+built-ins/Array/prototype/push/throws-if-integer-limit-exceeded.js fails
+built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js fails
+built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js fails
+built-ins/Array/prototype/slice/S15.4.4.10_A3_T1.js fails
+built-ins/Array/prototype/slice/S15.4.4.10_A3_T2.js fails
+built-ins/Array/prototype/slice/create-ctor-non-object.js fails
+built-ins/Array/prototype/slice/create-non-array-invalid-len.js fails
+built-ins/Array/prototype/slice/create-proto-from-ctor-realm-array.js fails
+built-ins/Array/prototype/slice/create-proto-from-ctor-realm-non-array.js fails
+built-ins/Array/prototype/slice/create-proxied-array-invalid-len.js fails
+built-ins/Array/prototype/slice/create-proxy.js fails
+built-ins/Array/prototype/slice/create-revoked-proxy.js fails
+built-ins/Array/prototype/slice/create-species-neg-zero.js fails
+built-ins/Array/prototype/slice/create-species-non-ctor.js fails
+built-ins/Array/prototype/slice/create-species.js fails
+built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js fails
+built-ins/Array/prototype/slice/length-exceeding-integer-limit.js fails
+built-ins/Array/prototype/some/15.4.4.17-3-28.js fails
+built-ins/Array/prototype/some/15.4.4.17-3-29.js fails
+built-ins/Array/prototype/sort/comparefn-nonfunction-call-throws.js fails
+built-ins/Array/prototype/splice/S15.4.4.12_A3_T1.js fails
+built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js fails
+built-ins/Array/prototype/splice/create-ctor-non-object.js fails
+built-ins/Array/prototype/splice/create-proto-from-ctor-realm-array.js fails
+built-ins/Array/prototype/splice/create-proto-from-ctor-realm-non-array.js fails
+built-ins/Array/prototype/splice/create-proxy.js fails
+built-ins/Array/prototype/splice/create-revoked-proxy.js fails
+built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js fails
+built-ins/Array/prototype/splice/create-species-neg-zero.js fails
+built-ins/Array/prototype/splice/create-species-non-ctor.js fails
+built-ins/Array/prototype/splice/create-species-undef-invalid-len.js fails
+built-ins/Array/prototype/splice/create-species.js fails
+built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js fails
+built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js fails
+built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js fails
+built-ins/Array/prototype/toLocaleString/S15.4.4.3_A1_T1.js fails
+built-ins/Array/prototype/toLocaleString/S15.4.4.3_A3_T1.js fails
+built-ins/Array/prototype/toLocaleString/primitive_this_value.js strictFails
+built-ins/Array/prototype/toLocaleString/primitive_this_value_getter.js strictFails
+built-ins/Array/prototype/unshift/clamps-to-integer-limit.js fails
+built-ins/Array/prototype/unshift/length-near-integer-limit.js fails
+built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js fails
+built-ins/ArrayBuffer/data-allocation-after-object-creation.js fails
+built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js fails
+built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js fails
+built-ins/ArrayBuffer/proto-from-ctor-realm.js fails
+built-ins/ArrayBuffer/prototype-from-newtarget.js fails
+built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js fails
+built-ins/ArrayBuffer/prototype/slice/end-default-if-absent.js fails
+built-ins/ArrayBuffer/prototype/slice/end-default-if-undefined.js fails
+built-ins/ArrayBuffer/prototype/slice/end-exceeds-length.js fails
+built-ins/ArrayBuffer/prototype/slice/negative-end.js fails
+built-ins/ArrayBuffer/prototype/slice/negative-start.js fails
+built-ins/ArrayBuffer/prototype/slice/nonconstructor.js fails
+built-ins/ArrayBuffer/prototype/slice/species-constructor-is-undefined.js fails
+built-ins/ArrayBuffer/prototype/slice/species-is-null.js fails
+built-ins/ArrayBuffer/prototype/slice/species-is-undefined.js fails
+built-ins/ArrayBuffer/prototype/slice/species-returns-larger-arraybuffer.js fails
+built-ins/ArrayBuffer/prototype/slice/species.js fails
+built-ins/ArrayBuffer/prototype/slice/start-default-if-absent.js fails
+built-ins/ArrayBuffer/prototype/slice/start-default-if-undefined.js fails
+built-ins/ArrayBuffer/prototype/slice/start-exceeds-end.js fails
+built-ins/ArrayBuffer/prototype/slice/start-exceeds-length.js fails
+built-ins/ArrayBuffer/prototype/slice/tointeger-conversion-end.js fails
+built-ins/ArrayBuffer/prototype/slice/tointeger-conversion-start.js fails
+built-ins/ArrayBuffer/undefined-newtarget-throws.js fails
+built-ins/ArrayIteratorPrototype/next/detach-typedarray-in-progress.js fails
+built-ins/AsyncFunction/AsyncFunction-construct.js fails
+built-ins/AsyncFunction/AsyncFunction-is-extensible.js fails
+built-ins/AsyncFunction/AsyncFunction-is-subclass.js fails
+built-ins/AsyncFunction/AsyncFunction-length.js fails
+built-ins/AsyncFunction/AsyncFunction-name.js fails
+built-ins/AsyncFunction/AsyncFunction-prototype.js fails
+built-ins/AsyncFunction/AsyncFunction.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-is-extensible.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-prototype.js fails
+built-ins/AsyncFunction/AsyncFunctionPrototype-to-string.js fails
+built-ins/AsyncFunction/instance-construct-throws.js fails
+built-ins/AsyncFunction/instance-has-name.js fails
+built-ins/AsyncFunction/instance-length.js fails
+built-ins/AsyncFunction/instance-prototype-property.js fails
+built-ins/AsyncGeneratorPrototype/next/name.js fails
+built-ins/AsyncGeneratorPrototype/return/name.js fails
+built-ins/AsyncGeneratorPrototype/throw/name.js fails
+built-ins/Atomics/Symbol.toStringTag.js fails
+built-ins/Atomics/add/descriptor.js fails
+built-ins/Atomics/add/length.js fails
+built-ins/Atomics/add/name.js fails
+built-ins/Atomics/add/nonshared-int-views.js fails
+built-ins/Atomics/add/shared-nonint-views.js fails
+built-ins/Atomics/and/descriptor.js fails
+built-ins/Atomics/and/length.js fails
+built-ins/Atomics/and/name.js fails
+built-ins/Atomics/and/nonshared-int-views.js fails
+built-ins/Atomics/and/shared-nonint-views.js fails
+built-ins/Atomics/compareExchange/descriptor.js fails
+built-ins/Atomics/compareExchange/length.js fails
+built-ins/Atomics/compareExchange/name.js fails
+built-ins/Atomics/compareExchange/nonshared-int-views.js fails
+built-ins/Atomics/compareExchange/shared-nonint-views.js fails
+built-ins/Atomics/exchange/descriptor.js fails
+built-ins/Atomics/exchange/length.js fails
+built-ins/Atomics/exchange/name.js fails
+built-ins/Atomics/exchange/nonshared-int-views.js fails
+built-ins/Atomics/exchange/shared-nonint-views.js fails
+built-ins/Atomics/isLockFree/corner-cases.js fails
+built-ins/Atomics/isLockFree/descriptor.js fails
+built-ins/Atomics/isLockFree/length.js fails
+built-ins/Atomics/isLockFree/name.js fails
+built-ins/Atomics/isLockFree/value.js fails
+built-ins/Atomics/load/descriptor.js fails
+built-ins/Atomics/load/length.js fails
+built-ins/Atomics/load/name.js fails
+built-ins/Atomics/load/nonshared-int-views.js fails
+built-ins/Atomics/load/shared-nonint-views.js fails
+built-ins/Atomics/or/descriptor.js fails
+built-ins/Atomics/or/length.js fails
+built-ins/Atomics/or/name.js fails
+built-ins/Atomics/or/nonshared-int-views.js fails
+built-ins/Atomics/or/shared-nonint-views.js fails
+built-ins/Atomics/prop-desc.js fails
+built-ins/Atomics/proto.js fails
+built-ins/Atomics/store/descriptor.js fails
+built-ins/Atomics/store/length.js fails
+built-ins/Atomics/store/name.js fails
+built-ins/Atomics/store/nonshared-int-views.js fails
+built-ins/Atomics/store/shared-nonint-views.js fails
+built-ins/Atomics/sub/descriptor.js fails
+built-ins/Atomics/sub/length.js fails
+built-ins/Atomics/sub/name.js fails
+built-ins/Atomics/sub/nonshared-int-views.js fails
+built-ins/Atomics/sub/shared-nonint-views.js fails
+built-ins/Atomics/wait/descriptor.js fails
+built-ins/Atomics/wait/did-timeout.js fails
+built-ins/Atomics/wait/good-views.js fails
+built-ins/Atomics/wait/length.js fails
+built-ins/Atomics/wait/name.js fails
+built-ins/Atomics/wait/nan-timeout.js fails
+built-ins/Atomics/wait/negative-timeout.js fails
+built-ins/Atomics/wait/no-spurious-wakeup.js fails
+built-ins/Atomics/wait/nonshared-int-views.js fails
+built-ins/Atomics/wait/shared-nonint-views.js fails
+built-ins/Atomics/wait/was-woken.js fails
+built-ins/Atomics/wake/counts.js fails
+built-ins/Atomics/wake/descriptor.js fails
+built-ins/Atomics/wake/length.js fails
+built-ins/Atomics/wake/name.js fails
+built-ins/Atomics/wake/nonshared-int-views.js fails
+built-ins/Atomics/wake/shared-nonint-views.js fails
+built-ins/Atomics/wake/wake-all-on-loc.js fails
+built-ins/Atomics/wake/wake-all.js fails
+built-ins/Atomics/wake/wake-in-order.js fails
+built-ins/Atomics/wake/wake-nan.js fails
+built-ins/Atomics/wake/wake-negative.js fails
+built-ins/Atomics/wake/wake-one.js fails
+built-ins/Atomics/wake/wake-two.js fails
+built-ins/Atomics/wake/wake-zero.js fails
+built-ins/Atomics/xor/descriptor.js fails
+built-ins/Atomics/xor/length.js fails
+built-ins/Atomics/xor/name.js fails
+built-ins/Atomics/xor/nonshared-int-views.js fails
+built-ins/Atomics/xor/shared-nonint-views.js fails
+built-ins/Boolean/proto-from-ctor-realm.js fails
+built-ins/DataView/custom-proto-access-throws.js fails
+built-ins/DataView/custom-proto-if-object-is-used.js fails
+built-ins/DataView/detached-buffer.js fails
+built-ins/DataView/length.js fails
+built-ins/DataView/newtarget-undefined-throws.js fails
+built-ins/DataView/proto-from-ctor-realm.js fails
+built-ins/DataView/prototype/buffer/detached-buffer.js fails
+built-ins/DataView/prototype/byteLength/detached-buffer.js fails
+built-ins/DataView/prototype/byteOffset/detached-buffer.js fails
+built-ins/DataView/prototype/getFloat32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getFloat32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getFloat32/detached-buffer.js fails
+built-ins/DataView/prototype/getFloat32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getFloat32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getFloat32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getFloat64/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getFloat64/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getFloat64/detached-buffer.js fails
+built-ins/DataView/prototype/getFloat64/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getFloat64/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getFloat64/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt16/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt16/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getInt16/detached-buffer.js fails
+built-ins/DataView/prototype/getInt16/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getInt16/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getInt16/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getInt32/detached-buffer.js fails
+built-ins/DataView/prototype/getInt32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getInt32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getInt32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt8/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getInt8/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getInt8/detached-buffer.js fails
+built-ins/DataView/prototype/getInt8/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getInt8/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getInt8/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint16/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint16/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getUint16/detached-buffer.js fails
+built-ins/DataView/prototype/getUint16/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getUint16/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getUint16/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getUint32/detached-buffer.js fails
+built-ins/DataView/prototype/getUint32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getUint32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getUint32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint8/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/getUint8/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/getUint8/detached-buffer.js fails
+built-ins/DataView/prototype/getUint8/index-is-out-of-range.js fails
+built-ins/DataView/prototype/getUint8/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/getUint8/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setFloat32/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setFloat32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setFloat32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setFloat32/detached-buffer.js fails
+built-ins/DataView/prototype/setFloat32/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setFloat32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setFloat32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setFloat32/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setFloat32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setFloat64/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setFloat64/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setFloat64/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setFloat64/detached-buffer.js fails
+built-ins/DataView/prototype/setFloat64/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setFloat64/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setFloat64/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setFloat64/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setFloat64/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt16/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setInt16/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt16/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setInt16/detached-buffer.js fails
+built-ins/DataView/prototype/setInt16/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setInt16/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setInt16/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setInt16/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setInt16/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt32/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setInt32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setInt32/detached-buffer.js fails
+built-ins/DataView/prototype/setInt32/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setInt32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setInt32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setInt32/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setInt32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt8/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setInt8/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setInt8/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setInt8/detached-buffer.js fails
+built-ins/DataView/prototype/setInt8/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setInt8/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setInt8/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setInt8/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setInt8/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint16/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setUint16/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint16/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setUint16/detached-buffer.js fails
+built-ins/DataView/prototype/setUint16/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setUint16/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setUint16/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setUint16/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setUint16/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint32/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setUint32/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint32/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setUint32/detached-buffer.js fails
+built-ins/DataView/prototype/setUint32/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setUint32/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setUint32/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setUint32/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setUint32/toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint8/detached-buffer-after-number-value.js fails
+built-ins/DataView/prototype/setUint8/detached-buffer-after-toindex-byteoffset.js fails
+built-ins/DataView/prototype/setUint8/detached-buffer-before-outofrange-byteoffset.js fails
+built-ins/DataView/prototype/setUint8/detached-buffer.js fails
+built-ins/DataView/prototype/setUint8/index-check-before-value-conversion.js fails
+built-ins/DataView/prototype/setUint8/index-is-out-of-range.js fails
+built-ins/DataView/prototype/setUint8/negative-byteoffset-throws.js fails
+built-ins/DataView/prototype/setUint8/range-check-after-value-conversion.js fails
+built-ins/DataView/prototype/setUint8/toindex-byteoffset.js fails
+built-ins/DataView/toindex-bytelength.js fails
+built-ins/DataView/toindex-byteoffset.js fails
+built-ins/Date/UTC/infinity-make-day.js fails
+built-ins/Date/UTC/nans.js fails
+built-ins/Date/UTC/no-arg.js fails
+built-ins/Date/UTC/non-integer-values.js fails
+built-ins/Date/UTC/return-value.js fails
+built-ins/Date/UTC/year-offset.js fails
+built-ins/Date/proto-from-ctor-realm-one.js fails
+built-ins/Date/proto-from-ctor-realm-two.js fails
+built-ins/Date/proto-from-ctor-realm-zero.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-invalid.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-non-callable.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-valid.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-invalid.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-non-callable.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-valid.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-invalid.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-non-callable.js fails
+built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-valid.js fails
+built-ins/Date/prototype/toDateString/format.js fails
+built-ins/Date/prototype/toDateString/invalid-date.js fails
+built-ins/Date/prototype/toString/format.js fails
+built-ins/Date/prototype/toTimeString/format.js fails
+built-ins/Date/prototype/toTimeString/invalid-date.js fails
+built-ins/Date/prototype/toUTCString/day-names.js fails
+built-ins/Date/prototype/toUTCString/format.js fails
+built-ins/Date/prototype/toUTCString/month-names.js fails
+built-ins/Date/subclassing.js fails
+built-ins/Error/proto-from-ctor-realm.js fails
+built-ins/Error/prototype/S15.11.4_A2.js fails
+built-ins/Function/call-bind-this-realm-undef.js fails
+built-ins/Function/call-bind-this-realm-value.js fails
+built-ins/Function/internals/Call/class-ctor-realm.js fails
+built-ins/Function/internals/Call/class-ctor.js fails
+built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js fails
+built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails
+built-ins/Function/internals/Construct/derived-return-val-realm.js fails
+built-ins/Function/internals/Construct/derived-return-val.js fails
+built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js fails
+built-ins/Function/internals/Construct/derived-this-uninitialized.js fails
+built-ins/Function/proto-from-ctor-realm.js fails
+built-ins/Function/prototype/Symbol.hasInstance/this-val-not-callable.js fails
+built-ins/Function/prototype/Symbol.hasInstance/this-val-poisoned-prototype.js fails
+built-ins/Function/prototype/Symbol.hasInstance/value-get-prototype-of-err.js fails
+built-ins/Function/prototype/Symbol.hasInstance/value-non-obj.js fails
+built-ins/Function/prototype/bind/BoundFunction_restricted-properties.js fails
+built-ins/Function/prototype/bind/get-fn-realm.js fails
+built-ins/Function/prototype/bind/instance-construct-newtarget-boundtarget-bound.js fails
+built-ins/Function/prototype/bind/instance-construct-newtarget-boundtarget.js fails
+built-ins/Function/prototype/bind/instance-construct-newtarget-self-new.js fails
+built-ins/Function/prototype/bind/instance-construct-newtarget-self-reflect.js fails
+built-ins/Function/prototype/bind/instance-name-chained.js fails
+built-ins/Function/prototype/bind/instance-name-non-string.js fails
+built-ins/Function/prototype/bind/instance-name.js fails
+built-ins/Function/prototype/bind/proto-from-ctor-realm.js fails
+built-ins/Function/prototype/toString/AsyncFunction.js fails
+built-ins/Function/prototype/toString/Function.js fails
+built-ins/Function/prototype/toString/GeneratorFunction.js fails
+built-ins/Function/prototype/toString/anonymous-intrinsics.js fails
+built-ins/Function/prototype/toString/arrow-function.js fails
+built-ins/Function/prototype/toString/async-arrow-function.js fails
+built-ins/Function/prototype/toString/async-function-declaration.js fails
+built-ins/Function/prototype/toString/async-function-expression.js fails
+built-ins/Function/prototype/toString/async-method-class-expression-static.js fails
+built-ins/Function/prototype/toString/async-method-class-expression.js fails
+built-ins/Function/prototype/toString/async-method-class-statement-static.js fails
+built-ins/Function/prototype/toString/async-method-class-statement.js fails
+built-ins/Function/prototype/toString/async-method-object.js fails
+built-ins/Function/prototype/toString/bound-function.js fails
+built-ins/Function/prototype/toString/class-declaration-complex-heritage.js fails
+built-ins/Function/prototype/toString/class-declaration-explicit-ctor.js fails
+built-ins/Function/prototype/toString/class-declaration-implicit-ctor.js fails
+built-ins/Function/prototype/toString/class-expression-explicit-ctor.js fails
+built-ins/Function/prototype/toString/class-expression-implicit-ctor.js fails
+built-ins/Function/prototype/toString/function-declaration-non-simple-parameter-list.js fails
+built-ins/Function/prototype/toString/function-declaration.js fails
+built-ins/Function/prototype/toString/function-expression.js fails
+built-ins/Function/prototype/toString/generator-function-declaration.js fails
+built-ins/Function/prototype/toString/generator-function-expression.js fails
+built-ins/Function/prototype/toString/generator-method.js fails
+built-ins/Function/prototype/toString/getter-class-expression-static.js fails
+built-ins/Function/prototype/toString/getter-class-expression.js fails
+built-ins/Function/prototype/toString/getter-class-statement-static.js fails
+built-ins/Function/prototype/toString/getter-class-statement.js fails
+built-ins/Function/prototype/toString/getter-object.js fails
+built-ins/Function/prototype/toString/intrinsics.js fails
+built-ins/Function/prototype/toString/line-terminator-normalisation-CR-LF.js fails
+built-ins/Function/prototype/toString/line-terminator-normalisation-CR.js fails
+built-ins/Function/prototype/toString/line-terminator-normalisation-LF.js fails
+built-ins/Function/prototype/toString/method-class-expression-static.js fails
+built-ins/Function/prototype/toString/method-class-expression.js fails
+built-ins/Function/prototype/toString/method-class-statement-static.js fails
+built-ins/Function/prototype/toString/method-class-statement.js fails
+built-ins/Function/prototype/toString/method-computed-property-name.js fails
+built-ins/Function/prototype/toString/method-object.js fails
+built-ins/Function/prototype/toString/proxy.js fails
+built-ins/Function/prototype/toString/setter-class-expression-static.js fails
+built-ins/Function/prototype/toString/setter-class-expression.js fails
+built-ins/Function/prototype/toString/setter-class-statement-static.js fails
+built-ins/Function/prototype/toString/setter-class-statement.js fails
+built-ins/Function/prototype/toString/setter-object.js fails
+built-ins/Function/prototype/toString/symbol-named-builtins.js fails
+built-ins/Function/prototype/toString/unicode.js fails
+built-ins/GeneratorFunction/proto-from-ctor-realm.js fails
+built-ins/JSON/parse/revived-proxy-revoked.js fails
+built-ins/JSON/parse/revived-proxy.js fails
+built-ins/JSON/parse/reviver-array-define-prop-err.js fails
+built-ins/JSON/parse/reviver-array-delete-err.js fails
+built-ins/JSON/parse/reviver-array-length-coerce-err.js fails
+built-ins/JSON/parse/reviver-array-length-get-err.js fails
+built-ins/JSON/parse/reviver-object-define-prop-err.js fails
+built-ins/JSON/parse/reviver-object-delete-err.js fails
+built-ins/JSON/parse/reviver-object-own-keys-err.js fails
+built-ins/JSON/stringify/replacer-proxy-revoked.js fails
+built-ins/JSON/stringify/replacer-proxy.js fails
+built-ins/JSON/stringify/value-proxy-revoked.js fails
+built-ins/JSON/stringify/value-proxy.js fails
+built-ins/Map/iterable-calls-set.js fails
+built-ins/Map/iterator-close-after-set-failure.js fails
+built-ins/Map/iterator-is-undefined-throws.js fails
+built-ins/Map/iterator-item-first-entry-returns-abrupt.js fails
+built-ins/Map/iterator-item-second-entry-returns-abrupt.js fails
+built-ins/Map/iterator-items-are-not-object-close-iterator.js fails
+built-ins/Map/iterator-items-are-not-object.js fails
+built-ins/Map/map-iterable-throws-when-set-is-not-callable.js fails
+built-ins/Map/map-iterable.js fails
+built-ins/Map/proto-from-ctor-realm.js fails
+built-ins/Map/prototype/clear/context-is-weakmap-object-throws.js fails
+built-ins/Map/prototype/delete/context-is-weakmap-object-throws.js fails
+built-ins/Map/prototype/delete/does-not-break-iterators.js fails
+built-ins/Map/prototype/delete/returns-true-for-deleted-entry.js fails
+built-ins/Map/prototype/entries/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/forEach/callback-parameters.js fails
+built-ins/Map/prototype/forEach/deleted-values-during-foreach.js fails
+built-ins/Map/prototype/forEach/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/forEach/iterates-in-key-insertion-order.js fails
+built-ins/Map/prototype/forEach/iterates-values-added-after-foreach-begins.js fails
+built-ins/Map/prototype/forEach/iterates-values-deleted-then-readded.js fails
+built-ins/Map/prototype/get/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/has/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/keys/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/set/append-new-values.js fails
+built-ins/Map/prototype/set/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/set/length.js fails
+built-ins/Map/prototype/size/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Map/prototype/size/returns-count-of-present-values-by-iterable.js fails
+built-ins/Map/prototype/values/does-not-have-mapdata-internal-slot-weakmap.js fails
+built-ins/Math/max/zeros.js fails
+built-ins/Math/round/S15.8.2.15_A7.js fails
+built-ins/NativeErrors/EvalError/proto.js fails
+built-ins/NativeErrors/EvalError/prototype/not-error-object.js fails
+built-ins/NativeErrors/RangeError/proto.js fails
+built-ins/NativeErrors/RangeError/prototype/not-error-object.js fails
+built-ins/NativeErrors/ReferenceError/proto.js fails
+built-ins/NativeErrors/ReferenceError/prototype/not-error-object.js fails
+built-ins/NativeErrors/SyntaxError/proto.js fails
+built-ins/NativeErrors/SyntaxError/prototype/not-error-object.js fails
+built-ins/NativeErrors/TypeError/proto.js fails
+built-ins/NativeErrors/TypeError/prototype/not-error-object.js fails
+built-ins/NativeErrors/URIError/proto.js fails
+built-ins/NativeErrors/URIError/prototype/not-error-object.js fails
+built-ins/Number/isFinite/arg-is-not-number.js fails
+built-ins/Number/isNaN/arg-is-not-number.js fails
+built-ins/Number/proto-from-ctor-realm.js fails
+built-ins/Number/prototype/toExponential/infinity.js fails
+built-ins/Number/prototype/toExponential/nan.js fails
+built-ins/Number/prototype/toExponential/range.js fails
+built-ins/Number/prototype/toFixed/range.js fails
+built-ins/Number/prototype/toPrecision/infinity.js fails
+built-ins/Number/prototype/toPrecision/nan.js fails
+built-ins/Number/prototype/toPrecision/range.js fails
+built-ins/Number/prototype/toPrecision/return-values.js fails
+built-ins/Number/string-binary-literal.js fails
+built-ins/Number/string-hex-literal-invalid.js fails
+built-ins/Number/string-octal-literal.js fails
+built-ins/Object/assign/Target-Symbol.js fails
+built-ins/Object/assign/source-own-prop-desc-missing.js fails
+built-ins/Object/assign/source-own-prop-error.js fails
+built-ins/Object/assign/source-own-prop-keys-error.js fails
+built-ins/Object/create/15.2.3.5-4-14.js strictFails
+built-ins/Object/create/15.2.3.5-4-37.js strictFails
+built-ins/Object/entries/exception-during-enumeration.js fails
+built-ins/Object/entries/function-length.js fails
+built-ins/Object/entries/function-name.js fails
+built-ins/Object/entries/function-property-descriptor.js fails
+built-ins/Object/entries/getter-adding-key.js fails
+built-ins/Object/entries/getter-making-future-key-nonenumerable.js fails
+built-ins/Object/entries/getter-removing-future-key.js fails
+built-ins/Object/entries/inherited-properties-omitted.js fails
+built-ins/Object/entries/observable-operations.js fails
+built-ins/Object/entries/primitive-booleans.js fails
+built-ins/Object/entries/primitive-numbers.js fails
+built-ins/Object/entries/primitive-strings.js fails
+built-ins/Object/entries/primitive-symbols.js fails
+built-ins/Object/entries/symbols-omitted.js fails
+built-ins/Object/entries/tamper-with-global-object.js fails
+built-ins/Object/entries/tamper-with-object-keys.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-191.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-194.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-201.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-212.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-213.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-214.js fails
+built-ins/Object/getOwnPropertyDescriptor/15.2.3.3-4-215.js fails
+built-ins/Object/getOwnPropertyDescriptors/function-length.js fails
+built-ins/Object/getOwnPropertyDescriptors/function-name.js fails
+built-ins/Object/getOwnPropertyDescriptors/function-property-descriptor.js fails
+built-ins/Object/getOwnPropertyDescriptors/inherited-properties-omitted.js fails
+built-ins/Object/getOwnPropertyDescriptors/normal-object.js fails
+built-ins/Object/getOwnPropertyDescriptors/observable-operations.js fails
+built-ins/Object/getOwnPropertyDescriptors/primitive-booleans.js fails
+built-ins/Object/getOwnPropertyDescriptors/primitive-numbers.js fails
+built-ins/Object/getOwnPropertyDescriptors/primitive-strings.js fails
+built-ins/Object/getOwnPropertyDescriptors/primitive-symbols.js fails
+built-ins/Object/getOwnPropertyDescriptors/proxy-undefined-descriptor.js fails
+built-ins/Object/getOwnPropertyDescriptors/symbols-included.js fails
+built-ins/Object/getOwnPropertyDescriptors/tamper-with-global-object.js fails
+built-ins/Object/getOwnPropertyDescriptors/tamper-with-object-keys.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-12.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-13.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-14.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-15.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-16.js fails
+built-ins/Object/getPrototypeOf/15.2.3.2-2-17.js fails
+built-ins/Object/isExtensible/15.2.3.13-1-1.js fails
+built-ins/Object/isExtensible/15.2.3.13-1-2.js fails
+built-ins/Object/isFrozen/15.2.3.12-1-1.js fails
+built-ins/Object/isFrozen/15.2.3.12-1-2.js fails
+built-ins/Object/keys/proxy-keys.js fails
+built-ins/Object/preventExtensions/15.2.3.10-1-1.js fails
+built-ins/Object/preventExtensions/15.2.3.10-1-2.js fails
+built-ins/Object/proto-from-ctor.js fails
+built-ins/Object/prototype/setPrototypeOf-with-different-values.js fails
+built-ins/Object/prototype/setPrototypeOf-with-same-value.js fails
+built-ins/Object/prototype/toLocaleString/primitive_this_value_getter.js strictFails
+built-ins/Object/prototype/toString/no-prototype-property.js fails
+built-ins/Object/prototype/toString/proxy-array.js fails
+built-ins/Object/prototype/toString/proxy-function.js fails
+built-ins/Object/prototype/toString/proxy-revoked.js fails
+built-ins/Object/prototype/valueOf/S15.2.4.4_A14.js fails
+built-ins/Object/setPrototypeOf/set-error.js fails
+built-ins/Object/values/exception-during-enumeration.js fails
+built-ins/Object/values/function-length.js fails
+built-ins/Object/values/function-name.js fails
+built-ins/Object/values/function-property-descriptor.js fails
+built-ins/Object/values/getter-adding-key.js fails
+built-ins/Object/values/getter-making-future-key-nonenumerable.js fails
+built-ins/Object/values/getter-removing-future-key.js fails
+built-ins/Object/values/inherited-properties-omitted.js fails
+built-ins/Object/values/observable-operations.js fails
+built-ins/Object/values/primitive-booleans.js fails
+built-ins/Object/values/primitive-numbers.js fails
+built-ins/Object/values/primitive-strings.js fails
+built-ins/Object/values/primitive-symbols.js fails
+built-ins/Object/values/symbols-omitted.js fails
+built-ins/Object/values/tamper-with-global-object.js fails
+built-ins/Object/values/tamper-with-object-keys.js fails
+built-ins/Promise/S25.4.3.1_A1.1_T1.js fails
+built-ins/Promise/S25.4.3.1_A2.1_T1.js fails
+built-ins/Promise/S25.4.3.1_A2.2_T1.js fails
+built-ins/Promise/S25.4.3.1_A3.1_T1.js fails
+built-ins/Promise/Symbol.species/length.js fails
+built-ins/Promise/Symbol.species/prop-desc.js fails
+built-ins/Promise/Symbol.species/return-value.js fails
+built-ins/Promise/Symbol.species/symbol-species-name.js fails
+built-ins/Promise/Symbol.species/symbol-species.js fails
+built-ins/Promise/all/S25.4.4.1_A1.1_T1.js fails
+built-ins/Promise/all/S25.4.4.1_A2.1_T1.js fails
+built-ins/Promise/all/S25.4.4.1_A4.1_T1.js fails
+built-ins/Promise/all/S25.4.4.1_A6.1_T1.js fails
+built-ins/Promise/all/call-resolve-element-after-return.js fails
+built-ins/Promise/all/call-resolve-element-items.js fails
+built-ins/Promise/all/call-resolve-element.js fails
+built-ins/Promise/all/capability-executor-called-twice.js fails
+built-ins/Promise/all/capability-executor-not-callable.js fails
+built-ins/Promise/all/capability-resolve-throws-no-close.js fails
+built-ins/Promise/all/ctx-ctor-throws.js fails
+built-ins/Promise/all/ctx-ctor.js fails
+built-ins/Promise/all/ctx-non-ctor.js fails
+built-ins/Promise/all/ctx-non-object.js fails
+built-ins/Promise/all/invoke-resolve-error-close.js fails
+built-ins/Promise/all/invoke-resolve-get-error-close.js fails
+built-ins/Promise/all/invoke-resolve-return.js fails
+built-ins/Promise/all/invoke-resolve.js fails
+built-ins/Promise/all/invoke-then-error-close.js fails
+built-ins/Promise/all/invoke-then-get-error-close.js fails
+built-ins/Promise/all/invoke-then.js fails
+built-ins/Promise/all/iter-next-val-err-no-close.js fails
+built-ins/Promise/all/iter-step-err-no-close.js fails
+built-ins/Promise/all/length.js fails
+built-ins/Promise/all/name.js fails
+built-ins/Promise/all/new-resolve-function.js fails
+built-ins/Promise/all/prop-desc.js fails
+built-ins/Promise/all/resolve-before-loop-exit-from-same.js fails
+built-ins/Promise/all/resolve-before-loop-exit.js fails
+built-ins/Promise/all/resolve-element-function-extensible.js fails
+built-ins/Promise/all/resolve-element-function-length.js fails
+built-ins/Promise/all/resolve-element-function-name.js fails
+built-ins/Promise/all/resolve-element-function-nonconstructor.js fails
+built-ins/Promise/all/resolve-element-function-prototype.js fails
+built-ins/Promise/all/resolve-from-same-thenable.js fails
+built-ins/Promise/all/same-reject-function.js fails
+built-ins/Promise/all/species-get-error.js fails
+built-ins/Promise/exec-args.js fails
+built-ins/Promise/executor-function-extensible.js fails
+built-ins/Promise/executor-function-length.js fails
+built-ins/Promise/executor-function-name.js fails
+built-ins/Promise/executor-function-nonconstructor.js fails
+built-ins/Promise/executor-function-prototype.js fails
+built-ins/Promise/length.js fails
+built-ins/Promise/name.js fails
+built-ins/Promise/proto-from-ctor-realm.js fails
+built-ins/Promise/prototype/S25.4.4.2_A1.1_T1.js fails
+built-ins/Promise/prototype/S25.4.5_A3.1_T1.js fails
+built-ins/Promise/prototype/Symbol.toStringTag.js fails
+built-ins/Promise/prototype/catch/S25.4.5.1_A1.1_T1.js fails
+built-ins/Promise/prototype/catch/S25.4.5.1_A2.1_T1.js fails
+built-ins/Promise/prototype/catch/invokes-then.js fails
+built-ins/Promise/prototype/catch/length.js fails
+built-ins/Promise/prototype/catch/name.js fails
+built-ins/Promise/prototype/catch/prop-desc.js fails
+built-ins/Promise/prototype/catch/this-value-non-object.js fails
+built-ins/Promise/prototype/catch/this-value-obj-coercible.js fails
+built-ins/Promise/prototype/catch/this-value-then-not-callable.js fails
+built-ins/Promise/prototype/catch/this-value-then-poisoned.js fails
+built-ins/Promise/prototype/catch/this-value-then-throws.js fails
+built-ins/Promise/prototype/no-promise-state.js fails
+built-ins/Promise/prototype/prop-desc.js fails
+built-ins/Promise/prototype/proto.js fails
+built-ins/Promise/prototype/then/S25.4.5.3_A1.1_T1.js fails
+built-ins/Promise/prototype/then/S25.4.5.3_A1.1_T2.js fails
+built-ins/Promise/prototype/then/S25.4.5.3_A2.1_T1.js fails
+built-ins/Promise/prototype/then/S25.4.5.3_A2.1_T2.js fails
+built-ins/Promise/prototype/then/capability-executor-called-twice.js fails
+built-ins/Promise/prototype/then/capability-executor-not-callable.js fails
+built-ins/Promise/prototype/then/context-check-on-entry.js fails
+built-ins/Promise/prototype/then/ctor-custom.js fails
+built-ins/Promise/prototype/then/ctor-null.js fails
+built-ins/Promise/prototype/then/ctor-poisoned.js fails
+built-ins/Promise/prototype/then/ctor-throws.js fails
+built-ins/Promise/prototype/then/ctor-undef.js fails
+built-ins/Promise/prototype/then/length.js fails
+built-ins/Promise/prototype/then/name.js fails
+built-ins/Promise/prototype/then/prop-desc.js fails
+built-ins/Promise/race/S25.4.4.3_A1.1_T1.js fails
+built-ins/Promise/race/S25.4.4.3_A2.1_T1.js fails
+built-ins/Promise/race/S25.4.4.3_A3.1_T1.js fails
+built-ins/Promise/race/S25.4.4.3_A3.1_T2.js fails
+built-ins/Promise/race/capability-executor-called-twice.js fails
+built-ins/Promise/race/capability-executor-not-callable.js fails
+built-ins/Promise/race/ctx-ctor-throws.js fails
+built-ins/Promise/race/ctx-ctor.js fails
+built-ins/Promise/race/ctx-non-ctor.js fails
+built-ins/Promise/race/ctx-non-object.js fails
+built-ins/Promise/race/invoke-resolve-error-close.js fails
+built-ins/Promise/race/invoke-resolve-get-error-close.js fails
+built-ins/Promise/race/invoke-resolve-return.js fails
+built-ins/Promise/race/invoke-resolve.js fails
+built-ins/Promise/race/invoke-then-error-close.js fails
+built-ins/Promise/race/invoke-then-get-error-close.js fails
+built-ins/Promise/race/invoke-then.js fails
+built-ins/Promise/race/iter-next-val-err-no-close.js fails
+built-ins/Promise/race/iter-step-err-no-close.js fails
+built-ins/Promise/race/length.js fails
+built-ins/Promise/race/name.js fails
+built-ins/Promise/race/prop-desc.js fails
+built-ins/Promise/race/same-reject-function.js fails
+built-ins/Promise/race/same-resolve-function.js fails
+built-ins/Promise/race/species-get-error.js fails
+built-ins/Promise/reject-function-extensible.js fails
+built-ins/Promise/reject-function-length.js fails
+built-ins/Promise/reject-function-name.js fails
+built-ins/Promise/reject-function-nonconstructor.js fails
+built-ins/Promise/reject-function-prototype.js fails
+built-ins/Promise/reject/S25.4.4.4_A1.1_T1.js fails
+built-ins/Promise/reject/S25.4.4.4_A3.1_T1.js fails
+built-ins/Promise/reject/capability-executor-called-twice.js fails
+built-ins/Promise/reject/capability-executor-not-callable.js fails
+built-ins/Promise/reject/capability-invocation-error.js fails
+built-ins/Promise/reject/capability-invocation.js fails
+built-ins/Promise/reject/ctx-ctor-throws.js fails
+built-ins/Promise/reject/ctx-ctor.js fails
+built-ins/Promise/reject/ctx-non-ctor.js fails
+built-ins/Promise/reject/ctx-non-object.js fails
+built-ins/Promise/reject/length.js fails
+built-ins/Promise/reject/name.js fails
+built-ins/Promise/reject/prop-desc.js fails
+built-ins/Promise/resolve-function-extensible.js fails
+built-ins/Promise/resolve-function-length.js fails
+built-ins/Promise/resolve-function-name.js fails
+built-ins/Promise/resolve-function-nonconstructor.js fails
+built-ins/Promise/resolve-function-prototype.js fails
+built-ins/Promise/resolve/S25.4.4.5_A1.1_T1.js fails
+built-ins/Promise/resolve/S25.4.4.5_A2.1_T1.js fails
+built-ins/Promise/resolve/arg-uniq-ctor.js fails
+built-ins/Promise/resolve/capability-executor-called-twice.js fails
+built-ins/Promise/resolve/capability-executor-not-callable.js fails
+built-ins/Promise/resolve/capability-invocation-error.js fails
+built-ins/Promise/resolve/context-non-object-with-promise.js fails
+built-ins/Promise/resolve/ctx-ctor-throws.js fails
+built-ins/Promise/resolve/ctx-ctor.js fails
+built-ins/Promise/resolve/ctx-non-ctor.js fails
+built-ins/Promise/resolve/ctx-non-object.js fails
+built-ins/Promise/resolve/length.js fails
+built-ins/Promise/resolve/name.js fails
+built-ins/Promise/resolve/prop-desc.js fails
+built-ins/Promise/resolve/resolve-from-promise-capability.js fails
+built-ins/Promise/resolve/resolve-prms-cstm-then.js fails
+built-ins/Proxy/apply/arguments-realm.js fails
+built-ins/Proxy/apply/call-parameters.js fails
+built-ins/Proxy/apply/call-result.js fails
+built-ins/Proxy/apply/null-handler.js fails
+built-ins/Proxy/apply/return-abrupt.js fails
+built-ins/Proxy/apply/trap-is-not-callable-realm.js fails
+built-ins/Proxy/apply/trap-is-not-callable.js fails
+built-ins/Proxy/apply/trap-is-null.js fails
+built-ins/Proxy/apply/trap-is-undefined-no-property.js fails
+built-ins/Proxy/apply/trap-is-undefined.js fails
+built-ins/Proxy/construct/arguments-realm.js fails
+built-ins/Proxy/construct/call-parameters-new-target.js fails
+built-ins/Proxy/construct/call-parameters.js fails
+built-ins/Proxy/construct/call-result.js fails
+built-ins/Proxy/construct/null-handler.js fails
+built-ins/Proxy/construct/return-is-abrupt.js fails
+built-ins/Proxy/construct/return-not-object-throws-boolean.js fails
+built-ins/Proxy/construct/return-not-object-throws-number.js fails
+built-ins/Proxy/construct/return-not-object-throws-string.js fails
+built-ins/Proxy/construct/return-not-object-throws-symbol.js fails
+built-ins/Proxy/construct/return-not-object-throws-undefined.js fails
+built-ins/Proxy/construct/trap-is-not-callable-realm.js fails
+built-ins/Proxy/construct/trap-is-not-callable.js fails
+built-ins/Proxy/construct/trap-is-null.js fails
+built-ins/Proxy/construct/trap-is-undefined-no-property.js fails
+built-ins/Proxy/construct/trap-is-undefined-proto-from-ctor-realm.js fails
+built-ins/Proxy/construct/trap-is-undefined.js fails
+built-ins/Proxy/constructor.js fails
+built-ins/Proxy/create-handler-is-revoked-proxy.js fails
+built-ins/Proxy/create-handler-not-object-throw-boolean.js fails
+built-ins/Proxy/create-handler-not-object-throw-null.js fails
+built-ins/Proxy/create-handler-not-object-throw-number.js fails
+built-ins/Proxy/create-handler-not-object-throw-string.js fails
+built-ins/Proxy/create-handler-not-object-throw-symbol.js fails
+built-ins/Proxy/create-handler-not-object-throw-undefined.js fails
+built-ins/Proxy/create-target-is-not-callable.js fails
+built-ins/Proxy/create-target-is-not-constructor.js fails
+built-ins/Proxy/create-target-is-revoked-proxy.js fails
+built-ins/Proxy/create-target-not-object-throw-boolean.js fails
+built-ins/Proxy/create-target-not-object-throw-null.js fails
+built-ins/Proxy/create-target-not-object-throw-number.js fails
+built-ins/Proxy/create-target-not-object-throw-string.js fails
+built-ins/Proxy/create-target-not-object-throw-symbol.js fails
+built-ins/Proxy/create-target-not-object-throw-undefined.js fails
+built-ins/Proxy/defineProperty/call-parameters.js fails
+built-ins/Proxy/defineProperty/desc-realm.js fails
+built-ins/Proxy/defineProperty/null-handler-realm.js fails
+built-ins/Proxy/defineProperty/null-handler.js fails
+built-ins/Proxy/defineProperty/return-boolean-and-define-target.js fails
+built-ins/Proxy/defineProperty/return-is-abrupt.js fails
+built-ins/Proxy/defineProperty/targetdesc-configurable-desc-not-configurable-realm.js fails
+built-ins/Proxy/defineProperty/targetdesc-configurable-desc-not-configurable.js fails
+built-ins/Proxy/defineProperty/targetdesc-not-compatible-descriptor-not-configurable-target-realm.js fails
+built-ins/Proxy/defineProperty/targetdesc-not-compatible-descriptor-not-configurable-target.js fails
+built-ins/Proxy/defineProperty/targetdesc-not-compatible-descriptor-realm.js fails
+built-ins/Proxy/defineProperty/targetdesc-not-compatible-descriptor.js fails
+built-ins/Proxy/defineProperty/targetdesc-undefined-not-configurable-descriptor-realm.js fails
+built-ins/Proxy/defineProperty/targetdesc-undefined-not-configurable-descriptor.js fails
+built-ins/Proxy/defineProperty/targetdesc-undefined-target-is-not-extensible-realm.js fails
+built-ins/Proxy/defineProperty/targetdesc-undefined-target-is-not-extensible.js fails
+built-ins/Proxy/defineProperty/trap-is-not-callable-realm.js fails
+built-ins/Proxy/defineProperty/trap-is-not-callable.js fails
+built-ins/Proxy/defineProperty/trap-is-undefined.js fails
+built-ins/Proxy/defineProperty/trap-return-is-false.js fails
+built-ins/Proxy/deleteProperty/boolean-trap-result-boolean-false.js fails
+built-ins/Proxy/deleteProperty/boolean-trap-result-boolean-true.js fails
+built-ins/Proxy/deleteProperty/call-parameters.js fails
+built-ins/Proxy/deleteProperty/null-handler.js fails
+built-ins/Proxy/deleteProperty/return-false-not-strict.js sloppyFails
+built-ins/Proxy/deleteProperty/return-false-strict.js strictFails
+built-ins/Proxy/deleteProperty/return-is-abrupt.js fails
+built-ins/Proxy/deleteProperty/targetdesc-is-not-configurable.js fails
+built-ins/Proxy/deleteProperty/targetdesc-is-undefined-return-true.js fails
+built-ins/Proxy/deleteProperty/trap-is-not-callable-realm.js fails
+built-ins/Proxy/deleteProperty/trap-is-not-callable.js fails
+built-ins/Proxy/deleteProperty/trap-is-undefined-not-strict.js sloppyFails
+built-ins/Proxy/deleteProperty/trap-is-undefined-strict.js strictFails
+built-ins/Proxy/enumerate/removed-does-not-trigger.js fails
+built-ins/Proxy/function-prototype.js fails
+built-ins/Proxy/get-fn-realm.js fails
+built-ins/Proxy/get/accessor-get-is-undefined-throws.js fails
+built-ins/Proxy/get/call-parameters.js fails
+built-ins/Proxy/get/not-same-value-configurable-false-writable-false-throws.js fails
+built-ins/Proxy/get/null-handler.js fails
+built-ins/Proxy/get/return-is-abrupt.js fails
+built-ins/Proxy/get/return-trap-result-accessor-property.js fails
+built-ins/Proxy/get/return-trap-result-configurable-false-writable-true.js fails
+built-ins/Proxy/get/return-trap-result-configurable-true-assessor-get-undefined.js fails
+built-ins/Proxy/get/return-trap-result-configurable-true-writable-false.js fails
+built-ins/Proxy/get/return-trap-result-same-value-configurable-false-writable-false.js fails
+built-ins/Proxy/get/return-trap-result.js fails
+built-ins/Proxy/get/trap-is-not-callable-realm.js fails
+built-ins/Proxy/get/trap-is-not-callable.js fails
+built-ins/Proxy/get/trap-is-undefined-no-property.js fails
+built-ins/Proxy/get/trap-is-undefined-receiver.js fails
+built-ins/Proxy/get/trap-is-undefined.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/call-parameters.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/null-handler.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-is-undefined-target-is-not-extensible.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-is-undefined-targetdesc-is-not-configurable.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-is-undefined-targetdesc-is-undefined.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-is-undefined.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-type-is-not-object-nor-undefined-realm.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/result-type-is-not-object-nor-undefined.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/resultdesc-is-invalid-descriptor.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/resultdesc-is-not-configurable-targetdesc-is-configurable.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/resultdesc-is-not-configurable-targetdesc-is-undefined.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/resultdesc-return-configurable.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/resultdesc-return-not-configurable.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/return-is-abrupt.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/trap-is-not-callable-realm.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/trap-is-not-callable.js fails
+built-ins/Proxy/getOwnPropertyDescriptor/trap-is-undefined.js fails
+built-ins/Proxy/getPrototypeOf/call-parameters.js fails
+built-ins/Proxy/getPrototypeOf/extensible-target-return-handlerproto.js fails
+built-ins/Proxy/getPrototypeOf/not-extensible-not-same-proto-throws.js fails
+built-ins/Proxy/getPrototypeOf/not-extensible-same-proto.js fails
+built-ins/Proxy/getPrototypeOf/null-handler.js fails
+built-ins/Proxy/getPrototypeOf/return-is-abrupt.js fails
+built-ins/Proxy/getPrototypeOf/trap-is-not-callable-realm.js fails
+built-ins/Proxy/getPrototypeOf/trap-is-not-callable.js fails
+built-ins/Proxy/getPrototypeOf/trap-is-undefined.js fails
+built-ins/Proxy/getPrototypeOf/trap-result-neither-object-nor-null-throws-boolean.js fails
+built-ins/Proxy/getPrototypeOf/trap-result-neither-object-nor-null-throws-number.js fails
+built-ins/Proxy/getPrototypeOf/trap-result-neither-object-nor-null-throws-string.js fails
+built-ins/Proxy/getPrototypeOf/trap-result-neither-object-nor-null-throws-symbol.js fails
+built-ins/Proxy/getPrototypeOf/trap-result-neither-object-nor-null-throws-undefined.js fails
+built-ins/Proxy/has/call-in.js fails
+built-ins/Proxy/has/call-object-create.js fails
+built-ins/Proxy/has/call-with.js sloppyFails
+built-ins/Proxy/has/null-handler-using-with.js sloppyFails
+built-ins/Proxy/has/null-handler.js fails
+built-ins/Proxy/has/return-false-target-not-extensible-using-with.js sloppyFails
+built-ins/Proxy/has/return-false-target-not-extensible.js fails
+built-ins/Proxy/has/return-false-target-prop-exists-using-with.js sloppyFails
+built-ins/Proxy/has/return-false-target-prop-exists.js fails
+built-ins/Proxy/has/return-false-targetdesc-not-configurable-using-with.js sloppyFails
+built-ins/Proxy/has/return-false-targetdesc-not-configurable.js fails
+built-ins/Proxy/has/return-is-abrupt-in.js fails
+built-ins/Proxy/has/return-is-abrupt-with.js sloppyFails
+built-ins/Proxy/has/return-true-target-prop-exists-using-with.js sloppyFails
+built-ins/Proxy/has/return-true-target-prop-exists.js fails
+built-ins/Proxy/has/return-true-without-same-target-prop.js fails
+built-ins/Proxy/has/trap-is-not-callable-realm.js fails
+built-ins/Proxy/has/trap-is-not-callable-using-with.js sloppyFails
+built-ins/Proxy/has/trap-is-not-callable.js fails
+built-ins/Proxy/has/trap-is-undefined-using-with.js sloppyFails
+built-ins/Proxy/has/trap-is-undefined.js fails
+built-ins/Proxy/isExtensible/call-parameters.js fails
+built-ins/Proxy/isExtensible/null-handler.js fails
+built-ins/Proxy/isExtensible/return-is-abrupt.js fails
+built-ins/Proxy/isExtensible/return-is-boolean.js fails
+built-ins/Proxy/isExtensible/return-is-different-from-target.js fails
+built-ins/Proxy/isExtensible/return-same-result-from-target.js fails
+built-ins/Proxy/isExtensible/trap-is-not-callable-realm.js fails
+built-ins/Proxy/isExtensible/trap-is-not-callable.js fails
+built-ins/Proxy/isExtensible/trap-is-undefined.js fails
+built-ins/Proxy/length.js fails
+built-ins/Proxy/name.js fails
+built-ins/Proxy/ownKeys/call-parameters-object-getownpropertynames.js fails
+built-ins/Proxy/ownKeys/call-parameters-object-getownpropertysymbols.js fails
+built-ins/Proxy/ownKeys/call-parameters-object-keys.js fails
+built-ins/Proxy/ownKeys/extensible-return-trap-result-absent-not-configurable-keys.js fails
+built-ins/Proxy/ownKeys/extensible-return-trap-result.js fails
+built-ins/Proxy/ownKeys/not-extensible-missing-keys-throws.js fails
+built-ins/Proxy/ownKeys/not-extensible-new-keys-throws.js fails
+built-ins/Proxy/ownKeys/not-extensible-return-keys.js fails
+built-ins/Proxy/ownKeys/null-handler.js fails
+built-ins/Proxy/ownKeys/return-all-non-configurable-keys.js fails
+built-ins/Proxy/ownKeys/return-duplicate-entries-throws.js fails
+built-ins/Proxy/ownKeys/return-duplicate-symbol-entries-throws.js fails
+built-ins/Proxy/ownKeys/return-is-abrupt.js fails
+built-ins/Proxy/ownKeys/return-not-list-object-throws-realm.js fails
+built-ins/Proxy/ownKeys/return-not-list-object-throws.js fails
+built-ins/Proxy/ownKeys/return-type-throws-array.js fails
+built-ins/Proxy/ownKeys/return-type-throws-boolean.js fails
+built-ins/Proxy/ownKeys/return-type-throws-null.js fails
+built-ins/Proxy/ownKeys/return-type-throws-number.js fails
+built-ins/Proxy/ownKeys/return-type-throws-object.js fails
+built-ins/Proxy/ownKeys/return-type-throws-undefined.js fails
+built-ins/Proxy/ownKeys/trap-is-not-callable-realm.js fails
+built-ins/Proxy/ownKeys/trap-is-not-callable.js fails
+built-ins/Proxy/ownKeys/trap-is-undefined.js fails
+built-ins/Proxy/preventExtensions/call-parameters.js fails
+built-ins/Proxy/preventExtensions/null-handler.js fails
+built-ins/Proxy/preventExtensions/return-false.js fails
+built-ins/Proxy/preventExtensions/return-is-abrupt.js fails
+built-ins/Proxy/preventExtensions/return-true-target-is-extensible.js fails
+built-ins/Proxy/preventExtensions/return-true-target-is-not-extensible.js fails
+built-ins/Proxy/preventExtensions/trap-is-not-callable-realm.js fails
+built-ins/Proxy/preventExtensions/trap-is-not-callable.js fails
+built-ins/Proxy/preventExtensions/trap-is-undefined.js fails
+built-ins/Proxy/proxy-newtarget.js fails
+built-ins/Proxy/proxy-no-prototype.js fails
+built-ins/Proxy/proxy-undefined-newtarget.js fails
+built-ins/Proxy/proxy.js fails
+built-ins/Proxy/revocable/length.js fails
+built-ins/Proxy/revocable/name.js fails
+built-ins/Proxy/revocable/proxy.js fails
+built-ins/Proxy/revocable/revocation-function-extensible.js fails
+built-ins/Proxy/revocable/revocation-function-length.js fails
+built-ins/Proxy/revocable/revocation-function-name.js fails
+built-ins/Proxy/revocable/revocation-function-nonconstructor.js fails
+built-ins/Proxy/revocable/revocation-function-prototype.js fails
+built-ins/Proxy/revocable/revoke-consecutive-call-returns-undefined.js fails
+built-ins/Proxy/revocable/revoke-returns-undefined.js fails
+built-ins/Proxy/revocable/revoke.js fails
+built-ins/Proxy/set/boolean-trap-result-is-false-boolean-return-false.js fails
+built-ins/Proxy/set/boolean-trap-result-is-false-null-return-false.js fails
+built-ins/Proxy/set/boolean-trap-result-is-false-number-return-false.js fails
+built-ins/Proxy/set/boolean-trap-result-is-false-string-return-false.js fails
+built-ins/Proxy/set/boolean-trap-result-is-false-undefined-return-false.js fails
+built-ins/Proxy/set/call-parameters.js fails
+built-ins/Proxy/set/null-handler.js fails
+built-ins/Proxy/set/return-is-abrupt.js fails
+built-ins/Proxy/set/return-true-target-property-accessor-is-configurable-set-is-undefined.js fails
+built-ins/Proxy/set/return-true-target-property-accessor-is-not-configurable.js fails
+built-ins/Proxy/set/return-true-target-property-is-not-configurable.js fails
+built-ins/Proxy/set/return-true-target-property-is-not-writable.js fails
+built-ins/Proxy/set/target-property-is-accessor-not-configurable-set-is-undefined.js fails
+built-ins/Proxy/set/target-property-is-not-configurable-not-writable-not-equal-to-v.js fails
+built-ins/Proxy/set/trap-is-not-callable-realm.js fails
+built-ins/Proxy/set/trap-is-not-callable.js fails
+built-ins/Proxy/set/trap-is-undefined-no-property.js fails
+built-ins/Proxy/set/trap-is-undefined-receiver.js fails
+built-ins/Proxy/set/trap-is-undefined.js fails
+built-ins/Proxy/setPrototypeOf/call-parameters.js fails
+built-ins/Proxy/setPrototypeOf/internals-call-order.js fails
+built-ins/Proxy/setPrototypeOf/not-extensible-target-not-same-target-prototype.js fails
+built-ins/Proxy/setPrototypeOf/not-extensible-target-same-target-prototype.js fails
+built-ins/Proxy/setPrototypeOf/null-handler.js fails
+built-ins/Proxy/setPrototypeOf/return-abrupt-from-get-trap.js fails
+built-ins/Proxy/setPrototypeOf/return-abrupt-from-isextensible-target.js fails
+built-ins/Proxy/setPrototypeOf/return-abrupt-from-target-getprototypeof.js fails
+built-ins/Proxy/setPrototypeOf/return-abrupt-from-trap.js fails
+built-ins/Proxy/setPrototypeOf/toboolean-trap-result-false.js fails
+built-ins/Proxy/setPrototypeOf/toboolean-trap-result-true-target-is-extensible.js fails
+built-ins/Proxy/setPrototypeOf/trap-is-not-callable-realm.js fails
+built-ins/Proxy/setPrototypeOf/trap-is-not-callable.js fails
+built-ins/Proxy/setPrototypeOf/trap-is-undefined-or-null.js fails
+built-ins/Reflect/construct/newtarget-is-not-constructor-throws.js fails
+built-ins/Reflect/construct/return-with-newtarget-argument.js fails
+built-ins/Reflect/defineProperty/return-abrupt-from-result.js fails
+built-ins/Reflect/deleteProperty/return-abrupt-from-result.js fails
+built-ins/Reflect/get/return-value-from-receiver.js fails
+built-ins/Reflect/getOwnPropertyDescriptor/return-abrupt-from-result.js fails
+built-ins/Reflect/getPrototypeOf/return-abrupt-from-result.js fails
+built-ins/Reflect/has/return-abrupt-from-result.js fails
+built-ins/Reflect/isExtensible/return-abrupt-from-result.js fails
+built-ins/Reflect/ownKeys/return-abrupt-from-result.js fails
+built-ins/Reflect/ownKeys/return-on-corresponding-order.js fails
+built-ins/Reflect/preventExtensions/return-abrupt-from-result.js fails
+built-ins/Reflect/preventExtensions/return-boolean-from-proxy-object.js fails
+built-ins/Reflect/set/creates-a-data-descriptor.js fails
+built-ins/Reflect/set/different-property-descriptors.js fails
+built-ins/Reflect/set/receiver-is-not-object.js fails
+built-ins/Reflect/set/return-false-if-target-is-not-writable.js fails
+built-ins/Reflect/set/set-value-on-accessor-descriptor-with-receiver.js fails
+built-ins/Reflect/set/set-value-on-data-descriptor.js fails
+built-ins/Reflect/set/symbol-property.js fails
+built-ins/Reflect/setPrototypeOf/return-abrupt-from-result.js fails
+built-ins/Reflect/setPrototypeOf/return-false-if-target-and-proto-are-the-same.js fails
+built-ins/Reflect/setPrototypeOf/return-false-if-target-is-not-extensible.js fails
+built-ins/Reflect/setPrototypeOf/return-false-if-target-is-prototype-of-proto.js fails
+built-ins/Reflect/setPrototypeOf/return-true-if-new-prototype-is-set.js fails
+built-ins/Reflect/setPrototypeOf/return-true-if-proto-is-current.js fails
+built-ins/RegExp/15.10.4.1-1.js fails
+built-ins/RegExp/S15.10.2.12_A2_T1.js fails
+built-ins/RegExp/S15.10.3.1_A2_T1.js fails
+built-ins/RegExp/S15.10.3.1_A2_T2.js fails
+built-ins/RegExp/S15.10.4.1_A2_T1.js fails
+built-ins/RegExp/S15.10.4.1_A2_T2.js fails
+built-ins/RegExp/call_with_non_regexp_same_constructor.js fails
+built-ins/RegExp/call_with_regexp_match_falsy.js fails
+built-ins/RegExp/call_with_regexp_not_same_constructor.js fails
+built-ins/RegExp/dotall/without-dotall-unicode.js fails
+built-ins/RegExp/from-regexp-like-flag-override.js fails
+built-ins/RegExp/from-regexp-like-get-source-err.js fails
+built-ins/RegExp/from-regexp-like-short-circuit.js fails
+built-ins/RegExp/from-regexp-like.js fails
+built-ins/RegExp/proto-from-ctor-realm.js fails
+built-ins/RegExp/prototype/15.10.6.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-coerce-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-g-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-return-val.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-y-return-val.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-y-set-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-failure-y-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-infer-unicode.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-g-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-return-val-groups.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-return-val.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-u-return-val-groups.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-y-set-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-success-y-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/builtin-y-coerce-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.match/coerce-arg-err.js fails
+built-ins/RegExp/prototype/Symbol.match/coerce-arg.js fails
+built-ins/RegExp/prototype/Symbol.match/coerce-global.js fails
+built-ins/RegExp/prototype/Symbol.match/exec-err.js fails
+built-ins/RegExp/prototype/Symbol.match/exec-invocation.js fails
+built-ins/RegExp/prototype/Symbol.match/exec-return-type-invalid.js fails
+built-ins/RegExp/prototype/Symbol.match/exec-return-type-valid.js fails
+built-ins/RegExp/prototype/Symbol.match/g-coerce-result-err.js fails
+built-ins/RegExp/prototype/Symbol.match/g-get-exec-err.js fails
+built-ins/RegExp/prototype/Symbol.match/g-get-result-err.js fails
+built-ins/RegExp/prototype/Symbol.match/g-init-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/g-match-empty-advance-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/g-match-empty-coerce-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.match/g-match-no-coerce-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/g-match-no-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/g-success-return-val.js fails
+built-ins/RegExp/prototype/Symbol.match/g-zero-matches.js fails
+built-ins/RegExp/prototype/Symbol.match/get-exec-err.js fails
+built-ins/RegExp/prototype/Symbol.match/get-global-err.js fails
+built-ins/RegExp/prototype/Symbol.match/get-unicode-error.js fails
+built-ins/RegExp/prototype/Symbol.match/length.js fails
+built-ins/RegExp/prototype/Symbol.match/name.js fails
+built-ins/RegExp/prototype/Symbol.match/prop-desc.js fails
+built-ins/RegExp/prototype/Symbol.match/this-val-non-regexp.js fails
+built-ins/RegExp/prototype/Symbol.match/u-advance-after-empty.js fails
+built-ins/RegExp/prototype/Symbol.match/y-fail-global-return.js fails
+built-ins/RegExp/prototype/Symbol.match/y-fail-lastindex-no-write.js fails
+built-ins/RegExp/prototype/Symbol.match/y-fail-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/y-fail-return.js fails
+built-ins/RegExp/prototype/Symbol.match/y-init-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.match/y-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.replace/arg-1-coerce-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/arg-1-coerce.js fails
+built-ins/RegExp/prototype/Symbol.replace/arg-2-coerce-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/arg-2-coerce.js fails
+built-ins/RegExp/prototype/Symbol.replace/coerce-global.js fails
+built-ins/RegExp/prototype/Symbol.replace/coerce-unicode.js fails
+built-ins/RegExp/prototype/Symbol.replace/exec-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/exec-invocation.js fails
+built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/fn-coerce-replacement.js fails
+built-ins/RegExp/prototype/Symbol.replace/fn-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args.js fails
+built-ins/RegExp/prototype/Symbol.replace/fn-invoke-this-no-strict.js sloppyFails
+built-ins/RegExp/prototype/Symbol.replace/fn-invoke-this-strict.js strictFails
+built-ins/RegExp/prototype/Symbol.replace/g-init-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/g-init-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.replace/g-pos-decrement.js fails
+built-ins/RegExp/prototype/Symbol.replace/g-pos-increment.js fails
+built-ins/RegExp/prototype/Symbol.replace/get-exec-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/get-global-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/get-unicode-error.js fails
+built-ins/RegExp/prototype/Symbol.replace/length.js fails
+built-ins/RegExp/prototype/Symbol.replace/match-failure.js fails
+built-ins/RegExp/prototype/Symbol.replace/name.js fails
+built-ins/RegExp/prototype/Symbol.replace/prop-desc.js fails
+built-ins/RegExp/prototype/Symbol.replace/replace-with-trailing.js fails
+built-ins/RegExp/prototype/Symbol.replace/replace-without-trailing.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-capture.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-index-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-index.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-length-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-length.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-coerce-matched.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-get-capture-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-get-index-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-get-length-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/result-get-matched-err.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-after.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-before.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-capture-idx-1.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-capture-idx-2.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-dollar.js fails
+built-ins/RegExp/prototype/Symbol.replace/subst-matched.js fails
+built-ins/RegExp/prototype/Symbol.replace/u-advance-after-empty.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-fail-global-return.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-fail-lastindex-no-write.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-fail-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-fail-return.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-init-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.replace/y-set-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.search/coerce-string-err.js fails
+built-ins/RegExp/prototype/Symbol.search/coerce-string.js fails
+built-ins/RegExp/prototype/Symbol.search/cstm-exec-return-index.js fails
+built-ins/RegExp/prototype/Symbol.search/failure-return-val.js fails
+built-ins/RegExp/prototype/Symbol.search/get-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.search/lastindex-no-restore.js fails
+built-ins/RegExp/prototype/Symbol.search/length.js fails
+built-ins/RegExp/prototype/Symbol.search/match-err.js fails
+built-ins/RegExp/prototype/Symbol.search/name.js fails
+built-ins/RegExp/prototype/Symbol.search/prop-desc.js fails
+built-ins/RegExp/prototype/Symbol.search/set-lastindex-init-err.js fails
+built-ins/RegExp/prototype/Symbol.search/set-lastindex-init.js fails
+built-ins/RegExp/prototype/Symbol.search/set-lastindex-restore-err.js fails
+built-ins/RegExp/prototype/Symbol.search/set-lastindex-restore.js fails
+built-ins/RegExp/prototype/Symbol.search/success-get-index-err.js fails
+built-ins/RegExp/prototype/Symbol.search/success-return-val.js fails
+built-ins/RegExp/prototype/Symbol.search/u-lastindex-advance.js fails
+built-ins/RegExp/prototype/Symbol.search/y-fail-return.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-flags-err.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-flags.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-limit-err.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-limit.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-string-err.js fails
+built-ins/RegExp/prototype/Symbol.split/coerce-string.js fails
+built-ins/RegExp/prototype/Symbol.split/get-flags-err.js fails
+built-ins/RegExp/prototype/Symbol.split/last-index-exceeds-str-size.js fails
+built-ins/RegExp/prototype/Symbol.split/length.js fails
+built-ins/RegExp/prototype/Symbol.split/limit-0-bail.js fails
+built-ins/RegExp/prototype/Symbol.split/name.js fails
+built-ins/RegExp/prototype/Symbol.split/prop-desc.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-ctor-get-err.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-ctor-non-obj.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-ctor-undef.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-err.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-species-get-err.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-species-non-ctor.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-species-undef.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor-y.js fails
+built-ins/RegExp/prototype/Symbol.split/species-ctor.js fails
+built-ins/RegExp/prototype/Symbol.split/splitter-proto-from-ctor-realm.js fails
+built-ins/RegExp/prototype/Symbol.split/str-adv-thru-empty-match.js fails
+built-ins/RegExp/prototype/Symbol.split/str-coerce-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-coerce-lastindex.js fails
+built-ins/RegExp/prototype/Symbol.split/str-empty-match-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-empty-match.js fails
+built-ins/RegExp/prototype/Symbol.split/str-empty-no-match.js fails
+built-ins/RegExp/prototype/Symbol.split/str-get-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-limit-capturing.js fails
+built-ins/RegExp/prototype/Symbol.split/str-limit.js fails
+built-ins/RegExp/prototype/Symbol.split/str-match-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-result-coerce-length-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-result-coerce-length.js fails
+built-ins/RegExp/prototype/Symbol.split/str-result-get-capture-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-result-get-length-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-set-lastindex-err.js fails
+built-ins/RegExp/prototype/Symbol.split/str-set-lastindex-match.js fails
+built-ins/RegExp/prototype/Symbol.split/str-set-lastindex-no-match.js fails
+built-ins/RegExp/prototype/Symbol.split/str-trailing-chars.js fails
+built-ins/RegExp/prototype/Symbol.split/u-lastindex-adv-thru-failure.js fails
+built-ins/RegExp/prototype/Symbol.split/u-lastindex-adv-thru-match.js fails
+built-ins/RegExp/prototype/exec/S15.10.6.2_A5_T3.js fails
+built-ins/RegExp/prototype/exec/failure-lastindex-access.js fails
+built-ins/RegExp/prototype/exec/success-lastindex-access.js fails
+built-ins/RegExp/prototype/exec/u-captured-value.js fails
+built-ins/RegExp/prototype/exec/u-lastindex-adv.js fails
+built-ins/RegExp/prototype/exec/u-lastindex-value.js fails
+built-ins/RegExp/prototype/exec/y-fail-lastindex-no-write.js fails
+built-ins/RegExp/prototype/exec/y-fail-lastindex.js fails
+built-ins/RegExp/prototype/exec/y-fail-return.js fails
+built-ins/RegExp/prototype/exec/y-init-lastindex.js fails
+built-ins/RegExp/prototype/exec/y-set-lastindex.js fails
+built-ins/RegExp/prototype/flags/coercion-global.js fails
+built-ins/RegExp/prototype/flags/coercion-ignoreCase.js fails
+built-ins/RegExp/prototype/flags/coercion-multiline.js fails
+built-ins/RegExp/prototype/flags/coercion-sticky.js fails
+built-ins/RegExp/prototype/flags/coercion-unicode.js fails
+built-ins/RegExp/prototype/flags/length.js fails
+built-ins/RegExp/prototype/flags/name.js fails
+built-ins/RegExp/prototype/flags/prop-desc.js fails
+built-ins/RegExp/prototype/flags/this-val-non-obj.js fails
+built-ins/RegExp/prototype/flags/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/global/15.10.7.2-2.js fails
+built-ins/RegExp/prototype/global/S15.10.7.2_A9.js fails
+built-ins/RegExp/prototype/global/length.js fails
+built-ins/RegExp/prototype/global/name.js fails
+built-ins/RegExp/prototype/global/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/ignoreCase/15.10.7.3-2.js fails
+built-ins/RegExp/prototype/ignoreCase/S15.10.7.3_A9.js fails
+built-ins/RegExp/prototype/ignoreCase/length.js fails
+built-ins/RegExp/prototype/ignoreCase/name.js fails
+built-ins/RegExp/prototype/ignoreCase/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/multiline/15.10.7.4-2.js fails
+built-ins/RegExp/prototype/multiline/S15.10.7.4_A9.js fails
+built-ins/RegExp/prototype/multiline/length.js fails
+built-ins/RegExp/prototype/multiline/name.js fails
+built-ins/RegExp/prototype/multiline/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/no-regexp-matcher.js fails
+built-ins/RegExp/prototype/source/length.js fails
+built-ins/RegExp/prototype/source/name.js fails
+built-ins/RegExp/prototype/source/prop-desc.js fails
+built-ins/RegExp/prototype/source/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/source/value-line-terminator.js fails
+built-ins/RegExp/prototype/source/value-u.js fails
+built-ins/RegExp/prototype/sticky/length.js fails
+built-ins/RegExp/prototype/sticky/name.js fails
+built-ins/RegExp/prototype/sticky/prop-desc.js fails
+built-ins/RegExp/prototype/sticky/this-val-invalid-obj.js fails
+built-ins/RegExp/prototype/sticky/this-val-non-obj.js fails
+built-ins/RegExp/prototype/sticky/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/sticky/this-val-regexp.js fails
+built-ins/RegExp/prototype/test/S15.10.6.3_A1_T22.js fails
+built-ins/RegExp/prototype/test/y-fail-lastindex-no-write.js fails
+built-ins/RegExp/prototype/test/y-fail-lastindex.js fails
+built-ins/RegExp/prototype/test/y-fail-return.js fails
+built-ins/RegExp/prototype/test/y-init-lastindex.js fails
+built-ins/RegExp/prototype/test/y-set-lastindex.js fails
+built-ins/RegExp/prototype/unicode/length.js fails
+built-ins/RegExp/prototype/unicode/name.js fails
+built-ins/RegExp/prototype/unicode/prop-desc.js fails
+built-ins/RegExp/prototype/unicode/this-val-invalid-obj.js fails
+built-ins/RegExp/prototype/unicode/this-val-non-obj.js fails
+built-ins/RegExp/prototype/unicode/this-val-regexp-prototype.js fails
+built-ins/RegExp/prototype/unicode/this-val-regexp.js fails
+built-ins/RegExp/u180e.js fails
+built-ins/RegExp/unicode_identity_escape.js fails
+built-ins/RegExp/valid-flags-y.js fails
+built-ins/Set/proto-from-ctor-realm.js fails
+built-ins/Set/prototype/add/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/clear/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/delete/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/entries/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/forEach/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/forEach/iterates-values-added-after-foreach-begins.js fails
+built-ins/Set/prototype/forEach/iterates-values-deleted-then-readded.js fails
+built-ins/Set/prototype/forEach/iterates-values-revisits-after-delete-re-add.js fails
+built-ins/Set/prototype/forEach/this-arg-explicit-cannot-override-lexical-this-arrow.js fails
+built-ins/Set/prototype/has/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/Set/prototype/values/does-not-have-setdata-internal-slot-weakset.js fails
+built-ins/SharedArrayBuffer/allocation-limit.js fails
+built-ins/SharedArrayBuffer/data-allocation-after-object-creation.js fails
+built-ins/SharedArrayBuffer/init-zero.js fails
+built-ins/SharedArrayBuffer/length-is-absent.js fails
+built-ins/SharedArrayBuffer/length-is-too-large-throws.js fails
+built-ins/SharedArrayBuffer/negative-length-throws.js fails
+built-ins/SharedArrayBuffer/newtarget-prototype-is-not-object.js fails
+built-ins/SharedArrayBuffer/proto-from-ctor-realm.js fails
+built-ins/SharedArrayBuffer/prototype-from-newtarget.js fails
+built-ins/SharedArrayBuffer/prototype/Symbol.toStringTag.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/invoked-as-accessor.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/invoked-as-func.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/length.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/name.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/prop-desc.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/return-bytelength.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/this-has-no-typedarrayname-internal.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/this-is-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/byteLength/this-is-not-object.js fails
+built-ins/SharedArrayBuffer/prototype/constructor.js fails
+built-ins/SharedArrayBuffer/prototype/slice/context-is-not-arraybuffer-object.js fails
+built-ins/SharedArrayBuffer/prototype/slice/context-is-not-object.js fails
+built-ins/SharedArrayBuffer/prototype/slice/descriptor.js fails
+built-ins/SharedArrayBuffer/prototype/slice/end-default-if-absent.js fails
+built-ins/SharedArrayBuffer/prototype/slice/end-default-if-undefined.js fails
+built-ins/SharedArrayBuffer/prototype/slice/end-exceeds-length.js fails
+built-ins/SharedArrayBuffer/prototype/slice/extensible.js fails
+built-ins/SharedArrayBuffer/prototype/slice/length.js fails
+built-ins/SharedArrayBuffer/prototype/slice/name.js fails
+built-ins/SharedArrayBuffer/prototype/slice/negative-end.js fails
+built-ins/SharedArrayBuffer/prototype/slice/negative-start.js fails
+built-ins/SharedArrayBuffer/prototype/slice/nonconstructor.js fails
+built-ins/SharedArrayBuffer/prototype/slice/number-conversion.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-constructor-is-not-object.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-constructor-is-undefined.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-is-not-constructor.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-is-not-object.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-is-null.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-is-undefined.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-returns-larger-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-returns-not-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-returns-same-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species-returns-smaller-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/slice/species.js fails
+built-ins/SharedArrayBuffer/prototype/slice/start-default-if-absent.js fails
+built-ins/SharedArrayBuffer/prototype/slice/start-default-if-undefined.js fails
+built-ins/SharedArrayBuffer/prototype/slice/start-exceeds-end.js fails
+built-ins/SharedArrayBuffer/prototype/slice/start-exceeds-length.js fails
+built-ins/SharedArrayBuffer/prototype/slice/this-is-arraybuffer.js fails
+built-ins/SharedArrayBuffer/prototype/slice/tointeger-conversion-end.js fails
+built-ins/SharedArrayBuffer/prototype/slice/tointeger-conversion-start.js fails
+built-ins/SharedArrayBuffer/return-abrupt-from-length-symbol.js fails
+built-ins/SharedArrayBuffer/return-abrupt-from-length.js fails
+built-ins/SharedArrayBuffer/toindex-length.js fails
+built-ins/SharedArrayBuffer/undefined-newtarget-throws.js fails
+built-ins/SharedArrayBuffer/zero-length.js fails
+built-ins/String/proto-from-ctor-realm.js fails
+built-ins/String/prototype/endsWith/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/includes/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/indexOf/position-tointeger-toprimitive.js fails
+built-ins/String/prototype/indexOf/position-tointeger.js fails
+built-ins/String/prototype/indexOf/searchstring-tostring-toprimitive.js fails
+built-ins/String/prototype/match/invoke-builtin-match.js fails
+built-ins/String/prototype/match/cstm-matcher-invocation.js fails
+built-ins/String/prototype/replace/cstm-replace-invocation.js fails
+built-ins/String/prototype/replace/this-value-not-obj-coercible.js fails
+built-ins/String/prototype/search/cstm-search-invocation.js fails
+built-ins/String/prototype/search/invoke-builtin-search-searcher-undef.js fails
+built-ins/String/prototype/search/invoke-builtin-search.js fails
+built-ins/String/prototype/slice/this-value-not-obj-coercible.js fails
+built-ins/String/prototype/split/cstm-split-invocation.js fails
+built-ins/String/prototype/startsWith/return-abrupt-from-searchstring-regexp-test.js fails
+built-ins/String/prototype/toLocaleLowerCase/Final_Sigma_U180E.js fails
+built-ins/String/prototype/toLocaleLowerCase/special_casing_conditional.js fails
+built-ins/String/prototype/toLowerCase/Final_Sigma_U180E.js fails
+built-ins/String/prototype/toLowerCase/special_casing_conditional.js fails
+built-ins/String/raw/length.js fails
+built-ins/String/raw/name.js fails
+built-ins/String/raw/raw.js fails
+built-ins/String/raw/return-empty-string-from-empty-array-length.js fails
+built-ins/String/raw/return-empty-string-if-length-is-negative-infinity.js fails
+built-ins/String/raw/return-empty-string-if-length-is-not-defined.js fails
+built-ins/String/raw/return-empty-string-if-length-is-undefined.js fails
+built-ins/String/raw/return-empty-string-if-length-is-zero-NaN.js fails
+built-ins/String/raw/return-empty-string-if-length-is-zero-boolean.js fails
+built-ins/String/raw/return-empty-string-if-length-is-zero-null.js fails
+built-ins/String/raw/return-empty-string-if-length-is-zero-or-less-number.js fails
+built-ins/String/raw/return-empty-string-if-length-is-zero-or-less-string.js fails
+built-ins/String/raw/return-the-string-value-from-template.js fails
+built-ins/String/raw/return-the-string-value.js fails
+built-ins/String/raw/returns-abrupt-from-next-key-toString.js fails
+built-ins/String/raw/returns-abrupt-from-next-key.js fails
+built-ins/String/raw/returns-abrupt-from-substitution.js fails
+built-ins/String/raw/special-characters.js fails
+built-ins/String/raw/substitutions-are-appended-on-same-index.js fails
+built-ins/String/raw/substitutions-are-limited-to-template-raw-length.js fails
+built-ins/String/raw/template-length-throws.js fails
+built-ins/String/raw/template-raw-throws.js fails
+built-ins/String/raw/template-substitutions-are-appended-on-same-index.js fails
+built-ins/String/raw/zero-literal-segments.js fails
+built-ins/Symbol/for/cross-realm.js fails
+built-ins/Symbol/hasInstance/cross-realm.js fails
+built-ins/Symbol/isConcatSpreadable/cross-realm.js fails
+built-ins/Symbol/iterator/cross-realm.js fails
+built-ins/Symbol/keyFor/cross-realm.js fails
+built-ins/Symbol/match/cross-realm.js fails
+built-ins/Symbol/replace/cross-realm.js fails
+built-ins/Symbol/search/cross-realm.js fails
+built-ins/Symbol/species/builtin-getter-name.js fails
+built-ins/Symbol/species/cross-realm.js fails
+built-ins/Symbol/species/subclassing.js fails
+built-ins/Symbol/split/cross-realm.js fails
+built-ins/Symbol/toPrimitive/cross-realm.js fails
+built-ins/Symbol/toStringTag/cross-realm.js fails
+built-ins/Symbol/unscopables/cross-realm.js fails
+built-ins/ThrowTypeError/distinct-cross-realm.js fails
+built-ins/TypedArray/from/arylk-get-length-error.js fails
+built-ins/TypedArray/from/arylk-to-length-error.js fails
+built-ins/TypedArray/from/iter-access-error.js fails
+built-ins/TypedArray/from/iter-invoke-error.js fails
+built-ins/TypedArray/from/iter-next-error.js fails
+built-ins/TypedArray/from/iter-next-value-error.js fails
+built-ins/TypedArray/from/length.js fails
+built-ins/TypedArray/from/name.js fails
+built-ins/TypedArray/from/prop-desc.js fails
+built-ins/TypedArray/name.js fails
+built-ins/TypedArray/of/length.js fails
+built-ins/TypedArray/of/name.js fails
+built-ins/TypedArray/of/prop-desc.js fails
+built-ins/TypedArray/prototype/Symbol.toStringTag/detached-buffer.js fails
+built-ins/TypedArray/prototype/buffer/detached-buffer.js fails
+built-ins/TypedArray/prototype/byteLength/detached-buffer.js fails
+built-ins/TypedArray/prototype/byteOffset/detached-buffer.js fails
+built-ins/TypedArray/prototype/constructor.js fails
+built-ins/TypedArray/prototype/copyWithin/bit-precision.js fails
+built-ins/TypedArray/prototype/copyWithin/coerced-values-end.js fails
+built-ins/TypedArray/prototype/copyWithin/coerced-values-start.js fails
+built-ins/TypedArray/prototype/copyWithin/coerced-values-target.js fails
+built-ins/TypedArray/prototype/copyWithin/detached-buffer.js fails
+built-ins/TypedArray/prototype/copyWithin/get-length-ignores-length-prop.js fails
+built-ins/TypedArray/prototype/copyWithin/invoked-as-func.js fails
+built-ins/TypedArray/prototype/copyWithin/invoked-as-method.js fails
+built-ins/TypedArray/prototype/copyWithin/length.js fails
+built-ins/TypedArray/prototype/copyWithin/name.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-end.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-out-of-bounds-end.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-out-of-bounds-start.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-out-of-bounds-target.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-start.js fails
+built-ins/TypedArray/prototype/copyWithin/negative-target.js fails
+built-ins/TypedArray/prototype/copyWithin/non-negative-out-of-bounds-end.js fails
+built-ins/TypedArray/prototype/copyWithin/non-negative-out-of-bounds-target-and-start.js fails
+built-ins/TypedArray/prototype/copyWithin/non-negative-target-and-start.js fails
+built-ins/TypedArray/prototype/copyWithin/non-negative-target-start-and-end.js fails
+built-ins/TypedArray/prototype/copyWithin/prop-desc.js fails
+built-ins/TypedArray/prototype/copyWithin/return-abrupt-from-end.js fails
+built-ins/TypedArray/prototype/copyWithin/return-abrupt-from-start.js fails
+built-ins/TypedArray/prototype/copyWithin/return-abrupt-from-target.js fails
+built-ins/TypedArray/prototype/copyWithin/return-this.js fails
+built-ins/TypedArray/prototype/copyWithin/undefined-end.js fails
+built-ins/TypedArray/prototype/entries/detached-buffer.js fails
+built-ins/TypedArray/prototype/every/callbackfn-arguments-with-thisarg.js fails
+built-ins/TypedArray/prototype/every/callbackfn-arguments-without-thisarg.js fails
+built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/every/callbackfn-no-interaction-over-non-integer.js fails
+built-ins/TypedArray/prototype/every/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/every/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/every/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/every/callbackfn-set-value-during-interaction.js fails
+built-ins/TypedArray/prototype/every/callbackfn-this.js fails
+built-ins/TypedArray/prototype/every/detached-buffer.js fails
+built-ins/TypedArray/prototype/every/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/every/invoked-as-func.js fails
+built-ins/TypedArray/prototype/every/invoked-as-method.js fails
+built-ins/TypedArray/prototype/every/length.js fails
+built-ins/TypedArray/prototype/every/name.js fails
+built-ins/TypedArray/prototype/every/prop-desc.js fails
+built-ins/TypedArray/prototype/every/returns-false-if-any-cb-returns-false.js fails
+built-ins/TypedArray/prototype/every/returns-true-if-every-cb-returns-true.js fails
+built-ins/TypedArray/prototype/every/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/fill/coerced-indexes.js fails
+built-ins/TypedArray/prototype/fill/detached-buffer.js fails
+built-ins/TypedArray/prototype/fill/fill-values-conversion-once.js fails
+built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails
+built-ins/TypedArray/prototype/fill/fill-values-conversion-operations.js fails
+built-ins/TypedArray/prototype/fill/fill-values-custom-start-and-end.js fails
+built-ins/TypedArray/prototype/fill/fill-values-non-numeric.js fails
+built-ins/TypedArray/prototype/fill/fill-values-relative-end.js fails
+built-ins/TypedArray/prototype/fill/fill-values-relative-start.js fails
+built-ins/TypedArray/prototype/fill/fill-values.js fails
+built-ins/TypedArray/prototype/fill/get-length-ignores-length-prop.js fails
+built-ins/TypedArray/prototype/fill/invoked-as-func.js fails
+built-ins/TypedArray/prototype/fill/invoked-as-method.js fails
+built-ins/TypedArray/prototype/fill/length.js fails
+built-ins/TypedArray/prototype/fill/name.js fails
+built-ins/TypedArray/prototype/fill/prop-desc.js fails
+built-ins/TypedArray/prototype/fill/return-abrupt-from-end.js fails
+built-ins/TypedArray/prototype/fill/return-abrupt-from-set-value.js fails
+built-ins/TypedArray/prototype/fill/return-abrupt-from-start.js fails
+built-ins/TypedArray/prototype/fill/return-this.js fails
+built-ins/TypedArray/prototype/filter/arraylength-internal.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-arguments-with-thisarg.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-arguments-without-thisarg.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-called-before-ctor.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-called-before-species.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-no-iteration-over-non-integer.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-set-value-during-iteration.js fails
+built-ins/TypedArray/prototype/filter/callbackfn-this.js fails
+built-ins/TypedArray/prototype/filter/detached-buffer.js fails
+built-ins/TypedArray/prototype/filter/invoked-as-func.js fails
+built-ins/TypedArray/prototype/filter/invoked-as-method.js fails
+built-ins/TypedArray/prototype/filter/length.js fails
+built-ins/TypedArray/prototype/filter/name.js fails
+built-ins/TypedArray/prototype/filter/prop-desc.js fails
+built-ins/TypedArray/prototype/filter/result-does-not-share-buffer.js fails
+built-ins/TypedArray/prototype/filter/result-empty-callbackfn-returns-false.js fails
+built-ins/TypedArray/prototype/filter/result-full-callbackfn-returns-true.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-ctor-abrupt.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-ctor-inherited.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-ctor.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-abrupt.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-custom-ctor-invocation.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-custom-ctor-length.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-custom-ctor-returns-another-instance.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-custom-ctor.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species-use-default-ctor.js fails
+built-ins/TypedArray/prototype/filter/speciesctor-get-species.js fails
+built-ins/TypedArray/prototype/filter/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/filter/values-are-set.js fails
+built-ins/TypedArray/prototype/find/detached-buffer.js fails
+built-ins/TypedArray/prototype/find/get-length-ignores-length-prop.js fails
+built-ins/TypedArray/prototype/find/invoked-as-func.js fails
+built-ins/TypedArray/prototype/find/invoked-as-method.js fails
+built-ins/TypedArray/prototype/find/length.js fails
+built-ins/TypedArray/prototype/find/name.js fails
+built-ins/TypedArray/prototype/find/predicate-call-changes-value.js fails
+built-ins/TypedArray/prototype/find/predicate-call-parameters.js fails
+built-ins/TypedArray/prototype/find/predicate-call-this-non-strict.js sloppyFails
+built-ins/TypedArray/prototype/find/predicate-call-this-strict.js strictFails
+built-ins/TypedArray/prototype/find/predicate-may-detach-buffer.js fails
+built-ins/TypedArray/prototype/find/predicate-not-called-on-empty-array.js fails
+built-ins/TypedArray/prototype/find/prop-desc.js fails
+built-ins/TypedArray/prototype/find/return-abrupt-from-predicate-call.js fails
+built-ins/TypedArray/prototype/find/return-found-value-predicate-result-is-true.js fails
+built-ins/TypedArray/prototype/find/return-undefined-if-predicate-returns-false-value.js fails
+built-ins/TypedArray/prototype/findIndex/detached-buffer.js fails
+built-ins/TypedArray/prototype/findIndex/get-length-ignores-length-prop.js fails
+built-ins/TypedArray/prototype/findIndex/invoked-as-func.js fails
+built-ins/TypedArray/prototype/findIndex/invoked-as-method.js fails
+built-ins/TypedArray/prototype/findIndex/length.js fails
+built-ins/TypedArray/prototype/findIndex/name.js fails
+built-ins/TypedArray/prototype/findIndex/predicate-call-changes-value.js fails
+built-ins/TypedArray/prototype/findIndex/predicate-call-parameters.js fails
+built-ins/TypedArray/prototype/findIndex/predicate-call-this-non-strict.js sloppyFails
+built-ins/TypedArray/prototype/findIndex/predicate-call-this-strict.js strictFails
+built-ins/TypedArray/prototype/findIndex/predicate-may-detach-buffer.js fails
+built-ins/TypedArray/prototype/findIndex/predicate-not-called-on-empty-array.js fails
+built-ins/TypedArray/prototype/findIndex/prop-desc.js fails
+built-ins/TypedArray/prototype/findIndex/return-abrupt-from-predicate-call.js fails
+built-ins/TypedArray/prototype/findIndex/return-index-predicate-result-is-true.js fails
+built-ins/TypedArray/prototype/findIndex/return-negative-one-if-predicate-returns-false-value.js fails
+built-ins/TypedArray/prototype/forEach/arraylength-internal.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-arguments-with-thisarg.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-arguments-without-thisarg.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-no-interaction-over-non-integer.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-set-value-during-interaction.js fails
+built-ins/TypedArray/prototype/forEach/callbackfn-this.js fails
+built-ins/TypedArray/prototype/forEach/detached-buffer.js fails
+built-ins/TypedArray/prototype/forEach/invoked-as-func.js fails
+built-ins/TypedArray/prototype/forEach/invoked-as-method.js fails
+built-ins/TypedArray/prototype/forEach/length.js fails
+built-ins/TypedArray/prototype/forEach/name.js fails
+built-ins/TypedArray/prototype/forEach/prop-desc.js fails
+built-ins/TypedArray/prototype/forEach/returns-undefined.js fails
+built-ins/TypedArray/prototype/forEach/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/includes/detached-buffer.js fails
+built-ins/TypedArray/prototype/includes/fromIndex-equal-or-greater-length-returns-false.js fails
+built-ins/TypedArray/prototype/includes/fromIndex-infinity.js fails
+built-ins/TypedArray/prototype/includes/fromIndex-minus-zero.js fails
+built-ins/TypedArray/prototype/includes/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/includes/invoked-as-func.js fails
+built-ins/TypedArray/prototype/includes/invoked-as-method.js fails
+built-ins/TypedArray/prototype/includes/length-zero-returns-false.js fails
+built-ins/TypedArray/prototype/includes/length.js fails
+built-ins/TypedArray/prototype/includes/name.js fails
+built-ins/TypedArray/prototype/includes/prop-desc.js fails
+built-ins/TypedArray/prototype/includes/return-abrupt-tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/includes/samevaluezero.js fails
+built-ins/TypedArray/prototype/includes/search-found-returns-true.js fails
+built-ins/TypedArray/prototype/includes/search-not-found-returns-false.js fails
+built-ins/TypedArray/prototype/includes/tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/indexOf/detached-buffer.js fails
+built-ins/TypedArray/prototype/indexOf/fromIndex-equal-or-greater-length-returns-minus-one.js fails
+built-ins/TypedArray/prototype/indexOf/fromIndex-infinity.js fails
+built-ins/TypedArray/prototype/indexOf/fromIndex-minus-zero.js fails
+built-ins/TypedArray/prototype/indexOf/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/indexOf/invoked-as-func.js fails
+built-ins/TypedArray/prototype/indexOf/invoked-as-method.js fails
+built-ins/TypedArray/prototype/indexOf/length-zero-returns-minus-one.js fails
+built-ins/TypedArray/prototype/indexOf/length.js fails
+built-ins/TypedArray/prototype/indexOf/name.js fails
+built-ins/TypedArray/prototype/indexOf/prop-desc.js fails
+built-ins/TypedArray/prototype/indexOf/return-abrupt-tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/indexOf/search-found-returns-index.js fails
+built-ins/TypedArray/prototype/indexOf/search-not-found-returns-minus-one.js fails
+built-ins/TypedArray/prototype/indexOf/strict-comparison.js fails
+built-ins/TypedArray/prototype/indexOf/tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/join/custom-separator-result-from-tostring-on-each-simple-value.js fails
+built-ins/TypedArray/prototype/join/custom-separator-result-from-tostring-on-each-value.js fails
+built-ins/TypedArray/prototype/join/detached-buffer.js fails
+built-ins/TypedArray/prototype/join/empty-instance-empty-string.js fails
+built-ins/TypedArray/prototype/join/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/join/invoked-as-func.js fails
+built-ins/TypedArray/prototype/join/invoked-as-method.js fails
+built-ins/TypedArray/prototype/join/length.js fails
+built-ins/TypedArray/prototype/join/name.js fails
+built-ins/TypedArray/prototype/join/prop-desc.js fails
+built-ins/TypedArray/prototype/join/result-from-tostring-on-each-simple-value.js fails
+built-ins/TypedArray/prototype/join/result-from-tostring-on-each-value.js fails
+built-ins/TypedArray/prototype/join/return-abrupt-from-separator.js fails
+built-ins/TypedArray/prototype/keys/detached-buffer.js fails
+built-ins/TypedArray/prototype/lastIndexOf/detached-buffer.js fails
+built-ins/TypedArray/prototype/lastIndexOf/fromIndex-infinity.js fails
+built-ins/TypedArray/prototype/lastIndexOf/fromIndex-minus-zero.js fails
+built-ins/TypedArray/prototype/lastIndexOf/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/lastIndexOf/invoked-as-func.js fails
+built-ins/TypedArray/prototype/lastIndexOf/invoked-as-method.js fails
+built-ins/TypedArray/prototype/lastIndexOf/length-zero-returns-minus-one.js fails
+built-ins/TypedArray/prototype/lastIndexOf/length.js fails
+built-ins/TypedArray/prototype/lastIndexOf/name.js fails
+built-ins/TypedArray/prototype/lastIndexOf/prop-desc.js fails
+built-ins/TypedArray/prototype/lastIndexOf/return-abrupt-tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/lastIndexOf/search-found-returns-index.js fails
+built-ins/TypedArray/prototype/lastIndexOf/search-not-found-returns-minus-one.js fails
+built-ins/TypedArray/prototype/lastIndexOf/strict-comparison.js fails
+built-ins/TypedArray/prototype/lastIndexOf/tointeger-fromindex.js fails
+built-ins/TypedArray/prototype/length/detached-buffer.js fails
+built-ins/TypedArray/prototype/map/arraylength-internal.js fails
+built-ins/TypedArray/prototype/map/callbackfn-arguments-with-thisarg.js fails
+built-ins/TypedArray/prototype/map/callbackfn-arguments-without-thisarg.js fails
+built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/map/callbackfn-no-interaction-over-non-integer-properties.js fails
+built-ins/TypedArray/prototype/map/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/map/callbackfn-return-affects-returned-object.js fails
+built-ins/TypedArray/prototype/map/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/map/callbackfn-return-does-not-copy-non-integer-properties.js fails
+built-ins/TypedArray/prototype/map/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/map/callbackfn-set-value-during-interaction.js fails
+built-ins/TypedArray/prototype/map/callbackfn-this.js fails
+built-ins/TypedArray/prototype/map/detached-buffer.js fails
+built-ins/TypedArray/prototype/map/invoked-as-func.js fails
+built-ins/TypedArray/prototype/map/invoked-as-method.js fails
+built-ins/TypedArray/prototype/map/length.js fails
+built-ins/TypedArray/prototype/map/name.js fails
+built-ins/TypedArray/prototype/map/prop-desc.js fails
+built-ins/TypedArray/prototype/map/return-new-typedarray-conversion-operation-consistent-nan.js fails
+built-ins/TypedArray/prototype/map/return-new-typedarray-conversion-operation.js fails
+built-ins/TypedArray/prototype/map/return-new-typedarray-from-empty-length.js fails
+built-ins/TypedArray/prototype/map/return-new-typedarray-from-positive-length.js fails
+built-ins/TypedArray/prototype/map/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-arguments-custom-accumulator.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-arguments-default-accumulator.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-no-iteration-over-non-integer-properties.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-set-value-during-iteration.js fails
+built-ins/TypedArray/prototype/reduce/callbackfn-this.js fails
+built-ins/TypedArray/prototype/reduce/detached-buffer.js fails
+built-ins/TypedArray/prototype/reduce/empty-instance-return-initialvalue.js fails
+built-ins/TypedArray/prototype/reduce/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/reduce/invoked-as-func.js fails
+built-ins/TypedArray/prototype/reduce/invoked-as-method.js fails
+built-ins/TypedArray/prototype/reduce/length.js fails
+built-ins/TypedArray/prototype/reduce/name.js fails
+built-ins/TypedArray/prototype/reduce/prop-desc.js fails
+built-ins/TypedArray/prototype/reduce/result-is-last-callbackfn-return.js fails
+built-ins/TypedArray/prototype/reduce/result-of-any-type.js fails
+built-ins/TypedArray/prototype/reduce/return-first-value-without-callbackfn.js fails
+built-ins/TypedArray/prototype/reduce/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-arguments-custom-accumulator.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-arguments-default-accumulator.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-no-iteration-over-non-integer-properties.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-set-value-during-iteration.js fails
+built-ins/TypedArray/prototype/reduceRight/callbackfn-this.js fails
+built-ins/TypedArray/prototype/reduceRight/detached-buffer.js fails
+built-ins/TypedArray/prototype/reduceRight/empty-instance-return-initialvalue.js fails
+built-ins/TypedArray/prototype/reduceRight/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/reduceRight/invoked-as-func.js fails
+built-ins/TypedArray/prototype/reduceRight/invoked-as-method.js fails
+built-ins/TypedArray/prototype/reduceRight/length.js fails
+built-ins/TypedArray/prototype/reduceRight/name.js fails
+built-ins/TypedArray/prototype/reduceRight/prop-desc.js fails
+built-ins/TypedArray/prototype/reduceRight/result-is-last-callbackfn-return.js fails
+built-ins/TypedArray/prototype/reduceRight/result-of-any-type.js fails
+built-ins/TypedArray/prototype/reduceRight/return-first-value-without-callbackfn.js fails
+built-ins/TypedArray/prototype/reduceRight/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/reverse/detached-buffer.js fails
+built-ins/TypedArray/prototype/reverse/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/reverse/invoked-as-func.js fails
+built-ins/TypedArray/prototype/reverse/invoked-as-method.js fails
+built-ins/TypedArray/prototype/reverse/length.js fails
+built-ins/TypedArray/prototype/reverse/name.js fails
+built-ins/TypedArray/prototype/reverse/preserves-non-numeric-properties.js fails
+built-ins/TypedArray/prototype/reverse/prop-desc.js fails
+built-ins/TypedArray/prototype/reverse/returns-original-object.js fails
+built-ins/TypedArray/prototype/reverse/reverts.js fails
+built-ins/TypedArray/prototype/set/array-arg-set-values-in-order.js fails
+built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js fails
+built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-tointeger-offset-throws.js fails
+built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-throws.js fails
+built-ins/TypedArray/prototype/set/typedarray-arg-srcbuffer-detached-during-tointeger-offset-throws.js fails
+built-ins/TypedArray/prototype/set/typedarray-arg-targetbuffer-detached-during-tointeger-offset-throws.js fails
+built-ins/TypedArray/prototype/slice/arraylength-internal.js fails
+built-ins/TypedArray/prototype/slice/bit-precision.js fails
+built-ins/TypedArray/prototype/slice/detached-buffer-zero-count-custom-ctor-other-targettype.js fails
+built-ins/TypedArray/prototype/slice/detached-buffer-zero-count-custom-ctor-same-targettype.js fails
+built-ins/TypedArray/prototype/slice/detached-buffer.js fails
+built-ins/TypedArray/prototype/slice/infinity.js fails
+built-ins/TypedArray/prototype/slice/invoked-as-func.js fails
+built-ins/TypedArray/prototype/slice/invoked-as-method.js fails
+built-ins/TypedArray/prototype/slice/length.js fails
+built-ins/TypedArray/prototype/slice/minus-zero.js fails
+built-ins/TypedArray/prototype/slice/name.js fails
+built-ins/TypedArray/prototype/slice/prop-desc.js fails
+built-ins/TypedArray/prototype/slice/result-does-not-copy-ordinary-properties.js fails
+built-ins/TypedArray/prototype/slice/results-with-different-length.js fails
+built-ins/TypedArray/prototype/slice/results-with-empty-length.js fails
+built-ins/TypedArray/prototype/slice/results-with-same-length.js fails
+built-ins/TypedArray/prototype/slice/return-abrupt-from-end.js fails
+built-ins/TypedArray/prototype/slice/return-abrupt-from-start.js fails
+built-ins/TypedArray/prototype/slice/set-values-from-different-ctor-type.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-ctor-abrupt.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-ctor-inherited.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-ctor.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-abrupt.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-custom-ctor-invocation.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-custom-ctor-length.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-custom-ctor-returns-another-instance.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-custom-ctor.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species-use-default-ctor.js fails
+built-ins/TypedArray/prototype/slice/speciesctor-get-species.js fails
+built-ins/TypedArray/prototype/slice/tointeger-end.js fails
+built-ins/TypedArray/prototype/slice/tointeger-start.js fails
+built-ins/TypedArray/prototype/some/callbackfn-arguments-with-thisarg.js fails
+built-ins/TypedArray/prototype/some/callbackfn-arguments-without-thisarg.js fails
+built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js fails
+built-ins/TypedArray/prototype/some/callbackfn-no-interaction-over-non-integer.js fails
+built-ins/TypedArray/prototype/some/callbackfn-not-called-on-empty.js fails
+built-ins/TypedArray/prototype/some/callbackfn-return-does-not-change-instance.js fails
+built-ins/TypedArray/prototype/some/callbackfn-returns-abrupt.js fails
+built-ins/TypedArray/prototype/some/callbackfn-set-value-during-interaction.js fails
+built-ins/TypedArray/prototype/some/callbackfn-this.js fails
+built-ins/TypedArray/prototype/some/detached-buffer.js fails
+built-ins/TypedArray/prototype/some/get-length-uses-internal-arraylength.js fails
+built-ins/TypedArray/prototype/some/invoked-as-func.js fails
+built-ins/TypedArray/prototype/some/invoked-as-method.js fails
+built-ins/TypedArray/prototype/some/length.js fails
+built-ins/TypedArray/prototype/some/name.js fails
+built-ins/TypedArray/prototype/some/prop-desc.js fails
+built-ins/TypedArray/prototype/some/returns-false-if-every-cb-returns-false.js fails
+built-ins/TypedArray/prototype/some/returns-true-if-any-cb-returns-true.js fails
+built-ins/TypedArray/prototype/some/values-are-not-cached.js fails
+built-ins/TypedArray/prototype/sort/arraylength-internal.js fails
+built-ins/TypedArray/prototype/sort/comparefn-call-throws.js fails
+built-ins/TypedArray/prototype/sort/comparefn-calls.js fails
+built-ins/TypedArray/prototype/sort/detached-buffer-comparefn.js fails
+built-ins/TypedArray/prototype/sort/detached-buffer.js fails
+built-ins/TypedArray/prototype/sort/invoked-as-func.js fails
+built-ins/TypedArray/prototype/sort/invoked-as-method.js fails
+built-ins/TypedArray/prototype/sort/length.js fails
+built-ins/TypedArray/prototype/sort/name.js fails
+built-ins/TypedArray/prototype/sort/prop-desc.js fails
+built-ins/TypedArray/prototype/sort/return-same-instance.js fails
+built-ins/TypedArray/prototype/sort/sortcompare-with-no-tostring.js fails
+built-ins/TypedArray/prototype/sort/sorted-values-nan.js fails
+built-ins/TypedArray/prototype/sort/sorted-values.js fails
+built-ins/TypedArray/prototype/subarray/detached-buffer.js fails
+built-ins/TypedArray/prototype/subarray/length.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-ctor-inherited.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-ctor.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species-abrupt.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species-custom-ctor-invocation.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species-custom-ctor-returns-another-instance.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species-custom-ctor.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species-use-default-ctor.js fails
+built-ins/TypedArray/prototype/subarray/speciesctor-get-species.js fails
+built-ins/TypedArray/prototype/toLocaleString/calls-tolocalestring-from-each-value.js fails
+built-ins/TypedArray/prototype/toLocaleString/calls-tostring-from-each-value.js fails
+built-ins/TypedArray/prototype/toLocaleString/calls-valueof-from-each-value.js fails
+built-ins/TypedArray/prototype/toLocaleString/detached-buffer.js fails
+built-ins/TypedArray/prototype/toLocaleString/empty-instance-returns-empty-string.js fails
+built-ins/TypedArray/prototype/toLocaleString/invoked-as-method.js fails
+built-ins/TypedArray/prototype/toLocaleString/prop-desc.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-tolocalestring.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-tostring.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-valueof.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-tolocalestring.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-tostring.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-valueof.js fails
+built-ins/TypedArray/prototype/toLocaleString/return-result.js fails
+built-ins/TypedArray/prototype/toLocaleString/this-is-not-object.js fails
+built-ins/TypedArray/prototype/toLocaleString/this-is-not-typedarray-instance.js fails
+built-ins/TypedArray/prototype/toString.js fails
+built-ins/TypedArray/prototype/toString/detached-buffer.js fails
+built-ins/TypedArray/prototype/values/detached-buffer.js fails
+built-ins/TypedArrays/ctors/buffer-arg/byteoffset-to-number-detachbuffer.js fails
+built-ins/TypedArrays/ctors/buffer-arg/custom-proto-access-throws.js fails
+built-ins/TypedArrays/ctors/buffer-arg/defined-negative-length.js fails
+built-ins/TypedArrays/ctors/buffer-arg/detachedbuffer.js fails
+built-ins/TypedArrays/ctors/buffer-arg/length-to-number-detachbuffer.js fails
+built-ins/TypedArrays/ctors/buffer-arg/proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/buffer-arg/use-custom-proto-if-object.js fails
+built-ins/TypedArrays/ctors/length-arg/custom-proto-access-throws.js fails
+built-ins/TypedArrays/ctors/length-arg/proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/length-arg/use-custom-proto-if-object.js fails
+built-ins/TypedArrays/ctors/no-args/custom-proto-access-throws.js fails
+built-ins/TypedArrays/ctors/no-args/proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/no-args/use-custom-proto-if-object.js fails
+built-ins/TypedArrays/ctors/object-arg/as-generator-iterable-returns.js fails
+built-ins/TypedArrays/ctors/object-arg/custom-proto-access-throws.js fails
+built-ins/TypedArrays/ctors/object-arg/iterator-not-callable-throws.js fails
+built-ins/TypedArrays/ctors/object-arg/proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/object-arg/use-custom-proto-if-object.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/custom-proto-access-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-different-type.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/detached-when-species-retrieved-same-type.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species-proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-custom-species.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-not-object-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-not-ctor-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/other-ctor-buffer-ctor-species-prototype-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom-proto-from-ctor-realm.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-custom.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-not-ctor.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-species-prototype-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/same-ctor-buffer-ctor-value-not-obj-throws.js fails
+built-ins/TypedArrays/ctors/typedarray-arg/use-custom-proto-if-object.js fails
+built-ins/TypedArrays/from/arylk-get-length-error.js fails
+built-ins/TypedArrays/from/arylk-to-length-error.js fails
+built-ins/TypedArrays/from/custom-ctor-returns-other-instance.js fails
+built-ins/TypedArrays/from/custom-ctor.js fails
+built-ins/TypedArrays/from/iter-access-error.js fails
+built-ins/TypedArrays/from/iter-invoke-error.js fails
+built-ins/TypedArrays/from/iter-next-error.js fails
+built-ins/TypedArrays/from/iter-next-value-error.js fails
+built-ins/TypedArrays/from/mapfn-abrupt-completion.js fails
+built-ins/TypedArrays/from/mapfn-arguments.js fails
+built-ins/TypedArrays/from/mapfn-this-with-thisarg.js fails
+built-ins/TypedArrays/from/mapfn-this-without-thisarg-non-strict.js sloppyFails
+built-ins/TypedArrays/from/mapfn-this-without-thisarg-strict.js strictFails
+built-ins/TypedArrays/from/nan-conversion.js fails
+built-ins/TypedArrays/from/new-instance-empty.js fails
+built-ins/TypedArrays/from/new-instance-from-ordinary-object.js fails
+built-ins/TypedArrays/from/new-instance-from-sparse-array.js fails
+built-ins/TypedArrays/from/new-instance-from-zero.js fails
+built-ins/TypedArrays/from/new-instance-using-custom-ctor.js fails
+built-ins/TypedArrays/from/new-instance-with-mapfn.js fails
+built-ins/TypedArrays/from/new-instance-without-mapfn.js fails
+built-ins/TypedArrays/from/property-abrupt-completion.js fails
+built-ins/TypedArrays/from/set-value-abrupt-completion.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/conversion-operation-consistent-nan.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/conversion-operation.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer-realm.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/detached-buffer.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-greater-than-last-index.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-lower-than-zero.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-minus-zero.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-not-integer.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-accessor-desc.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-configurable.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-not-enumerable.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex-desc-not-writable.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/key-is-numericindex.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/set-value.js fails
+built-ins/TypedArrays/internals/DefineOwnProperty/tonumber-value-detached-buffer.js fails
+built-ins/TypedArrays/internals/Get/detached-buffer-key-is-not-numeric-index.js fails
+built-ins/TypedArrays/internals/Get/detached-buffer-key-is-symbol.js fails
+built-ins/TypedArrays/internals/Get/detached-buffer-realm.js fails
+built-ins/TypedArrays/internals/Get/detached-buffer.js fails
+built-ins/TypedArrays/internals/Get/infinity-detached-buffer.js fails
+built-ins/TypedArrays/internals/Get/key-is-not-integer.js fails
+built-ins/TypedArrays/internals/Get/key-is-not-minus-zero.js fails
+built-ins/TypedArrays/internals/Get/key-is-out-of-bounds.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer-key-is-not-number.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer-key-is-symbol.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer-realm.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/detached-buffer.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/enumerate-detached-buffer.js fails
+built-ins/TypedArrays/internals/GetOwnProperty/index-prop-desc.js fails
+built-ins/TypedArrays/internals/HasProperty/abrupt-from-ordinary-has-parent-hasproperty.js fails
+built-ins/TypedArrays/internals/HasProperty/detached-buffer-key-is-not-number.js fails
+built-ins/TypedArrays/internals/HasProperty/detached-buffer-key-is-symbol.js fails
+built-ins/TypedArrays/internals/HasProperty/detached-buffer-realm.js fails
+built-ins/TypedArrays/internals/HasProperty/detached-buffer.js fails
+built-ins/TypedArrays/internals/HasProperty/infinity-with-detached-buffer.js sloppyFails
+built-ins/TypedArrays/internals/HasProperty/key-is-lower-than-zero.js fails
+built-ins/TypedArrays/internals/HasProperty/key-is-minus-zero.js fails
+built-ins/TypedArrays/internals/HasProperty/key-is-not-integer.js fails
+built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes-and-string-and-symbol-keys-.js fails
+built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes-and-string-keys.js fails
+built-ins/TypedArrays/internals/OwnPropertyKeys/integer-indexes.js fails
+built-ins/TypedArrays/internals/OwnPropertyKeys/not-enumerable-keys.js fails
+built-ins/TypedArrays/internals/Set/detached-buffer-key-is-not-numeric-index.js fails
+built-ins/TypedArrays/internals/Set/detached-buffer-key-is-symbol.js fails
+built-ins/TypedArrays/internals/Set/detached-buffer-realm.js fails
+built-ins/TypedArrays/internals/Set/detached-buffer.js fails
+built-ins/TypedArrays/internals/Set/indexed-value.js fails
+built-ins/TypedArrays/internals/Set/key-is-minus-zero.js fails
+built-ins/TypedArrays/internals/Set/key-is-not-canonical-index.js fails
+built-ins/TypedArrays/internals/Set/key-is-not-integer.js fails
+built-ins/TypedArrays/internals/Set/key-is-not-numeric-index.js fails
+built-ins/TypedArrays/internals/Set/key-is-out-of-bounds.js fails
+built-ins/TypedArrays/internals/Set/key-is-symbol.js fails
+built-ins/TypedArrays/internals/Set/tonumber-value-detached-buffer.js fails
+built-ins/TypedArrays/internals/Set/tonumber-value-throws.js strictFails
+built-ins/TypedArrays/of/argument-number-value-throws.js fails
+built-ins/TypedArrays/of/custom-ctor-returns-other-instance.js fails
+built-ins/TypedArrays/of/custom-ctor.js fails
+built-ins/TypedArrays/of/nan-conversion.js fails
+built-ins/TypedArrays/of/new-instance-empty.js fails
+built-ins/TypedArrays/of/new-instance-from-zero.js fails
+built-ins/TypedArrays/of/new-instance-using-custom-ctor.js fails
+built-ins/TypedArrays/of/new-instance.js fails
+built-ins/WeakMap/constructor.js fails
+built-ins/WeakMap/empty-iterable.js fails
+built-ins/WeakMap/get-set-method-failure.js fails
+built-ins/WeakMap/iterable-failure.js fails
+built-ins/WeakMap/iterable.js fails
+built-ins/WeakMap/iterator-close-after-set-failure.js fails
+built-ins/WeakMap/iterator-item-first-entry-returns-abrupt.js fails
+built-ins/WeakMap/iterator-item-second-entry-returns-abrupt.js fails
+built-ins/WeakMap/iterator-items-are-not-object-close-iterator.js fails
+built-ins/WeakMap/iterator-items-are-not-object.js fails
+built-ins/WeakMap/iterator-next-failure.js fails
+built-ins/WeakMap/iterator-value-failure.js fails
+built-ins/WeakMap/length.js fails
+built-ins/WeakMap/name.js fails
+built-ins/WeakMap/no-iterable.js fails
+built-ins/WeakMap/properties-of-map-instances.js fails
+built-ins/WeakMap/properties-of-the-weakmap-prototype-object.js fails
+built-ins/WeakMap/proto-from-ctor-realm.js fails
+built-ins/WeakMap/prototype-of-weakmap.js fails
+built-ins/WeakMap/prototype/Symbol.toStringTag.js fails
+built-ins/WeakMap/prototype/constructor.js fails
+built-ins/WeakMap/prototype/delete/delete-entry-initial-iterable.js fails
+built-ins/WeakMap/prototype/delete/delete-entry.js fails
+built-ins/WeakMap/prototype/delete/delete.js fails
+built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-array.js fails
+built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-map.js fails
+built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-object.js fails
+built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-set.js fails
+built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
+built-ins/WeakMap/prototype/delete/length.js fails
+built-ins/WeakMap/prototype/delete/name.js fails
+built-ins/WeakMap/prototype/delete/returns-false-value-is-not-object.js fails
+built-ins/WeakMap/prototype/delete/returns-false-when-delete-is-noop.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-boolean.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-null.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-number.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-string.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-symbol.js fails
+built-ins/WeakMap/prototype/delete/this-not-object-throw-undefined.js fails
+built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-map.js fails
+built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-set.js fails
+built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot.js fails
+built-ins/WeakMap/prototype/get/get.js fails
+built-ins/WeakMap/prototype/get/length.js fails
+built-ins/WeakMap/prototype/get/name.js fails
+built-ins/WeakMap/prototype/get/returns-undefined-key-is-not-object.js fails
+built-ins/WeakMap/prototype/get/returns-undefined.js fails
+built-ins/WeakMap/prototype/get/returns-value.js fails
+built-ins/WeakMap/prototype/get/this-not-object-throw.js fails
+built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-array.js fails
+built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-map.js fails
+built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-object.js fails
+built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-set.js fails
+built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
+built-ins/WeakMap/prototype/has/has.js fails
+built-ins/WeakMap/prototype/has/length.js fails
+built-ins/WeakMap/prototype/has/name.js fails
+built-ins/WeakMap/prototype/has/returns-false-when-value-is-not-object.js fails
+built-ins/WeakMap/prototype/has/returns-false-when-value-not-present.js fails
+built-ins/WeakMap/prototype/has/returns-true-when-value-present.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-boolean.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-null.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-number.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-string.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-symbol.js fails
+built-ins/WeakMap/prototype/has/this-not-object-throw-undefined.js fails
+built-ins/WeakMap/prototype/prototype-attributes.js fails
+built-ins/WeakMap/prototype/set/adds-element.js fails
+built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-array.js fails
+built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-map.js fails
+built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-object.js fails
+built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-set.js fails
+built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
+built-ins/WeakMap/prototype/set/key-not-object-throw.js fails
+built-ins/WeakMap/prototype/set/length.js fails
+built-ins/WeakMap/prototype/set/name.js fails
+built-ins/WeakMap/prototype/set/returns-this-when-ignoring-duplicate.js fails
+built-ins/WeakMap/prototype/set/returns-this.js fails
+built-ins/WeakMap/prototype/set/set.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-boolean.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-null.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-number.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-string.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-symbol.js fails
+built-ins/WeakMap/prototype/set/this-not-object-throw-undefined.js fails
+built-ins/WeakMap/set-not-callable-throws.js fails
+built-ins/WeakMap/undefined-newtarget.js fails
+built-ins/WeakMap/weakmap.js fails
+built-ins/WeakSet/add-not-callable-throws.js fails
+built-ins/WeakSet/constructor.js fails
+built-ins/WeakSet/empty-iterable.js fails
+built-ins/WeakSet/get-add-method-failure.js fails
+built-ins/WeakSet/iterable-failure.js fails
+built-ins/WeakSet/iterable.js fails
+built-ins/WeakSet/iterator-close-after-add-failure.js fails
+built-ins/WeakSet/iterator-next-failure.js fails
+built-ins/WeakSet/iterator-value-failure.js fails
+built-ins/WeakSet/length.js fails
+built-ins/WeakSet/name.js fails
+built-ins/WeakSet/no-iterable.js fails
+built-ins/WeakSet/properties-of-the-weakset-prototype-object.js fails
+built-ins/WeakSet/proto-from-ctor-realm.js fails
+built-ins/WeakSet/prototype-of-weakset.js fails
+built-ins/WeakSet/prototype/Symbol.toStringTag.js fails
+built-ins/WeakSet/prototype/add/add.js fails
+built-ins/WeakSet/prototype/add/adds-element.js fails
+built-ins/WeakSet/prototype/add/does-not-have-weaksetdata-internal-slot-array.js fails
+built-ins/WeakSet/prototype/add/does-not-have-weaksetdata-internal-slot-map.js fails
+built-ins/WeakSet/prototype/add/does-not-have-weaksetdata-internal-slot-object.js fails
+built-ins/WeakSet/prototype/add/does-not-have-weaksetdata-internal-slot-set.js fails
+built-ins/WeakSet/prototype/add/does-not-have-weaksetdata-internal-slot-weakset-prototype.js fails
+built-ins/WeakSet/prototype/add/length.js fails
+built-ins/WeakSet/prototype/add/name.js fails
+built-ins/WeakSet/prototype/add/returns-this-when-ignoring-duplicate.js fails
+built-ins/WeakSet/prototype/add/returns-this.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-boolean.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-null.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-number.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-string.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-symbol.js fails
+built-ins/WeakSet/prototype/add/this-not-object-throw-undefined.js fails
+built-ins/WeakSet/prototype/add/value-not-object-throw.js fails
+built-ins/WeakSet/prototype/constructor/weakset-prototype-constructor-intrinsic.js fails
+built-ins/WeakSet/prototype/constructor/weakset-prototype-constructor.js fails
+built-ins/WeakSet/prototype/delete/delete-entry-initial-iterable.js fails
+built-ins/WeakSet/prototype/delete/delete-entry.js fails
+built-ins/WeakSet/prototype/delete/delete.js fails
+built-ins/WeakSet/prototype/delete/does-not-have-weaksetdata-internal-slot-array.js fails
+built-ins/WeakSet/prototype/delete/does-not-have-weaksetdata-internal-slot-map.js fails
+built-ins/WeakSet/prototype/delete/does-not-have-weaksetdata-internal-slot-object.js fails
+built-ins/WeakSet/prototype/delete/does-not-have-weaksetdata-internal-slot-set.js fails
+built-ins/WeakSet/prototype/delete/does-not-have-weaksetdata-internal-slot-weakset-prototype.js fails
+built-ins/WeakSet/prototype/delete/length.js fails
+built-ins/WeakSet/prototype/delete/name.js fails
+built-ins/WeakSet/prototype/delete/returns-false-value-is-not-object.js fails
+built-ins/WeakSet/prototype/delete/returns-false-when-delete-is-noop.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-boolean.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-null.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-number.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-string.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-symbol.js fails
+built-ins/WeakSet/prototype/delete/this-not-object-throw-undefined.js fails
+built-ins/WeakSet/prototype/has/does-not-have-weaksetdata-internal-slot-array.js fails
+built-ins/WeakSet/prototype/has/does-not-have-weaksetdata-internal-slot-map.js fails
+built-ins/WeakSet/prototype/has/does-not-have-weaksetdata-internal-slot-object.js fails
+built-ins/WeakSet/prototype/has/does-not-have-weaksetdata-internal-slot-set.js fails
+built-ins/WeakSet/prototype/has/does-not-have-weaksetdata-internal-slot-weakset-prototype.js fails
+built-ins/WeakSet/prototype/has/has.js fails
+built-ins/WeakSet/prototype/has/length.js fails
+built-ins/WeakSet/prototype/has/name.js fails
+built-ins/WeakSet/prototype/has/returns-false-when-value-is-not-object.js fails
+built-ins/WeakSet/prototype/has/returns-false-when-value-not-present.js fails
+built-ins/WeakSet/prototype/has/returns-true-when-value-present.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-boolean.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-null.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-number.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-string.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-symbol.js fails
+built-ins/WeakSet/prototype/has/this-not-object-throw-undefined.js fails
+built-ins/WeakSet/prototype/prototype-attributes.js fails
+built-ins/WeakSet/symbol-disallowed-as-weakset-key.js fails
+built-ins/WeakSet/undefined-newtarget.js fails
+built-ins/WeakSet/weakset.js fails
+built-ins/eval/length-non-configurable.js fails
+built-ins/global/global-object.js fails
+built-ins/global/property-descriptor.js fails
+built-ins/isFinite/toprimitive-not-callable-throws.js fails
+built-ins/isNaN/toprimitive-not-callable-throws.js fails
+language/arguments-object/cls-decl-gen-meth-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-decl-gen-meth-args-trailing-comma-null.js fails
+language/arguments-object/cls-decl-gen-meth-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-decl-gen-meth-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-decl-gen-meth-static-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-decl-gen-meth-static-args-trailing-comma-null.js fails
+language/arguments-object/cls-decl-gen-meth-static-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-decl-gen-meth-static-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-decl-meth-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-decl-meth-args-trailing-comma-null.js fails
+language/arguments-object/cls-decl-meth-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-decl-meth-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-decl-meth-static-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-decl-meth-static-args-trailing-comma-null.js fails
+language/arguments-object/cls-decl-meth-static-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-decl-meth-static-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-expr-gen-meth-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-expr-gen-meth-args-trailing-comma-null.js fails
+language/arguments-object/cls-expr-gen-meth-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-expr-gen-meth-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-expr-gen-meth-static-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-expr-gen-meth-static-args-trailing-comma-null.js fails
+language/arguments-object/cls-expr-gen-meth-static-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-expr-gen-meth-static-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-expr-meth-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-expr-meth-args-trailing-comma-null.js fails
+language/arguments-object/cls-expr-meth-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-expr-meth-args-trailing-comma-undefined.js fails
+language/arguments-object/cls-expr-meth-static-args-trailing-comma-multiple.js fails
+language/arguments-object/cls-expr-meth-static-args-trailing-comma-null.js fails
+language/arguments-object/cls-expr-meth-static-args-trailing-comma-single-args.js fails
+language/arguments-object/cls-expr-meth-static-args-trailing-comma-undefined.js fails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js sloppyFails
+language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-descriptors-set-value-by-arguments.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-descriptors-set-value-with-define-property.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-descriptors-with-param-assign.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-param.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-nonwritable-descriptors-set-by-arguments.js sloppyFails
+language/arguments-object/mapped/nonconfigurable-nonwritable-descriptors-set-by-param.js sloppyFails
+language/arguments-object/mapped/nonwritable-nonconfigurable-descriptors-set-by-arguments.js sloppyFails
+language/computed-property-names/class/accessor/getter-duplicates.js fails
+language/computed-property-names/class/accessor/getter.js fails
+language/computed-property-names/class/accessor/setter-duplicates.js fails
+language/computed-property-names/class/accessor/setter.js fails
+language/computed-property-names/class/method/constructor-can-be-generator.js fails
+language/computed-property-names/class/method/constructor-can-be-getter.js fails
+language/computed-property-names/class/method/constructor-can-be-setter.js fails
+language/computed-property-names/class/method/constructor-duplicate-1.js fails
+language/computed-property-names/class/method/constructor-duplicate-2.js fails
+language/computed-property-names/class/method/constructor-duplicate-3.js fails
+language/computed-property-names/class/method/constructor.js fails
+language/computed-property-names/class/method/generator.js fails
+language/computed-property-names/class/method/number.js fails
+language/computed-property-names/class/method/string.js fails
+language/computed-property-names/class/method/symbol.js fails
+language/computed-property-names/class/static/generator-constructor.js fails
+language/computed-property-names/class/static/generator-prototype.js fails
+language/computed-property-names/class/static/getter-constructor.js fails
+language/computed-property-names/class/static/getter-prototype.js fails
+language/computed-property-names/class/static/method-constructor.js fails
+language/computed-property-names/class/static/method-number.js fails
+language/computed-property-names/class/static/method-prototype.js fails
+language/computed-property-names/class/static/method-string.js fails
+language/computed-property-names/class/static/method-symbol.js fails
+language/computed-property-names/class/static/setter-constructor.js fails
+language/computed-property-names/class/static/setter-prototype.js fails
+language/computed-property-names/object/accessor/getter-super.js fails
+language/computed-property-names/object/accessor/setter-super.js fails
+language/computed-property-names/object/method/super.js fails
+language/computed-property-names/to-name-side-effects/class.js fails
+language/computed-property-names/to-name-side-effects/numbers-class.js fails
+language/eval-code/direct/lex-env-distinct-cls.js fails
+language/eval-code/direct/lex-env-no-init-cls.js fails
+language/eval-code/direct/lex-env-no-init-const.js fails
+language/eval-code/direct/lex-env-no-init-let.js fails
+language/eval-code/direct/new.target-fn.js fails
+language/eval-code/direct/non-definable-function-with-function.js sloppyFails
+language/eval-code/direct/non-definable-function-with-variable.js sloppyFails
+language/eval-code/direct/non-definable-global-function.js sloppyFails
+language/eval-code/direct/non-definable-global-generator.js sloppyFails
+language/eval-code/direct/super-prop-method.js fails
+language/eval-code/direct/this-value-func-strict-source.js sloppyFails
+language/eval-code/direct/var-env-func-init-global-update-configurable.js sloppyFails
+language/eval-code/direct/var-env-global-lex-non-strict.js sloppyFails
+language/eval-code/direct/var-env-lower-lex-catch-non-strict.js sloppyFails
+language/eval-code/direct/var-env-lower-lex-non-strict.js sloppyFails
+language/eval-code/indirect/always-non-strict.js strictFails
+language/eval-code/indirect/lex-env-distinct-cls.js fails
+language/eval-code/indirect/lex-env-no-init-cls.js fails
+language/eval-code/indirect/lex-env-no-init-const.js fails
+language/eval-code/indirect/lex-env-no-init-let.js fails
+language/eval-code/indirect/non-definable-function-with-function.js sloppyFails
+language/eval-code/indirect/non-definable-function-with-variable.js sloppyFails
+language/eval-code/indirect/non-definable-global-function.js fails
+language/eval-code/indirect/non-definable-global-generator.js fails
+language/eval-code/indirect/realm.js fails
+language/eval-code/indirect/this-value-func.js strictFails
+language/eval-code/indirect/var-env-func-init-global-new.js strictFails
+language/eval-code/indirect/var-env-func-init-global-update-configurable.js fails
+language/eval-code/indirect/var-env-func-init-multi.js strictFails
+language/eval-code/indirect/var-env-func-non-strict.js strictFails
+language/eval-code/indirect/var-env-global-lex-non-strict.js fails
+language/eval-code/indirect/var-env-var-init-global-exstng.js strictFails
+language/eval-code/indirect/var-env-var-init-global-new.js strictFails
+language/eval-code/indirect/var-env-var-non-strict.js strictFails
+language/expressions/arrow-function/cannot-override-this-with-thisArg.js fails
+language/expressions/arrow-function/dflt-params-ref-later.js fails
+language/expressions/arrow-function/dflt-params-ref-self.js fails
+language/expressions/arrow-function/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/arrow-function/dstr-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/arrow-function/dstr-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/arrow-function/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/arrow-function/lexical-arguments.js fails
+language/expressions/arrow-function/lexical-new.target-closure-returned.js fails
+language/expressions/arrow-function/lexical-new.target.js fails
+language/expressions/arrow-function/lexical-super-call-from-within-constructor.js fails
+language/expressions/arrow-function/lexical-super-property-from-within-constructor.js fails
+language/expressions/arrow-function/lexical-super-property.js fails
+language/expressions/arrow-function/lexical-supercall-from-immediately-invoked-arrow.js fails
+language/expressions/arrow-function/lexical-this.js fails
+language/expressions/arrow-function/prototype-rules.js fails
+language/expressions/arrow-function/scope-body-lex-distinct.js sloppyFails
+language/expressions/arrow-function/scope-param-elem-var-close.js sloppyFails
+language/expressions/arrow-function/scope-param-elem-var-open.js sloppyFails
+language/expressions/arrow-function/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/arrow-function/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/arrow-function/scope-paramsbody-var-open.js fails
+language/expressions/arrow-function/throw-new.js fails
+language/expressions/assignment/S11.13.1_A5_T1.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T2.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T3.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T4.js sloppyFails
+language/expressions/assignment/S11.13.1_A5_T5.js fails
+language/expressions/assignment/S11.13.1_A6_T1.js sloppyFails
+language/expressions/assignment/S11.13.1_A6_T2.js sloppyFails
+language/expressions/assignment/S11.13.1_A6_T3.js sloppyFails
+language/expressions/assignment/S11.13.1_A7_T1.js fails
+language/expressions/assignment/S11.13.1_A7_T2.js fails
+language/expressions/assignment/S11.13.1_A7_T3.js fails
+language/expressions/assignment/destructuring/iterator-destructuring-property-reference-target-evaluation-order.js fails
+language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order.js fails
+language/expressions/assignment/dstr-array-elem-init-fn-name-class.js fails
+language/expressions/assignment/dstr-array-elem-init-let.js fails
+language/expressions/assignment/dstr-array-elem-iter-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-elem-iter-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-elem-iter-rtrn-close.js fails
+language/expressions/assignment/dstr-array-elem-iter-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-iter-thrw-close.js fails
+language/expressions/assignment/dstr-array-elem-put-const.js fails
+language/expressions/assignment/dstr-array-elem-put-let.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-rtrn-close.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-list-thrw-close.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-rtrn-close.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-elem-trlg-iter-rest-thrw-close.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close-err.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close-null.js fails
+language/expressions/assignment/dstr-array-rest-iter-rtrn-close.js fails
+language/expressions/assignment/dstr-array-rest-iter-thrw-close-err.js fails
+language/expressions/assignment/dstr-array-rest-iter-thrw-close.js fails
+language/expressions/assignment/dstr-array-rest-lref-err.js fails
+language/expressions/assignment/dstr-array-rest-put-const.js fails
+language/expressions/assignment/dstr-array-rest-put-let.js fails
+language/expressions/assignment/dstr-obj-empty-null.js fails
+language/expressions/assignment/dstr-obj-empty-undef.js fails
+language/expressions/assignment/dstr-obj-id-init-fn-name-class.js fails
+language/expressions/assignment/dstr-obj-id-init-let.js fails
+language/expressions/assignment/dstr-obj-id-put-const.js fails
+language/expressions/assignment/dstr-obj-id-put-let.js fails
+language/expressions/assignment/dstr-obj-prop-elem-init-fn-name-class.js fails
+language/expressions/assignment/dstr-obj-prop-elem-init-let.js fails
+language/expressions/assignment/dstr-obj-prop-put-const.js fails
+language/expressions/assignment/dstr-obj-prop-put-let.js fails
+language/expressions/assignment/fn-name-class.js fails
+language/expressions/assignment/fn-name-lhs-cover.js fails
+language/expressions/assignment/fn-name-lhs-member.js fails
+language/expressions/async-function/expression-returns-promise.js fails
+language/expressions/async-function/syntax-expression-is-PrimaryExpression.js fails
+language/expressions/await/await-BindingIdentifier-in-global.js fails
+language/expressions/await/await-in-nested-function.js fails
+language/expressions/await/await-in-nested-generator.js fails
+language/expressions/await/await-throws-rejections.js fails
+language/expressions/call/11.2.3-3_3.js fails
+language/expressions/call/eval-realm-indirect.js sloppyFails
+language/expressions/call/eval-spread-empty-leading.js fails
+language/expressions/call/eval-spread-empty-trailing.js fails
+language/expressions/call/eval-spread.js fails
+language/expressions/call/scope-lex-open.js fails
+language/expressions/call/tco-call-args.js strictFails
+language/expressions/call/tco-cross-realm-class-construct.js fails
+language/expressions/call/tco-cross-realm-class-derived-construct.js fails
+language/expressions/call/tco-cross-realm-fun-call.js fails
+language/expressions/call/tco-cross-realm-fun-construct.js fails
+language/expressions/call/tco-member-args.js strictFails
+language/expressions/call/tco-non-eval-function-dynamic.js sloppyFails
+language/expressions/call/tco-non-eval-function.js sloppyFails
+language/expressions/call/tco-non-eval-global.js sloppyFails
+language/expressions/call/tco-non-eval-with.js sloppyFails
+language/expressions/class/accessor-name-inst-computed-err-evaluation.js fails
+language/expressions/class/accessor-name-inst-computed-err-to-prop-key.js fails
+language/expressions/class/accessor-name-inst-computed-err-unresolvable.js fails
+language/expressions/class/accessor-name-inst-computed-in.js fails
+language/expressions/class/accessor-name-inst-computed-yield-expr.js fails
+language/expressions/class/accessor-name-inst-computed.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-binary.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-exponent.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-hex.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-leading-decimal.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-non-canonical.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-octal.js fails
+language/expressions/class/accessor-name-inst-literal-numeric-zero.js fails
+language/expressions/class/accessor-name-inst-literal-string-char-escape.js fails
+language/expressions/class/accessor-name-inst-literal-string-double-quote.js fails
+language/expressions/class/accessor-name-inst-literal-string-empty.js fails
+language/expressions/class/accessor-name-inst-literal-string-hex-escape.js fails
+language/expressions/class/accessor-name-inst-literal-string-line-continuation.js fails
+language/expressions/class/accessor-name-inst-literal-string-single-quote.js fails
+language/expressions/class/accessor-name-inst-literal-string-unicode-escape.js fails
+language/expressions/class/accessor-name-static-computed-err-evaluation.js fails
+language/expressions/class/accessor-name-static-computed-err-to-prop-key.js fails
+language/expressions/class/accessor-name-static-computed-err-unresolvable.js fails
+language/expressions/class/accessor-name-static-computed-in.js fails
+language/expressions/class/accessor-name-static-computed-yield-expr.js fails
+language/expressions/class/accessor-name-static-computed.js fails
+language/expressions/class/accessor-name-static-literal-numeric-binary.js fails
+language/expressions/class/accessor-name-static-literal-numeric-exponent.js fails
+language/expressions/class/accessor-name-static-literal-numeric-hex.js fails
+language/expressions/class/accessor-name-static-literal-numeric-leading-decimal.js fails
+language/expressions/class/accessor-name-static-literal-numeric-non-canonical.js fails
+language/expressions/class/accessor-name-static-literal-numeric-octal.js fails
+language/expressions/class/accessor-name-static-literal-numeric-zero.js fails
+language/expressions/class/accessor-name-static-literal-string-char-escape.js fails
+language/expressions/class/accessor-name-static-literal-string-double-quote.js fails
+language/expressions/class/accessor-name-static-literal-string-empty.js fails
+language/expressions/class/accessor-name-static-literal-string-hex-escape.js fails
+language/expressions/class/accessor-name-static-literal-string-line-continuation.js fails
+language/expressions/class/accessor-name-static-literal-string-single-quote.js fails
+language/expressions/class/accessor-name-static-literal-string-unicode-escape.js fails
+language/expressions/class/dstr-gen-meth-ary-init-iter-close.js fails
+language/expressions/class/dstr-gen-meth-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-gen-meth-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-gen-meth-ary-name-iter-val.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-elision.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-gen-meth-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-init-iter-close.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-name-iter-val.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-elision.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-init-null.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-init-undefined.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-gen-meth-obj-init-null.js fails
+language/expressions/class/dstr-gen-meth-obj-init-undefined.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-gen-meth-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-gen-meth-static-ary-init-iter-close.js fails
+language/expressions/class/dstr-gen-meth-static-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-gen-meth-static-ary-name-iter-val.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-elision.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-gen-meth-static-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-init-iter-close.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-name-iter-val.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-elision.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-init-null.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-init-undefined.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-gen-meth-static-obj-init-null.js fails
+language/expressions/class/dstr-gen-meth-static-obj-init-undefined.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-empty.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-gen-meth-static-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-meth-ary-init-iter-close.js fails
+language/expressions/class/dstr-meth-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-meth-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-meth-ary-name-iter-val.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-elision.js fails
+language/expressions/class/dstr-meth-ary-ptrn-empty.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-meth-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-meth-dflt-ary-init-iter-close.js fails
+language/expressions/class/dstr-meth-dflt-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-meth-dflt-ary-name-iter-val.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-elision.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-empty.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-meth-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-meth-dflt-obj-init-null.js fails
+language/expressions/class/dstr-meth-dflt-obj-init-undefined.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-empty.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-meth-dflt-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-meth-obj-init-null.js fails
+language/expressions/class/dstr-meth-obj-init-undefined.js fails
+language/expressions/class/dstr-meth-obj-ptrn-empty.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-meth-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-meth-static-ary-init-iter-close.js fails
+language/expressions/class/dstr-meth-static-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-meth-static-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-meth-static-ary-name-iter-val.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-elision.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-empty.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-meth-static-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-init-iter-close.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-init-iter-get-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-init-iter-no-close.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-name-iter-val.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-id.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elision-exhausted.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elision-step-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-elision.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-empty.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-elem.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-elision.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-empty.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-rest.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id-elision.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-id.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-obj-id.js fails
+language/expressions/class/dstr-meth-static-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-init-null.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-init-undefined.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-empty.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-meth-static-dflt-obj-ptrn-prop-obj.js fails
+language/expressions/class/dstr-meth-static-obj-init-null.js fails
+language/expressions/class/dstr-meth-static-obj-init-undefined.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-empty.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-get-value-err.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-fn-name-arrow.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-fn-name-cover.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-fn-name-fn.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-fn-name-gen.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-list-err.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-ary-init.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-ary-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-ary-value-null.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-ary.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-eval-err.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-get-value-err.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-init-skipped.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-init-throws.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-init-unresolvable.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-init.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id-trailing-comma.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-id.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-obj-init.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-obj-value-null.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-obj-value-undef.js fails
+language/expressions/class/dstr-meth-static-obj-ptrn-prop-obj.js fails
+language/expressions/class/gen-meth-dflt-params-abrupt.js fails
+language/expressions/class/gen-meth-dflt-params-arg-val-not-undefined.js fails
+language/expressions/class/gen-meth-dflt-params-arg-val-undefined.js fails
+language/expressions/class/gen-meth-dflt-params-ref-later.js fails
+language/expressions/class/gen-meth-dflt-params-ref-prior.js fails
+language/expressions/class/gen-meth-dflt-params-ref-self.js fails
+language/expressions/class/gen-meth-dflt-params-trailing-comma.js fails
+language/expressions/class/gen-meth-params-trailing-comma-multiple.js fails
+language/expressions/class/gen-meth-params-trailing-comma-single.js fails
+language/expressions/class/gen-meth-static-dflt-params-abrupt.js fails
+language/expressions/class/gen-meth-static-dflt-params-arg-val-not-undefined.js fails
+language/expressions/class/gen-meth-static-dflt-params-arg-val-undefined.js fails
+language/expressions/class/gen-meth-static-dflt-params-ref-later.js fails
+language/expressions/class/gen-meth-static-dflt-params-ref-prior.js fails
+language/expressions/class/gen-meth-static-dflt-params-ref-self.js fails
+language/expressions/class/gen-meth-static-dflt-params-trailing-comma.js fails
+language/expressions/class/gen-meth-static-params-trailing-comma-multiple.js fails
+language/expressions/class/gen-meth-static-params-trailing-comma-single.js fails
+language/expressions/class/gen-method-length-dflt.js fails
+language/expressions/class/gen-method-static-yield-spread-arr-multiple.js fails
+language/expressions/class/gen-method-static-yield-spread-arr-single.js fails
+language/expressions/class/gen-method-yield-spread-arr-multiple.js fails
+language/expressions/class/gen-method-yield-spread-arr-single.js fails
+language/expressions/class/meth-dflt-params-abrupt.js fails
+language/expressions/class/meth-dflt-params-arg-val-not-undefined.js fails
+language/expressions/class/meth-dflt-params-arg-val-undefined.js fails
+language/expressions/class/meth-dflt-params-ref-later.js fails
+language/expressions/class/meth-dflt-params-ref-prior.js fails
+language/expressions/class/meth-dflt-params-ref-self.js fails
+language/expressions/class/meth-dflt-params-trailing-comma.js fails
+language/expressions/class/meth-params-trailing-comma-multiple.js fails
+language/expressions/class/meth-params-trailing-comma-single.js fails
+language/expressions/class/meth-static-dflt-params-abrupt.js fails
+language/expressions/class/meth-static-dflt-params-arg-val-not-undefined.js fails
+language/expressions/class/meth-static-dflt-params-arg-val-undefined.js fails
+language/expressions/class/meth-static-dflt-params-ref-later.js fails
+language/expressions/class/meth-static-dflt-params-ref-prior.js fails
+language/expressions/class/meth-static-dflt-params-ref-self.js fails
+language/expressions/class/meth-static-dflt-params-trailing-comma.js fails
+language/expressions/class/meth-static-params-trailing-comma-multiple.js fails
+language/expressions/class/meth-static-params-trailing-comma-single.js fails
+language/expressions/class/method-length-dflt.js fails
+language/expressions/class/name.js fails
+language/expressions/class/params-dflt-gen-meth-args-unmapped.js fails
+language/expressions/class/params-dflt-gen-meth-ref-arguments.js fails
+language/expressions/class/params-dflt-gen-meth-static-args-unmapped.js fails
+language/expressions/class/params-dflt-gen-meth-static-ref-arguments.js fails
+language/expressions/class/params-dflt-meth-args-unmapped.js fails
+language/expressions/class/params-dflt-meth-ref-arguments.js fails
+language/expressions/class/params-dflt-meth-static-args-unmapped.js fails
+language/expressions/class/params-dflt-meth-static-ref-arguments.js fails
+language/expressions/class/restricted-properties.js fails
+language/expressions/class/scope-gen-meth-paramsbody-var-close.js fails
+language/expressions/class/scope-gen-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-meth-paramsbody-var-close.js fails
+language/expressions/class/scope-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-name-lex-close.js fails
+language/expressions/class/scope-name-lex-open-heritage.js fails
+language/expressions/class/scope-name-lex-open-no-heritage.js fails
+language/expressions/class/scope-setter-paramsbody-var-close.js fails
+language/expressions/class/scope-setter-paramsbody-var-open.js fails
+language/expressions/class/scope-static-gen-meth-paramsbody-var-close.js fails
+language/expressions/class/scope-static-gen-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-static-meth-paramsbody-var-close.js fails
+language/expressions/class/scope-static-meth-paramsbody-var-open.js fails
+language/expressions/class/scope-static-setter-paramsbody-var-close.js fails
+language/expressions/class/scope-static-setter-paramsbody-var-open.js fails
+language/expressions/class/setter-length-dflt.js fails
+language/expressions/class/static-method-length-dflt.js fails
+language/expressions/comma/tco-final.js strictFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.10_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.11_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.11_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.1_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.1_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.2_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.2_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.3_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.3_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.4_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.4_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.5_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.5_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.6_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.6_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.7_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.7_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.8_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.8_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A5.9_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T2.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T3.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T4.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A5.9_T5.js fails
+language/expressions/compound-assignment/S11.13.2_A6.10_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.11_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.1_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.2_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.3_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.4_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.5_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.6_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.7_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.8_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A6.9_T1.js sloppyFails
+language/expressions/compound-assignment/S11.13.2_A7.10_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.11_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.1_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.2_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.3_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.4_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.5_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.6_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.7_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.8_T4.js fails
+language/expressions/compound-assignment/S11.13.2_A7.9_T4.js fails
+language/expressions/conditional/tco-cond.js strictFails
+language/expressions/conditional/tco-pos.js strictFails
+language/expressions/delete/super-property.js fails
+language/expressions/function/arguments-with-arguments-fn.js sloppyFails
+language/expressions/function/arguments-with-arguments-lex.js sloppyFails
+language/expressions/function/dflt-params-ref-later.js fails
+language/expressions/function/dflt-params-ref-self.js fails
+language/expressions/function/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/function/dstr-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/function/dstr-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/function/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/function/name.js fails
+language/expressions/function/param-dflt-yield-non-strict.js sloppyFails
+language/expressions/function/scope-body-lex-distinct.js sloppyFails
+language/expressions/function/scope-name-var-open-non-strict.js sloppyFails
+language/expressions/function/scope-name-var-open-strict.js strictFails
+language/expressions/function/scope-param-elem-var-close.js sloppyFails
+language/expressions/function/scope-param-elem-var-open.js sloppyFails
+language/expressions/function/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/function/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/function/scope-paramsbody-var-open.js fails
+language/expressions/generators/arguments-with-arguments-fn.js sloppyFails
+language/expressions/generators/arguments-with-arguments-lex.js sloppyFails
+language/expressions/generators/default-proto.js fails
+language/expressions/generators/dflt-params-ref-later.js fails
+language/expressions/generators/dflt-params-ref-self.js fails
+language/expressions/generators/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/generators/dstr-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/generators/dstr-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/generators/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/generators/eval-body-proto-realm.js fails
+language/expressions/generators/name.js fails
+language/expressions/generators/named-yield-identifier-non-strict.js sloppyFails
+language/expressions/generators/scope-body-lex-distinct.js sloppyFails
+language/expressions/generators/scope-name-var-open-non-strict.js sloppyFails
+language/expressions/generators/scope-name-var-open-strict.js strictFails
+language/expressions/generators/scope-param-elem-var-close.js sloppyFails
+language/expressions/generators/scope-param-elem-var-open.js sloppyFails
+language/expressions/generators/scope-param-rest-elem-var-close.js sloppyFails
+language/expressions/generators/scope-param-rest-elem-var-open.js sloppyFails
+language/expressions/generators/scope-paramsbody-var-open.js fails
+language/expressions/generators/yield-as-function-expression-binding-identifier.js sloppyFails
+language/expressions/generators/yield-as-identifier-in-nested-function.js sloppyFails
+language/expressions/generators/yield-as-literal-property-name.js fails
+language/expressions/generators/yield-as-property-name.js fails
+language/expressions/generators/yield-identifier-non-strict.js sloppyFails
+language/expressions/generators/yield-star-before-newline.js fails
+language/expressions/instanceof/prototype-getter-with-object-throws.js fails
+language/expressions/instanceof/prototype-getter-with-object.js fails
+language/expressions/logical-and/tco-right.js strictFails
+language/expressions/logical-or/tco-right.js strictFails
+language/expressions/new.target/asi.js fails
+language/expressions/new.target/value-via-call.js fails
+language/expressions/new.target/value-via-fpapply.js fails
+language/expressions/new.target/value-via-fpcall.js fails
+language/expressions/new.target/value-via-member.js fails
+language/expressions/new.target/value-via-new.js fails
+language/expressions/new.target/value-via-reflect-apply.js fails
+language/expressions/new.target/value-via-reflect-construct.js fails
+language/expressions/new.target/value-via-super-call.js fails
+language/expressions/new.target/value-via-super-property.js fails
+language/expressions/new.target/value-via-tagged-template.js fails
+language/expressions/new/non-ctor-err-realm.js fails
+language/expressions/object/concise-generator.js fails
+language/expressions/object/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/object/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/object/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/object/dstr-gen-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/object/dstr-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/object/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/expressions/object/dstr-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/object/dstr-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/expressions/object/fn-name-accessor-get.js fails
+language/expressions/object/fn-name-accessor-set.js fails
+language/expressions/object/fn-name-arrow.js fails
+language/expressions/object/fn-name-class.js fails
+language/expressions/object/fn-name-cover.js fails
+language/expressions/object/fn-name-fn.js fails
+language/expressions/object/fn-name-gen.js fails
+language/expressions/object/getter-super-prop.js fails
+language/expressions/object/let-non-strict-access.js sloppyFails
+language/expressions/object/let-non-strict-syntax.js sloppyFails
+language/expressions/object/method-definition/fn-name-fn.js fails
+language/expressions/object/method-definition/fn-name-gen.js fails
+language/expressions/object/method-definition/gen-meth-dflt-params-ref-later.js fails
+language/expressions/object/method-definition/gen-meth-dflt-params-ref-self.js fails
+language/expressions/object/method-definition/gen-yield-identifier-non-strict.js sloppyFails
+language/expressions/object/method-definition/generator-name-prop-symbol.js fails
+language/expressions/object/method-definition/generator-super-prop-body.js fails
+language/expressions/object/method-definition/generator-super-prop-param.js fails
+language/expressions/object/method-definition/meth-dflt-params-ref-later.js fails
+language/expressions/object/method-definition/meth-dflt-params-ref-self.js fails
+language/expressions/object/method-definition/name-invoke-ctor.js fails
+language/expressions/object/method-definition/name-name-prop-symbol.js fails
+language/expressions/object/method-definition/name-prototype-prop.js fails
+language/expressions/object/method-definition/name-super-prop-body.js fails
+language/expressions/object/method-definition/name-super-prop-param.js fails
+language/expressions/object/method-definition/object-method-returns-promise.js fails
+language/expressions/object/method-definition/yield-as-function-expression-binding-identifier.js sloppyFails
+language/expressions/object/method-definition/yield-as-identifier-in-nested-function.js sloppyFails
+language/expressions/object/method-definition/yield-as-literal-property-name.js fails
+language/expressions/object/method-definition/yield-as-property-name.js fails
+language/expressions/object/method-definition/yield-star-before-newline.js fails
+language/expressions/object/method.js fails
+language/expressions/object/prop-def-id-eval-error-2.js sloppyFails
+language/expressions/object/properties-names-eval-arguments.js strictFails
+language/expressions/object/scope-gen-meth-body-lex-distinct.js sloppyFails
+language/expressions/object/scope-gen-meth-param-elem-var-close.js sloppyFails
+language/expressions/object/scope-gen-meth-param-elem-var-open.js sloppyFails
+language/expressions/object/scope-gen-meth-param-rest-elem-var-close.js sloppyFails
+language/expressions/object/scope-gen-meth-param-rest-elem-var-open.js sloppyFails
+language/expressions/object/scope-gen-meth-paramsbody-var-open.js fails
+language/expressions/object/scope-getter-body-lex-distinc.js sloppyFails
+language/expressions/object/scope-meth-body-lex-distinct.js sloppyFails
+language/expressions/object/scope-meth-param-elem-var-close.js sloppyFails
+language/expressions/object/scope-meth-param-elem-var-open.js sloppyFails
+language/expressions/object/scope-meth-param-rest-elem-var-close.js sloppyFails
+language/expressions/object/scope-meth-param-rest-elem-var-open.js sloppyFails
+language/expressions/object/scope-meth-paramsbody-var-open.js fails
+language/expressions/object/scope-setter-body-lex-distinc.js sloppyFails
+language/expressions/object/scope-setter-paramsbody-var-open.js fails
+language/expressions/object/setter-super-prop.js fails
+language/expressions/postfix-decrement/S11.3.2_A5_T1.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T2.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T3.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T4.js sloppyFails
+language/expressions/postfix-decrement/S11.3.2_A5_T5.js fails
+language/expressions/postfix-decrement/S11.3.2_A6_T3.js fails
+language/expressions/postfix-increment/S11.3.1_A5_T1.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T2.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T3.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T4.js sloppyFails
+language/expressions/postfix-increment/S11.3.1_A5_T5.js fails
+language/expressions/postfix-increment/S11.3.1_A6_T3.js fails
+language/expressions/prefix-decrement/S11.4.5_A5_T1.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T2.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T3.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T4.js sloppyFails
+language/expressions/prefix-decrement/S11.4.5_A5_T5.js fails
+language/expressions/prefix-decrement/S11.4.5_A6_T3.js fails
+language/expressions/prefix-increment/S11.4.4_A5_T1.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T2.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails
+language/expressions/prefix-increment/S11.4.4_A5_T5.js fails
+language/expressions/prefix-increment/S11.4.4_A6_T3.js fails
+language/expressions/super/call-arg-evaluation-err.js fails
+language/expressions/super/call-bind-this-value-twice.js fails
+language/expressions/super/call-bind-this-value.js fails
+language/expressions/super/call-construct-error.js fails
+language/expressions/super/call-construct-invocation.js fails
+language/expressions/super/call-expr-value.js fails
+language/expressions/super/call-proto-not-ctor.js fails
+language/expressions/super/call-spread-err-mult-err-expr-throws.js fails
+language/expressions/super/call-spread-err-mult-err-iter-get-value.js fails
+language/expressions/super/call-spread-err-mult-err-itr-get-call.js fails
+language/expressions/super/call-spread-err-mult-err-itr-get-get.js fails
+language/expressions/super/call-spread-err-mult-err-itr-step.js fails
+language/expressions/super/call-spread-err-mult-err-itr-value.js fails
+language/expressions/super/call-spread-err-mult-err-unresolvable.js fails
+language/expressions/super/call-spread-err-sngl-err-expr-throws.js fails
+language/expressions/super/call-spread-err-sngl-err-itr-get-call.js fails
+language/expressions/super/call-spread-err-sngl-err-itr-get-get.js fails
+language/expressions/super/call-spread-err-sngl-err-itr-get-value.js fails
+language/expressions/super/call-spread-err-sngl-err-itr-step.js fails
+language/expressions/super/call-spread-err-sngl-err-itr-value.js fails
+language/expressions/super/call-spread-err-sngl-err-unresolvable.js fails
+language/expressions/super/call-spread-mult-empty.js fails
+language/expressions/super/call-spread-mult-expr.js fails
+language/expressions/super/call-spread-mult-iter.js fails
+language/expressions/super/call-spread-mult-literal.js fails
+language/expressions/super/call-spread-sngl-empty.js fails
+language/expressions/super/call-spread-sngl-expr.js fails
+language/expressions/super/call-spread-sngl-iter.js fails
+language/expressions/super/call-spread-sngl-literal.js fails
+language/expressions/super/prop-dot-cls-null-proto.js fails
+language/expressions/super/prop-dot-cls-ref-strict.js fails
+language/expressions/super/prop-dot-cls-ref-this.js fails
+language/expressions/super/prop-dot-cls-this-uninit.js fails
+language/expressions/super/prop-dot-cls-val-from-arrow.js fails
+language/expressions/super/prop-dot-cls-val-from-eval.js fails
+language/expressions/super/prop-dot-cls-val.js fails
+language/expressions/super/prop-dot-obj-null-proto.js fails
+language/expressions/super/prop-dot-obj-ref-non-strict.js sloppyFails
+language/expressions/super/prop-dot-obj-ref-strict.js strictFails
+language/expressions/super/prop-dot-obj-ref-this.js fails
+language/expressions/super/prop-dot-obj-val-from-arrow.js fails
+language/expressions/super/prop-dot-obj-val-from-eval.js fails
+language/expressions/super/prop-dot-obj-val.js fails
+language/expressions/super/prop-expr-cls-err.js fails
+language/expressions/super/prop-expr-cls-key-err.js fails
+language/expressions/super/prop-expr-cls-null-proto.js fails
+language/expressions/super/prop-expr-cls-ref-strict.js fails
+language/expressions/super/prop-expr-cls-ref-this.js fails
+language/expressions/super/prop-expr-cls-this-uninit.js fails
+language/expressions/super/prop-expr-cls-unresolvable.js fails
+language/expressions/super/prop-expr-cls-val-from-arrow.js fails
+language/expressions/super/prop-expr-cls-val-from-eval.js fails
+language/expressions/super/prop-expr-cls-val.js fails
+language/expressions/super/prop-expr-obj-err.js fails
+language/expressions/super/prop-expr-obj-key-err.js fails
+language/expressions/super/prop-expr-obj-null-proto.js fails
+language/expressions/super/prop-expr-obj-ref-non-strict.js sloppyFails
+language/expressions/super/prop-expr-obj-ref-strict.js strictFails
+language/expressions/super/prop-expr-obj-ref-this.js fails
+language/expressions/super/prop-expr-obj-unresolvable.js fails
+language/expressions/super/prop-expr-obj-val-from-arrow.js fails
+language/expressions/super/prop-expr-obj-val-from-eval.js fails
+language/expressions/super/prop-expr-obj-val.js fails
+language/expressions/super/realm.js fails
+language/expressions/tagged-template/cache-different-functions-same-site.js fails
+language/expressions/tagged-template/cache-eval-inner-function.js fails
+language/expressions/tagged-template/cache-realm.js fails
+language/expressions/tagged-template/cache-same-site-top-level.js fails
+language/expressions/tagged-template/cache-same-site.js fails
+language/expressions/tagged-template/invalid-escape-sequences.js fails
+language/expressions/tagged-template/tco-call.js strictFails
+language/expressions/tagged-template/tco-member.js strictFails
+language/expressions/tagged-template/template-object-frozen-non-strict.js sloppyFails
+language/expressions/tagged-template/template-object-frozen-strict.js strictFails
+language/expressions/tagged-template/template-object.js fails
+language/expressions/tco-pos.js strictFails
+language/expressions/template-literal/tv-character-escape-sequence.js fails
+language/expressions/template-literal/tv-hex-escape-sequence.js fails
+language/expressions/template-literal/tv-line-continuation.js fails
+language/expressions/template-literal/tv-line-terminator-sequence.js fails
+language/expressions/template-literal/tv-no-substitution.js fails
+language/expressions/template-literal/tv-null-character-escape-sequence.js fails
+language/expressions/template-literal/tv-template-character.js fails
+language/expressions/template-literal/tv-template-characters.js fails
+language/expressions/template-literal/tv-template-head.js fails
+language/expressions/template-literal/tv-template-middle.js fails
+language/expressions/template-literal/tv-template-tail.js fails
+language/expressions/template-literal/tv-utf16-escape-sequence.js fails
+language/expressions/template-literal/tv-zwnbsp.js fails
+language/expressions/yield/star-array.js fails
+language/expressions/yield/star-in-rltn-expr.js fails
+language/expressions/yield/star-iterable.js fails
+language/expressions/yield/star-rhs-iter-get-call-err.js fails
+language/expressions/yield/star-rhs-iter-get-call-non-obj.js fails
+language/expressions/yield/star-rhs-iter-get-get-err.js fails
+language/expressions/yield/star-rhs-iter-nrml-next-call-err.js fails
+language/expressions/yield/star-rhs-iter-nrml-next-call-non-obj.js fails
+language/expressions/yield/star-rhs-iter-nrml-next-get-err.js fails
+language/expressions/yield/star-rhs-iter-nrml-next-invoke.js fails
+language/expressions/yield/star-rhs-iter-nrml-res-done-err.js fails
+language/expressions/yield/star-rhs-iter-nrml-res-done-no-value.js fails
+language/expressions/yield/star-rhs-iter-nrml-res-value-err.js fails
+language/expressions/yield/star-rhs-iter-nrml-res-value-final.js fails
+language/expressions/yield/star-rhs-iter-rtrn-no-rtrn.js fails
+language/expressions/yield/star-rhs-iter-rtrn-res-done-err.js fails
+language/expressions/yield/star-rhs-iter-rtrn-res-done-no-value.js fails
+language/expressions/yield/star-rhs-iter-rtrn-res-value-err.js fails
+language/expressions/yield/star-rhs-iter-rtrn-res-value-final.js fails
+language/expressions/yield/star-rhs-iter-rtrn-rtrn-call-err.js fails
+language/expressions/yield/star-rhs-iter-rtrn-rtrn-call-non-obj.js fails
+language/expressions/yield/star-rhs-iter-rtrn-rtrn-get-err.js fails
+language/expressions/yield/star-rhs-iter-rtrn-rtrn-invoke.js fails
+language/expressions/yield/star-rhs-iter-thrw-res-done-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-res-done-no-value.js fails
+language/expressions/yield/star-rhs-iter-thrw-res-value-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-res-value-final.js fails
+language/expressions/yield/star-rhs-iter-thrw-thrw-call-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-thrw-call-non-obj.js fails
+language/expressions/yield/star-rhs-iter-thrw-thrw-get-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-thrw-invoke.js fails
+language/expressions/yield/star-rhs-iter-thrw-violation-no-rtrn.js fails
+language/expressions/yield/star-rhs-iter-thrw-violation-rtrn-call-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-violation-rtrn-call-non-obj.js fails
+language/expressions/yield/star-rhs-iter-thrw-violation-rtrn-get-err.js fails
+language/expressions/yield/star-rhs-iter-thrw-violation-rtrn-invoke.js fails
+language/expressions/yield/star-rhs-unresolvable.js fails
+language/expressions/yield/star-string.js fails
+language/function-code/each-param-has-own-non-shared-eval-scope.js sloppyFails
+language/function-code/each-param-has-own-scope.js sloppyFails
+language/function-code/eval-param-env-with-computed-key.js sloppyFails
+language/function-code/eval-param-env-with-prop-initializer.js sloppyFails
+language/global-code/decl-lex-deletion.js sloppyFails
+language/global-code/decl-lex-restricted-global.js fails
+language/global-code/decl-lex.js fails
+language/global-code/script-decl-func-dups.js fails
+language/global-code/script-decl-func-err-non-configurable.js fails
+language/global-code/script-decl-func-err-non-extensible.js fails
+language/global-code/script-decl-func.js fails
+language/global-code/script-decl-lex-deletion.js sloppyFails
+language/global-code/script-decl-lex-lex.js fails
+language/global-code/script-decl-lex-restricted-global.js fails
+language/global-code/script-decl-lex-var.js fails
+language/global-code/script-decl-lex.js fails
+language/global-code/script-decl-var-collision.js fails
+language/global-code/script-decl-var-err.js fails
+language/global-code/script-decl-var.js fails
+language/identifiers/other_id_continue.js fails
+language/identifiers/other_id_start-escaped.js fails
+language/identifiers/other_id_start.js fails
+language/literals/regexp/u-astral.js fails
+language/literals/regexp/u-case-mapping.js fails
+language/literals/regexp/u-surrogate-pairs-atom-char-class.js fails
+language/literals/regexp/u-surrogate-pairs-atom-dot.js fails
+language/literals/regexp/u-surrogate-pairs-atom-escape-char-class.js fails
+language/literals/regexp/u-surrogate-pairs-atom-escape-decimal.js fails
+language/literals/regexp/u-surrogate-pairs.js fails
+language/literals/regexp/u-unicode-esc.js fails
+language/literals/regexp/y-assertion-start.js fails
+language/module-code/eval-gtbndng-indirect-trlng-comma_FIXTURE.js fails
+language/module-code/eval-gtbndng-indirect-update-as_FIXTURE.js fails
+language/module-code/eval-gtbndng-indirect-update-dflt_FIXTURE.js fails
+language/module-code/eval-gtbndng-indirect-update_FIXTURE.js fails
+language/module-code/eval-rqstd-abrupt-err-type_FIXTURE.js fails
+language/module-code/eval-rqstd-abrupt-err-uri_FIXTURE.js fails
+language/module-code/eval-rqstd-once_FIXTURE.js fails
+language/module-code/eval-rqstd-order-4_FIXTURE.js fails
+language/module-code/eval-rqstd-order-6_FIXTURE.js fails
+language/module-code/eval-rqstd-order-8_FIXTURE.js fails
+language/module-code/instn-iee-bndng-cls_FIXTURE.js fails
+language/module-code/instn-iee-bndng-const_FIXTURE.js fails
+language/module-code/instn-iee-bndng-fun_FIXTURE.js fails
+language/module-code/instn-iee-bndng-gen_FIXTURE.js fails
+language/module-code/instn-iee-bndng-let_FIXTURE.js fails
+language/module-code/instn-iee-bndng-var_FIXTURE.js fails
+language/module-code/instn-iee-err-ambiguous-1_FIXTURE.js fails
+language/module-code/instn-iee-err-ambiguous-2_FIXTURE.js fails
+language/module-code/instn-iee-err-ambiguous_FIXTURE.js fails
+language/module-code/instn-iee-err-circular_FIXTURE.js fails
+language/module-code/instn-iee-err-dflt-thru-star-dflt_FIXTURE.js fails
+language/module-code/instn-iee-err-dflt-thru-star-int_FIXTURE.js fails
+language/module-code/instn-iee-iee-cycle-2_FIXTURE.js fails
+language/module-code/instn-iee-star-cycle-2_FIXTURE.js fails
+language/module-code/instn-iee-star-cycle-indirect-x_FIXTURE.js fails
+language/module-code/instn-iee-trlng-comma_FIXTURE.js fails
+language/module-code/instn-named-err-ambiguous-1_FIXTURE.js fails
+language/module-code/instn-named-err-ambiguous-2_FIXTURE.js fails
+language/module-code/instn-named-err-ambiguous_FIXTURE.js fails
+language/module-code/instn-named-err-dflt-thru-star-dflt_FIXTURE.js fails
+language/module-code/instn-named-err-dflt-thru-star-int_FIXTURE.js fails
+language/module-code/instn-named-iee-cycle-2_FIXTURE.js fails
+language/module-code/instn-named-star-cycle-2_FIXTURE.js fails
+language/module-code/instn-named-star-cycle-indirect-x_FIXTURE.js fails
+language/module-code/instn-resolve-empty-export_FIXTURE.js fails
+language/module-code/instn-resolve-empty-import_FIXTURE.js fails
+language/module-code/instn-resolve-err-reference_FIXTURE.js fails
+language/module-code/instn-resolve-err-syntax_FIXTURE.js fails
+language/module-code/instn-resolve-order-depth-child_FIXTURE.js fails
+language/module-code/instn-resolve-order-depth-reference_FIXTURE.js fails
+language/module-code/instn-resolve-order-depth-syntax_FIXTURE.js fails
+language/module-code/instn-resolve-order-src-reference_FIXTURE.js fails
+language/module-code/instn-resolve-order-src-syntax_FIXTURE.js fails
+language/module-code/instn-star-ambiguous-1_FIXTURE.js fails
+language/module-code/instn-star-ambiguous-2_FIXTURE.js fails
+language/module-code/instn-star-ambiguous_FIXTURE.js fails
+language/module-code/instn-star-equality-other_FIXTURE.js fails
+language/module-code/instn-star-err-not-found-faulty_FIXTURE.js fails
+language/module-code/instn-star-iee-cycle-2_FIXTURE.js fails
+language/module-code/instn-star-props-circular-a_FIXTURE.js fails
+language/module-code/instn-star-props-circular-b_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-keep-indirect-def_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-keep-indirect-reexport_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-keep-local-named_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-keep-local-prod_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-skip-named_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-skip-prod_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-skip-star-named_FIXTURE.js fails
+language/module-code/instn-star-props-dflt-skip-star-prod_FIXTURE.js fails
+language/module-code/instn-star-props-nrml-1_FIXTURE.js fails
+language/module-code/instn-star-props-nrml-indirect_FIXTURE.js fails
+language/module-code/instn-star-props-nrml-star_FIXTURE.js fails
+language/module-code/instn-star-star-cycle-2_FIXTURE.js fails
+language/module-code/instn-star-star-cycle-indirect-x_FIXTURE.js fails
+language/module-code/instn-uniq-env-rec-other_FIXTURE.js fails
+language/module-code/namespace/internals/own-property-keys-binding-types_FIXTURE.js fails
+language/rest-parameters/with-new-target.js fails
+language/statements/async-function/cptn-decl.js fails
+language/statements/async-function/declaration-returns-promise.js fails
+language/statements/async-function/evaluation-body.js fails
+language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails
+language/statements/block/tco-stmt-list.js strictFails
+language/statements/block/tco-stmt.js strictFails
+language/statements/class/accessor-name-inst-computed-err-evaluation.js fails
+language/statements/class/accessor-name-inst-computed-err-to-prop-key.js fails
+language/statements/class/accessor-name-inst-computed-err-unresolvable.js fails
+language/statements/class/accessor-name-inst-computed-yield-expr.js fails
+language/statements/class/accessor-name-inst-computed.js fails
+language/statements/class/accessor-name-inst-literal-numeric-binary.js fails
+language/statements/class/accessor-name-inst-literal-numeric-exponent.js fails
+language/statements/class/accessor-name-inst-literal-numeric-hex.js fails
+language/statements/class/accessor-name-inst-literal-numeric-leading-decimal.js fails
+language/statements/class/accessor-name-inst-literal-numeric-non-canonical.js fails
+language/statements/class/accessor-name-inst-literal-numeric-octal.js fails
+language/statements/class/accessor-name-inst-literal-numeric-zero.js fails
+language/statements/class/accessor-name-inst-literal-string-char-escape.js fails
+language/statements/class/accessor-name-inst-literal-string-double-quote.js fails
+language/statements/class/accessor-name-inst-literal-string-empty.js fails
+language/statements/class/accessor-name-inst-literal-string-hex-escape.js fails
+language/statements/class/accessor-name-inst-literal-string-line-continuation.js fails
+language/statements/class/accessor-name-inst-literal-string-single-quote.js fails
+language/statements/class/accessor-name-inst-literal-string-unicode-escape.js fails
+language/statements/class/accessor-name-static-computed-err-evaluation.js fails
+language/statements/class/accessor-name-static-computed-err-to-prop-key.js fails
+language/statements/class/accessor-name-static-computed-err-unresolvable.js fails
+language/statements/class/accessor-name-static-computed-yield-expr.js fails
+language/statements/class/accessor-name-static-computed.js fails
+language/statements/class/accessor-name-static-literal-numeric-binary.js fails
+language/statements/class/accessor-name-static-literal-numeric-exponent.js fails
+language/statements/class/accessor-name-static-literal-numeric-hex.js fails
+language/statements/class/accessor-name-static-literal-numeric-leading-decimal.js fails
+language/statements/class/accessor-name-static-literal-numeric-non-canonical.js fails
+language/statements/class/accessor-name-static-literal-numeric-octal.js fails
+language/statements/class/accessor-name-static-literal-numeric-zero.js fails
+language/statements/class/accessor-name-static-literal-string-char-escape.js fails
+language/statements/class/accessor-name-static-literal-string-double-quote.js fails
+language/statements/class/accessor-name-static-literal-string-empty.js fails
+language/statements/class/accessor-name-static-literal-string-hex-escape.js fails
+language/statements/class/accessor-name-static-literal-string-line-continuation.js fails
+language/statements/class/accessor-name-static-literal-string-single-quote.js fails
+language/statements/class/accessor-name-static-literal-string-unicode-escape.js fails
+language/statements/class/arguments/access.js fails
+language/statements/class/arguments/default-constructor.js fails
+language/statements/class/constructor-inferred-observable-iteration.js fails
+language/statements/class/cptn-decl.js fails
+language/statements/class/definition/accessors.js fails
+language/statements/class/definition/basics.js fails
+language/statements/class/definition/class-method-returns-promise.js fails
+language/statements/class/definition/constructable-but-no-prototype.js fails
+language/statements/class/definition/constructor-property.js fails
+language/statements/class/definition/constructor-strict-by-default.js fails
+language/statements/class/definition/constructor.js fails
+language/statements/class/definition/fn-name-accessor-get.js fails
+language/statements/class/definition/fn-name-accessor-set.js fails
+language/statements/class/definition/fn-name-gen-method.js fails
+language/statements/class/definition/fn-name-method.js fails
+language/statements/class/definition/fn-name-static-precedence.js fails
+language/statements/class/definition/getters-non-configurable-err.js fails
+language/statements/class/definition/getters-prop-desc.js fails
+language/statements/class/definition/getters-restricted-ids.js fails
+language/statements/class/definition/implicit-constructor.js fails
+language/statements/class/definition/invalid-extends.js fails
+language/statements/class/definition/methods-gen-no-yield.js fails
+language/statements/class/definition/methods-gen-return.js fails
+language/statements/class/definition/methods-gen-yield-as-expression-with-rhs.js fails
+language/statements/class/definition/methods-gen-yield-as-expression-without-rhs.js fails
+language/statements/class/definition/methods-gen-yield-as-generator-method-binding-identifier.js fails
+language/statements/class/definition/methods-gen-yield-as-literal-property-name.js fails
+language/statements/class/definition/methods-gen-yield-as-property-name.js fails
+language/statements/class/definition/methods-gen-yield-as-statement.js fails
+language/statements/class/definition/methods-gen-yield-as-yield-operand.js fails
+language/statements/class/definition/methods-gen-yield-newline.js fails
+language/statements/class/definition/methods-gen-yield-star-before-newline.js fails
+language/statements/class/definition/methods-named-eval-arguments.js fails
+language/statements/class/definition/methods-restricted-properties.js fails
+language/statements/class/definition/methods.js fails
+language/statements/class/definition/numeric-property-names.js fails
+language/statements/class/definition/prototype-getter.js fails
+language/statements/class/definition/prototype-property.js fails
+language/statements/class/definition/prototype-setter.js fails
+language/statements/class/definition/prototype-wiring.js fails
+language/statements/class/definition/setters-non-configurable-err.js fails
+language/statements/class/definition/setters-prop-desc.js fails
+language/statements/class/definition/setters-restricted-ids.js fails
+language/statements/class/definition/side-effects-in-extends.js fails
+language/statements/class/definition/side-effects-in-property-define.js fails
+language/statements/class/definition/this-access-restriction-2.js fails
+language/statements/class/definition/this-access-restriction.js fails
+language/statements/class/definition/this-check-ordering.js fails
+language/statements/class/dstr-gen-meth-ary-init-iter-close.js fails
+language/statements/class/dstr-gen-meth-ary-init-iter-get-err.js fails
+language/statements/class/dstr-gen-meth-ary-init-iter-no-close.js fails
+language/statements/class/dstr-gen-meth-ary-name-iter-val.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-elision.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-gen-meth-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-init-iter-close.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-init-iter-get-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-init-iter-no-close.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-name-iter-val.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-elision.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-gen-meth-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-init-null.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-init-undefined.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-list-err.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-gen-meth-dflt-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-gen-meth-obj-init-null.js fails
+language/statements/class/dstr-gen-meth-obj-init-undefined.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-list-err.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-gen-meth-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-gen-meth-static-ary-init-iter-close.js fails
+language/statements/class/dstr-gen-meth-static-ary-init-iter-get-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-init-iter-no-close.js fails
+language/statements/class/dstr-gen-meth-static-ary-name-iter-val.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-elision.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-gen-meth-static-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-init-iter-close.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-init-iter-get-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-init-iter-no-close.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-name-iter-val.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-elision.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-init-null.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-init-undefined.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-list-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-gen-meth-static-dflt-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-gen-meth-static-obj-init-null.js fails
+language/statements/class/dstr-gen-meth-static-obj-init-undefined.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-empty.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-list-err.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-gen-meth-static-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-meth-ary-init-iter-close.js fails
+language/statements/class/dstr-meth-ary-init-iter-get-err.js fails
+language/statements/class/dstr-meth-ary-init-iter-no-close.js fails
+language/statements/class/dstr-meth-ary-name-iter-val.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-meth-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-meth-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-meth-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-elision.js fails
+language/statements/class/dstr-meth-ary-ptrn-empty.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-meth-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-meth-dflt-ary-init-iter-close.js fails
+language/statements/class/dstr-meth-dflt-ary-init-iter-get-err.js fails
+language/statements/class/dstr-meth-dflt-ary-init-iter-no-close.js fails
+language/statements/class/dstr-meth-dflt-ary-name-iter-val.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-elision.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-empty.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-meth-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-meth-dflt-obj-init-null.js fails
+language/statements/class/dstr-meth-dflt-obj-init-undefined.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-empty.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-list-err.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-meth-dflt-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-meth-obj-init-null.js fails
+language/statements/class/dstr-meth-obj-init-undefined.js fails
+language/statements/class/dstr-meth-obj-ptrn-empty.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-meth-obj-ptrn-list-err.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-meth-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-meth-static-ary-init-iter-close.js fails
+language/statements/class/dstr-meth-static-ary-init-iter-get-err.js fails
+language/statements/class/dstr-meth-static-ary-init-iter-no-close.js fails
+language/statements/class/dstr-meth-static-ary-name-iter-val.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-elision.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-empty.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-meth-static-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-meth-static-dflt-ary-init-iter-close.js fails
+language/statements/class/dstr-meth-static-dflt-ary-init-iter-get-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-init-iter-no-close.js fails
+language/statements/class/dstr-meth-static-dflt-ary-name-iter-val.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elem-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elem-iter.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elision-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-elision-iter.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-empty-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-empty-iter.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-rest-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-rest-iter.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-ary-val-null.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-exhausted.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-hole.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-throws.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-undef.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-complete.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-done.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-step-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-val-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-id-iter-val.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-id-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-id.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-prop-id-init.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-prop-id.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-val-null.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elem-obj-val-undef.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elision-exhausted.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elision-step-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-elision.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-empty.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-elem.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-elision.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-empty.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-ary-rest.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id-elision-next-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id-elision.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id-exhausted.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id-iter-step-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id-iter-val-err.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-id.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-obj-id.js fails
+language/statements/class/dstr-meth-static-dflt-ary-ptrn-rest-obj-prop-id.js fails
+language/statements/class/dstr-meth-static-dflt-obj-init-null.js fails
+language/statements/class/dstr-meth-static-dflt-obj-init-undefined.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-empty.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-list-err.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-meth-static-dflt-obj-ptrn-prop-obj.js fails
+language/statements/class/dstr-meth-static-obj-init-null.js fails
+language/statements/class/dstr-meth-static-obj-init-undefined.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-empty.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-get-value-err.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-fn-name-arrow.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-fn-name-cover.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-fn-name-fn.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-fn-name-gen.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-throws.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-id-trailing-comma.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-list-err.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-ary-init.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-ary-trailing-comma.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-ary-value-null.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-ary.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-eval-err.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-get-value-err.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-init-skipped.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-init-throws.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-init-unresolvable.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-init.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id-trailing-comma.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-id.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-obj-init.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-obj-value-null.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-obj-value-undef.js fails
+language/statements/class/dstr-meth-static-obj-ptrn-prop-obj.js fails
+language/statements/class/gen-meth-dflt-params-abrupt.js fails
+language/statements/class/gen-meth-dflt-params-arg-val-not-undefined.js fails
+language/statements/class/gen-meth-dflt-params-arg-val-undefined.js fails
+language/statements/class/gen-meth-dflt-params-ref-later.js fails
+language/statements/class/gen-meth-dflt-params-ref-prior.js fails
+language/statements/class/gen-meth-dflt-params-ref-self.js fails
+language/statements/class/gen-meth-dflt-params-trailing-comma.js fails
+language/statements/class/gen-meth-params-trailing-comma-multiple.js fails
+language/statements/class/gen-meth-params-trailing-comma-single.js fails
+language/statements/class/gen-meth-static-dflt-params-abrupt.js fails
+language/statements/class/gen-meth-static-dflt-params-arg-val-not-undefined.js fails
+language/statements/class/gen-meth-static-dflt-params-arg-val-undefined.js fails
+language/statements/class/gen-meth-static-dflt-params-ref-later.js fails
+language/statements/class/gen-meth-static-dflt-params-ref-prior.js fails
+language/statements/class/gen-meth-static-dflt-params-ref-self.js fails
+language/statements/class/gen-meth-static-dflt-params-trailing-comma.js fails
+language/statements/class/gen-meth-static-params-trailing-comma-multiple.js fails
+language/statements/class/gen-meth-static-params-trailing-comma-single.js fails
+language/statements/class/gen-method-length-dflt.js fails
+language/statements/class/gen-method-static-yield-spread-arr-multiple.js fails
+language/statements/class/gen-method-static-yield-spread-arr-single.js fails
+language/statements/class/gen-method-yield-spread-arr-multiple.js fails
+language/statements/class/gen-method-yield-spread-arr-single.js fails
+language/statements/class/meth-dflt-params-abrupt.js fails
+language/statements/class/meth-dflt-params-arg-val-not-undefined.js fails
+language/statements/class/meth-dflt-params-arg-val-undefined.js fails
+language/statements/class/meth-dflt-params-ref-later.js fails
+language/statements/class/meth-dflt-params-ref-prior.js fails
+language/statements/class/meth-dflt-params-ref-self.js fails
+language/statements/class/meth-dflt-params-trailing-comma.js fails
+language/statements/class/meth-params-trailing-comma-multiple.js fails
+language/statements/class/meth-params-trailing-comma-single.js fails
+language/statements/class/meth-static-dflt-params-abrupt.js fails
+language/statements/class/meth-static-dflt-params-arg-val-not-undefined.js fails
+language/statements/class/meth-static-dflt-params-arg-val-undefined.js fails
+language/statements/class/meth-static-dflt-params-ref-later.js fails
+language/statements/class/meth-static-dflt-params-ref-prior.js fails
+language/statements/class/meth-static-dflt-params-ref-self.js fails
+language/statements/class/meth-static-dflt-params-trailing-comma.js fails
+language/statements/class/meth-static-params-trailing-comma-multiple.js fails
+language/statements/class/meth-static-params-trailing-comma-single.js fails
+language/statements/class/method-length-dflt.js fails
+language/statements/class/name-binding/basic.js fails
+language/statements/class/name-binding/const.js fails
+language/statements/class/name-binding/expression.js fails
+language/statements/class/name-binding/in-extends-expression-assigned.js fails
+language/statements/class/name-binding/in-extends-expression-grouped.js fails
+language/statements/class/name-binding/in-extends-expression.js fails
+language/statements/class/name.js fails
+language/statements/class/params-dflt-gen-meth-args-unmapped.js fails
+language/statements/class/params-dflt-gen-meth-ref-arguments.js fails
+language/statements/class/params-dflt-gen-meth-static-args-unmapped.js fails
+language/statements/class/params-dflt-gen-meth-static-ref-arguments.js fails
+language/statements/class/params-dflt-meth-args-unmapped.js fails
+language/statements/class/params-dflt-meth-ref-arguments.js fails
+language/statements/class/params-dflt-meth-static-args-unmapped.js fails
+language/statements/class/params-dflt-meth-static-ref-arguments.js fails
+language/statements/class/restricted-properties.js fails
+language/statements/class/scope-gen-meth-paramsbody-var-close.js fails
+language/statements/class/scope-gen-meth-paramsbody-var-open.js fails
+language/statements/class/scope-meth-paramsbody-var-close.js fails
+language/statements/class/scope-meth-paramsbody-var-open.js fails
+language/statements/class/scope-name-lex-close.js fails
+language/statements/class/scope-name-lex-open-heritage.js fails
+language/statements/class/scope-name-lex-open-no-heritage.js fails
+language/statements/class/scope-setter-paramsbody-var-close.js fails
+language/statements/class/scope-setter-paramsbody-var-open.js fails
+language/statements/class/scope-static-gen-meth-paramsbody-var-close.js fails
+language/statements/class/scope-static-gen-meth-paramsbody-var-open.js fails
+language/statements/class/scope-static-meth-paramsbody-var-close.js fails
+language/statements/class/scope-static-meth-paramsbody-var-open.js fails
+language/statements/class/scope-static-setter-paramsbody-var-close.js fails
+language/statements/class/scope-static-setter-paramsbody-var-open.js fails
+language/statements/class/setter-length-dflt.js fails
+language/statements/class/static-method-gen-non-configurable-err.js fails
+language/statements/class/static-method-length-dflt.js fails
+language/statements/class/static-method-non-configurable-err.js fails
+language/statements/class/strict-mode/arguments-callee.js fails
+language/statements/class/subclass/binding.js fails
+language/statements/class/subclass/bound-function.js fails
+language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js fails
+language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js fails
+language/statements/class/subclass/builtin-objects/Array/length.js fails
+language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Array/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Boolean/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/DataView/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/DataView/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Date/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Date/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Error/message-property-assignment.js fails
+language/statements/class/subclass/builtin-objects/Error/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Error/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Function/instance-length.js fails
+language/statements/class/subclass/builtin-objects/Function/instance-name.js fails
+language/statements/class/subclass/builtin-objects/Function/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Function/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-length.js fails
+language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-name.js fails
+language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-prototype.js fails
+language/statements/class/subclass/builtin-objects/GeneratorFunction/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/GeneratorFunction/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Map/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Map/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/NativeError/EvalError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/EvalError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/EvalError-super.js fails
+language/statements/class/subclass/builtin-objects/NativeError/RangeError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/RangeError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/RangeError-super.js fails
+language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-super.js fails
+language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-super.js fails
+language/statements/class/subclass/builtin-objects/NativeError/TypeError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/TypeError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/TypeError-super.js fails
+language/statements/class/subclass/builtin-objects/NativeError/URIError-message.js fails
+language/statements/class/subclass/builtin-objects/NativeError/URIError-name.js fails
+language/statements/class/subclass/builtin-objects/NativeError/URIError-super.js fails
+language/statements/class/subclass/builtin-objects/Number/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Number/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Object/constructor-return-undefined-throws.js fails
+language/statements/class/subclass/builtin-objects/Object/constructor-returns-non-object.js fails
+language/statements/class/subclass/builtin-objects/Object/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Object/replacing-prototype.js fails
+language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Proxy/no-prototype-throws.js fails
+language/statements/class/subclass/builtin-objects/RegExp/lastIndex.js fails
+language/statements/class/subclass/builtin-objects/RegExp/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Set/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/String/length.js fails
+language/statements/class/subclass/builtin-objects/String/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/String/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js fails
+language/statements/class/subclass/builtin-objects/Symbol/symbol-valid-as-extends-value.js fails
+language/statements/class/subclass/builtin-objects/TypedArray/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js fails
+language/statements/class/subclass/builtin-objects/WeakSet/regular-subclassing.js fails
+language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js fails
+language/statements/class/subclass/builtins.js fails
+language/statements/class/subclass/class-definition-evaluation-empty-constructor-heritage-present.js fails
+language/statements/class/subclass/class-definition-null-proto-contains-return-override.js fails
+language/statements/class/subclass/class-definition-null-proto-missing-return-override.js fails
+language/statements/class/subclass/class-definition-null-proto-super.js fails
+language/statements/class/subclass/class-definition-null-proto-this.js fails
+language/statements/class/subclass/class-definition-null-proto.js fails
+language/statements/class/subclass/class-definition-parent-proto-null.js fails
+language/statements/class/subclass/class-definition-superclass-generator.js fails
+language/statements/class/subclass/default-constructor-2.js fails
+language/statements/class/subclass/default-constructor-spread-override.js fails
+language/statements/class/subclass/default-constructor.js fails
+language/statements/class/subclass/derived-class-return-override-with-boolean.js fails
+language/statements/class/subclass/derived-class-return-override-with-empty.js fails
+language/statements/class/subclass/derived-class-return-override-with-null.js fails
+language/statements/class/subclass/derived-class-return-override-with-number.js fails
+language/statements/class/subclass/derived-class-return-override-with-object.js fails
+language/statements/class/subclass/derived-class-return-override-with-string.js fails
+language/statements/class/subclass/derived-class-return-override-with-symbol.js fails
+language/statements/class/subclass/derived-class-return-override-with-this.js fails
+language/statements/class/subclass/derived-class-return-override-with-undefined.js fails
+language/statements/class/subclass/superclass-prototype-setter-constructor.js fails
+language/statements/class/subclass/superclass-prototype-setter-method-override.js fails
+language/statements/class/subclass/superclass-static-method-override.js fails
+language/statements/class/super/in-constructor.js fails
+language/statements/class/super/in-getter.js fails
+language/statements/class/super/in-methods.js fails
+language/statements/class/super/in-setter.js fails
+language/statements/class/super/in-static-getter.js fails
+language/statements/class/super/in-static-methods.js fails
+language/statements/class/super/in-static-setter.js fails
+language/statements/class/syntax/class-body-has-direct-super-class-heritage.js fails
+language/statements/class/syntax/class-body-method-definition-super-property.js fails
+language/statements/class/syntax/class-declaration-binding-identifier-class-element-list.js fails
+language/statements/class/syntax/class-declaration-computed-method-definition.js fails
+language/statements/class/syntax/class-declaration-computed-method-generator-definition.js fails
+language/statements/class/syntax/class-declaration-heritage-identifier-reference-class-element-list.js fails
+language/statements/class/syntax/class-expression-binding-identifier-opt-class-element-list.js fails
+language/statements/class/syntax/class-expression-heritage-identifier-reference.js fails
+language/statements/class/syntax/class-expression.js fails
+language/statements/class/syntax/class-method-propname-constructor.js fails
+language/statements/class/syntax/early-errors/class-body-constructor-empty-missing-class-heritage.js fails
+language/statements/const/block-local-closure-get-before-initialization.js fails
+language/statements/const/block-local-use-before-initialization-in-declaration-statement.js fails
+language/statements/const/block-local-use-before-initialization-in-prior-statement.js fails
+language/statements/const/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/const/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/const/fn-name-class.js fails
+language/statements/const/function-local-closure-get-before-initialization.js fails
+language/statements/const/function-local-use-before-initialization-in-declaration-statement.js fails
+language/statements/const/function-local-use-before-initialization-in-prior-statement.js fails
+language/statements/const/global-closure-get-before-initialization.js fails
+language/statements/const/global-use-before-initialization-in-declaration-statement.js fails
+language/statements/const/global-use-before-initialization-in-prior-statement.js fails
+language/statements/const/syntax/const-invalid-assignment-next-expression-for.js fails
+language/statements/const/syntax/const-invalid-assignment-statement-body-for-in.js fails
+language/statements/const/syntax/const-invalid-assignment-statement-body-for-of.js fails
+language/statements/do-while/tco-body.js strictFails
+language/statements/for-in/head-const-bound-names-fordecl-tdz.js fails
+language/statements/for-in/head-const-fresh-binding-per-iteration.js fails
+language/statements/for-in/head-let-bound-names-fordecl-tdz.js fails
+language/statements/for-in/head-lhs-let.js sloppyFails
+language/statements/for-in/head-var-bound-names-let.js sloppyFails
+language/statements/for-in/identifier-let-allowed-as-lefthandside-expression-not-strict.js sloppyFails
+language/statements/for-in/scope-body-lex-open.js fails
+language/statements/for-in/scope-head-lex-close.js fails
+language/statements/for-in/scope-head-lex-open.js fails
+language/statements/for-of/body-dstr-assign-error.js fails
+language/statements/for-of/body-put-error.js fails
+language/statements/for-of/dstr-array-elem-init-fn-name-class.js fails
+language/statements/for-of/dstr-array-elem-init-let.js fails
+language/statements/for-of/dstr-array-elem-iter-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-elem-iter-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-elem-iter-rtrn-close.js fails
+language/statements/for-of/dstr-array-elem-iter-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-iter-thrw-close.js fails
+language/statements/for-of/dstr-array-elem-put-const.js fails
+language/statements/for-of/dstr-array-elem-put-let.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-rtrn-close.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-list-thrw-close.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-rtrn-close.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-thrw-close-err.js fails
+language/statements/for-of/dstr-array-elem-trlg-iter-rest-thrw-close.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close-err.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close-null.js fails
+language/statements/for-of/dstr-array-rest-iter-rtrn-close.js fails
+language/statements/for-of/dstr-array-rest-iter-thrw-close-err.js fails
+language/statements/for-of/dstr-array-rest-iter-thrw-close.js fails
+language/statements/for-of/dstr-array-rest-lref-err.js fails
+language/statements/for-of/dstr-array-rest-put-const.js fails
+language/statements/for-of/dstr-array-rest-put-let.js fails
+language/statements/for-of/dstr-const-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-const-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-let-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-let-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-obj-empty-null.js fails
+language/statements/for-of/dstr-obj-empty-undef.js fails
+language/statements/for-of/dstr-obj-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-obj-id-init-let.js fails
+language/statements/for-of/dstr-obj-id-put-const.js fails
+language/statements/for-of/dstr-obj-id-put-let.js fails
+language/statements/for-of/dstr-obj-prop-elem-init-fn-name-class.js fails
+language/statements/for-of/dstr-obj-prop-elem-init-let.js fails
+language/statements/for-of/dstr-obj-prop-put-const.js fails
+language/statements/for-of/dstr-obj-prop-put-let.js fails
+language/statements/for-of/dstr-var-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for-of/dstr-var-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for-of/generator-close-via-continue.js fails
+language/statements/for-of/generator-close-via-return.js fails
+language/statements/for-of/generator-close-via-throw.js fails
+language/statements/for-of/head-const-bound-names-fordecl-tdz.js fails
+language/statements/for-of/head-const-fresh-binding-per-iteration.js fails
+language/statements/for-of/head-let-bound-names-fordecl-tdz.js fails
+language/statements/for-of/head-var-bound-names-let.js sloppyFails
+language/statements/for-of/iterator-as-proxy.js fails
+language/statements/for-of/iterator-close-via-continue.js fails
+language/statements/for-of/iterator-close-via-return.js fails
+language/statements/for-of/iterator-close-via-throw.js fails
+language/statements/for-of/iterator-next-reference.js fails
+language/statements/for-of/iterator-next-result-type.js fails
+language/statements/for-of/scope-body-lex-open.js fails
+language/statements/for-of/scope-head-lex-close.js fails
+language/statements/for-of/scope-head-lex-open.js fails
+language/statements/for-of/yield-star-from-catch.js fails
+language/statements/for-of/yield-star-from-finally.js fails
+language/statements/for-of/yield-star-from-try.js fails
+language/statements/for-of/yield-star.js fails
+language/statements/for/dstr-const-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for/dstr-const-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for/dstr-let-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for/dstr-let-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for/dstr-var-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/for/dstr-var-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/for/head-lhs-let.js sloppyFails
+language/statements/for/scope-body-lex-open.js fails
+language/statements/for/tco-const-body.js strictFails
+language/statements/for/tco-let-body.js strictFails
+language/statements/for/tco-lhs-body.js strictFails
+language/statements/for/tco-var-body.js strictFails
+language/statements/function/13.2-30-s.js fails
+language/statements/function/S13_A15_T4.js sloppyFails
+language/statements/function/arguments-with-arguments-fn.js sloppyFails
+language/statements/function/arguments-with-arguments-lex.js sloppyFails
+language/statements/function/dflt-params-ref-later.js fails
+language/statements/function/dflt-params-ref-self.js fails
+language/statements/function/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/function/dstr-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/function/dstr-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/function/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/function/param-dflt-yield-non-strict.js sloppyFails
+language/statements/function/scope-body-lex-distinct.js sloppyFails
+language/statements/function/scope-param-elem-var-close.js sloppyFails
+language/statements/function/scope-param-elem-var-open.js sloppyFails
+language/statements/function/scope-param-rest-elem-var-close.js sloppyFails
+language/statements/function/scope-param-rest-elem-var-open.js sloppyFails
+language/statements/function/scope-paramsbody-var-open.js fails
+language/statements/generators/arguments-with-arguments-fn.js sloppyFails
+language/statements/generators/arguments-with-arguments-lex.js sloppyFails
+language/statements/generators/default-proto.js fails
+language/statements/generators/dflt-params-ref-later.js fails
+language/statements/generators/dflt-params-ref-self.js fails
+language/statements/generators/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/generators/dstr-dflt-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/generators/dstr-dflt-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/generators/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/generators/scope-body-lex-distinct.js sloppyFails
+language/statements/generators/scope-param-elem-var-close.js sloppyFails
+language/statements/generators/scope-param-elem-var-open.js sloppyFails
+language/statements/generators/scope-param-rest-elem-var-close.js sloppyFails
+language/statements/generators/scope-param-rest-elem-var-open.js sloppyFails
+language/statements/generators/scope-paramsbody-var-open.js fails
+language/statements/generators/yield-as-function-expression-binding-identifier.js sloppyFails
+language/statements/generators/yield-as-identifier-in-nested-function.js sloppyFails
+language/statements/generators/yield-as-literal-property-name.js fails
+language/statements/generators/yield-as-property-name.js fails
+language/statements/generators/yield-identifier-non-strict.js sloppyFails
+language/statements/generators/yield-star-before-newline.js fails
+language/statements/if/tco-else-body.js strictFails
+language/statements/if/tco-if-body.js strictFails
+language/statements/labeled/tco.js strictFails
+language/statements/let/block-local-closure-get-before-initialization.js fails
+language/statements/let/block-local-closure-set-before-initialization.js fails
+language/statements/let/block-local-use-before-initialization-in-declaration-statement.js fails
+language/statements/let/block-local-use-before-initialization-in-prior-statement.js fails
+language/statements/let/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/let/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/let/fn-name-class.js fails
+language/statements/let/function-local-closure-get-before-initialization.js fails
+language/statements/let/function-local-closure-set-before-initialization.js fails
+language/statements/let/function-local-use-before-initialization-in-declaration-statement.js fails
+language/statements/let/function-local-use-before-initialization-in-prior-statement.js fails
+language/statements/let/global-closure-get-before-initialization.js fails
+language/statements/let/global-closure-set-before-initialization.js fails
+language/statements/let/global-use-before-initialization-in-declaration-statement.js fails
+language/statements/let/global-use-before-initialization-in-prior-statement.js fails
+language/statements/let/syntax/let.js fails
+language/statements/return/tco.js strictFails
+language/statements/switch/scope-lex-open-case.js fails
+language/statements/switch/scope-lex-open-dflt.js fails
+language/statements/switch/tco-case-body-dflt.js strictFails
+language/statements/switch/tco-case-body.js strictFails
+language/statements/switch/tco-dftl-body.js strictFails
+language/statements/throw/S12.13_A2_T6.js strictFails
+language/statements/try/S12.14_A18_T6.js strictFails
+language/statements/try/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/try/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/try/scope-catch-block-lex-open.js fails
+language/statements/try/tco-catch-finally.js strictFails
+language/statements/try/tco-catch.js strictFails
+language/statements/try/tco-finally.js strictFails
+language/statements/variable/binding-resolution.js sloppyFails
+language/statements/variable/dstr-ary-ptrn-elem-id-init-fn-name-class.js fails
+language/statements/variable/dstr-obj-ptrn-id-init-fn-name-class.js fails
+language/statements/variable/fn-name-class.js fails
+language/statements/while/tco-body.js strictFails
+language/statements/with/binding-blocked-by-unscopables.js sloppyFails
+language/statements/with/has-property-err.js sloppyFails
+language/statements/with/unscopables-inc-dec.js sloppyFails
+language/types/reference/get-value-prop-base-primitive-realm.js fails
+language/types/reference/put-value-prop-base-primitive-realm.js fails
+language/types/reference/put-value-prop-base-primitive.js fails
diff --git a/tests/auto/qml/ecmascripttests/ecmascripttests.pro b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
index 6d3ee12307..9c09ee701e 100644
--- a/tests/auto/qml/ecmascripttests/ecmascripttests.pro
+++ b/tests/auto/qml/ecmascripttests/ecmascripttests.pro
@@ -1,20 +1,13 @@
-CONFIG += testcase
-TARGET = tst_ecmascripttests
-QT += testlib
-macos:CONFIG -= app_bundle
-SOURCES += tst_ecmascripttests.cpp
-DEFINES += SRCDIR=\\\"$$PWD\\\"
-
-TESTSCRIPT=$$PWD/test262.py
-isEmpty(V4CMD): V4CMD = qmljs
+TEMPLATE = subdirs
+SUBDIRS = testcase.pro qjstest
checkjittarget.target = check-jit
-checkjittarget.commands = python $$TESTSCRIPT --command=$$V4CMD --parallel --with-test-expectations --update-expectations
+checkjittarget.commands = qjstest --jit --parallel --with-test-expectations --update-expectations
checkjittarget.depends = all
QMAKE_EXTRA_TARGETS += checkjittarget
checkmothtarget.target = check-interpreter
-checkmothtarget.commands = python $$TESTSCRIPT --command=\"$$V4CMD --interpret\" --parallel --with-test-expectations
+checkmothtarget.commands = qjstest --interpret --parallel --with-test-expectations
checkmothtarget.depends = all
QMAKE_EXTRA_TARGETS += checkmothtarget
diff --git a/tests/auto/qml/ecmascripttests/qjstest/main.cpp b/tests/auto/qml/ecmascripttests/qjstest/main.cpp
new file mode 100644
index 0000000000..4a3541d892
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/main.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QJSEngine>
+#include <QCoreApplication>
+#include <QCommandLineParser>
+#include <qdebug.h>
+#include <stdlib.h>
+
+#include "test262runner.h"
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption verbose("verbose", "Verbose output");
+ parser.addOption(verbose);
+ QCommandLineOption commandOption("command", "Javascript command line interpreter", "command");
+ parser.addOption(commandOption);
+ QCommandLineOption testDir("tests", "path to the tests", "tests", "test262");
+ parser.addOption(testDir);
+ QCommandLineOption cat("cat", "Print packaged test code that would be run");
+ parser.addOption(cat);
+ QCommandLineOption parallel("parallel", "Run tests in parallel");
+ parser.addOption(parallel);
+ QCommandLineOption jit("jit", "JIT all code");
+ parser.addOption(jit);
+ QCommandLineOption bytecode("interpret", "Run using the bytecode interpreter");
+ parser.addOption(bytecode);
+ QCommandLineOption withExpectations("with-test-expectations", "Parse TestExpectations to deal with known failures");
+ parser.addOption(withExpectations);
+ QCommandLineOption updateExpectations("update-expectations", "Update TestExpectations to remove unexepected passes");
+ parser.addOption(updateExpectations);
+ QCommandLineOption writeExpectations("write-expectations", "Generate a new TestExpectations file based on the results of the run");
+ parser.addOption(writeExpectations);
+ parser.addPositionalArgument("[filter]", "Only run tests that contain filter in their name");
+
+ parser.process(app);
+
+ Test262Runner testRunner(parser.value(commandOption), parser.value(testDir));
+
+ QStringList otherArgs = parser.positionalArguments();
+ if (otherArgs.size() > 1) {
+ qWarning() << "too many arguments";
+ return 1;
+ } else if (otherArgs.size()) {
+ testRunner.setFilter(otherArgs.at(0));
+ }
+
+ if (parser.isSet(cat)) {
+ testRunner.cat();
+ return 0;
+ }
+
+ if (parser.isSet(updateExpectations) && parser.isSet(writeExpectations)) {
+ qWarning() << "Can only specify one of --update-expectations and --write-expectations.";
+ exit(1);
+ }
+
+ if (parser.isSet(jit) && parser.isSet(bytecode)) {
+ qWarning() << "Can only specify one of --jit and --interpret.";
+ exit(1);
+ }
+
+ int flags = 0;
+ if (parser.isSet(verbose))
+ flags |= Test262Runner::Verbose;
+ if (parser.isSet(parallel))
+ flags |= Test262Runner::Parallel;
+ if (parser.isSet(jit))
+ flags |= Test262Runner::ForceJIT;
+ if (parser.isSet(bytecode))
+ flags |= Test262Runner::ForceBytecode;
+ if (parser.isSet(withExpectations))
+ flags |= Test262Runner::WithTestExpectations;
+ if (parser.isSet(updateExpectations))
+ flags |= Test262Runner::UpdateTestExpectations;
+ if (parser.isSet(writeExpectations))
+ flags |= Test262Runner::WriteTestExpectations;
+ testRunner.setFlags(flags);
+
+ if (testRunner.run())
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
diff --git a/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro b/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro
new file mode 100644
index 0000000000..6dec5f8f23
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/qjstest.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET = qjstest
+QT += qml-private
+INCLUDEPATH += .
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+HEADERS += test262runner.h
+SOURCES += main.cpp test262runner.cpp
+
+QMAKE_TARGET_DESCRIPTION = Javascript test runner
+
+load(qt_tool)
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
new file mode 100644
index 0000000000..d2d389305a
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -0,0 +1,758 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "test262runner.h"
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qdiriterator.h>
+#include <qdebug.h>
+#include <qprocess.h>
+#include <qtemporaryfile.h>
+
+#include <private/qv4script_p.h>
+#include "private/qv4globalobject_p.h"
+#include "private/qqmlbuiltinfunctions_p.h"
+
+#include "qrunnable.h"
+
+static const char *excludedFeatures[] = {
+ "BigInt",
+ "class-fields-public",
+ "class-fields-private",
+ "Promise.prototype.finally",
+ "async-iteration",
+ "Symbol.asyncIterator",
+ "object-rest",
+ "object-spread",
+ "optional-catch-binding",
+ "regexp-dotall",
+ "regexp-lookbehind",
+ "regexp-named-groups",
+ "regexp-unicode-property-escapes",
+ "Atomics",
+ "SharedArrayBuffer",
+ "Array.prototype.flatten",
+ "Array.prototype.flatMap",
+ "string-trimming",
+ "String.prototype.trimEnd",
+ "String.prototype.trimStart",
+ "numeric-separator-literal",
+
+ // optional features, not supported by us
+ "caller",
+ nullptr
+};
+
+Test262Runner::Test262Runner(const QString &command, const QString &dir)
+ : command(command), testDir(dir)
+{
+ if (testDir.endsWith(QLatin1Char('/')))
+ testDir = testDir.chopped(1);
+}
+
+Test262Runner::~Test262Runner()
+{
+ delete threadPool;
+}
+
+void Test262Runner::cat()
+{
+ if (!loadTests())
+ return;
+
+ if (testCases.size() != 1)
+ qWarning() << "test262 --cat: Ambiguous test case, using" << testCases.begin().key();
+ TestData data = getTestData(testCases.begin().value());
+ printf("%s", data.content.constData());
+}
+
+bool Test262Runner::run()
+{
+ if (!loadTests())
+ return false;
+
+ if (flags & Parallel) {
+ threadPool = new QThreadPool;
+ threadPool->setStackSize(16*1024*1024);
+ if (flags & Verbose)
+ qDebug() << "Running in parallel with" << QThread::idealThreadCount() << "threads.";
+ }
+
+ if (flags & ForceJIT)
+ qputenv("QV4_JIT_CALL_THRESHOLD", QByteArray("0"));
+ else if (flags & ForceBytecode)
+ qputenv("QV4_FORCE_INTERPRETER", QByteArray("1"));
+
+ if (flags & WithTestExpectations)
+ loadTestExpectations();
+
+ for (auto it = testCases.constBegin(); it != testCases.constEnd(); ++it) {
+ auto c = it.value();
+ if (!c.skipTestCase) {
+ int result = runSingleTest(c);
+ if (result == -2)
+ return false;
+ }
+ }
+
+ if (threadPool)
+ threadPool->waitForDone();
+
+ report();
+
+ if (flags & WriteTestExpectations)
+ writeTestExpectations();
+ else if (flags & UpdateTestExpectations)
+ updateTestExpectations();
+
+ return true;
+}
+
+void Test262Runner::report()
+{
+ qDebug() << "Test execution summary:";
+ qDebug() << " Executed" << testCases.size() << "test cases.";
+ QStringList crashes;
+ QStringList unexpectedFailures;
+ QStringList unexpectedPasses;
+ for (auto it = testCases.constBegin(); it != testCases.constEnd(); ++it) {
+ const auto c = it.value();
+ if (c.strictResult == c.strictExpectation && c.sloppyResult == c.sloppyExpectation)
+ continue;
+ auto report = [&] (TestCase::Result expected, TestCase::Result result, const char *s) {
+ if (result == TestCase::Crashes)
+ crashes << (it.key() + " crashed in " + s + " mode");
+ if (result == TestCase::Fails && expected == TestCase::Passes)
+ unexpectedFailures << (it.key() + " failed in " + s + " mode");
+ if (result == TestCase::Passes && expected == TestCase::Fails)
+ unexpectedPasses << (it.key() + " unexpectedly passed in " + s + " mode");
+ };
+ report(c.strictExpectation, c.strictResult, "strict");
+ report(c.sloppyExpectation, c.sloppyResult, "sloppy");
+ }
+ if (!crashes.isEmpty()) {
+ qDebug() << " Encountered" << crashes.size() << "crashes in the following files:";
+ for (const QString &f : qAsConst(crashes))
+ qDebug() << " " << f;
+ }
+ if (!unexpectedFailures.isEmpty()) {
+ qDebug() << " Encountered" << unexpectedFailures.size() << "unexpected failures in the following files:";
+ for (const QString &f : qAsConst(unexpectedFailures))
+ qDebug() << " " << f;
+ }
+ if (!unexpectedPasses.isEmpty()) {
+ qDebug() << " Encountered" << unexpectedPasses.size() << "unexpected passes in the following files:";
+ for (const QString &f : qAsConst(unexpectedPasses))
+ qDebug() << " " << f;
+ }
+}
+
+bool Test262Runner::loadTests()
+{
+ QDir dir(testDir + "/test");
+ if (!dir.exists()) {
+ qWarning() << "Could not load tests," << dir.path() << "does not exist.";
+ return false;
+ }
+
+ QString annexB = "annexB";
+ QString harness = "harness";
+ QString intl402 = "intl402";
+
+ int pathlen = dir.path().length() + 1;
+ QDirIterator it(dir, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ QString file = it.next().mid(pathlen);
+ if (!file.endsWith(".js"))
+ continue;
+ if (!filter.isEmpty() && !file.contains(filter))
+ continue;
+ if (file.startsWith(annexB) || file.startsWith(harness) || file.startsWith(intl402))
+ continue;
+
+ testCases.insert(file, TestCase{ file });
+ }
+ if (testCases.isEmpty()) {
+ qWarning() << "No tests to run.";
+ return false;
+ }
+
+ return true;
+}
+
+
+struct TestExpectationLine {
+ TestExpectationLine(const QByteArray &line);
+ enum State {
+ Fails,
+ SloppyFails,
+ StrictFails,
+ Skip,
+ Passes
+ } state;
+ QString testCase;
+
+ QByteArray toLine() const;
+ void update(const TestCase &testCase);
+
+ static TestExpectationLine fromTestCase(const TestCase &testCase);
+private:
+ TestExpectationLine() = default;
+ static State stateFromTestCase(const TestCase &testCase);
+};
+
+TestExpectationLine::TestExpectationLine(const QByteArray &line)
+{
+ int space = line.indexOf(' ');
+
+ testCase = QString::fromUtf8(space > 0 ? line.left(space) : line);
+ if (!testCase.endsWith(".js"))
+ testCase += ".js";
+
+ state = Fails;
+ if (space < 0)
+ return;
+ QByteArray qualifier = line.mid(space + 1);
+ if (qualifier == "skip")
+ state = Skip;
+ else if (qualifier == "strictFails")
+ state = StrictFails;
+ else if (qualifier == "sloppyFails")
+ state = SloppyFails;
+ else if (qualifier == "fails")
+ state = Fails;
+ else
+ qWarning() << "illegal format in TestExpectations, line" << line;
+}
+
+QByteArray TestExpectationLine::toLine() const {
+ const char *res = nullptr;
+ switch (state) {
+ case Fails:
+ res = " fails\n";
+ break;
+ case SloppyFails:
+ res = " sloppyFails\n";
+ break;
+ case StrictFails:
+ res = " strictFails\n";
+ break;
+ case Skip:
+ res = " skip\n";
+ break;
+ case Passes:
+ // no need for an entry
+ return QByteArray();
+ }
+ QByteArray result = testCase.toUtf8() + res;
+ return result;
+}
+
+void TestExpectationLine::update(const TestCase &testCase)
+{
+ Q_ASSERT(testCase.test == this->testCase);
+
+ State resultState = stateFromTestCase(testCase);
+ switch (resultState) {
+ case Fails:
+ // no improvement, don't update
+ break;
+ case SloppyFails:
+ if (state == Fails)
+ state = SloppyFails;
+ else if (state == StrictFails)
+ // we have a regression in sloppy mode, but strict now passes
+ state = Passes;
+ break;
+ case StrictFails:
+ if (state == Fails)
+ state = StrictFails;
+ else if (state == SloppyFails)
+ // we have a regression in strict mode, but sloppy now passes
+ state = Passes;
+ break;
+ case Skip:
+ Q_ASSERT(state == Skip);
+ // nothing to do
+ break;
+ case Passes:
+ state = Passes;
+ }
+}
+
+TestExpectationLine TestExpectationLine::fromTestCase(const TestCase &testCase)
+{
+ TestExpectationLine l;
+ l.testCase = testCase.test;
+ l.state = stateFromTestCase(testCase);
+ return l;
+}
+
+TestExpectationLine::State TestExpectationLine::stateFromTestCase(const TestCase &testCase)
+{
+ // keep skipped tests
+ if (testCase.skipTestCase)
+ return Skip;
+
+ bool strictFails = (testCase.strictResult == TestCase::Crashes || testCase.strictResult == TestCase::Fails);
+ bool sloppyFails = (testCase.sloppyResult == TestCase::Crashes || testCase.sloppyResult == TestCase::Fails);
+ if (strictFails && sloppyFails)
+ return Fails;
+ if (strictFails)
+ return StrictFails;
+ if (sloppyFails)
+ return SloppyFails;
+ return Passes;
+}
+
+
+void Test262Runner::loadTestExpectations()
+{
+ QFile file("TestExpectations");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Could not open TestExpectations file.";
+ return;
+ }
+
+ int line = 0;
+ while (!file.atEnd()) {
+ ++line;
+ QByteArray line = file.readLine().trimmed();
+ if (line.startsWith('#') || line.isEmpty())
+ continue;
+ TestExpectationLine expectation(line);
+ if (!filter.isEmpty() && !expectation.testCase.contains(filter))
+ continue;
+
+ if (!testCases.contains(expectation.testCase))
+ qWarning() << "Unknown test case" << expectation.testCase << "in TestExpectations file.";
+ //qDebug() << "TestExpectations:" << expectation.testCase << expectation.state;
+ TestCase &s = testCases[expectation.testCase];
+ switch (expectation.state) {
+ case TestExpectationLine::Fails:
+ s.strictExpectation = TestCase::Fails;
+ s.sloppyExpectation = TestCase::Fails;
+ break;
+ case TestExpectationLine::SloppyFails:
+ s.strictExpectation = TestCase::Passes;
+ s.sloppyExpectation = TestCase::Fails;
+ break;
+ case TestExpectationLine::StrictFails:
+ s.strictExpectation = TestCase::Fails;
+ s.sloppyExpectation = TestCase::Passes;
+ break;
+ case TestExpectationLine::Skip:
+ s.skipTestCase = true;
+ break;
+ case TestExpectationLine::Passes:
+ Q_UNREACHABLE();
+ }
+ }
+}
+
+void Test262Runner::updateTestExpectations()
+{
+ QFile file("TestExpectations");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Could not open TestExpectations file.";
+ return;
+ }
+
+ QTemporaryFile updatedExpectations;
+ updatedExpectations.open();
+
+ int line = 0;
+ while (!file.atEnd()) {
+ ++line;
+ QByteArray originalLine = file.readLine();
+ QByteArray line = originalLine.trimmed();
+ if (line.startsWith('#') || line.isEmpty()) {
+ updatedExpectations.write(originalLine);
+ continue;
+ }
+
+ TestExpectationLine expectation(line);
+// qDebug() << "checking: " << expectation.testCase;
+ if (!testCases.contains(expectation.testCase)) {
+ updatedExpectations.write(originalLine);
+ continue;
+ }
+ const TestCase &testcase = testCases.value(expectation.testCase);
+ expectation.update(testcase);
+
+ line = expectation.toLine();
+// qDebug() << "updated line:" << line;
+ updatedExpectations.write(line);
+ }
+ file.close();
+ updatedExpectations.close();
+ file.remove();
+ qDebug() << updatedExpectations.fileName() << file.fileName();
+ updatedExpectations.copy(file.fileName());
+ qDebug() << "Updated TestExpectations file written!";
+}
+
+void Test262Runner::writeTestExpectations()
+{
+ QFile file("TestExpectations");
+
+ QTemporaryFile expectations;
+ expectations.open();
+
+ for (auto c : qAsConst(testCases)) {
+ TestExpectationLine line = TestExpectationLine::fromTestCase(c);
+ expectations.write(line.toLine());
+ }
+
+ expectations.close();
+ if (file.exists())
+ file.remove();
+ qDebug() << expectations.fileName() << file.fileName();
+ expectations.copy(file.fileName());
+ qDebug() << "new TestExpectations file written!";
+
+}
+
+static bool executeTest(const QByteArray &data)
+{
+ QString testData = QString::fromUtf8(data);
+
+ QV4::ExecutionEngine vm;
+
+ QV4::Scope scope(&vm);
+ QV4::ScopedContext ctx(scope, vm.rootContext());
+
+ QV4::GlobalExtensions::init(vm.globalObject, QJSEngine::ConsoleExtension | QJSEngine::GarbageCollectionExtension);
+
+ QV4::Script script(ctx, QV4::Compiler::ContextType::Global, testData, QString());
+ script.parse();
+
+ QV4::ScopedValue result(scope);
+ if (!scope.engine->hasException)
+ result = script.run();
+
+ if (scope.engine->hasException)
+ return false;
+ return true;
+}
+
+class SingleTest : public QRunnable
+{
+public:
+ SingleTest(Test262Runner *runner, const TestData &data)
+ : runner(runner), data(data)
+ {
+ command = runner->command;
+ }
+ void run();
+
+ void runExternalTest();
+
+ QString command;
+ Test262Runner *runner;
+ TestData data;
+};
+
+void SingleTest::run()
+{
+ if (!command.isEmpty()) {
+ runExternalTest();
+ return;
+ }
+
+ if (data.runInSloppyMode) {
+ bool ok = ::executeTest(data.content);
+ if (data.negative)
+ ok = !ok;
+
+ data.sloppyResult = ok ? TestCase::Passes : TestCase::Fails;
+ } else {
+ data.sloppyResult = TestCase::Skipped;
+ }
+ if (data.runInStrictMode) {
+ QByteArray c = "'use strict';\n" + data.content;
+ bool ok = ::executeTest(c);
+ if (data.negative)
+ ok = !ok;
+
+ data.strictResult = ok ? TestCase::Passes : TestCase::Fails;
+ } else {
+ data.strictResult = TestCase::Skipped;
+ }
+ runner->addResult(data);
+}
+
+void SingleTest::runExternalTest()
+{
+ auto runTest = [=] (const char *header, TestCase::Result *result) {
+ QTemporaryFile tempFile;
+ tempFile.open();
+ tempFile.write(header);
+ tempFile.write(data.content);
+ tempFile.close();
+
+ QProcess process;
+// if (flags & Verbose)
+// process.setReadChannelMode(QProcess::ForwardedChannels);
+
+ process.start(command, QStringList(tempFile.fileName()));
+ if (!process.waitForFinished(-1) || process.error() == QProcess::FailedToStart) {
+ qWarning() << "Could not execute" << command;
+ *result = TestCase::Crashes;
+ }
+ if (process.exitStatus() != QProcess::NormalExit) {
+ *result = TestCase::Crashes;
+ }
+ bool ok = (process.exitCode() == EXIT_SUCCESS);
+ if (data.negative)
+ ok = !ok;
+ *result = ok ? TestCase::Passes : TestCase::Fails;
+ };
+
+ if (data.runInSloppyMode)
+ runTest("", &data.sloppyResult);
+ if (data.runInStrictMode)
+ runTest("'use strict';\n", &data.strictResult);
+
+ runner->addResult(data);
+}
+
+int Test262Runner::runSingleTest(TestCase testCase)
+{
+ TestData data = getTestData(testCase);
+// qDebug() << "starting test" << data.test;
+
+ if (data.isExcluded || data.async || data.runAsModuleCode)
+ return 0;
+
+ if (threadPool) {
+ SingleTest *test = new SingleTest(this, data);
+ threadPool->start(test);
+ return 0;
+ }
+ SingleTest test(this, data);
+ test.run();
+ return 0;
+}
+
+void Test262Runner::addResult(TestCase result)
+{
+ {
+ QMutexLocker locker(&mutex);
+ Q_ASSERT(result.strictExpectation == testCases[result.test].strictExpectation);
+ Q_ASSERT(result.sloppyExpectation == testCases[result.test].sloppyExpectation);
+ testCases[result.test] = result;
+ }
+
+ if (!(flags & Verbose))
+ return;
+
+ QString test = result.test;
+ if (result.strictResult == TestCase::Skipped) {
+ ;
+ } else if (result.strictResult == TestCase::Crashes) {
+ qDebug() << "FAIL:" << test << "crashed in strict mode!";
+ } else if ((result.strictResult == TestCase::Fails) && (result.strictExpectation == TestCase::Fails)) {
+ qDebug() << "PASS:" << test << "failed in strict mode as expected";
+ } else if ((result.strictResult == TestCase::Passes) == (result.strictExpectation == TestCase::Passes)) {
+ qDebug() << "PASS:" << test << "passed in strict mode";
+ } else if (!(result.strictExpectation == TestCase::Fails)) {
+ qDebug() << "FAIL:" << test << "failed in strict mode";
+ } else {
+ qDebug() << "XPASS:" << test << "unexpectedly passed in strict mode";
+ }
+
+ if (result.sloppyResult == TestCase::Skipped) {
+ ;
+ } else if (result.sloppyResult == TestCase::Crashes) {
+ qDebug() << "FAIL:" << test << "crashed in sloppy mode!";
+ } else if ((result.sloppyResult == TestCase::Fails) && (result.sloppyExpectation == TestCase::Fails)) {
+ qDebug() << "PASS:" << test << "failed in sloppy mode as expected";
+ } else if ((result.sloppyResult == TestCase::Passes) == (result.sloppyExpectation == TestCase::Passes)) {
+ qDebug() << "PASS:" << test << "passed in sloppy mode";
+ } else if (!(result.sloppyExpectation == TestCase::Fails)) {
+ qDebug() << "FAIL:" << test << "failed in sloppy mode";
+ } else {
+ qDebug() << "XPASS:" << test << "unexpectedly passed in sloppy mode";
+ }
+}
+
+TestData Test262Runner::getTestData(const TestCase &testCase)
+{
+ QFile testFile(testDir + "/test/" + testCase.test);
+ if (!testFile.open(QFile::ReadOnly)) {
+ qWarning() << "wrong test file" << testCase.test;
+ exit(1);
+ }
+ QByteArray content = testFile.readAll();
+
+// qDebug() << "parsing test file" << test;
+
+ TestData data(testCase);
+ parseYaml(content, &data);
+
+ data.content += harness("assert.js");
+ data.content += harness("sta.js");
+
+ for (QByteArray inc : qAsConst(data.includes)) {
+ inc = inc.trimmed();
+ data.content += harness(inc);
+ }
+
+ if (data.async)
+ data.content += harness("doneprintHandle.js");
+
+ data.content += content;
+
+ return data;
+}
+
+struct YamlSection {
+ YamlSection(const QByteArray &yaml, const char *sectionName);
+
+ bool contains(const char *keyword) const;
+ QList<QByteArray> keywords() const;
+
+ QByteArray yaml;
+ int start = -1;
+ int length = 0;
+ bool shortSection = false;
+};
+
+YamlSection::YamlSection(const QByteArray &yaml, const char *sectionName)
+ : yaml(yaml)
+{
+ start = yaml.indexOf(sectionName);
+ if (start < 0)
+ return;
+ start += static_cast<int>(strlen(sectionName));
+ int end = yaml.indexOf('\n', start + 1);
+ if (end < 0)
+ end = yaml.length();
+
+ int s = yaml.indexOf('[', start);
+ if (s > 0 && s < end) {
+ shortSection = true;
+ start = s + 1;
+ end = yaml.indexOf(']', s);
+ } else {
+ while (end < yaml.size() - 1 && yaml.at(end + 1) == ' ')
+ end = yaml.indexOf('\n', end + 1);
+ }
+ length = end - start;
+}
+
+bool YamlSection::contains(const char *keyword) const
+{
+ if (start < 0)
+ return false;
+ int idx = yaml.indexOf(keyword, start);
+ if (idx >= start && idx < start + length)
+ return true;
+ return false;
+}
+
+QList<QByteArray> YamlSection::keywords() const
+{
+ if (start < 0)
+ return QList<QByteArray>();
+
+ QByteArray content = yaml.mid(start, length);
+ QList<QByteArray> keywords;
+ if (shortSection) {
+ keywords = content.split(',');
+ } else {
+ const QList<QByteArray> list = content.split('\n');
+ for (const QByteArray &l : list) {
+ int i = 0;
+ while (i < l.size() && (l.at(i) == ' ' || l.at(i) == '-'))
+ ++i;
+ QByteArray entry = l.mid(i);
+ if (!entry.isEmpty())
+ keywords.append(entry);
+ }
+ }
+// qDebug() << "keywords:" << keywords;
+ return keywords;
+}
+
+
+void Test262Runner::parseYaml(const QByteArray &content, TestData *data)
+{
+ int start = content.indexOf("/*---");
+ if (start < 0)
+ return;
+ start += sizeof("/*---");
+
+ int end = content.indexOf("---*/");
+ if (end < 0)
+ return;
+
+ QByteArray yaml = content.mid(start, end - start);
+
+ if (yaml.contains("negative:"))
+ data->negative = true;
+
+ YamlSection flags(yaml, "flags:");
+ data->runInSloppyMode = !flags.contains("onlyStrict");
+ data->runInStrictMode = !flags.contains("noStrict") && !flags.contains("raw");
+ data->runAsModuleCode = flags.contains("module");
+ data->async = flags.contains("async");
+
+ YamlSection includes(yaml, "includes:");
+ data->includes = includes.keywords();
+
+ YamlSection features = YamlSection(yaml, "features:");
+
+ const char **f = excludedFeatures;
+ while (*f) {
+ if (features.contains(*f)) {
+ data->isExcluded = true;
+ break;
+ }
+ ++f;
+ }
+
+// qDebug() << "Yaml:\n" << yaml;
+}
+
+QByteArray Test262Runner::harness(const QByteArray &name)
+{
+ if (harnessFiles.contains(name))
+ return harnessFiles.value(name);
+
+ QFile h(testDir + QLatin1String("/harness/") + name);
+ if (!h.open(QFile::ReadOnly)) {
+ qWarning() << "Illegal test harness file" << name;
+ exit(1);
+ }
+
+ QByteArray content = h.readAll();
+ harnessFiles.insert(name, content);
+ return content;
+}
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.h b/tests/auto/qml/ecmascripttests/qjstest/test262runner.h
new file mode 100644
index 0000000000..a4035e0b72
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the V4VM module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TEST262RUNNER_H
+#define TEST262RUNNER_H
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qset.h>
+#include <qmap.h>
+#include <qmutex.h>
+#include <qthreadpool.h>
+
+struct TestCase {
+ TestCase() = default;
+ TestCase(const QString &test)
+ : test(test) {}
+ enum Result {
+ Skipped,
+ Passes,
+ Fails,
+ Crashes
+ };
+ bool skipTestCase = false;
+ Result strictExpectation = Passes;
+ Result sloppyExpectation = Passes;
+ Result strictResult = Skipped;
+ Result sloppyResult = Skipped;
+
+ QString test;
+};
+
+struct TestData : TestCase {
+ TestData(const TestCase &testCase)
+ : TestCase(testCase) {}
+ // flags
+ bool negative = false;
+ bool runInStrictMode = true;
+ bool runInSloppyMode = true;
+ bool runAsModuleCode = false;
+ bool async = false;
+
+ bool isExcluded = false;
+
+ QList<QByteArray> includes;
+
+ QByteArray content;
+};
+
+class Test262Runner
+{
+public:
+ Test262Runner(const QString &command, const QString &testDir);
+ ~Test262Runner();
+
+ enum Mode {
+ Sloppy = 0,
+ Strict = 1
+ };
+
+ enum Flags {
+ Verbose = 0x1,
+ Parallel = 0x2,
+ ForceBytecode = 0x4,
+ ForceJIT = 0x8,
+ WithTestExpectations = 0x10,
+ UpdateTestExpectations = 0x20,
+ WriteTestExpectations = 0x40,
+ };
+ void setFlags(int f) { flags = f; }
+
+ void setFilter(const QString &f) { filter = f; }
+
+ void cat();
+ bool run();
+
+ void report();
+
+private:
+ friend class SingleTest;
+ bool loadTests();
+ void loadTestExpectations();
+ void updateTestExpectations();
+ void writeTestExpectations();
+ int runSingleTest(TestCase testCase);
+
+ TestData getTestData(const TestCase &testCase);
+ void parseYaml(const QByteArray &content, TestData *data);
+
+ QByteArray harness(const QByteArray &name);
+
+ void addResult(TestCase result);
+
+ QString command;
+ QString testDir;
+ int flags = 0;
+
+ QMutex mutex;
+ QString filter;
+
+ QMap<QString, TestCase> testCases;
+ QHash<QByteArray, QByteArray> harnessFiles;
+
+ QThreadPool *threadPool = nullptr;
+};
+
+
+#endif
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject 40b4f28e98c416a092e26aa17489bf94ccb8bf4
+Subproject 3c69133cc419840c1be34638039cd8c48a7ef58
diff --git a/tests/auto/qml/ecmascripttests/test262.py b/tests/auto/qml/ecmascripttests/test262.py
index e055c7a8e7..19551e3ba2 100755
--- a/tests/auto/qml/ecmascripttests/test262.py
+++ b/tests/auto/qml/ecmascripttests/test262.py
@@ -61,6 +61,35 @@ from parseTestRecord import parseTestRecord, stripHeader
from packagerConfig import *
+# excluded features that are still experimental and not part of any official standard
+# see also the features.txt file in test262/
+excludedFeatures = [
+ "BigInt",
+ "class-fields-public",
+ "class-fields-private",
+ "Promise.prototype.finally",
+ "async-iteration",
+ "Symbol.asyncIterator",
+ "object-rest",
+ "object-spread",
+ "optional-catch-binding",
+ "regexp-dotall",
+ "regexp-lookbehind",
+ "regexp-named-groups",
+ "regexp-unicode-property-escapes",
+ "Atomics",
+ "SharedArrayBuffer",
+ "Array.prototype.flatten",
+ "Array.prototype.flatMap",
+ "string-trimming",
+ "String.prototype.trimEnd",
+ "String.prototype.trimStart",
+ "numeric-separator-literal",
+
+ # optional features, not supported by us
+ "caller"
+]
+
# ############# Helpers needed for parallel multi-process test execution ############
def runTest(case, args):
@@ -95,19 +124,19 @@ class TestExpectations:
continue
record = line.split()
if len(record) == 1:
- self.testsToSkip.append(record[0])
+ self.failingTests.append(record[0])
else:
test = record[0]
expectation = record[1]
- if expectation == "failing":
- self.failingTests.append(test)
+ if expectation == "skip":
+ self.testsToSkip.append(test)
f.close()
def update(self, progress):
- unexpectedPasses = [c.case.name[-1] for c in progress.failed_tests if c.case.IsNegative()]
+ unexpectedPasses = [c.case.name for c in progress.failed_tests if c.case.IsNegative()]
# If a test fails that we expected to fail, then it actually passed unexpectedly.
- failures = [c.case.name[-1] for c in progress.failed_tests if not c.case.IsNegative()]
+ failures = [c.case.name for c in progress.failed_tests if not c.case.IsNegative()]
for failure in failures:
if failure in self.failingTests:
unexpectedPasses.append(failure)
@@ -116,7 +145,7 @@ class TestExpectations:
lines = f.read().splitlines()
oldLen = len(lines)
for result in unexpectedPasses:
- expectationLine = result + " failing"
+ expectationLine = result
try:
lines.remove(expectationLine)
except ValueError:
@@ -277,14 +306,17 @@ class TestCase(object):
f.close()
testRecord = parseTestRecord(self.contents, name)
self.test = testRecord["test"]
+ if 'features' in testRecord:
+ self.features = testRecord["features"];
+ else:
+ self.features = []
del testRecord["test"]
del testRecord["header"]
- del testRecord["commentary"]
self.testRecord = testRecord;
def GetName(self):
- return path.join(*self.name)
+ return self.name
def GetMode(self):
if self.strict_mode:
@@ -310,14 +342,20 @@ class TestCase(object):
def IsNoStrict(self):
return 'noStrict' in self.testRecord
+ def IsExperimental(self):
+ for f in self.features:
+ if excludedFeatures.count(f) >= 1:
+ return True;
+ return False
+
def GetSource(self):
# "var testDescrip = " + str(self.testRecord) + ';\n\n' + \
- source = self.suite.GetInclude("cth.js") + \
+ source = self.suite.GetInclude("assert.js") + \
self.suite.GetInclude("sta.js") + \
- self.suite.GetInclude("ed.js") + \
- self.suite.GetInclude("testBuiltInObject.js") + \
- self.suite.GetInclude("testIntl.js") + \
self.test + '\n'
+ if 'includes' in self.testRecord:
+ for inc in self.testRecord['includes']:
+ source += self.suite.GetInclude(inc);
if self.strict_mode:
source = '"use strict";\nvar strict_mode = true;\n' + source
@@ -403,14 +441,23 @@ class TestSuite(object):
def __init__(self, root, strict_only, non_strict_only, unmarked_default, load_expectations):
# TODO: derive from packagerConfig.py
- self.test_root = path.join(root, 'test', 'suite')
- self.lib_root = path.join(root, 'test', 'harness')
+ self.test_root = path.join(root, 'test')
+ self.lib_root = path.join(root, 'harness')
self.strict_only = strict_only
self.non_strict_only = non_strict_only
self.unmarked_default = unmarked_default
self.include_cache = { }
self.expectations = TestExpectations(load_expectations)
+ def IsExcludedTest(self, path):
+ if path.startswith('annexB'):
+ return True;
+ if path.startswith('harness'):
+ return True;
+ if path.startswith('intl402'):
+ return True;
+ return False;
+
def Validate(self):
if not path.exists(self.test_root):
ReportError("No test repository found")
@@ -459,25 +506,25 @@ class TestSuite(object):
else:
logging.warning("Unexpected path %s", full_path)
rel_path = full_path
- if self.ShouldRun(rel_path, tests) and not rel_path.startswith("intl402" + os.sep):
+ if self.ShouldRun(rel_path, tests) and not self.IsExcludedTest(rel_path):
basename = path.basename(full_path)[:-3]
- name = rel_path.split(path.sep)[:-1] + [basename]
- if EXCLUDE_LIST.count(basename) >= 1 or self.expectations.testsToSkip.count(basename) >= 1:
- print 'Excluded: ' + basename
+ name = rel_path.replace('.js', '')
+ if EXCLUDE_LIST.count(basename) >= 1 or self.expectations.testsToSkip.count(name) >= 1:
+ print 'Excluded: ' + rel_path
else:
if not self.non_strict_only:
strict_case = TestCase(self, name, full_path, True)
- if self.expectations.failingTests.count(basename) >= 1:
+ if self.expectations.failingTests.count(name) >= 1:
strict_case.NegateResult()
- if not strict_case.IsNoStrict():
+ if not strict_case.IsNoStrict() and not strict_case.IsExperimental():
if strict_case.IsOnlyStrict() or \
self.unmarked_default in ['both', 'strict']:
cases.append(strict_case)
if not self.strict_only:
non_strict_case = TestCase(self, name, full_path, False)
- if self.expectations.failingTests.count(basename) >= 1:
+ if self.expectations.failingTests.count(name) >= 1:
non_strict_case.NegateResult()
- if not non_strict_case.IsOnlyStrict():
+ if not non_strict_case.IsOnlyStrict() and not non_strict_case.IsExperimental():
if non_strict_case.IsNoStrict() or \
self.unmarked_default in ['both', 'non_strict']:
cases.append(non_strict_case)
diff --git a/tests/auto/qml/ecmascripttests/testcase.pro b/tests/auto/qml/ecmascripttests/testcase.pro
new file mode 100644
index 0000000000..5bf7ecd696
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/testcase.pro
@@ -0,0 +1,15 @@
+CONFIG += testcase
+TARGET = tst_ecmascripttests
+QT += testlib qml-private
+macos:CONFIG -= app_bundle
+SOURCES += tst_ecmascripttests.cpp qjstest/test262runner.cpp
+HEADERS += qjstest/test262runner.h
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+
+# The ES test suite takes approximately 5 mins to run, on a fairly
+# vanilla developer machine, so the default watchdog timer kills the
+# test some of the time. Fix by raising time-out to 400s when
+# invoking tst_ecmascripttests:
+checkenv.name = QTEST_FUNCTION_TIMEOUT
+checkenv.value = 500000
+QT_TOOL_ENV += checkenv
diff --git a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
index 0d58d045b9..27d2822762 100644
--- a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
+++ b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp
@@ -30,55 +30,37 @@
#include <QtTest/QtTest>
#include <QProcess>
#include <QLibraryInfo>
+#include <qjstest/test262runner.h>
class tst_EcmaScriptTests : public QObject
{
Q_OBJECT
- void runTests(bool interpret);
-
private slots:
void runInterpreted();
void runJitted();
};
-void tst_EcmaScriptTests::runTests(bool interpret)
-{
-#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_X86_64)
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- if (interpret)
- env.insert("QV4_FORCE_INTERPRETER", "1");
- else
- env.insert("QV4_JIT_CALL_THRESHOLD", "0");
-
- QProcess process;
- process.setProcessChannelMode(QProcess::ForwardedChannels);
- process.setWorkingDirectory(QLatin1String(SRCDIR));
- process.setProgram("python");
- process.setProcessEnvironment(env);
- process.setArguments(QStringList() << "test262.py" << "--command=" + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs" << "--parallel" << "--with-test-expectations");
-
- qDebug() << "Going to run" << process.program() << process.arguments() << "in" << process.workingDirectory();
-
- process.start();
- QVERIFY(process.waitForStarted());
- const int timeoutInMSecs = 20 * 60 * 1000;
- QVERIFY2(process.waitForFinished(timeoutInMSecs), "Tests did not terminate in time -- see output above for details");
- QVERIFY2(process.exitStatus() == QProcess::NormalExit, "Running the test harness failed -- see output above for details");
- QVERIFY2(process.exitCode() == 0, "Tests failed -- see output above for details");
-#else
- QSKIP("Currently the ecmascript tests are only run on Linux/x86-64");
-#endif
-}
-
void tst_EcmaScriptTests::runInterpreted()
{
- runTests(true);
+#if defined(Q_PROCESSOR_X86_64)
+ QDir::setCurrent(QLatin1String(SRCDIR));
+ Test262Runner runner(QString(), "test262");
+ runner.setFlags(Test262Runner::ForceBytecode|Test262Runner::WithTestExpectations|Test262Runner::Parallel|Test262Runner::Verbose);
+ bool result = runner.run();
+ QVERIFY(result);
+#endif
}
void tst_EcmaScriptTests::runJitted()
{
- runTests(false);
+#if defined(Q_PROCESSOR_X86_64)
+ QDir::setCurrent(QLatin1String(SRCDIR));
+ Test262Runner runner(QString(), "test262");
+ runner.setFlags(Test262Runner::ForceJIT|Test262Runner::WithTestExpectations|Test262Runner::Parallel|Test262Runner::Verbose);
+ bool result = runner.run();
+ QVERIFY(result);
+#endif
}
QTEST_GUILESS_MAIN(tst_EcmaScriptTests)
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index bb923951a8..08f69618c4 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -206,7 +206,18 @@ private slots:
void scriptScopes();
+ void binaryNumbers();
+ void octalNumbers();
+
+ void incrementAfterNewline();
+
+ void deleteInsideForIn();
+
+ void functionToString_data();
+ void functionToString();
+
void protoChanges_QTBUG68369();
+ void multilineStrings();
signals:
void testSignal();
@@ -942,6 +953,7 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "decodeURIComponent"
<< "Date"
<< "Array"
+ << "Symbol"
<< "escape"
<< "unescape"
<< "SyntaxError"
@@ -958,6 +970,9 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "Uint32Array"
<< "Float32Array"
<< "Float64Array"
+ << "Set"
+ << "Map"
+ << "Reflect"
;
QSet<QString> actualNames;
{
@@ -3207,9 +3222,7 @@ void tst_QJSEngine::threadedEngine()
void tst_QJSEngine::functionDeclarationsInConditionals()
{
- // Even though this is bad practice (and test262 covers it with best practices test cases),
- // we do allow for function declarations in if and while statements, as unfortunately that's
- // real world JavaScript. (QTBUG-33064 for example)
+ // Visibility of function declarations inside blocks is limited to the block
QJSEngine eng;
QJSValue result = eng.evaluate("if (true) {\n"
" function blah() { return false; }\n"
@@ -3217,8 +3230,7 @@ void tst_QJSEngine::functionDeclarationsInConditionals()
" function blah() { return true; }\n"
"}\n"
"blah();");
- QVERIFY(result.isBool());
- QCOMPARE(result.toBool(), true);
+ QVERIFY(result.isError());
}
void tst_QJSEngine::arrayPop_QTBUG_35979()
@@ -4169,6 +4181,88 @@ void tst_QJSEngine::scriptScopes()
QCOMPARE(use.toInt(), 42);
}
+void tst_QJSEngine::binaryNumbers()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("0b1001");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0B1001");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0b2");
+ QVERIFY(result.isError());
+}
+
+void tst_QJSEngine::octalNumbers()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("0o11");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0O11");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 9);
+
+ result = engine.evaluate("0o9");
+ QVERIFY(result.isError());
+}
+
+void tst_QJSEngine::incrementAfterNewline()
+{
+ QJSEngine engine;
+
+ QJSValue result = engine.evaluate("var x = 0; if (\n++x) x; else -x;");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == 1);
+
+ result = engine.evaluate("var x = 0; if (\n--x) x; else -x;");
+ QVERIFY(result.isNumber());
+ QVERIFY(result.toNumber() == -1);
+}
+
+void tst_QJSEngine::deleteInsideForIn()
+{
+ QJSEngine engine;
+
+ QJSValue iterationCount = engine.evaluate(
+ "var o = { a: 1, b: 2, c: 3, d: 4};\n"
+ "var count = 0;\n"
+ "for (var prop in o) { count++; delete o[prop]; }\n"
+ "count");
+ QVERIFY(iterationCount.isNumber());
+ QCOMPARE(iterationCount.toInt(), 4);
+}
+
+void tst_QJSEngine::functionToString_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("expectedString");
+
+ QTest::newRow("named function") << QString::fromLatin1("function f() {}; f.toString()")
+ << QString::fromLatin1("function f() { [code] }");
+ QTest::newRow("anonymous function") << QString::fromLatin1("(function() {}).toString()")
+ << QString::fromLatin1("function() { [code] }");
+}
+
+// Tests that function.toString() prints the function's name.
+void tst_QJSEngine::functionToString()
+{
+ QFETCH(QString, source);
+ QFETCH(QString, expectedString);
+
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::AllExtensions);
+ QJSValue evaluationResult = engine.evaluate(source);
+ QVERIFY(!evaluationResult.isError());
+ QCOMPARE(evaluationResult.toString(), expectedString);
+}
+
void tst_QJSEngine::protoChanges_QTBUG68369()
{
QJSEngine engine;
@@ -4185,6 +4279,17 @@ void tst_QJSEngine::protoChanges_QTBUG68369()
QVERIFY(ok.toBool() == true);
}
+void tst_QJSEngine::multilineStrings()
+{
+ QJSEngine engine;
+ QJSValue result = engine.evaluate(
+ "var x = `a\nb`; x;"
+ );
+ QVERIFY(result.isString());
+ QVERIFY(result.toString() == QStringLiteral("a\nb"));
+
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index f5905758f3..d363180c06 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -106,7 +106,7 @@ struct TestCompiler
{
closeMapping();
testFilePath = baseDirectory + QStringLiteral("/test.qml");
- cacheFilePath = baseDirectory + QStringLiteral("/test.qmlc");
+ cacheFilePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
mappedFile.setFileName(cacheFilePath);
}
@@ -499,7 +499,7 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
- QFile cacheFile(testFilePath + "c");
+ QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
@@ -514,7 +514,7 @@ void tst_qmldiskcache::fileSelectors()
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 100);
- QFile cacheFile(selectedTestFilePath + "c");
+ QFile cacheFile(QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(selectedTestFilePath)));
QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName()));
}
}
@@ -667,7 +667,7 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes()
QVERIFY2(firstDependentTypeClassName.contains("QMLTYPE"), firstDependentTypeClassName.constData());
QVERIFY2(secondDependentTypeClassName.contains("QMLTYPE"), secondDependentTypeClassName.constData());
- const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -745,7 +745,7 @@ void tst_qmldiskcache::singletonDependency()
QCOMPARE(obj->property("value").toInt(), 42);
}
- const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
@@ -802,7 +802,7 @@ void tst_qmldiskcache::cppRegisteredSingletonDependency()
QCOMPARE(value.toInt(), 42);
}
- const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ const QString testFileCachePath = QV4::CompiledData::CompilationUnit::localCacheFilePath(QUrl::fromLocalFile(testFilePath));
QVERIFY(QFile::exists(testFileCachePath));
QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
index 5941385c80..e1ba6d12c0 100644
--- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp
+++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp
@@ -125,6 +125,8 @@ void tst_qmlmin::initTestCase()
invalidFiles << "tests/auto/qml/qqmlecmascript/data/stringParsing_error.6.qml";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.1.qml";
invalidFiles << "tests/auto/qml/qqmlecmascript/data/numberParsing_error.2.qml";
+ invalidFiles << "tests/auto/qml/parserstress/tests/ecma_3/FunExpr/fe-001.js";
+ invalidFiles << "tests/auto/qml/qjsengine/script/com/trolltech/syntaxerror/__init__.js";
}
QStringList tst_qmlmin::findFiles(const QDir &d)
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index 3a70890362..efd5bb571b 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -116,6 +116,7 @@ private slots:
void onDestructionCount();
void recursion();
void recursionContinuation();
+ void partialComponentCreation();
void callingContextForInitialProperties();
void setNonExistentInitialProperty();
void relativeUrl_data();
@@ -527,6 +528,29 @@ void tst_qqmlcomponent::recursionContinuation()
QVERIFY(object->property("success").toBool());
}
+void tst_qqmlcomponent::partialComponentCreation()
+{
+ const int maxCount = 17;
+ QQmlEngine engine;
+ QScopedPointer<QQmlComponent> components[maxCount];
+ QScopedPointer<QObject> objects[maxCount];
+ QQmlTestMessageHandler messageHandler;
+
+ QCOMPARE(engine.outputWarningsToStandardError(), true);
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i].reset(new QQmlComponent(&engine, testFileUrl("QtObjectComponent.qml")));
+ objects[i].reset(components[i]->beginCreate(engine.rootContext()));
+ QVERIFY(objects[i].isNull() == false);
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i]->completeCreate();
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+}
+
class CallingContextCheckingClass : public QObject
{
Q_OBJECT
diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml
index d55c99bcbd..0764ad7545 100644
--- a/tests/auto/qml/qqmlconsole/data/logging.qml
+++ b/tests/auto/qml/qqmlconsole/data/logging.qml
@@ -67,6 +67,8 @@ QtObject {
console.log(1, "pong!", new Object);
console.log(1, ["ping","pong"], new Object, 2);
+ console.log(contextStringListProperty);
+
try {
console.log(exception);
} catch (e) {
diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
index 0d915f98f8..40a9295e50 100644
--- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
+++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp
@@ -29,6 +29,7 @@
#include <QDebug>
#include <QQmlEngine>
#include <QQmlComponent>
+#include <QQmlContext>
#include <QLoggingCategory>
#include "../../shared/util.h"
@@ -74,18 +75,22 @@ void tst_qqmlconsole::logging()
QTest::ignoreMessage(QtDebugMsg, "{\"a\":\"hello\",\"d\":1}");
QTest::ignoreMessage(QtDebugMsg, "undefined");
QTest::ignoreMessage(QtDebugMsg, "12");
- QTest::ignoreMessage(QtDebugMsg, "function() { [code] }");
+ QTest::ignoreMessage(QtDebugMsg, "function e() { [code] }");
QTest::ignoreMessage(QtDebugMsg, "true");
// Printing QML object prints out the class/type of QML object with the memory address
// QTest::ignoreMessage(QtDebugMsg, "QtObject_QML_0(0xABCD..)");
// QTest::ignoreMessage(QtDebugMsg, "[object Object]");
QTest::ignoreMessage(QtDebugMsg, "1 pong! [object Object]");
QTest::ignoreMessage(QtDebugMsg, "1 [ping,pong] [object Object] 2");
+ QTest::ignoreMessage(QtDebugMsg, "[Hello,World]");
+
+ QScopedPointer<QQmlContext> loggingContext(new QQmlContext(engine.rootContext()));
+ QStringList stringList; stringList << QStringLiteral("Hello") << QStringLiteral("World");
+ loggingContext->setContextProperty("contextStringListProperty", stringList);
QQmlComponent component(&engine, testUrl);
- QObject *object = component.create();
+ QScopedPointer<QObject> object(component.create(loggingContext.data()));
QVERIFY(object != nullptr);
- delete object;
}
void tst_qqmlconsole::categorized_logging()
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml
new file mode 100644
index 0000000000..3f838fe8f2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.8.qml
@@ -0,0 +1,16 @@
+import QtQml 2.0
+QtObject {
+ function tryWritingReadOnlySequence() {
+ try {
+ Qt.application.arguments.push("hello")
+ } catch (e) {
+
+ try {
+ Qt.application.arguments.sort()
+ } catch (e) {
+ return true
+ }
+ }
+ return false
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js
new file mode 100644
index 0000000000..500f04bec7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.js
@@ -0,0 +1,7 @@
+.pragma library
+var Shadowed = 2;
+var global = (function(){return this})()
+
+// set Shadowed on the global object as well. This should be different from
+// the variable above, as the library has it's on context
+global.Shadowed = 1;
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml
new file mode 100644
index 0000000000..7cac09d342
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_shadow.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import "include_pragma_shadow.js" as Shadowed
+import "include_pragma_shadow.js" as Other
+
+Item {
+ property bool result
+
+ Component.onCompleted: {
+ result = false;
+ var global = (function(){return this})()
+ if (Shadowed.Shadowed === 2 && Other.Shadowed === 2 && global.Shadowed === 1)
+ result = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
index fa6497d99b..66e18ac2a9 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
@@ -7,5 +7,5 @@ function importIncrementedValue() {
i = i + 1;
// because LibraryImport is shared, and used in previous tests,
// the value will be large (already incremented a bunch of times).
- return (i + LibraryImport.importIncrementedValue());
+ return (i + LibraryImport.importIncrementedValue()); // 11 + 5
}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
index 01f08dbdc3..8264b7229d 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
@@ -3,5 +3,5 @@ import "importPragmaLibraryWithPragmaLibraryImports.js" as LibraryImport
QtObject {
id: root
- property int testValue: LibraryImport.importIncrementedValue(); // 10 + 1 + (7 due to previous tests) = 18
+ property int testValue: LibraryImport.importIncrementedValue(); // 16
}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
index ae43e90210..0e314b20ea 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsImport.qml
@@ -1,7 +1,7 @@
import QtQuick 2.0
-import com.nokia.JsModule 1.0
-import com.nokia.JsModule 1.0 as RenamedModule
+import com.qt.JsModule 1.0
+import com.qt.JsModule 1.0 as RenamedModule
import "testJsModuleImport.js" as TestJsModuleImport
QtObject {
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
index 2d21953d2c..7440f610c1 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleImport.js
@@ -1,4 +1,4 @@
-.import com.nokia.JsModule 1.0 as JsModule
+.import com.qt.JsModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
index e6e41bc6b2..6826f09da2 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsModuleRemoteImport.js
@@ -1,4 +1,4 @@
-.import com.nokia.JsRemoteModule 1.0 as JsModule
+.import com.qt.JsRemoteModule 1.0 as JsModule
function importedValue() {
return JsModule.ScriptAPI.greeting();
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
index 4199bb022d..f49b38df23 100644
--- a/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testJsRemoteImport.qml
@@ -1,7 +1,7 @@
import QtQuick 2.0
-import com.nokia.JsModule 1.0
-import com.nokia.JsModule 1.0 as RenamedModule
+import com.qt.JsModule 1.0
+import com.qt.JsModule 1.0 as RenamedModule
import "testJsModuleRemoteImport.js" as TestJsModuleImport
QtObject {
diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js
index b90033eeb4..b90033eeb4 100644
--- a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/ScriptAPI.js
+++ b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/ScriptAPI.js
diff --git a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir
index c33d1e7a0d..c33d1e7a0d 100644
--- a/tests/auto/qml/qqmlecmascript/data/lib/com/nokia/JsModule/qmldir
+++ b/tests/auto/qml/qqmlecmascript/data/lib/com/qt/JsModule/qmldir
diff --git a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/ScriptAPI.js b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/ScriptAPI.js
index b90033eeb4..b90033eeb4 100644
--- a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/ScriptAPI.js
+++ b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/ScriptAPI.js
diff --git a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir
index c33d1e7a0d..c33d1e7a0d 100644
--- a/tests/auto/qml/qqmlecmascript/data/remote/com/nokia/JsRemoteModule/qmldir
+++ b/tests/auto/qml/qqmlecmascript/data/remote/com/qt/JsRemoteModule/qmldir
diff --git a/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml
new file mode 100644
index 0000000000..aacf16474d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+Item {
+ property rect placement: Qt.rect(0, 0, 100, 100)
+
+ function someFunction() { return 42; }
+
+ property rect partialPlacement
+ partialPlacement.x: someFunction()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
index 04b39f73d5..7f5a22a459 100644
--- a/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
@@ -8,6 +8,6 @@ MyQmlObject {
return 321
}
- value: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 123 }
+ qjsvalue: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 123 }
}
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
index 231aaf0683..39d4f74e97 100644
--- a/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
@@ -7,6 +7,6 @@ MyQmlObject {
return 321
}
- value: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 321 }
+ qjsvalue: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 321 }
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index f40a9758f7..acdee3a808 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -49,6 +49,8 @@
#include <private/qv4object_p.h>
#include <private/qqmlcomponentattached_p.h>
#include <private/qv4objectiterator_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
#ifdef Q_CC_MSVC
#define NO_INLINE __declspec(noinline)
@@ -353,11 +355,11 @@ private slots:
void anotherNaN();
void callPropertyOnUndefined();
void jumpStrictNotEqualUndefined();
+ void removeBindingsWithNoDependencies();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
static void verifyContextLifetime(QQmlContextData *ctxt);
- QQmlEngine engine;
// When calling into JavaScript, the specific type of the return value can differ if that return
// value is a number. This is not only the case for non-integral numbers, or numbers that do not
@@ -384,13 +386,11 @@ void tst_qqmlecmascript::initTestCase()
{
QQmlDataTest::initTestCase();
registerTypes();
-
- QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
- engine.addImportPath(dataDir);
}
void tst_qqmlecmascript::assignBasicTypes()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
@@ -470,6 +470,7 @@ void tst_qqmlecmascript::assignDate()
QFETCH(QUrl, source);
QFETCH(int, timeOffset);
+ QQmlEngine engine;
QQmlComponent component(&engine, source);
QScopedPointer<QObject> obj(component.create());
MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data());
@@ -550,6 +551,7 @@ void tst_qqmlecmascript::exportDate()
void tst_qqmlecmascript::idShortcutInvalidates()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -573,6 +575,7 @@ void tst_qqmlecmascript::idShortcutInvalidates()
void tst_qqmlecmascript::boolPropertiesEvaluateAsBool()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -591,6 +594,7 @@ void tst_qqmlecmascript::boolPropertiesEvaluateAsBool()
void tst_qqmlecmascript::signalAssignment()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -628,6 +632,7 @@ void tst_qqmlecmascript::signalAssignment()
void tst_qqmlecmascript::signalArguments()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("signalArguments.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -653,6 +658,7 @@ void tst_qqmlecmascript::signalArguments()
void tst_qqmlecmascript::methods()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("methods.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -706,6 +712,7 @@ void tst_qqmlecmascript::methods()
void tst_qqmlecmascript::bindingLoop()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("bindingLoop.qml"));
QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
@@ -747,6 +754,8 @@ void tst_qqmlecmascript::basicExpressions()
QFETCH(QVariant, result);
QFETCH(bool, nest);
+ QQmlEngine engine;
+
MyQmlObject object1;
MyQmlObject object2;
MyQmlObject object3;
@@ -779,6 +788,7 @@ void tst_qqmlecmascript::arrayExpressions()
QObject obj2;
QObject obj3;
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
context.setContextProperty("a", &obj1);
context.setContextProperty("b", &obj2);
@@ -798,6 +808,7 @@ void tst_qqmlecmascript::arrayExpressions()
// Tests that modifying a context property will reevaluate expressions
void tst_qqmlecmascript::contextPropertiesTriggerReeval()
{
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
MyQmlObject object1;
MyQmlObject object2;
@@ -861,6 +872,7 @@ void tst_qqmlecmascript::contextPropertiesTriggerReeval()
void tst_qqmlecmascript::objectPropertiesTriggerReeval()
{
+ QQmlEngine engine;
QQmlContext context(engine.rootContext());
MyQmlObject object1;
MyQmlObject object2;
@@ -927,6 +939,7 @@ void tst_qqmlecmascript::dependenciesWithFunctions()
void tst_qqmlecmascript::deferredProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
@@ -950,6 +963,7 @@ void tst_qqmlecmascript::deferredProperties()
// Check errors on deferred properties are correctly emitted
void tst_qqmlecmascript::deferredPropertiesErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
@@ -958,7 +972,7 @@ void tst_qqmlecmascript::deferredPropertiesErrors()
QVERIFY(!object->objectProperty());
QVERIFY(!object->objectProperty2());
- QString warning = component.url().toString() + ":6:21: Unable to assign [undefined] to QObject*";
+ QString warning = component.url().toString() + ":6:5: Unable to assign [undefined] to QObject*";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
qmlExecuteDeferred(object);
@@ -969,6 +983,7 @@ void tst_qqmlecmascript::deferredPropertiesErrors()
void tst_qqmlecmascript::deferredPropertiesInComponents()
{
// Test that it works when the property is set inside and outside component
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesInComponents.qml"));
QObject *object = component.create();
if (!object)
@@ -1002,6 +1017,7 @@ void tst_qqmlecmascript::deferredPropertiesInDestruction()
//Test that the component does not get created at all if creation is deferred until the containing context is destroyed
//Very specific operation ordering is needed for this to occur, currently accessing object from object destructor.
//
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deferredPropertiesInDestruction.qml"));
QObject *object = component.create();
if (!object)
@@ -1012,6 +1028,7 @@ void tst_qqmlecmascript::deferredPropertiesInDestruction()
void tst_qqmlecmascript::extensionObjects()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extensionObjects.qml"));
MyExtendedObject *object =
qobject_cast<MyExtendedObject *>(component.create());
@@ -1037,6 +1054,7 @@ void tst_qqmlecmascript::extensionObjects()
void tst_qqmlecmascript::overrideExtensionProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
OverrideDefaultPropertyObject *object =
qobject_cast<OverrideDefaultPropertyObject *>(component.create());
@@ -1049,6 +1067,8 @@ void tst_qqmlecmascript::overrideExtensionProperties()
void tst_qqmlecmascript::attachedProperties()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("attachedProperty.qml"));
QObject *object = component.create();
@@ -1090,6 +1110,8 @@ void tst_qqmlecmascript::attachedProperties()
void tst_qqmlecmascript::enums()
{
+ QQmlEngine engine;
+
// Existent enums
{
QQmlComponent component(&engine, testFileUrl("enums.1.qml"));
@@ -1119,13 +1141,13 @@ void tst_qqmlecmascript::enums()
{
QUrl file = testFileUrl("enums.2.qml");
QString w1 = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'MyEnum' for property 'MyUnregisteredEnumTypeObject::enumProperty'");
- QString w2 = QLatin1String("QQmlExpression: Expression ") + testFileUrl("enums.2.qml").toString() + QLatin1String(":9:21 depends on non-NOTIFYable properties:");
+ QString w2 = QLatin1String("QQmlExpression: Expression ") + testFileUrl("enums.2.qml").toString() + QLatin1String(":9:5 depends on non-NOTIFYable properties:");
QString w3 = QLatin1String(" MyUnregisteredEnumTypeObject::enumProperty");
- QString w4 = file.toString() + ":7:21: Unable to assign [undefined] to int";
- QString w5 = file.toString() + ":8:21: Unable to assign [undefined] to int";
- QString w6 = file.toString() + ":9:21: Unable to assign [undefined] to int";
- QString w7 = file.toString() + ":13:23: Unable to assign [undefined] to [unknown property type]";
- QString w8 = file.toString() + ":31:23: Unable to assign int to [unknown property type]";
+ QString w4 = file.toString() + ":7:5: Unable to assign [undefined] to int";
+ QString w5 = file.toString() + ":8:5: Unable to assign [undefined] to int";
+ QString w6 = file.toString() + ":9:5: Unable to assign [undefined] to int";
+ QString w7 = file.toString() + ":13:9: Unable to assign [undefined] to [unknown property type]";
+ QString w8 = file.toString() + ":31:9: Unable to assign int to [unknown property type]";
QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
@@ -1196,6 +1218,7 @@ void tst_qqmlecmascript::enums()
void tst_qqmlecmascript::valueTypeFunctions()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
QVERIFY(obj != nullptr);
@@ -1211,6 +1234,8 @@ binding.
*/
void tst_qqmlecmascript::constantsOverrideBindings()
{
+ QQmlEngine engine;
+
// From ECMAScript
{
QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
@@ -1288,6 +1313,7 @@ the original binding to be disabled.
*/
void tst_qqmlecmascript::outerBindingOverridesInnerBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine,
testFileUrl("outerBindingOverridesInnerBinding.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -1317,9 +1343,10 @@ Tests for a regression where this used to crash.
*/
void tst_qqmlecmascript::nonExistentAttachedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
- QString warning = component.url().toString() + ":4:21: Unable to assign [undefined] to QString";
+ QString warning = component.url().toString() + ":4:5: Unable to assign [undefined] to QString";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
@@ -1330,6 +1357,8 @@ void tst_qqmlecmascript::nonExistentAttachedObject()
void tst_qqmlecmascript::scope()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scope.qml"));
QObject *object = component.create();
@@ -1420,6 +1449,7 @@ void tst_qqmlecmascript::scope()
// importing context
void tst_qqmlecmascript::importScope()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("importScope.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -1435,6 +1465,7 @@ is essentially a test of QQmlMetaType::copy()
*/
void tst_qqmlecmascript::signalParameterTypes()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != nullptr);
@@ -1462,6 +1493,7 @@ Test that two JS objects for the same QObject compare as equal.
*/
void tst_qqmlecmascript::objectsCompareAsEqual()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -1482,6 +1514,7 @@ Tests for a regression where the binding would not reevaluate.
*/
void tst_qqmlecmascript::aliasPropertyAndBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -1503,6 +1536,7 @@ and that the aliased property is reset correctly if possible.
*/
void tst_qqmlecmascript::aliasPropertyReset()
{
+ QQmlEngine engine;
QObject *object = nullptr;
// test that a manual write (of undefined) to a resettable aliased property succeeds
@@ -1631,6 +1665,7 @@ void tst_qqmlecmascript::componentCreation()
QFETCH(QString, creationError);
QFETCH(QString, createdParent);
+ QQmlEngine engine;
QUrl testUrl(testFileUrl("componentCreation.qml"));
if (!creationError.isEmpty()) {
@@ -1677,6 +1712,7 @@ void tst_qqmlecmascript::dynamicCreation()
QFETCH(QString, method);
QFETCH(QString, createdName);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -1694,6 +1730,8 @@ void tst_qqmlecmascript::dynamicCreation()
*/
void tst_qqmlecmascript::dynamicDestruction()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
QPointer<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
@@ -1777,6 +1815,7 @@ void tst_qqmlecmascript::dynamicDestruction()
*/
void tst_qqmlecmascript::objectToString()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qmlToString.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -1797,6 +1836,7 @@ void tst_qqmlecmascript::objectHasOwnProperty()
QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
+ QQmlEngine engine;
QQmlComponent component(&engine, url);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -1843,6 +1883,8 @@ This test is best run under valgrind to ensure no invalid memory access occur.
*/
void tst_qqmlecmascript::selfDeletingBinding()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
QObject *object = component.create();
@@ -1869,6 +1911,7 @@ and no synthesiszed properties).
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -1880,6 +1923,7 @@ Test that extended object properties can be accessed correctly.
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -1896,6 +1940,7 @@ Test failure when trying to create and uncreatable extended type object.
*/
void tst_qqmlecmascript::uncreatableExtendedObjectFailureCheck()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("uncreatableExtendedObjectFailureCheck.qml"));
QObject *object = component.create();
@@ -1907,6 +1952,7 @@ Test that an subclass of an uncreatable extended object contains all the require
*/
void tst_qqmlecmascript::extendedObjectPropertyLookup3()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup3.qml"));
QObject *object = component.create();
@@ -1927,6 +1973,7 @@ Test file/lineNumbers for binding/Script errors.
*/
void tst_qqmlecmascript::scriptErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("scriptErrors.qml"));
QString url = component.url().toString();
@@ -1935,7 +1982,7 @@ void tst_qqmlecmascript::scriptErrors()
QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
QString warning4 = url + ":13: ReferenceError: a is not defined";
QString warning5 = url + ":11: ReferenceError: a is not defined";
- QString warning6 = url + ":10:21: Unable to assign [undefined] to int";
+ QString warning6 = url + ":10:5: Unable to assign [undefined] to int";
QString warning7 = url + ":15: TypeError: Cannot assign to read-only property \"trueProperty\"";
QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
@@ -1964,6 +2011,7 @@ Test file/lineNumbers for inline functions.
*/
void tst_qqmlecmascript::functionErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionErrors.qml"));
QString url = component.url().toString();
@@ -1994,6 +2042,7 @@ Test various errors that can occur when assigning a property from script
*/
void tst_qqmlecmascript::propertyAssignmentErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
QString url = component.url().toString();
@@ -2013,6 +2062,7 @@ a signal script.
*/
void tst_qqmlecmascript::signalTriggeredBindings()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -2041,6 +2091,7 @@ Test that list properties can be iterated from ECMAScript
*/
void tst_qqmlecmascript::listProperties()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listProperties.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -2055,6 +2106,7 @@ void tst_qqmlecmascript::listProperties()
void tst_qqmlecmascript::exceptionClearsOnReeval()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
QString url = component.url().toString();
@@ -2078,6 +2130,7 @@ void tst_qqmlecmascript::exceptionClearsOnReeval()
void tst_qqmlecmascript::exceptionSlotProducesWarning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
QString url = component.url().toString();
@@ -2091,6 +2144,7 @@ void tst_qqmlecmascript::exceptionSlotProducesWarning()
void tst_qqmlecmascript::exceptionBindingProducesWarning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
QString url = component.url().toString();
@@ -2105,6 +2159,7 @@ void tst_qqmlecmascript::exceptionBindingProducesWarning()
void tst_qqmlecmascript::compileInvalidBinding()
{
// QTBUG-23387: ensure that invalid bindings don't cause a crash.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("v8bindingException.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -2114,6 +2169,8 @@ void tst_qqmlecmascript::compileInvalidBinding()
// Check that transient binding errors are not displayed
void tst_qqmlecmascript::transientErrors()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("transientErrors.qml"));
@@ -2145,6 +2202,7 @@ void tst_qqmlecmascript::transientErrors()
// Check that errors during shutdown are minimized
void tst_qqmlecmascript::shutdownErrors()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("shutdownErrors.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -2158,6 +2216,7 @@ void tst_qqmlecmascript::shutdownErrors()
void tst_qqmlecmascript::compositePropertyType()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compositePropertyType.qml"));
QTest::ignoreMessage(QtDebugMsg, "hello world");
@@ -2168,6 +2227,7 @@ void tst_qqmlecmascript::compositePropertyType()
// QTBUG-5759
void tst_qqmlecmascript::jsObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("jsObject.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -2179,6 +2239,8 @@ void tst_qqmlecmascript::jsObject()
void tst_qqmlecmascript::undefinedResetsProperty()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
QObject *object = component.create();
@@ -2214,6 +2276,7 @@ void tst_qqmlecmascript::undefinedResetsProperty()
// Aliases to variant properties should work
void tst_qqmlecmascript::qtbug_22464()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_22464.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -2225,6 +2288,7 @@ void tst_qqmlecmascript::qtbug_22464()
void tst_qqmlecmascript::qtbug_21580()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_21580.qml"));
QObject *object = component.create();
@@ -2238,6 +2302,7 @@ void tst_qqmlecmascript::qtbug_21580()
// Causes a v8 binding, but not all v8 bindings to be destroyed during evaluation
void tst_qqmlecmascript::singleV8BindingDestroyedDuringEvaluation()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singleV8BindingDestroyedDuringEvaluation.qml"));
QObject *object = component.create();
@@ -2248,6 +2313,7 @@ void tst_qqmlecmascript::singleV8BindingDestroyedDuringEvaluation()
// QTBUG-6781
void tst_qqmlecmascript::bug1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("bug.1.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -2268,6 +2334,7 @@ void tst_qqmlecmascript::bug1()
#ifndef QT_NO_WIDGETS
void tst_qqmlecmascript::bug2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
@@ -2281,6 +2348,7 @@ void tst_qqmlecmascript::bug2()
// Don't crash in createObject when the component has errors.
void tst_qqmlecmascript::dynamicCreationCrash()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -2331,6 +2399,8 @@ void tst_qqmlecmascript::dynamicCreationOwnership()
void tst_qqmlecmascript::regExpBug()
{
+ QQmlEngine engine;
+
//QTBUG-9367
{
QQmlComponent component(&engine, testFileUrl("regExp.qml"));
@@ -2357,7 +2427,7 @@ static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o,
QLatin1String(source) + QLatin1String(" })");
QV4::Scope scope(v4);
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -2383,7 +2453,7 @@ static inline bool evaluate_value(QV4::ExecutionEngine *v4, const QV4::Value &o,
QLatin1String(source) + QLatin1String(" })");
QV4::Scope scope(v4);
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -2414,7 +2484,7 @@ static inline QV4::ReturnedValue evaluate(QV4::ExecutionEngine *v4, const QV4::V
QV4::Scope scope(v4);
- QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource);
+ QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::ContextType::Eval, functionSource);
program.inheritContext = true;
QV4::ScopedFunctionObject function(scope, program.run());
@@ -3058,6 +3128,7 @@ void tst_qqmlecmascript::resolveClashingProperties()
// QTBUG-13047 (check that you can pass registered object types as args)
void tst_qqmlecmascript::invokableObjectArg()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
QObject *o = component.create();
@@ -3072,6 +3143,7 @@ void tst_qqmlecmascript::invokableObjectArg()
// QTBUG-13047 (check that you can return registered object types from methods)
void tst_qqmlecmascript::invokableObjectRet()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
QObject *o = component.create();
@@ -3082,6 +3154,7 @@ void tst_qqmlecmascript::invokableObjectRet()
void tst_qqmlecmascript::invokableEnumRet()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("invokableEnumRet.qml"));
QObject *o = component.create();
@@ -3093,6 +3166,7 @@ void tst_qqmlecmascript::invokableEnumRet()
// QTBUG-5675
void tst_qqmlecmascript::listToVariant()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listToVariant.qml"));
MyQmlContainer container;
@@ -3113,6 +3187,7 @@ void tst_qqmlecmascript::listToVariant()
// QTBUG-16316
void tst_qqmlecmascript::listAssignment()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("listAssignment.qml"));
QObject *obj = component.create();
QCOMPARE(obj->property("list1length").toInt(), 2);
@@ -3151,6 +3226,7 @@ void tst_qqmlecmascript::multiEngineObject()
// Test that references to QObjects are cleanup when the object is destroyed
void tst_qqmlecmascript::deletedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deletedObject.qml"));
QObject *object = component.create();
@@ -3165,6 +3241,7 @@ void tst_qqmlecmascript::deletedObject()
void tst_qqmlecmascript::attachedPropertyScope()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
QObject *object = component.create();
@@ -3185,6 +3262,8 @@ void tst_qqmlecmascript::attachedPropertyScope()
void tst_qqmlecmascript::scriptConnect()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
@@ -3266,6 +3345,8 @@ void tst_qqmlecmascript::scriptConnect()
void tst_qqmlecmascript::scriptDisconnect()
{
+ QQmlEngine engine;
+
{
QQmlComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
@@ -3356,6 +3437,7 @@ public slots:
void tst_qqmlecmascript::ownership()
{
+ QQmlEngine engine;
OwnershipObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3453,6 +3535,7 @@ void tst_qqmlecmascript::cppOwnershipReturnValue()
// QTBUG-15697
void tst_qqmlecmascript::ownershipCustomReturnValue()
{
+ QQmlEngine engine;
CppOwnershipReturnValue source;
{
@@ -3496,6 +3579,7 @@ public slots:
void tst_qqmlecmascript::ownershipRootObject()
{
+ QQmlEngine engine;
OwnershipChangingObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3517,6 +3601,7 @@ void tst_qqmlecmascript::ownershipRootObject()
void tst_qqmlecmascript::ownershipConsistency()
{
+ QQmlEngine engine;
OwnershipChangingObject own;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&own);
@@ -3547,6 +3632,7 @@ void tst_qqmlecmascript::ownershipConsistency()
void tst_qqmlecmascript::ownershipQmlIncubated()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("ownershipQmlIncubated.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -3586,6 +3672,7 @@ private:
// Tests that returning a QList<QObject*> from a method works
void tst_qqmlecmascript::qlistqobjectMethods()
{
+ QQmlEngine engine;
QListQObjectMethodsObject obj;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&obj);
@@ -3604,6 +3691,7 @@ void tst_qqmlecmascript::qlistqobjectMethods()
// QTBUG-9205
void tst_qqmlecmascript::strictlyEquals()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("strictlyEquals.qml"));
QObject *object = component.create();
@@ -3623,6 +3711,7 @@ void tst_qqmlecmascript::strictlyEquals()
void tst_qqmlecmascript::compiled()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compiled.qml"));
QObject *object = component.create();
@@ -3663,6 +3752,7 @@ void tst_qqmlecmascript::compiled()
// Test that numbers assigned in bindings as strings work consistently
void tst_qqmlecmascript::numberAssignment()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("numberAssignment.qml"));
QObject *object = component.create();
@@ -3689,6 +3779,7 @@ void tst_qqmlecmascript::numberAssignment()
void tst_qqmlecmascript::propertySplicing()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertySplicing.qml"));
QObject *object = component.create();
@@ -3702,6 +3793,7 @@ void tst_qqmlecmascript::propertySplicing()
// QTBUG-16683
void tst_qqmlecmascript::signalWithUnknownTypes()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -3755,6 +3847,7 @@ void tst_qqmlecmascript::signalWithJSValueInVariant()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
@@ -3779,6 +3872,7 @@ void tst_qqmlecmascript::signalWithJSValueInVariant_twoEngines()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
@@ -3809,6 +3903,7 @@ void tst_qqmlecmascript::signalWithQJSValue()
QFETCH(QString, expression);
QFETCH(QString, compare);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != nullptr);
@@ -4029,6 +4124,7 @@ void tst_qqmlecmascript::singletonTypeCaching()
void tst_qqmlecmascript::singletonTypeImportOrder()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonTypeImportOrder.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -4038,6 +4134,7 @@ void tst_qqmlecmascript::singletonTypeImportOrder()
void tst_qqmlecmascript::singletonTypeResolution()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonTypeResolution.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -4181,7 +4278,7 @@ void tst_qqmlecmascript::importScripts_data()
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(18));
+ << (QVariantList() << QVariant(16));
QTest::newRow("import singleton type into js import")
<< testFileUrl("jsimport/testImportSingletonType.qml")
@@ -4315,6 +4412,10 @@ void tst_qqmlecmascript::importScripts()
ThreadedTestHTTPServer server(dataDirectory() + "/remote");
+ QQmlEngine engine;
+ QString dataDir(dataDirectory() + QLatin1Char('/') + QLatin1String("lib"));
+ engine.addImportPath(dataDir);
+
QStringList importPathList = engine.importPathList();
QString remotePath(server.urlString("/"));
@@ -4358,6 +4459,7 @@ void tst_qqmlecmascript::importScripts()
void tst_qqmlecmascript::importCreationContext()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("jsimport/creationContext.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -4378,6 +4480,7 @@ void tst_qqmlecmascript::scarceResources_other()
QPixmap origPixmap(100, 100);
origPixmap.fill(Qt::blue);
QString srp_name, expectedWarning;
+ QQmlEngine engine;
QV4::ExecutionEngine *v4 = engine.handle();
ScarceResourceObject *eo = nullptr;
QObject *srsc = nullptr;
@@ -4749,6 +4852,7 @@ void tst_qqmlecmascript::scarceResources()
QFETCH(QVariantList, expectedValues);
QFETCH(QStringList, expectedErrors);
+ QQmlEngine engine;
QV4::ExecutionEngine *v4 = engine.handle();
ScarceResourceObject *eo = nullptr;
QObject *object = nullptr;
@@ -4781,6 +4885,7 @@ void tst_qqmlecmascript::scarceResources()
void tst_qqmlecmascript::propertyChangeSlots()
{
// ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -4847,6 +4952,7 @@ void tst_qqmlecmascript::propertyVar()
{
QFETCH(QUrl, qmlFile);
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -4886,6 +4992,7 @@ void tst_qqmlecmascript::propertyQJSValue()
{
QFETCH(QUrl, qmlFile);
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -4903,6 +5010,7 @@ void tst_qqmlecmascript::propertyVarCpp()
// ensure that writing to and reading from a var property from cpp works as required.
// Literal values stored in var properties can be read and written as QVariants
// of a specific type, whereas object values are read as QVariantMaps.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
object = component.create();
QVERIFY(object != nullptr);
@@ -4924,6 +5032,8 @@ void tst_qqmlecmascript::propertyVarCpp()
void tst_qqmlecmascript::propertyVarOwnership()
{
+ QQmlEngine engine;
+
// Referenced JS objects are not collected
{
QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
@@ -5005,6 +5115,7 @@ void tst_qqmlecmascript::propertyVarImplicitOwnership()
// The childObject has a reference to a different QObject. We want to ensure
// that the different item will not be cleaned up until required. IE, the childObject
// has implicit ownership of the constructed QObject.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5032,6 +5143,7 @@ void tst_qqmlecmascript::propertyVarImplicitOwnership()
void tst_qqmlecmascript::propertyVarReparent()
{
// ensure that nothing breaks if we re-parent objects
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5074,6 +5186,7 @@ void tst_qqmlecmascript::propertyVarReparentNullContext()
// sometimes reparenting can cause problems
// (eg, if the ctxt is collected, varproperties are no longer available)
// this test ensures that no crash occurs in that situation.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5110,6 +5223,7 @@ void tst_qqmlecmascript::propertyVarReparentNullContext()
void tst_qqmlecmascript::propertyVarCircular()
{
// enforce behaviour regarding circular references - ensure qdvmemo deletion.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5142,6 +5256,7 @@ void tst_qqmlecmascript::propertyVarCircular2()
{
// track deletion of JS-owned parent item with Cpp-owned child
// where the child has a var property referencing its parent.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5170,6 +5285,7 @@ void tst_qqmlecmascript::propertyVarInheritance()
{
// enforce behaviour regarding element inheritance - ensure handle disposal.
// The particular component under test here has a chain of references.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5215,6 +5331,7 @@ void tst_qqmlecmascript::propertyVarInheritance2()
{
// The particular component under test here does NOT have a chain of references; the
// only link between rootObject and childObject is that rootObject is the parent of childObject.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5248,6 +5365,7 @@ void tst_qqmlecmascript::propertyVarInheritance2()
// Ensure that QObject type conversion works on binding assignment
void tst_qqmlecmascript::elementAssign()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("elementAssign.qml"));
QObject *object = component.create();
@@ -5261,6 +5379,7 @@ void tst_qqmlecmascript::elementAssign()
// QTBUG-12457
void tst_qqmlecmascript::objectPassThroughSignals()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
QObject *object = component.create();
@@ -5274,6 +5393,7 @@ void tst_qqmlecmascript::objectPassThroughSignals()
// QTBUG-21626
void tst_qqmlecmascript::objectConversion()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectConversion.qml"));
QObject *object = component.create();
@@ -5289,6 +5409,7 @@ void tst_qqmlecmascript::objectConversion()
// QTBUG-20242
void tst_qqmlecmascript::booleanConversion()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("booleanConversion.qml"));
QObject *object = component.create();
@@ -5401,6 +5522,7 @@ void tst_qqmlecmascript::handleReferenceManagement()
void tst_qqmlecmascript::stringArg()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringArg.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5417,6 +5539,7 @@ void tst_qqmlecmascript::stringArg()
void tst_qqmlecmascript::readonlyDeclaration()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
QObject *object = component.create();
@@ -5434,6 +5557,8 @@ Q_DECLARE_METATYPE(QList<QString>)
Q_DECLARE_METATYPE(QList<QUrl>)
void tst_qqmlecmascript::sequenceConversionRead()
{
+ QQmlEngine engine;
+
{
QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
QQmlComponent component(&engine, qmlFile);
@@ -5514,6 +5639,7 @@ void tst_qqmlecmascript::sequenceConversionRead()
void tst_qqmlecmascript::sequenceConversionWrite()
{
+ QQmlEngine engine;
{
QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
QQmlComponent component(&engine, qmlFile);
@@ -5562,6 +5688,7 @@ void tst_qqmlecmascript::sequenceConversionArray()
{
// ensure that in JS the returned sequences act just like normal JS Arrays.
QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -5583,6 +5710,7 @@ void tst_qqmlecmascript::sequenceConversionIndexes()
// ensure that we gracefully fail if unsupported index values are specified.
// Qt container classes only support non-negative, signed integer index values.
QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5604,6 +5732,7 @@ void tst_qqmlecmascript::sequenceConversionThreads()
// ensure that sequence conversion operations work correctly in a worker thread
// and that serialisation between the main and worker thread succeeds.
QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5641,6 +5770,7 @@ void tst_qqmlecmascript::sequenceConversionThreads()
void tst_qqmlecmascript::sequenceConversionBindings()
{
+ QQmlEngine engine;
{
QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
QQmlComponent component(&engine, qmlFile);
@@ -5656,7 +5786,7 @@ void tst_qqmlecmascript::sequenceConversionBindings()
{
QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
- QString warning = QString(QLatin1String("%1:17:27: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
+ QString warning = QString(QLatin1String("%1:17:9: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
@@ -5668,6 +5798,7 @@ void tst_qqmlecmascript::sequenceConversionBindings()
void tst_qqmlecmascript::sequenceConversionCopy()
{
QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -5686,6 +5817,8 @@ void tst_qqmlecmascript::sequenceConversionCopy()
void tst_qqmlecmascript::assignSequenceTypes()
{
+ QQmlEngine engine;
+
// test binding array to sequence type property
{
QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
@@ -5784,12 +5917,23 @@ void tst_qqmlecmascript::assignSequenceTypes()
QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
delete object;
}
+
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.8.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+ QVariant result;
+ QMetaObject::invokeMethod(object.data(), "tryWritingReadOnlySequence", Q_RETURN_ARG(QVariant, result));
+ QVERIFY(result.type() == QVariant::Bool);
+ QVERIFY(result.toBool());
+ }
}
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qqmlecmascript::nullObjectBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
QObject *object = component.create();
@@ -5802,6 +5946,7 @@ void tst_qqmlecmascript::nullObjectBinding()
void tst_qqmlecmascript::nullObjectInitializer()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -5832,7 +5977,7 @@ void tst_qqmlecmascript::nullObjectInitializer()
{
const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty");
QVERIFY(propertyIndex > 0);
- QVERIFY(ddata->hasBindingBit(propertyIndex));
+ QVERIFY(!ddata->hasBindingBit(propertyIndex));
}
QVERIFY(obj->property("success").toBool());
@@ -5869,6 +6014,7 @@ void tst_qqmlecmascript::deletedEngine()
// Test the crashing part of QTBUG-9705
void tst_qqmlecmascript::libraryScriptAssert()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
QObject *object = component.create();
@@ -5879,6 +6025,7 @@ void tst_qqmlecmascript::libraryScriptAssert()
void tst_qqmlecmascript::variantsAssignedUndefined()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
QObject *object = component.create();
@@ -5898,6 +6045,7 @@ void tst_qqmlecmascript::variantsAssignedUndefined()
void tst_qqmlecmascript::variants()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("variants.qml"));
QObject *object = component.create();
@@ -5921,6 +6069,7 @@ void tst_qqmlecmascript::variants()
void tst_qqmlecmascript::qtbug_9792()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_9792.qml"));
QQmlContext *context = new QQmlContext(engine.rootContext());
@@ -5945,6 +6094,7 @@ void tst_qqmlecmascript::qtbug_9792()
// Verifies that QPointer<>s used in the vmemetaobject are cleaned correctly
void tst_qqmlecmascript::qtcreatorbug_1289()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
QObject *o = component.create();
@@ -5966,6 +6116,7 @@ void tst_qqmlecmascript::qtcreatorbug_1289()
// Test that we shut down without stupid warnings
void tst_qqmlecmascript::noSpuriousWarningsAtShutdown()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
@@ -5994,6 +6145,7 @@ void tst_qqmlecmascript::noSpuriousWarningsAtShutdown()
void tst_qqmlecmascript::canAssignNullToQObject()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
@@ -6023,13 +6175,14 @@ void tst_qqmlecmascript::canAssignNullToQObject()
void tst_qqmlecmascript::functionAssignment_fromBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
QString url = component.url().toString();
- QString w1 = url + ":4:25: Unable to assign a function to a property of any type other than var.";
- QString w2 = url + ":5:25: Invalid use of Qt.binding() in a binding declaration.";
- QString w3 = url + ":6:21: Invalid use of Qt.binding() in a binding declaration.";
- QString w4 = url + ":7:15: Invalid use of Qt.binding() in a binding declaration.";
+ QString w1 = url + ":4:5: Unable to assign a function to a property of any type other than var.";
+ QString w2 = url + ":5:5: Invalid use of Qt.binding() in a binding declaration.";
+ QString w3 = url + ":6:5: Invalid use of Qt.binding() in a binding declaration.";
+ QString w4 = url + ":7:5: Invalid use of Qt.binding() in a binding declaration.";
QTest::ignoreMessage(QtWarningMsg, w1.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, w2.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, w3.toLatin1().constData());
@@ -6047,6 +6200,7 @@ void tst_qqmlecmascript::functionAssignment_fromJS()
{
QFETCH(QString, triggerProperty);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
@@ -6079,6 +6233,7 @@ void tst_qqmlecmascript::functionAssignment_fromJS_data()
void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
@@ -6103,6 +6258,7 @@ void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
void tst_qqmlecmascript::functionAssignment_afterBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("functionAssignment.3.qml"));
QString url = component.url().toString();
@@ -6119,6 +6275,7 @@ void tst_qqmlecmascript::functionAssignment_afterBinding()
void tst_qqmlecmascript::eval()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("eval.qml"));
QObject *o = component.create();
@@ -6135,6 +6292,7 @@ void tst_qqmlecmascript::eval()
void tst_qqmlecmascript::function()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("function.qml"));
QObject *o = component.create();
@@ -6150,6 +6308,7 @@ void tst_qqmlecmascript::function()
// Test the "Qt.include" method
void tst_qqmlecmascript::include()
{
+ QQmlEngine engine;
// Non-library relative include
{
QQmlComponent component(&engine, testFileUrl("include.qml"));
@@ -6208,6 +6367,14 @@ void tst_qqmlecmascript::include()
delete o;
}
+ // Including file with ".pragma library", shadowing a global var
+ {
+ QQmlComponent component(&engine, testFileUrl("include_pragma_shadow.qml"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("result").toBool(), true);
+ }
+
// Remote - error
{
TestHTTPServer server;
@@ -6254,6 +6421,7 @@ void tst_qqmlecmascript::includeRemoteSuccess()
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory());
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("include_remote.qml"));
QObject *o = component.beginCreate(engine.rootContext());
QVERIFY(o != nullptr);
@@ -6280,6 +6448,7 @@ void tst_qqmlecmascript::includeRemoteSuccess()
void tst_qqmlecmascript::signalHandlers()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("signalHandlers.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -6340,6 +6509,7 @@ void tst_qqmlecmascript::qtbug_37351()
void tst_qqmlecmascript::qtbug_10696()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_10696.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6348,6 +6518,7 @@ void tst_qqmlecmascript::qtbug_10696()
void tst_qqmlecmascript::qtbug_11606()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_11606.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6357,6 +6528,7 @@ void tst_qqmlecmascript::qtbug_11606()
void tst_qqmlecmascript::qtbug_11600()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_11600.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6366,6 +6538,7 @@ void tst_qqmlecmascript::qtbug_11600()
void tst_qqmlecmascript::qtbug_21864()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_21864.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6375,6 +6548,7 @@ void tst_qqmlecmascript::qtbug_21864()
void tst_qqmlecmascript::rewriteMultiLineStrings()
{
+ QQmlEngine engine;
{
// QTBUG-23387
QQmlComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
@@ -6395,6 +6569,7 @@ void tst_qqmlecmascript::rewriteMultiLineStrings()
void tst_qqmlecmascript::qobjectConnectionListExceptionHandling()
{
// QTBUG-23375
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
@@ -6409,6 +6584,7 @@ void tst_qqmlecmascript::qobjectConnectionListExceptionHandling()
// Reading and writing non-scriptable properties should fail
void tst_qqmlecmascript::nonscriptable()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonscriptable.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6420,6 +6596,7 @@ void tst_qqmlecmascript::nonscriptable()
// deleteLater() should not be callable from QML
void tst_qqmlecmascript::deleteLater()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteLater.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6430,6 +6607,7 @@ void tst_qqmlecmascript::deleteLater()
// objectNameChanged() should be usable from QML
void tst_qqmlecmascript::objectNameChangedSignal()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectNameChangedSignal.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6442,6 +6620,7 @@ void tst_qqmlecmascript::objectNameChangedSignal()
// destroyed() should not be usable from QML
void tst_qqmlecmascript::destroyedSignal()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("destroyedSignal.qml"));
QVERIFY(component.isError());
@@ -6451,6 +6630,7 @@ void tst_qqmlecmascript::destroyedSignal()
void tst_qqmlecmascript::in()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("in.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6461,6 +6641,7 @@ void tst_qqmlecmascript::in()
void tst_qqmlecmascript::typeOf()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("typeOf.qml"));
QObject *o = component.create();
@@ -6481,6 +6662,7 @@ void tst_qqmlecmascript::typeOf()
void tst_qqmlecmascript::qtbug_24448()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_24448.qml"));
QScopedPointer<QObject> o(component.create());
QVERIFY(o != nullptr);
@@ -6489,6 +6671,7 @@ void tst_qqmlecmascript::qtbug_24448()
void tst_qqmlecmascript::sharedAttachedObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6500,6 +6683,7 @@ void tst_qqmlecmascript::sharedAttachedObject()
// QTBUG-13999
void tst_qqmlecmascript::objectName()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectName.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6517,6 +6701,7 @@ void tst_qqmlecmascript::objectName()
void tst_qqmlecmascript::writeRemovesBinding()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6529,6 +6714,7 @@ void tst_qqmlecmascript::writeRemovesBinding()
// Test bindings assigned to alias properties actually assign to the alias' target
void tst_qqmlecmascript::aliasBindingsAssignCorrectly()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
QObject *o = component.create();
QVERIFY(o != nullptr);
@@ -6541,6 +6727,7 @@ void tst_qqmlecmascript::aliasBindingsAssignCorrectly()
// Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
void tst_qqmlecmascript::aliasBindingsOverrideTarget()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
QObject *o = component.create();
@@ -6575,6 +6762,7 @@ void tst_qqmlecmascript::aliasBindingsOverrideTarget()
// Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
void tst_qqmlecmascript::aliasWritesOverrideBindings()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
QObject *o = component.create();
@@ -6610,6 +6798,7 @@ void tst_qqmlecmascript::aliasWritesOverrideBindings()
// QTBUG-20200
void tst_qqmlecmascript::aliasToCompositeElement()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
QObject *object = component.create();
@@ -6620,6 +6809,7 @@ void tst_qqmlecmascript::aliasToCompositeElement()
void tst_qqmlecmascript::qtbug_20344()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_20344.qml"));
QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
@@ -6633,6 +6823,7 @@ void tst_qqmlecmascript::qtbug_20344()
void tst_qqmlecmascript::revisionErrors()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
QString url = component.url().toString();
@@ -6690,6 +6881,7 @@ void tst_qqmlecmascript::revisionErrors()
void tst_qqmlecmascript::revision()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
QString url = component.url().toString();
@@ -6736,6 +6928,7 @@ void tst_qqmlecmascript::revision()
void tst_qqmlecmascript::realToInt()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("realToInt.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != nullptr);
@@ -6748,6 +6941,7 @@ void tst_qqmlecmascript::realToInt()
void tst_qqmlecmascript::urlProperty()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
@@ -6762,6 +6956,7 @@ void tst_qqmlecmascript::urlProperty()
void tst_qqmlecmascript::urlPropertyWithEncoding()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlProperty.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
@@ -6776,6 +6971,7 @@ void tst_qqmlecmascript::urlPropertyWithEncoding()
void tst_qqmlecmascript::urlListPropertyWithEncoding()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("urlListProperty.qml"));
QObject *object = component.create();
@@ -6796,6 +6992,7 @@ void tst_qqmlecmascript::urlListPropertyWithEncoding()
void tst_qqmlecmascript::dynamicString()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("dynamicString.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6805,6 +7002,7 @@ void tst_qqmlecmascript::dynamicString()
void tst_qqmlecmascript::deleteLaterObjectMethodCall()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteLaterObjectMethodCall.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6812,6 +7010,7 @@ void tst_qqmlecmascript::deleteLaterObjectMethodCall()
void tst_qqmlecmascript::automaticSemicolon()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6819,6 +7018,7 @@ void tst_qqmlecmascript::automaticSemicolon()
void tst_qqmlecmascript::compatibilitySemicolon()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("compatibilitySemicolon.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6826,6 +7026,7 @@ void tst_qqmlecmascript::compatibilitySemicolon()
void tst_qqmlecmascript::incrDecrSemicolon1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon1.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6833,6 +7034,7 @@ void tst_qqmlecmascript::incrDecrSemicolon1()
void tst_qqmlecmascript::incrDecrSemicolon2()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon2.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6840,6 +7042,7 @@ void tst_qqmlecmascript::incrDecrSemicolon2()
void tst_qqmlecmascript::incrDecrSemicolon_error1()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("incrDecrSemicolon_error1.qml"));
QObject *object = component.create();
QVERIFY(!object);
@@ -6847,6 +7050,7 @@ void tst_qqmlecmascript::incrDecrSemicolon_error1()
void tst_qqmlecmascript::unaryExpression()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("unaryExpression.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6855,6 +7059,7 @@ void tst_qqmlecmascript::unaryExpression()
// Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
void tst_qqmlecmascript::doubleEvaluate()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6871,6 +7076,7 @@ void tst_qqmlecmascript::doubleEvaluate()
void tst_qqmlecmascript::nonNotifyable()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonNotifyable.qml"));
QQmlTestMessageHandler messageHandler;
@@ -6881,7 +7087,7 @@ void tst_qqmlecmascript::nonNotifyable()
QString expected1 = QLatin1String("QQmlExpression: Expression ") +
component.url().toString() +
- QLatin1String(":5:24 depends on non-NOTIFYable properties:");
+ QLatin1String(":5:5 depends on non-NOTIFYable properties:");
QString expected2 = QLatin1String(" ") +
QLatin1String(object->metaObject()->className()) +
QLatin1String("::value");
@@ -6895,6 +7101,7 @@ void tst_qqmlecmascript::nonNotifyable()
void tst_qqmlecmascript::nonNotifyableConstant()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nonNotifyableConstant.qml"));
QQmlTestMessageHandler messageHandler;
@@ -6907,6 +7114,7 @@ void tst_qqmlecmascript::nonNotifyableConstant()
void tst_qqmlecmascript::forInLoop()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("forInLoop.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6927,6 +7135,7 @@ void tst_qqmlecmascript::forInLoop()
// An object the binding depends on is deleted while the binding is still running
void tst_qqmlecmascript::deleteWhileBindingRunning()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -6937,6 +7146,7 @@ void tst_qqmlecmascript::qtbug_22679()
{
MyQmlObject object;
object.setStringProperty(QLatin1String("Please work correctly"));
+ QQmlEngine engine;
engine.rootContext()->setContextProperty("contextProp", &object);
QQmlComponent component(&engine, testFileUrl("qtbug_22679.qml"));
@@ -6966,6 +7176,7 @@ void tst_qqmlecmascript::qtbug_22843()
fileName += QLatin1String(".library");
fileName += QLatin1String(".qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(fileName));
QString url = component.url().toString();
@@ -6978,6 +7189,7 @@ void tst_qqmlecmascript::qtbug_22843()
void tst_qqmlecmascript::switchStatement()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("switchStatement.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -7050,7 +7262,7 @@ void tst_qqmlecmascript::switchStatement()
{
QQmlComponent component(&engine, testFileUrl("switchStatement.4.qml"));
- QString warning = component.url().toString() + ":4:12: Unable to assign [undefined] to int";
+ QString warning = component.url().toString() + ":4:5: Unable to assign [undefined] to int";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -7124,6 +7336,7 @@ void tst_qqmlecmascript::switchStatement()
void tst_qqmlecmascript::withStatement()
{
+ QQmlEngine engine;
{
QUrl url = testFileUrl("withStatement.1.qml");
QQmlComponent component(&engine, url);
@@ -7136,6 +7349,7 @@ void tst_qqmlecmascript::withStatement()
void tst_qqmlecmascript::tryStatement()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("tryStatement.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
@@ -7157,7 +7371,7 @@ void tst_qqmlecmascript::tryStatement()
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != nullptr);
- QCOMPARE(object->value(), 1);
+ QVERIFY(object->qjsvalue().isUndefined());
}
{
@@ -7165,7 +7379,7 @@ void tst_qqmlecmascript::tryStatement()
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != nullptr);
- QCOMPARE(object->value(), 1);
+ QVERIFY(object->qjsvalue().isUndefined());
}
}
@@ -7211,6 +7425,7 @@ void tst_qqmlecmascript::invokableWithQObjectDerived()
void tst_qqmlecmascript::realTypePrecision()
{
// Properties and signal parameters of type real should have double precision.
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("realTypePrecision.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -7261,8 +7476,8 @@ void tst_qqmlecmascript::bindingBoundFunctions()
void tst_qqmlecmascript::deleteRootObjectInCreation()
{
- {
QQmlEngine engine;
+ {
QQmlComponent c(&engine, testFileUrl("deleteRootObjectInCreation.qml"));
QObject *obj = c.create();
QVERIFY(obj != nullptr);
@@ -7401,7 +7616,7 @@ void tst_qqmlecmascript::onDestructionViaGC()
QVERIFY2(!weakReferenceMutator.isNull(), qPrintable(component.errorString()));
weakReferenceMutator->init(v4, weakRef.data(), &mutatorResult);
- v4->memoryManager->allocObject<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult);
+ v4->memoryManager->allocate<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult);
}
gc(engine);
@@ -7475,6 +7690,7 @@ void tst_qqmlecmascript::signalEmitted()
// QTBUG-25647
void tst_qqmlecmascript::threadSignal()
{
+ QQmlEngine engine;
{
QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
QScopedPointer<QObject> object(c.create());
@@ -7493,6 +7709,7 @@ void tst_qqmlecmascript::threadSignal()
// ensure that the qqmldata::destroyed() handler doesn't cause problems
void tst_qqmlecmascript::qqmldataDestroyed()
{
+ QQmlEngine engine;
// gc cleans up a qobject, later the qqmldata destroyed handler will run.
{
QQmlComponent c(&engine, testFileUrl("qqmldataDestroyed.qml"));
@@ -7526,6 +7743,7 @@ void tst_qqmlecmascript::qqmldataDestroyed()
void tst_qqmlecmascript::secondAlias()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("secondAlias.qml"));
QObject *object = c.create();
QVERIFY(object != nullptr);
@@ -7536,6 +7754,7 @@ void tst_qqmlecmascript::secondAlias()
// An alias to a var property works
void tst_qqmlecmascript::varAlias()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("varAlias.qml"));
QObject *object = c.create();
QVERIFY(object != nullptr);
@@ -7546,6 +7765,7 @@ void tst_qqmlecmascript::varAlias()
// Used to trigger an assert in the lazy meta object creation stage
void tst_qqmlecmascript::overrideDataAssert()
{
+ QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("overrideDataAssert.qml"));
QObject *object = c.create();
QVERIFY(object != nullptr);
@@ -7571,6 +7791,7 @@ void tst_qqmlecmascript::fallbackBindings()
{
QFETCH(QString, source);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(source));
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -7580,6 +7801,7 @@ void tst_qqmlecmascript::fallbackBindings()
void tst_qqmlecmascript::propertyOverride()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("propertyOverride.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(object != nullptr);
@@ -7615,6 +7837,7 @@ void tst_qqmlecmascript::sequenceSort()
QFETCH(QString, function);
QFETCH(bool, useComparer);
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("sequenceSort.qml"));
QObject *object = component.create();
@@ -7631,6 +7854,7 @@ void tst_qqmlecmascript::sequenceSort()
void tst_qqmlecmascript::dateParse()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("date.qml"));
QObject *object = component.create();
@@ -7651,6 +7875,7 @@ void tst_qqmlecmascript::dateParse()
void tst_qqmlecmascript::utcDate()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("utcdate.qml"));
QObject *object = component.create();
@@ -7666,6 +7891,7 @@ void tst_qqmlecmascript::utcDate()
void tst_qqmlecmascript::negativeYear()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("negativeyear.qml"));
QObject *object = component.create();
@@ -7687,6 +7913,7 @@ void tst_qqmlecmascript::negativeYear()
void tst_qqmlecmascript::concatenatedStringPropertyAccess()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("concatenatedStringPropertyAccess.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -7732,6 +7959,7 @@ void tst_qqmlecmascript::updateCall()
// documented it can be called from within QML. Make sure
// we don't crash when calling it.
QString file("updateCall.qml");
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl(file));
QObject *object = component.create();
QVERIFY(object != nullptr);
@@ -7739,6 +7967,7 @@ void tst_qqmlecmascript::updateCall()
void tst_qqmlecmascript::numberParsing()
{
+ QQmlEngine engine;
for (int i = 1; i < 8; ++i) {
QString file("numberParsing.%1.qml");
file = file.arg(i);
@@ -7756,6 +7985,7 @@ void tst_qqmlecmascript::numberParsing()
void tst_qqmlecmascript::stringParsing()
{
+ QQmlEngine engine;
for (int i = 1; i < 7; ++i) {
QString file("stringParsing_error.%1.qml");
file = file.arg(i);
@@ -7779,6 +8009,7 @@ void tst_qqmlecmascript::push_and_shift()
void tst_qqmlecmascript::qtbug_32801()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_32801.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -7791,6 +8022,7 @@ void tst_qqmlecmascript::qtbug_32801()
void tst_qqmlecmascript::thisObject()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("thisObject.qml"));
QObject *object = component.create();
QVERIFY(object);
@@ -7800,6 +8032,7 @@ void tst_qqmlecmascript::thisObject()
void tst_qqmlecmascript::qtbug_33754()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_33754.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -7808,6 +8041,7 @@ void tst_qqmlecmascript::qtbug_33754()
void tst_qqmlecmascript::qtbug_34493()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_34493.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -7823,6 +8057,7 @@ void tst_qqmlecmascript::qtbug_34493()
// as its type*, it's parent type* and as QObject*
void tst_qqmlecmascript::singletonFromQMLToCpp()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFile("singletonTest.qml"));
QScopedPointer<QObject> obj(component.create());
if (component.errors().size())
@@ -7840,6 +8075,7 @@ void tst_qqmlecmascript::singletonFromQMLToCpp()
// and correctly compares to itself
void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFile("singletonTest2.qml"));
QScopedPointer<QObject> o(component.create());
if (component.errors().size())
@@ -7864,6 +8100,7 @@ void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
void tst_qqmlecmascript::setPropertyOnInvalid()
{
+ QQmlEngine engine;
{
QQmlComponent component(&engine, testFileUrl("setPropertyOnNull.qml"));
QString warning = component.url().toString() + ":4: TypeError: Type error";
@@ -7885,6 +8122,7 @@ void tst_qqmlecmascript::setPropertyOnInvalid()
void tst_qqmlecmascript::miscTypeTest()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("misctypetest.qml"));
QObject *object = component.create();
@@ -7913,6 +8151,7 @@ void tst_qqmlecmascript::stackLimits()
void tst_qqmlecmascript::idsAsLValues()
{
+ QQmlEngine engine;
QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString());
QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
@@ -7923,6 +8162,7 @@ void tst_qqmlecmascript::idsAsLValues()
void tst_qqmlecmascript::qtbug_34792()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug34792.qml"));
QObject *object = component.create();
@@ -7934,6 +8174,7 @@ void tst_qqmlecmascript::qtbug_34792()
void tst_qqmlecmascript::noCaptureWhenWritingProperty()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("noCaptureWhenWritingProperty.qml"));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
@@ -7942,6 +8183,7 @@ void tst_qqmlecmascript::noCaptureWhenWritingProperty()
void tst_qqmlecmascript::singletonWithEnum()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("singletontype/singletonWithEnum.qml"));
QScopedPointer<QObject> obj(component.create());
if (obj.isNull())
@@ -7963,48 +8205,53 @@ void tst_qqmlecmascript::singletonWithEnum()
void tst_qqmlecmascript::lazyBindingEvaluation()
{
- QQmlComponent component(&engine, testFileUrl("lazyBindingEvaluation.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("lazyBindingEvaluation.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QVariant prop = obj->property("arrayLength");
- QCOMPARE(prop.type(), QVariant::Int);
- QCOMPARE(prop.toInt(), 2);
+ QVERIFY(!obj.isNull());
+ QVariant prop = obj->property("arrayLength");
+ QCOMPARE(prop.type(), QVariant::Int);
+ QCOMPARE(prop.toInt(), 2);
}
void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext()
{
- QQmlComponent component(&engine, testFileUrl("varPropertyAccessOnObjectWithInvalidContext.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("varPropertyAccessOnObjectWithInvalidContext.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QVERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QVERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::importedScriptsAccessOnObjectWithInvalidContext()
{
- QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QTRY_VERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::importedScriptsWithoutQmlMode()
{
- QQmlComponent component(&engine, testFileUrl("importScriptsWithoutQmlMode.qml"));
- QScopedPointer<QObject> obj(component.create());
- if (obj.isNull())
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("importScriptsWithoutQmlMode.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (obj.isNull())
qDebug() << component.errors().first().toString();
- QVERIFY(!obj.isNull());
- QTRY_VERIFY(obj->property("success").toBool());
+ QVERIFY(!obj.isNull());
+ QTRY_VERIFY(obj->property("success").toBool());
}
void tst_qqmlecmascript::contextObjectOnLazyBindings()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("contextObjectOnLazyBindings.qml"));
QScopedPointer<QObject> obj(component.create());
if (obj.isNull())
@@ -8017,6 +8264,7 @@ void tst_qqmlecmascript::contextObjectOnLazyBindings()
void tst_qqmlecmascript::garbageCollectionDuringCreation()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import Qt.test 1.0\n"
"QObjectContainerWithGCOnAppend {\n"
@@ -8044,6 +8292,7 @@ void tst_qqmlecmascript::garbageCollectionDuringCreation()
void tst_qqmlecmascript::qtbug_39520()
{
+ QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\n"
"Item {\n"
@@ -8165,6 +8414,7 @@ void tst_qqmlecmascript::switchExpression()
void tst_qqmlecmascript::qtbug_46022()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_46022.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -8175,6 +8425,7 @@ void tst_qqmlecmascript::qtbug_46022()
void tst_qqmlecmascript::qtbug_52340()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_52340.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY(!object.isNull());
@@ -8186,6 +8437,7 @@ void tst_qqmlecmascript::qtbug_52340()
void tst_qqmlecmascript::qtbug_54589()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -8197,11 +8449,12 @@ void tst_qqmlecmascript::qtbug_54687()
{
QJSEngine e;
// it's simple: this shouldn't crash.
- engine.evaluate("12\n----12");
+ e.evaluate("12\n----12");
}
void tst_qqmlecmascript::stringify_qtbug_50592()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringify_qtbug_50592.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -8389,6 +8642,7 @@ void tst_qqmlecmascript::freeze_empty_object()
void tst_qqmlecmascript::singleBlockLoops()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug_59012.qml"));
QScopedPointer<QObject> obj(component.create());
@@ -8400,6 +8654,7 @@ void tst_qqmlecmascript::singleBlockLoops()
// This fix ensures it looks up the right thing.
void tst_qqmlecmascript::qtbug_60547()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("qtbug60547/main.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
@@ -8408,6 +8663,7 @@ void tst_qqmlecmascript::qtbug_60547()
void tst_qqmlecmascript::anotherNaN()
{
+ QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("nans.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
@@ -8513,6 +8769,35 @@ void tst_qqmlecmascript::jumpStrictNotEqualUndefined()
QCOMPARE(v.toInt(), 2);
}
+void tst_qqmlecmascript::removeBindingsWithNoDependencies()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("removeBindingsWithNoDependencies.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+ QVariant rect = object->property("placement");
+ QCOMPARE(rect.toRectF(), QRectF(0, 0, 100, 100));
+ const QMetaObject *metaObject = object->metaObject();
+
+ {
+ const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("placement"));
+ QVERIFY(prop.isValid());
+ QVERIFY(!QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex())));
+ }
+
+ {
+ const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("partialPlacement"));
+ QVERIFY(prop.isValid());
+ QQmlAbstractBinding *vtProxyBinding = QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex()));
+ QVERIFY(vtProxyBinding);
+ QVERIFY(vtProxyBinding->isValueTypeProxy());
+
+ QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding*>(vtProxyBinding);
+ QVERIFY(!proxy->subBindings());
+ }
+
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index 95098648fa..f58ae38264 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -79,6 +79,7 @@ private slots:
void componentFromEval();
void qrcUrls();
void cppSignalAndEval();
+ void singletonInstance();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -543,7 +544,7 @@ void tst_qqmlengine::outputWarningsToStandardError()
delete o;
QCOMPARE(messageHandler.messages().count(), 1);
- QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:48: Unable to assign [undefined] to int"));
+ QCOMPARE(messageHandler.messages().at(0), QLatin1String("<Unknown File>:1:32: Unable to assign [undefined] to int"));
messageHandler.clear();
engine.setOutputWarningsToStandardError(false);
@@ -905,23 +906,19 @@ void tst_qqmlengine::qrcUrls()
QQmlEnginePrivate *pEngine = QQmlEnginePrivate::get(&engine);
{
- QQmlRefPointer<QQmlTypeData> oneQml(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.qml")),
- QQmlRefPointer<QQmlTypeData>::Adopt);
- QVERIFY(oneQml != nullptr);
- QQmlRefPointer<QQmlTypeData> twoQml(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.qml")),
- QQmlRefPointer<QQmlTypeData>::Adopt);
- QVERIFY(twoQml != nullptr);
- QCOMPARE(oneQml, twoQml);
+ QQmlRefPointer<QQmlTypeData> oneQml(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.qml")));
+ QVERIFY(oneQml.data() != nullptr);
+ QQmlRefPointer<QQmlTypeData> twoQml(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.qml")));
+ QVERIFY(twoQml.data() != nullptr);
+ QCOMPARE(oneQml.data(), twoQml.data());
}
{
- QQmlRefPointer<QQmlTypeData> oneJS(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.js")),
- QQmlRefPointer<QQmlTypeData>::Adopt);
- QVERIFY(oneJS != nullptr);
- QQmlRefPointer<QQmlTypeData> twoJS(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.js")),
- QQmlRefPointer<QQmlTypeData>::Adopt);
- QVERIFY(twoJS != nullptr);
- QCOMPARE(oneJS, twoJS);
+ QQmlRefPointer<QQmlTypeData> oneJS(pEngine->typeLoader.getType(QUrl("qrc:/qrcurls.js")));
+ QVERIFY(oneJS.data() != nullptr);
+ QQmlRefPointer<QQmlTypeData> twoJS(pEngine->typeLoader.getType(QUrl("qrc:///qrcurls.js")));
+ QVERIFY(twoJS.data() != nullptr);
+ QCOMPARE(oneJS.data(), twoJS.data());
}
}
@@ -956,6 +953,96 @@ void tst_qqmlengine::cppSignalAndEval()
QCOMPARE(object->property("r"), 1.1234);
}
+class CppSingleton : public QObject {
+ Q_OBJECT
+public:
+ CppSingleton() {}
+
+ static QObject *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
+ {
+ Q_UNUSED(qmlEngine);
+ Q_UNUSED(jsEngine);
+ return new CppSingleton();
+ }
+};
+
+class JsSingleton : public QObject {
+ Q_OBJECT
+public:
+ JsSingleton() {}
+
+ static QJSValue create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
+ {
+ Q_UNUSED(qmlEngine);
+ QJSValue value = jsEngine->newQObject(new JsSingleton());
+ return value;
+ }
+};
+
+class SomeQObjectClass : public QObject {
+ Q_OBJECT
+public:
+ SomeQObjectClass() : QObject(nullptr){}
+};
+
+void tst_qqmlengine::singletonInstance()
+{
+ QQmlEngine engine;
+
+ int cppSingletonTypeId = qmlRegisterSingletonType<CppSingleton>("Test", 1, 0, "CppSingleton", &CppSingleton::create);
+ int jsValueSingletonTypeId = qmlRegisterSingletonType("Test", 1, 0, "JsSingleton", &JsSingleton::create);
+
+ {
+ // Cpp QObject singleton type
+ QJSValue value = engine.singletonInstance<QJSValue>(cppSingletonTypeId);
+ QVERIFY(!value.isUndefined());
+ QVERIFY(value.isQObject());
+ QObject *instance = value.toQObject();
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+ }
+
+ {
+ // QJSValue QObject singleton type
+ QJSValue value = engine.singletonInstance<QJSValue>(jsValueSingletonTypeId);
+ QVERIFY(!value.isUndefined());
+ QVERIFY(value.isQObject());
+ QObject *instance = value.toQObject();
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "JsSingleton");
+ }
+
+ {
+ // Invalid types
+ QJSValue value;
+ value = engine.singletonInstance<QJSValue>(-4711);
+ QVERIFY(value.isUndefined());
+ value = engine.singletonInstance<QJSValue>(1701);
+ QVERIFY(value.isUndefined());
+ }
+
+ {
+ // Valid, but non-singleton type
+ int typeId = qmlRegisterType<CppSingleton>("Test", 1, 0, "NotASingleton");
+ QJSValue value = engine.singletonInstance<QJSValue>(typeId);
+ QVERIFY(value.isUndefined());
+ }
+
+ {
+ // Cpp QObject singleton type
+ CppSingleton *instance = engine.singletonInstance<CppSingleton*>(cppSingletonTypeId);
+ QVERIFY(instance);
+ QCOMPARE(instance->metaObject()->className(), "CppSingleton");
+ QCOMPARE(instance, engine.singletonInstance<QJSValue>(cppSingletonTypeId).toQObject());
+ }
+
+ {
+ // Wrong destination type
+ SomeQObjectClass * instance = engine.singletonInstance<SomeQObjectClass*>(cppSingletonTypeId);
+ QVERIFY(!instance);
+ }
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt b/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
index 015d55b03b..30b5193cd5 100644
--- a/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/dynamicMeta.5.errors.txt
@@ -1 +1 @@
-3:1:UnknownType is not a type
+4:5:UnknownType is not a type
diff --git a/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt b/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
index 3813680562..4f3f758b7e 100644
--- a/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
+++ b/tests/auto/qml/qqmllanguage/data/incorrectCase.errors.insensitive.txt
@@ -1,2 +1,2 @@
-3:1:Type IncorrectCaseType unavailable
+3:1:IncorrectCaseType is not a type
-1:-1:File name case mismatch
diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
index db7d9c0f60..cefd62f9d4 100644
--- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
@@ -1 +1 @@
-4:18:Unexpected object assignment
+4:18:Unexpected object assignment for property "x"
diff --git a/tests/auto/qml/qqmllanguage/data/property.4.errors.txt b/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
index b447186849..2807384ec4 100644
--- a/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/property.4.errors.txt
@@ -1 +1 @@
-5:1:Syntax error
+5:1:Expected token `:'
diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest18.qml b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml
new file mode 100644
index 0000000000..7616c23531
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singletonTest18.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import "singleton"
+import Test 1.0
+
+Item {
+ property var qmlSingleton: SingletonType
+ property var jsSingleton: MyQJSValueQObjectSingleton
+ property var cppSingleton: MyTypeObjectSingleton
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 0eb4f26878..7e247b1906 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -35,6 +35,14 @@ static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngin
return new MyTypeObject();
}
+static QJSValue myQJSValueQObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+
+ QJSValue value = scriptEngine->newQObject(new MyTypeObject());
+ return value;
+}
+
void registerTypes()
{
qmlRegisterInterface<MyInterface>("MyInterface");
@@ -101,6 +109,7 @@ void registerTypes()
qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType");
qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton);
+ qmlRegisterSingletonType("Test", 1, 0, "MyQJSValueQObjectSingleton", myQJSValueQObjectSingleton);
qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass");
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 8913528d79..f3569c2efe 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -246,6 +246,8 @@ private slots:
void compositeSingletonRegistered();
void compositeSingletonCircular();
+ void singletonsHaveContextAndEngine();
+
void customParserBindingScopes();
void customParserEvaluateEnum();
void customParserProperties();
@@ -288,6 +290,8 @@ private slots:
void valueTypeGroupPropertiesInBehavior();
+ void retrieveQmlTypeId();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -2193,7 +2197,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
QUrl url = testFileUrl("scriptString7.qml");
{
QQmlEnginePrivate *eng = QQmlEnginePrivate::get(&engine);
- QQmlTypeData *td = eng->typeLoader.getType(url);
+ QQmlRefPointer<QQmlTypeData> td = eng->typeLoader.getType(url);
Q_ASSERT(td);
const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data;
@@ -3923,11 +3927,13 @@ void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName
return;
QVariant variant = o->property(propertyName);
- QVERIFY(variant.userType() == qMetaTypeId<QObject *>());
+ QVERIFY(variant.isValid());
QObject *singleton = nullptr;
- if (variant.canConvert<QObject*>())
+ if (variant.userType() == qMetaTypeId<QObject *>())
singleton = variant.value<QObject*>();
+ else if (variant.userType() == qMetaTypeId<QJSValue>())
+ singleton = variant.value<QJSValue>().toQObject();
QVERIFY(singleton != nullptr);
*result = singleton;
@@ -4232,6 +4238,24 @@ void tst_qqmllanguage::compositeSingletonCircular()
QCOMPARE(o->property("value").toInt(), 2);
}
+void tst_qqmllanguage::singletonsHaveContextAndEngine()
+{
+ QObject *qmlSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "qmlSingleton", &qmlSingleton);
+ QVERIFY(qmlContext(qmlSingleton));
+ QCOMPARE(qmlEngine(qmlSingleton), &engine);
+
+ QObject *jsSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "jsSingleton", &jsSingleton);
+ QVERIFY(qmlContext(jsSingleton));
+ QCOMPARE(qmlEngine(jsSingleton), &engine);
+
+ QObject *cppSingleton = nullptr;
+ getSingletonInstance(engine, "singletonTest18.qml", "cppSingleton", &cppSingleton);
+ QVERIFY(qmlContext(cppSingleton));
+ QCOMPARE(qmlEngine(cppSingleton), &engine);
+}
+
void tst_qqmllanguage::customParserBindingScopes()
{
QQmlComponent component(&engine, testFile("customParserBindingScopes.qml"));
@@ -4934,6 +4958,26 @@ void tst_qqmllanguage::valueTypeGroupPropertiesInBehavior()
QCOMPARE(animation->property("easing").value<QEasingCurve>().type(), QEasingCurve::InOutQuad);
}
+void tst_qqmllanguage::retrieveQmlTypeId()
+{
+ // Register in reverse order to provoke wrong minor version matching.
+ int id2 = qmlRegisterType<QObject>("Test", 2, 3, "SomeTestType");
+ int id1 = qmlRegisterType<QObject>("Test", 2, 1, "SomeTestType");
+ QCOMPARE(qmlTypeId("Test", 2, 1, "SomeTestType"), id1);
+ QCOMPARE(qmlTypeId("Test", 2, 2, "SomeTestType"), id1);
+ QCOMPARE(qmlTypeId("Test", 2, 3, "SomeTestType"), id2);
+
+ // Error cases
+ QCOMPARE(qmlTypeId("Test", 2, 0, "SomeTestType"), -1);
+ QCOMPARE(qmlTypeId("Test", 2, 3, "DoesNotExist"), -1);
+ QCOMPARE(qmlTypeId("DoesNotExist", 2, 3, "SomeTestType"), -1);
+
+ // Must also work for other types (defined in testtpes.cpp)
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyExtendedUncreateableBaseClass") >= 0);
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyUncreateableBaseClass") >= 0);
+ QVERIFY(qmlTypeId("Test", 1, 0, "MyTypeObjectSingleton") >= 0);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml b/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml
new file mode 100644
index 0000000000..7d3650c3b9
--- /dev/null
+++ b/tests/auto/qml/qqmllistmodel/data/dynamicroles.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ ListModel {
+ id: listModel
+ objectName: "listModel"
+ dynamicRoles: true
+
+ // have to add elements dynamically when dynamicRoles = true
+ function appendNewElement() {
+ listModel.append({"name": "test", "obj": null})
+ }
+
+ function setElementAgain() {
+ var element = listModel.get(0)
+ listModel.set(0, element)
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml b/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml
new file mode 100644
index 0000000000..0abf221f60
--- /dev/null
+++ b/tests/auto/qml/qqmllistmodel/data/qtbug38907.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+import QtTest 1.0
+
+Item {
+
+ Item {
+ id : testItem
+ property string name : "testObject"
+ property var object : this
+ function testMethod() {
+ return -1;
+ }
+ }
+
+ ListModel {
+ id : listModel
+ dynamicRoles : true
+ }
+
+ function exec() {
+ listModel.append(testItem);
+ listModel.append({ item : testItem });
+ return true;
+ }
+}
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index 9fdc54f067..771f3e5c4e 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -106,6 +106,7 @@ private slots:
void get_nested_data();
void crash_model_with_multiple_roles();
void crash_model_with_unknown_roles();
+ void crash_model_with_dynamic_roles();
void set_model_cache();
void property_changes();
void property_changes_data();
@@ -126,6 +127,7 @@ private slots:
void stringifyModelEntry();
void qobjectTrackerForDynamicModelObjects();
void crash_append_empty_array();
+ void dynamic_roles_crash_QTBUG_38907();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -984,6 +986,97 @@ void tst_qqmllistmodel::crash_model_with_unknown_roles()
model->index(0, 0, QModelIndex()).data(Qt::UserRole);
}
+//QTBUG-35639
+void tst_qqmllistmodel::crash_model_with_dynamic_roles()
+{
+ {
+ // setting a dynamic role to a QObject value, then triggering dtor
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+
+ // delete the root item, which will cause the model dtor to run
+ // previously, this would crash as it attempted to delete testObj.
+ delete rootItem;
+ }
+
+ {
+ // setting a dynamic role to a QObject value, then triggering
+ // DynamicRoleModelNode::updateValues() to trigger unsafe qobject_cast
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+
+ QMetaObject::invokeMethod(model, "setElementAgain");
+
+ delete rootItem;
+ }
+
+ {
+ // setting a dynamic role to a QObject value, then triggering
+ // DynamicRoleModelNodeMetaObject::propertyWrite()
+
+ /*
+ XXX TODO: I couldn't reproduce this one simply - I think it
+ requires a WorkerScript sync() call, and that's non-trivial.
+ I thought I could do it simply via:
+
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("dynamicroles.qml"));
+ QObject *rootItem = component.create();
+ qWarning() << component.errorString();
+ QVERIFY(component.errorString().isEmpty());
+ QVERIFY(rootItem != 0);
+ QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel");
+ QVERIFY(model != 0);
+
+ QMetaObject::invokeMethod(model, "appendNewElement");
+
+ QObject *testObj = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj));
+ delete testObj;
+ QObject *testObj2 = new QObject;
+ model->setProperty(0, "obj", QVariant::fromValue<QObject*>(testObj2));
+
+ But it turns out that that doesn't work (the setValue() call within
+ setProperty() doesn't seem to trigger the right codepath, for some
+ reason), and you can't trigger it manually via:
+
+ QObject *testObj2 = new QObject;
+ void *a[] = { testObj2, 0 };
+ QMetaObject::metacall(dynamicNodeModel, QMetaObject::WriteProperty, 0, a);
+
+ because the dynamicNodeModel for that index cannot be retrieved
+ using the public API.
+
+ But, anyway, I think the above two test cases are sufficient to
+ show that QObject* values should be guarded internally.
+ */
+ }
+}
+
//QTBUG-15190
void tst_qqmllistmodel::set_model_cache()
{
@@ -1556,6 +1649,24 @@ void tst_qqmllistmodel::crash_append_empty_array()
QCOMPARE(spy.count(), 0);
}
+void tst_qqmllistmodel::dynamic_roles_crash_QTBUG_38907()
+{
+ QQmlEngine eng;
+ QQmlComponent component(&eng, testFileUrl("qtbug38907.qml"));
+ QVERIFY(!component.isError());
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create()));
+ QVERIFY(item != 0);
+
+ QVariant retVal;
+
+ QMetaObject::invokeMethod(item.data(),
+ "exec",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, retVal));
+
+ QVERIFY(retVal.toBool());
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
index 7fd4d69b5e..44ce1d6987 100644
--- a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
+++ b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp
@@ -53,7 +53,7 @@ void tst_qqmlopenmetaobject::createProperties()
QQmlEngine engine;
CustomObject object;
const QQmlRefPointer<QQmlOpenMetaObjectType> mot = new QQmlOpenMetaObjectType(object.metaObject(), &engine);
- QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot);
+ QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot.data());
mo->setCached(true);
mot->createProperty("customProperty");
QVERIFY(true);
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index ba2b836a6d..ce9d0ac894 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -50,6 +50,9 @@ private slots:
void qmlParser();
#endif
void invalidEscapeSequence();
+ void stringLiteral();
+ void noSubstitutionTemplateLiteral();
+ void templateLiteral();
private:
QStringList excludedDirs;
@@ -78,6 +81,13 @@ public:
const quint32 parentBegin = parent->firstSourceLocation().begin();
const quint32 parentEnd = parent->lastSourceLocation().end();
+ if (node->firstSourceLocation().begin() < parentBegin)
+ qDebug() << "first source loc failed: node:" << node->kind << "at" << node->firstSourceLocation().startLine << "/" << node->firstSourceLocation().startColumn
+ << "parent" << parent->kind << "at" << parent->firstSourceLocation().startLine << "/" << parent->firstSourceLocation().startColumn;
+ if (node->lastSourceLocation().end() > parentEnd)
+ qDebug() << "first source loc failed: node:" << node->kind << "at" << node->lastSourceLocation().startLine << "/" << node->lastSourceLocation().startColumn
+ << "parent" << parent->kind << "at" << parent->lastSourceLocation().startLine << "/" << parent->lastSourceLocation().startColumn;
+
QVERIFY(node->firstSourceLocation().begin() >= parentBegin);
QVERIFY(node->lastSourceLocation().end() <= parentEnd);
}
@@ -183,13 +193,12 @@ void tst_qqmlparser::qmlParser()
Lexer lexer(&engine);
lexer.setCode(code, 1, qmlMode);
Parser parser(&engine);
- if (qmlMode)
- parser.parse();
- else
- parser.parseProgram();
+ bool ok = qmlMode ? parser.parse() : parser.parseProgram();
- check::Check chk;
- chk(parser.rootNode());
+ if (ok) {
+ check::Check chk;
+ chk(parser.rootNode());
+ }
}
#endif
@@ -204,6 +213,67 @@ void tst_qqmlparser::invalidEscapeSequence()
parser.parse();
}
+void tst_qqmlparser::stringLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("'hello string'");
+ lexer.setCode(code , 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+ auto *literal = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expression);
+ QVERIFY(literal);
+ QCOMPARE(literal->value, "hello string");
+ QCOMPARE(literal->firstSourceLocation().begin(), 0);
+ QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::noSubstitutionTemplateLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("`hello template`");
+ lexer.setCode(code, 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+
+ auto *literal = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+ QVERIFY(literal);
+
+ QCOMPARE(literal->value, "hello template");
+ QCOMPARE(literal->firstSourceLocation().begin(), 0);
+ QCOMPARE(literal->lastSourceLocation().end(), code.size());
+}
+
+void tst_qqmlparser::templateLiteral()
+{
+ using namespace QQmlJS;
+
+ Engine engine;
+ Lexer lexer(&engine);
+ QLatin1String code("`one plus one equals ${1+1}!`");
+ lexer.setCode(code, 1);
+ Parser parser(&engine);
+ QVERIFY(parser.parseExpression());
+ AST::ExpressionNode *expression = parser.expression();
+ QVERIFY(expression);
+
+ auto *templateLiteral = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expression);
+ QVERIFY(templateLiteral);
+
+ QCOMPARE(templateLiteral->firstSourceLocation().begin(), 0);
+ auto *e = templateLiteral->expression;
+ QVERIFY(e);
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 1e9ba80264..b8d5a4d3a3 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -2007,15 +2007,15 @@ void tst_qqmlproperty::warnOnInvalidBinding()
QString expectedWarning;
// V4 error message for property-to-property binding
- expectedWarning = testUrl.toString() + QString::fromLatin1(":6:36: Unable to assign QQuickText to QQuickRectangle");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":6:5: Unable to assign QQuickText to QQuickRectangle");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
// V8 error message for function-to-property binding
- expectedWarning = testUrl.toString() + QString::fromLatin1(":7:36: Unable to assign QQuickText to QQuickRectangle");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":7:5: Unable to assign QQuickText to QQuickRectangle");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
// V8 error message for invalid binding to anchor
- expectedWarning = testUrl.toString() + QString::fromLatin1(":14:33: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
+ expectedWarning = testUrl.toString() + QString::fromLatin1(":14:9: Unable to assign QQuickItem_QML_8 to QQuickAnchorLine");
QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
QQmlComponent component(&engine, testUrl);
diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
index b9e56b39a2..29f70c4e46 100644
--- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
+++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp
@@ -95,7 +95,7 @@ Q_SIGNALS:
void signalB();
};
-QQmlPropertyData *cacheProperty(QQmlPropertyCache *cache, const char *name)
+QQmlPropertyData *cacheProperty(const QQmlRefPointer<QQmlPropertyCache> &cache, const char *name)
{
return cache->property(QLatin1String(name), nullptr, nullptr);
}
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index b96eecafe8..2d8115e867 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -505,8 +505,14 @@ void tst_qqmlqt::font()
QObject *object = component.create();
QVERIFY(object != nullptr);
- QCOMPARE(qvariant_cast<QFont>(object->property("test1")), QFont("Arial", 22));
- QCOMPARE(qvariant_cast<QFont>(object->property("test2")), QFont("Arial", 20, QFont::DemiBold, true));
+ QFont f;
+ f.setFamily("Arial");
+ f.setPointSize(22);
+ QCOMPARE(qvariant_cast<QFont>(object->property("test1")), f);
+ f.setPointSize(20);
+ f.setWeight(QFont::DemiBold);
+ f.setItalic(true);
+ QCOMPARE(qvariant_cast<QFont>(object->property("test2")), f);
QCOMPARE(qvariant_cast<QFont>(object->property("test3")), QFont());
QCOMPARE(qvariant_cast<QFont>(object->property("test4")), QFont());
diff --git a/tests/auto/qml/qqmltranslation/data/translationChange.qml b/tests/auto/qml/qqmltranslation/data/translationChange.qml
index c48a482138..ae3231935c 100644
--- a/tests/auto/qml/qqmltranslation/data/translationChange.qml
+++ b/tests/auto/qml/qqmltranslation/data/translationChange.qml
@@ -3,6 +3,13 @@ import QtQuick 2.0
TranslationChangeBase {
id: root
+ ListModel {
+ id: listModel
+ ListElement {
+ text: qsTr("translate me")
+ }
+ }
+
baseProperty: "do not translate"
property string text1: qsTr("translate me")
function weDoTranslations() {
@@ -10,6 +17,7 @@ TranslationChangeBase {
}
property string text2: weDoTranslations()
property string text3
+ property string fromListModel: listModel.get(0).text
states: [
State {
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 1c67ba5541..5042a236d4 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -76,7 +76,7 @@ void tst_qqmltranslation::translation()
if (verifyCompiledData) {
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
- QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
+ QQmlRefPointer<QQmlTypeData> typeData = engine->typeLoader.getType(context->baseUrl());
QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
QVERIFY(compilationUnit);
@@ -136,7 +136,7 @@ void tst_qqmltranslation::idTranslation()
{
QQmlContext *context = qmlContext(object);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine());
- QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl());
+ QQmlRefPointer<QQmlTypeData> typeData = engine->typeLoader.getType(context->baseUrl());
QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit();
QVERIFY(compilationUnit);
@@ -195,6 +195,7 @@ void tst_qqmltranslation::translationChange()
QCOMPARE(object->property("text1").toString(), QString::fromUtf8("translate me"));
QCOMPARE(object->property("text2").toString(), QString::fromUtf8("translate me"));
QCOMPARE(object->property("text3").toString(), QString::fromUtf8("translate me"));
+ QCOMPARE(object->property("fromListModel").toString(), QString::fromUtf8("translate me"));
DummyTranslator translator;
QCoreApplication::installTranslator(&translator);
@@ -206,6 +207,7 @@ void tst_qqmltranslation::translationChange()
QCOMPARE(object->property("text1").toString(), QString::fromUtf8("xxx"));
QCOMPARE(object->property("text2").toString(), QString::fromUtf8("xxx"));
QCOMPARE(object->property("text3").toString(), QString::fromUtf8("xxx"));
+ QCOMPARE(object->property("fromListModel").toString(), QString::fromUtf8("xxx"));
QCoreApplication::removeTranslator(&translator);
}
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index d336d033a3..cf3bc8b050 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -87,7 +87,7 @@ void tst_QQMLTypeLoader::trimCache()
QUrl url = testFileUrl("trim_cache.qml");
url.setQuery(QString::number(i));
- QQmlTypeData *data = loader.getType(url);
+ QQmlTypeData *data = loader.getType(url).take();
// Run an event loop to receive the callback that release()es.
QTRY_COMPARE(data->count(), 2);
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index a456facd2f..1ee4510e30 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -1020,7 +1020,7 @@ void tst_qqmlvaluetypes::bindingAssignment()
// function assignment should fail without crashing
{
- QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6:13: Invalid use of Qt.binding() in a binding declaration.");
+ QString warning1 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":6:5: Invalid use of Qt.binding() in a binding declaration.");
QString warning2 = testFileUrl("bindingAssignment.2.qml").toString() + QLatin1String(":10: Cannot assign JavaScript function to value-type property");
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
@@ -1125,7 +1125,7 @@ void tst_qqmlvaluetypes::autoBindingRemoval()
{
QQmlComponent component(&engine, testFileUrl("autoBindingRemoval.3.qml"));
- QString warning = component.url().toString() + ":6:11: Unable to assign [undefined] to QRect";
+ QString warning = component.url().toString() + ":6:5: Unable to assign [undefined] to QRect";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
QVERIFY(object != nullptr);
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index d4ba363d00..07f8e9f1d1 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QQmlEngine>
+#include <QLoggingCategory>
#include <private/qv4mm_p.h>
class tst_qv4mm : public QObject
@@ -36,23 +37,15 @@ class tst_qv4mm : public QObject
private slots:
void gcStats();
- void tweaks();
};
void tst_qv4mm::gcStats()
{
- qputenv(QV4_MM_STATS, "1");
+ QLoggingCategory::setFilterRules("qt.qml.gc.*=true");
QQmlEngine engine;
engine.collectGarbage();
}
-void tst_qv4mm::tweaks()
-{
- qputenv(QV4_MM_MAXBLOCK_SHIFT, "5");
- qputenv(QV4_MM_MAX_CHUNK_SIZE, "65536");
- QQmlEngine engine;
-}
-
QTEST_MAIN(tst_qv4mm)
#include "tst_qv4mm.moc"
diff --git a/tests/auto/qmltest/rectangle/tst_rectangle.qml b/tests/auto/qmltest/rectangle/tst_rectangle.qml
index 9af55b6a79..cf57da0d73 100644
--- a/tests/auto/qmltest/rectangle/tst_rectangle.qml
+++ b/tests/auto/qmltest/rectangle/tst_rectangle.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.0
+import QtQuick 2.12
import QtTest 1.1
Item {
@@ -83,6 +83,17 @@ Item {
}
Rectangle {
+ id: horizontalGradient
+ width: 300
+ height: 100
+ gradient: Gradient {
+ orientation: Gradient.Horizontal
+ GradientStop { position: 0.0; color: "red" }
+ GradientStop { position: 1.0; color: "green" }
+ }
+ }
+
+ Rectangle {
id: rectangleborder
width: 300
height: 150
@@ -132,8 +143,18 @@ Item {
compare(gstops[0].color.toString(), "#ff0000")
compare(gstops[1].color.toString(), "#ffff00")
compare(gstops[2].color.toString(), "#008000")
+ compare(grad.orientation, Gradient.Vertical)
+ }
+
+ function test_horizontalGradient() {
+ var grad = horizontalGradient.gradient;
+ var gstops = grad.stops;
+ compare(gstops[0].color.toString(), "#ff0000")
+ compare(gstops[1].color.toString(), "#008000")
+ compare(grad.orientation, Gradient.Horizontal)
}
+
function test_borders() {
compare(rectangleborder.border.width, 1)
compare(rectangleborder.border.color.toString(), "#808080")
diff --git a/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml
new file mode 100644
index 0000000000..551329a457
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+AnimatedSprite {
+ loops: AnimatedSprite.Infinite
+ source: "squarefacesprite.png"
+ frameCount: 6
+ frameDuration: 240
+ width: 160
+ height: 160
+}
diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
index d24ebd9878..4ca31fd957 100644
--- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
+++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
@@ -53,6 +53,7 @@ private slots:
void test_largeAnimation();
void test_reparenting();
void test_changeSourceToSmallerImgKeepingBigFrameSize();
+ void test_infiniteLoops();
void test_implicitSize();
};
@@ -79,8 +80,13 @@ void tst_qquickanimatedsprite::test_properties()
QVERIFY(sprite->interpolate());
QCOMPARE(sprite->loops(), 30);
+ QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
sprite->setRunning(false);
QVERIFY(!sprite->running());
+ // The finished() signal shouldn't be emitted when running is manually set to false.
+ QCOMPARE(finishedSpy.count(), 0);
sprite->setInterpolate(false);
QVERIFY(!sprite->interpolate());
}
@@ -100,10 +106,15 @@ void tst_qquickanimatedsprite::test_runningChangedSignal()
QVERIFY(!sprite->running());
QSignalSpy runningChangedSpy(sprite, SIGNAL(runningChanged(bool)));
+ QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
sprite->setRunning(true);
QTRY_COMPARE(runningChangedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
QTRY_VERIFY(!sprite->running());
QTRY_COMPARE(runningChangedSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 1);
}
template <typename T>
@@ -357,6 +368,28 @@ void tst_qquickanimatedsprite::test_implicitSize()
QCOMPARE(frameImplicitHeightChangedSpy.count(), 1);
}
+void tst_qquickanimatedsprite::test_infiniteLoops()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("infiniteLoops.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QVERIFY(window.rootObject());
+
+ QQuickAnimatedSprite* sprite = qobject_cast<QQuickAnimatedSprite*>(window.rootObject());
+ QVERIFY(sprite);
+
+ QTRY_VERIFY(sprite->running());
+
+ QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
+ // The finished() signal shouldn't be emitted for infinite animations.
+ const int previousFrame = sprite->currentFrame();
+ QTRY_VERIFY(sprite->currentFrame() != previousFrame);
+ QCOMPARE(finishedSpy.count(), 0);
+}
+
QTEST_MAIN(tst_qquickanimatedsprite)
#include "tst_qquickanimatedsprite.moc"
diff --git a/tests/auto/quick/qquickanimations/data/finished.qml b/tests/auto/quick/qquickanimations/data/finished.qml
new file mode 100644
index 0000000000..a18b321501
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/finished.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+
+Item {
+ id: root
+ width: 400
+ height: 400
+
+ property bool finishedUsableInQml: false
+
+ property alias simpleTopLevelAnimation: simpleTopLevelAnimation
+ property real foo: 0
+
+ property alias transitionRect: transitionRect
+ property alias transition: transition
+ property alias animationWithinTransition: animationWithinTransition
+
+ property real bar: 0
+ property alias animationWithinBehavior: animationWithinBehavior
+ property alias behavior: behavior
+
+ NumberAnimation {
+ id: simpleTopLevelAnimation
+ target: root
+ property: "foo"
+ from: 0
+ to: 1
+ duration: 10
+
+ onFinished: finishedUsableInQml = true
+ }
+
+ Rectangle {
+ id: transitionRect
+ color: "green"
+ width: 50
+ height: 50
+ anchors.centerIn: parent
+
+ states: State {
+ name: "go"
+ }
+ transitions: Transition {
+ id: transition
+ to: "go"
+ SequentialAnimation {
+ NumberAnimation {
+ id: animationWithinTransition
+ duration: 10
+ property: "foo"
+ from: 1
+ to: 2
+ }
+ }
+ }
+ }
+
+ Behavior on bar {
+ id: behavior
+ NumberAnimation {
+ id: animationWithinBehavior
+ duration: 10
+ property: "bar"
+ from: 0
+ to: 1
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index de86bb16db..3cfe03a376 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -105,6 +105,7 @@ private slots:
void pathSvgAnimation();
void pathLineUnspecifiedXYBug();
void unsetAnimatorProxyJobWindow();
+ void finished();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -1612,6 +1613,79 @@ void tst_qquickanimations::unsetAnimatorProxyJobWindow()
QCOMPARE(proxy.job().data(), job);
}
+void tst_qquickanimations::finished()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("finished.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+
+ // Test that finished() is emitted for a simple top-level animation.
+ // (Each test is in its own block so that we can reuse the nice signal names :))
+ {
+ QQuickAbstractAnimation *simpleTopLevelAnimation
+ = root->property("simpleTopLevelAnimation").value<QQuickAbstractAnimation*>();
+ QVERIFY(simpleTopLevelAnimation);
+
+ QSignalSpy stoppedSpy(simpleTopLevelAnimation, SIGNAL(stopped()));
+ QVERIFY(stoppedSpy.isValid());
+
+ QSignalSpy finishedSpy(simpleTopLevelAnimation, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
+ QVERIFY(simpleTopLevelAnimation->setProperty("running", QVariant(true)));
+ QTRY_COMPARE(stoppedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 1);
+
+ // Test that the signal is properly revisioned and hence accessible from QML.
+ QCOMPARE(root->property("finishedUsableInQml").toBool(), true);
+ }
+
+ // Test that finished() is not emitted for animations within a Transition.
+ {
+ QObject *transition = root->property("transition").value<QObject*>();
+ QVERIFY(transition);
+
+ QSignalSpy runningChangedSpy(transition, SIGNAL(runningChanged()));
+ QVERIFY(runningChangedSpy.isValid());
+
+ QQuickAbstractAnimation *animationWithinTransition
+ = root->property("animationWithinTransition").value<QQuickAbstractAnimation*>();
+ QVERIFY(animationWithinTransition);
+
+ QSignalSpy stoppedSpy(animationWithinTransition, SIGNAL(stopped()));
+ QVERIFY(stoppedSpy.isValid());
+
+ QSignalSpy finishedSpy(animationWithinTransition, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
+ QObject *transitionRect = root->property("transitionRect").value<QObject*>();
+ QVERIFY(transitionRect);
+ QVERIFY(transitionRect->setProperty("state", QVariant(QLatin1String("go"))));
+ QTRY_COMPARE(runningChangedSpy.count(), 1);
+ QCOMPARE(stoppedSpy.count(), 0);
+ QCOMPARE(finishedSpy.count(), 0);
+ }
+
+ // Test that finished() is not emitted for animations within a Behavior.
+ {
+ QQuickAbstractAnimation *animationWithinBehavior
+ = root->property("animationWithinBehavior").value<QQuickAbstractAnimation*>();
+ QVERIFY(animationWithinBehavior);
+
+ QSignalSpy stoppedSpy(animationWithinBehavior, SIGNAL(stopped()));
+ QVERIFY(stoppedSpy.isValid());
+
+ QSignalSpy finishedSpy(animationWithinBehavior, SIGNAL(finished()));
+ QVERIFY(finishedSpy.isValid());
+
+ QVERIFY(root->setProperty("bar", QVariant(1.0)));
+ QTRY_COMPARE(root->property("bar").toReal(), 1.0);
+ QCOMPARE(stoppedSpy.count(), 0);
+ QCOMPARE(finishedSpy.count(), 0);
+ }
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml
index 68f456af99..63d65b435c 100644
--- a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml
+++ b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml
@@ -4,6 +4,8 @@ Item {
width: 100
height: 62
- x: Math.max(0, 200)
+ // Add a dummy dependency to parent.x to ensure that the
+ // binding stays for the test.
+ x: parent.x + Math.max(0, 200) - parent.x
}
diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
index 805baebc7a..6aff66d61e 100644
--- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
+++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
@@ -193,7 +193,7 @@ void tst_QQuickFramebufferObject::testThatStuffWorks()
view.show();
view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QImage result = view.grabWindow();
@@ -233,7 +233,7 @@ void tst_QQuickFramebufferObject::testInvalidate()
view.show();
view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QCOMPARE(frameInfo.fboSize, QSize(200, 200));
diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
index d8464ebc74..4b75a7e008 100644
--- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
+++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
@@ -65,6 +65,7 @@ private slots:
void threadTest();
void asyncTextureTest();
+ void instantAsyncTextureTest();
private:
QString newImageFileName() const;
@@ -550,6 +551,70 @@ void tst_qquickimageprovider::asyncTextureTest()
}
}
+class InstantAsyncImageResponse : public QQuickImageResponse
+{
+ public:
+ InstantAsyncImageResponse(const QString &id, const QSize &requestedSize)
+ {
+ QImage image(50, 50, QImage::Format_RGB32);
+ image.fill(QColor(id).rgb());
+ if (requestedSize.isValid())
+ image = image.scaled(requestedSize);
+ m_texture = QQuickTextureFactory::textureFactoryForImage(image);
+ emit finished();
+ }
+
+ QQuickTextureFactory *textureFactory() const
+ {
+ return m_texture;
+ }
+
+ QQuickTextureFactory *m_texture;
+};
+
+class InstancAsyncProvider : public QQuickAsyncImageProvider
+{
+ public:
+ InstancAsyncProvider()
+ {
+ }
+
+ ~InstancAsyncProvider() {}
+
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize)
+ {
+ return new InstantAsyncImageResponse(id, requestedSize);
+ }
+};
+
+void tst_qquickimageprovider::instantAsyncTextureTest()
+{
+ QQmlEngine engine;
+
+ InstancAsyncProvider *provider = new InstancAsyncProvider;
+
+ engine.addImageProvider("test_instantasync", provider);
+ QVERIFY(engine.imageProvider("test_instantasync") != nullptr);
+
+ QString componentStr = "import QtQuick 2.0\nItem { \n"
+ "Image { source: \"image://test_instantasync/blue\"; }\n"
+ "Image { source: \"image://test_instantasync/red\"; }\n"
+ "Image { source: \"image://test_instantasync/green\"; }\n"
+ "Image { source: \"image://test_instantasync/yellow\"; }\n"
+ " }";
+ QQmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QScopedPointer<QObject> obj(component.create());
+
+ QVERIFY(!obj.isNull());
+ const QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
+ QCOMPARE(images.count(), 4);
+
+ for (QQuickImage *img: images) {
+ QTRY_COMPARE(img->status(), QQuickImage::Ready);
+ }
+}
+
QTEST_MAIN(tst_qquickimageprovider)
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index c1daddb561..5d6708a765 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -118,6 +118,7 @@ private slots:
void noCurrentIndex();
void keyNavigation();
void keyNavigation_data();
+ void checkCountForMultiColumnModels();
void enforceRange();
void enforceRange_withoutHighlight();
void spacing();
@@ -1855,6 +1856,38 @@ void tst_QQuickListView::swapWithFirstItem()
delete testObject;
}
+void tst_QQuickListView::checkCountForMultiColumnModels()
+{
+ // Check that a list view will only load items for the first
+ // column, even if the model reports that it got several columns.
+ // We test this since QQmlDelegateModel has been changed to
+ // also understand multi-column models, but this should not affect ListView.
+ QScopedPointer<QQuickView> window(createView());
+
+ const int rowCount = 10;
+ const int columnCount = 10;
+
+ QaimModel model;
+ model.columns = columnCount;
+ for (int i = 0; i < rowCount; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QQmlContext *ctxt = window->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ QScopedPointer<TestObject> testObject(new TestObject);
+ ctxt->setContextProperty("testObject", testObject.data());
+
+ window->setSource(testFileUrl("listviewtest.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != nullptr);
+
+ QCOMPARE(listview->count(), rowCount);
+}
+
void tst_QQuickListView::enforceRange()
{
QScopedPointer<QQuickView> window(createView());
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 7a176661e8..fd9fed39b5 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -737,7 +737,7 @@ void tst_QQuickLoader::initialPropertyValuesError_data()
<< (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory"));
QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
- << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
+ << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'"));
QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml")
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object")
@@ -883,7 +883,7 @@ void tst_QQuickLoader::asynchronous_data()
<< (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory"));
QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
- << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
+ << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'"));
}
void tst_QQuickLoader::asynchronous()
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index 4211d08393..7a6f302403 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -366,6 +366,10 @@ void tst_QQuickPathView::insertModel_data()
void tst_QQuickPathView::insertModel()
{
+#ifdef Q_OS_MACOS
+ QSKIP("this test currently crashes on MacOS. See QTBUG-68048");
+#endif
+
QFETCH(int, mode);
QFETCH(int, idx);
QFETCH(int, count);
@@ -772,6 +776,10 @@ void tst_QQuickPathView::path()
void tst_QQuickPathView::dataModel()
{
+#ifdef Q_OS_MACOS
+ QSKIP("this test currently crashes on MacOS. See QTBUG-68047");
+#endif
+
QScopedPointer<QQuickView> window(createView());
window->show();
diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
index 0395b08f10..ec31acf035 100644
--- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
+++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
@@ -40,6 +40,8 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
class tst_qquickpositioners : public QQmlDataTest
{
Q_OBJECT
@@ -3772,6 +3774,10 @@ void tst_qquickpositioners::test_mirroring()
QList<QString> objectNames;
objectNames << "one" << "two" << "three" << "four" << "five";
+#ifdef Q_OS_MACOS
+ qputenv("QSG_RENDER_LOOP","basic"); // QTBUG-69040
+#endif
+
foreach (const QString qmlFile, qmlFiles) {
QScopedPointer<QQuickView> windowA(createView(testFile(qmlFile)));
QQuickItem *rootA = qobject_cast<QQuickItem*>(windowA->rootObject());
@@ -4007,15 +4013,19 @@ void tst_qquickpositioners::test_attachedproperties_dynamic()
QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait)
{
QQuickView *window = new QQuickView(nullptr);
- qDebug() << "1";
+ qCDebug(lcTests) << "created window";
window->setSource(QUrl::fromLocalFile(filename));
- qDebug() << "2";
+ qCDebug(lcTests) << "loaded content from" << filename;
window->show();
- qDebug() << "3";
+ qCDebug(lcTests) << "window shown";
+ bool exposed = true;
if (wait)
- QTest::qWaitForWindowExposed(window); //It may not relayout until the next frame, so it needs to be drawn
- qDebug() << "4";
+ exposed = QTest::qWaitForWindowExposed(window); //It may not relayout until the next frame, so it needs to be drawn
+ if (exposed)
+ qCDebug(lcTests) << "window exposed";
+ else
+ qCWarning(lcTests) << "window NOT exposed";
return window;
}
diff --git a/tests/auto/quick/qquickrepeater/data/ownership.qml b/tests/auto/quick/qquickrepeater/data/ownership.qml
new file mode 100644
index 0000000000..e13df3ab3a
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/ownership.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+Repeater {
+}
diff --git a/tests/auto/quick/qquickrepeater/data/package.qml b/tests/auto/quick/qquickrepeater/data/package.qml
new file mode 100644
index 0000000000..1f9eb0d970
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/package.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.0
+import QtQml.Models 2.2
+import QtQuick.Window 2.0
+
+Window {
+ width: 300
+ height: 300
+ visible: true
+ DelegateModel {
+ id: mdl
+
+ model: 1
+ delegate: Package {
+ Item {
+ id: first
+ Package.name: "first"
+ objectName: "firstItem"
+ }
+ Item{
+ id: second
+ Package.name: "second"
+ objectName: "secondItem"
+ }
+ }
+ }
+
+ Repeater {
+ id: repeater1
+ model: mdl.parts.first
+ }
+ Repeater {
+ id: repeater2
+ model: mdl.parts.second
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
index 0499e2f9a6..0860956224 100644
--- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
+++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
@@ -37,6 +37,7 @@
#include <QtQuick/private/qquicktext_p.h>
#include <QtQml/private/qqmllistmodel_p.h>
#include <QtQml/private/qqmlobjectmodel_p.h>
+#include <QtGui/qstandarditemmodel.h>
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
@@ -76,6 +77,8 @@ private slots:
void stackingOrder();
void objectModel();
void QTBUG54859_asynchronousMove();
+ void package();
+ void ownership();
};
class TestObject : public QObject
@@ -1014,6 +1017,91 @@ void tst_QQuickRepeater::QTBUG54859_asynchronousMove()
QTRY_COMPARE(item->property("finished"), QVariant(true));
}
+void tst_QQuickRepeater::package()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("package.qml"));
+
+ QScopedPointer<QObject>o(component.create()); // don't crash!
+ QVERIFY(o != nullptr);
+
+ {
+ QQuickRepeater *repeater1 = qobject_cast<QQuickRepeater*>(qmlContext(o.data())->contextProperty("repeater1").value<QObject*>());
+ QVERIFY(repeater1);
+ QCOMPARE(repeater1->count(), 1);
+ QCOMPARE(repeater1->itemAt(0)->objectName(), "firstItem");
+ }
+
+ {
+ QQuickRepeater *repeater2 = qobject_cast<QQuickRepeater*>(qmlContext(o.data())->contextProperty("repeater2").value<QObject*>());
+ QVERIFY(repeater2);
+ QCOMPARE(repeater2->count(), 1);
+ QCOMPARE(repeater2->itemAt(0)->objectName(), "secondItem");
+ }
+}
+
+void tst_QQuickRepeater::ownership()
+{
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, testFileUrl("ownership.qml"));
+
+ QScopedPointer<QAbstractItemModel> aim(new QStandardItemModel);
+ QPointer<QAbstractItemModel> modelGuard(aim.data());
+ QQmlEngine::setObjectOwnership(aim.data(), QQmlEngine::JavaScriptOwnership);
+ {
+ QJSValue wrapper = engine.newQObject(aim.data());
+ }
+
+ QScopedPointer<QObject> repeater(component.create());
+ QVERIFY(!repeater.isNull());
+
+ QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(aim.data()));
+
+ repeater->setProperty("model", QVariant::fromValue<QObject*>(aim.data()));
+
+ QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(aim.data()));
+
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+
+ QVERIFY(modelGuard);
+
+ QScopedPointer<QQmlComponent> delegate(new QQmlComponent(&engine));
+ delegate->setData(QByteArrayLiteral("import QtQuick 2.0\nItem{}"), dataDirectoryUrl().resolved(QUrl("inline.qml")));
+ QPointer<QQmlComponent> delegateGuard(delegate.data());
+ QQmlEngine::setObjectOwnership(delegate.data(), QQmlEngine::JavaScriptOwnership);
+ {
+ QJSValue wrapper = engine.newQObject(delegate.data());
+ }
+
+ QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(delegate.data()));
+
+ repeater->setProperty("delegate", QVariant::fromValue<QObject*>(delegate.data()));
+
+ QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(delegate.data()));
+
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+
+ QVERIFY(delegateGuard);
+
+ repeater->setProperty("model", QVariant());
+ repeater->setProperty("delegate", QVariant());
+
+ QVERIFY(delegateGuard);
+ QVERIFY(modelGuard);
+
+ delegate.take();
+ aim.take();
+
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+
+ QVERIFY(!delegateGuard);
+ QVERIFY(!modelGuard);
+}
+
QTEST_MAIN(tst_QQuickRepeater)
#include "tst_qquickrepeater.moc"
diff --git a/tests/auto/quick/qquickshape/qquickshape.pro b/tests/auto/quick/qquickshape/qquickshape.pro
index 29c3502b86..a0e5c002e0 100644
--- a/tests/auto/quick/qquickshape/qquickshape.pro
+++ b/tests/auto/quick/qquickshape/qquickshape.pro
@@ -9,27 +9,5 @@ include (../shared/util.pri)
TESTDATA = data/*
-HEADERS += \
- ../../../../src/imports/shapes/qquickshape_p.h \
- ../../../../src/imports/shapes/qquickshape_p_p.h \
- ../../../../src/imports/shapes/qquickshapegenericrenderer_p.h \
- ../../../../src/imports/shapes/qquickshapesoftwarerenderer_p.h
-
-SOURCES += \
- ../../../../src/imports/shapes/qquickshape.cpp \
- ../../../../src/imports/shapes/qquickshapegenericrenderer.cpp \
- ../../../../src/imports/shapes/qquickshapesoftwarerenderer.cpp
-
-qtConfig(opengl) {
- HEADERS += \
- ../../../../src/imports/shapes/qquicknvprfunctions_p.h \
- ../../../../src/imports/shapes/qquicknvprfunctions_p_p.h \
- ../../../../src/imports/shapes/qquickshapenvprrenderer_p.h
-
- SOURCES += \
- ../../../../src/imports/shapes/qquicknvprfunctions.cpp \
- ../../../../src/imports/shapes/qquickshapenvprrenderer.cpp
-}
-
-QT += core-private gui-private qml-private quick-private testlib
+QT += core-private gui-private qml-private quick-private testlib quickshapes-private
qtHaveModule(widgets): QT += widgets
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index 2a349d2013..72f987ce4a 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -33,7 +33,7 @@
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlincubator.h>
-#include "../../../../src/imports/shapes/qquickshape_p.h"
+#include <QtQuickShapes/private/qquickshape_p.h>
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
diff --git a/tests/auto/quick/qquicktableview/data/countingtableview.qml b/tests/auto/quick/qquicktableview/data/countingtableview.qml
new file mode 100644
index 0000000000..d8315be54f
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/countingtableview.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import Qt.labs.tableview 1.0
+
+Item {
+ id: root
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+ property int currentDelegateCount: 0
+ property int maxDelegateCount: 0
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ cacheBuffer: 0
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ TableView.cellWidth: 100
+ TableView.cellHeight: 50
+ color: "lightgray"
+ border.width: 1
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ Component.onCompleted: {
+ currentDelegateCount++;
+ maxDelegateCount = Math.max(maxDelegateCount, currentDelegateCount);
+ }
+ Component.onDestruction: {
+ currentDelegateCount--;
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/plaintableview.qml b/tests/auto/quick/qquicktableview/data/plaintableview.qml
new file mode 100644
index 0000000000..7668f0ca01
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/plaintableview.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import Qt.labs.tableview 1.0
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+ property real delegateWidth: 100
+ property real delegateHeight: 50
+ property Component delegate: tableViewDelegate
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ cacheBuffer: 0
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ TableView.cellWidth: delegateWidth
+ TableView.cellHeight: delegateHeight
+ color: "lightgray"
+ border.width: 1
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml
new file mode 100644
index 0000000000..65e4d0861c
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import Qt.labs.tableview 1.0
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ cacheBuffer: 0
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ color: "lightgray"
+ border.width: 1
+ implicitWidth: 90
+ implicitHeight: 60
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/qquicktableview.pro b/tests/auto/quick/qquicktableview/qquicktableview.pro
new file mode 100644
index 0000000000..f4d0265dd3
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/qquicktableview.pro
@@ -0,0 +1,14 @@
+CONFIG += testcase
+TARGET = tst_qquicktableview
+macos:CONFIG -= app_bundle
+
+HEADERS += testmodel.h
+SOURCES += tst_qquicktableview.cpp
+
+include (../../shared/util.pri)
+include (../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += core-private gui-private qml-private quick-private testlib
+
diff --git a/tests/auto/quick/qquicktableview/testmodel.h b/tests/auto/quick/qquicktableview/testmodel.h
new file mode 100644
index 0000000000..06384f7a5e
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/testmodel.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtCore>
+#include <QtGui/QStandardItemModel>
+
+class TestModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged)
+ Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged)
+
+public:
+ TestModel(QObject *parent = nullptr)
+ : QAbstractTableModel(parent)
+ {}
+
+ TestModel(int rows, int columns, QObject *parent = nullptr)
+ : QAbstractTableModel(parent)
+ , m_rows(rows)
+ , m_columns(columns)
+ {}
+
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; }
+ void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); }
+
+ int columnCount(const QModelIndex & = QModelIndex()) const override { return m_columns; }
+ void setColumnCount(int count) { beginResetModel(); m_columns = count; emit columnCountChanged(); endResetModel(); }
+
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (!index.isValid() || role != Qt::DisplayRole)
+ return QVariant();
+
+ int cell = index.row() + (index.column() * m_columns);
+ if (selectedCells.contains(cell))
+ return QStringLiteral("selected");
+ return QString("%1").arg(index.row());
+ }
+
+ QHash<int, QByteArray> roleNames() const override
+ {
+ return { {Qt::DisplayRole, "display"} };
+ }
+
+ Q_INVOKABLE void selectCell(int row, int column)
+ {
+ int cell = row + (column * m_columns);
+ selectedCells.insert(cell);
+ auto index = createIndex(row, column, nullptr);
+ emit dataChanged(index, index);
+ }
+
+signals:
+ void rowCountChanged();
+ void columnCountChanged();
+
+private:
+ int m_rows = 0;
+ int m_columns = 0;
+ QSet<int> selectedCells;
+};
+
+#define TestModelAsVariant(...) QVariant::fromValue(QSharedPointer<TestModel>(new TestModel(__VA_ARGS__)))
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
new file mode 100644
index 0000000000..1de40aaae0
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -0,0 +1,822 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquicktableview_p.h>
+#include <QtQuick/private/qquicktableview_p_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlexpression.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/private/qqmlobjectmodel_p.h>
+#include <QtQml/private/qqmllistmodel_p.h>
+#include <QtQml/private/qqmldelegatemodel_p.h>
+
+#include "testmodel.h"
+
+#include "../../shared/util.h"
+#include "../shared/viewtestutil.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickViewTestUtil;
+using namespace QQuickVisualTestUtil;
+
+static const char* kTableViewPropName = "tableView";
+static const char* kDelegateObjectName = "tableViewDelegate";
+
+Q_DECLARE_METATYPE(QMarginsF);
+
+#define LOAD_TABLEVIEW(fileName) \
+ QScopedPointer<QQuickView> view(createView()); \
+ view->setSource(testFileUrl(fileName)); \
+ view->show(); \
+ QVERIFY(QTest::qWaitForWindowActive(view.data())); \
+ auto tableView = view->rootObject()->property(kTableViewPropName).value<QQuickTableView *>(); \
+ QVERIFY(tableView); \
+ auto tableViewPrivate = QQuickTableViewPrivate::get(tableView); \
+ Q_UNUSED(tableViewPrivate)
+
+#define WAIT_UNTIL_POLISHED \
+ QVERIFY(tableViewPrivate->polishScheduled); \
+ QTRY_VERIFY(!tableViewPrivate->polishScheduled)
+
+class tst_QQuickTableView : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_QQuickTableView();
+
+ QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+ FxTableItem *findFxTableItem(int row, int column, const QList<FxTableItem *> items) const;
+ FxTableItem *findLoadedBottomRightItem(const QList<FxTableItem *> items) const;
+
+private slots:
+ void initTestCase() override;
+
+ void setAndGetModel_data();
+ void setAndGetModel();
+ void emptyModel_data();
+ void emptyModel();
+ void checkZeroSizedDelegate();
+ void checkImplicitSizeDelegate();
+ void noDelegate();
+ void countDelegateItems_data();
+ void countDelegateItems();
+ void checkLayoutOfEqualSizedDelegateItems_data();
+ void checkLayoutOfEqualSizedDelegateItems();
+ void checkTableMargins_data();
+ void checkTableMargins();
+ void fillTableViewButNothingMore_data();
+ void fillTableViewButNothingMore();
+ void checkInitialAttachedProperties_data();
+ void checkInitialAttachedProperties();
+ void flick_data();
+ void flick();
+ void flickOvershoot_data();
+ void flickOvershoot();
+ void checkRowColumnCount();
+};
+
+tst_QQuickTableView::tst_QQuickTableView()
+{
+}
+
+void tst_QQuickTableView::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<TestModel>("TestModel", 0, 1, "TestModel");
+}
+
+QQuickTableViewAttached *tst_QQuickTableView::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object);
+ return static_cast<QQuickTableViewAttached *>(attachedObject);
+}
+
+FxTableItem *tst_QQuickTableView::findFxTableItem(int row, int column, const QList<FxTableItem *> items) const
+{
+ for (int i = 0; i < items.count(); ++i) {
+ FxTableItem *fxitem = items[i];
+ auto attached = getAttachedObject(fxitem->item);
+ if (row == attached->row() && column == attached->column())
+ return fxitem;
+ }
+ return nullptr;
+}
+
+FxTableItem *tst_QQuickTableView::findLoadedBottomRightItem(const QList<FxTableItem *> items) const
+{
+ FxTableItem *bottomRightItem = nullptr;
+ int bottomRightIndex = 0;
+
+ for (int i = items.count() - 1; i > 0; --i) {
+ FxTableItem *fxitem = items[i];
+ if (fxitem->index > bottomRightIndex) {
+ bottomRightItem = fxitem;
+ bottomRightIndex = fxitem->index;
+ }
+ }
+ return bottomRightItem;
+}
+
+void tst_QQuickTableView::setAndGetModel_data()
+{
+ QTest::addColumn<QVariant>("model");
+
+ QTest::newRow("QAIM 1x1") << TestModelAsVariant(1, 1);
+ QTest::newRow("Number model 1") << QVariant::fromValue(1);
+ QTest::newRow("QStringList 1") << QVariant::fromValue(QStringList() << "one");
+}
+
+void tst_QQuickTableView::setAndGetModel()
+{
+ // Test that we can set and get different kind of models
+ QFETCH(QVariant, model);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+ QCOMPARE(model, tableView->model());
+}
+
+void tst_QQuickTableView::emptyModel_data()
+{
+ QTest::addColumn<QVariant>("model");
+
+ QTest::newRow("QAIM") << TestModelAsVariant(0, 0);
+ QTest::newRow("Number model") << QVariant::fromValue(0);
+ QTest::newRow("QStringList") << QVariant::fromValue(QStringList());
+}
+
+void tst_QQuickTableView::emptyModel()
+{
+ // Check that if we assign an empty model to
+ // TableView, no delegate items will be created.
+ QFETCH(QVariant, model);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(tableViewPrivate->loadedItems.count(), 0);
+}
+
+void tst_QQuickTableView::checkZeroSizedDelegate()
+{
+ // Check that if we assign a delegate with empty width and height, we
+ // fall back to use kDefaultColumnWidth and kDefaultRowHeight as
+ // column/row sizes.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+
+ view->rootObject()->setProperty("delegateWidth", 0);
+ view->rootObject()->setProperty("delegateHeight", 0);
+
+ WAIT_UNTIL_POLISHED;
+
+ auto items = tableViewPrivate->loadedItems;
+ QVERIFY(!items.isEmpty());
+
+ for (auto fxItem : tableViewPrivate->loadedItems) {
+ auto item = fxItem->item;
+ QCOMPARE(item->width(), kDefaultColumnWidth);
+ QCOMPARE(item->height(), kDefaultRowHeight);
+ }
+}
+
+void tst_QQuickTableView::checkImplicitSizeDelegate()
+{
+ // Check that we can set the size of delegate items using
+ // implicit width/height, instead of forcing the user to
+ // create an attached object by using TableView.cellWidth/Height.
+ LOAD_TABLEVIEW("tableviewimplicitsize.qml");
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ auto items = tableViewPrivate->loadedItems;
+ QVERIFY(!items.isEmpty());
+
+ for (auto fxItem : tableViewPrivate->loadedItems) {
+ auto item = fxItem->item;
+ QCOMPARE(item->width(), 90);
+ QCOMPARE(item->height(), 60);
+ }
+}
+
+void tst_QQuickTableView::noDelegate()
+{
+ // Check that you can skip setting a delegate without
+ // it causing any problems (like crashing or asserting).
+ // And then set a delegate, and do a quick check that the
+ // view gets populated as expected.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const int rows = 5;
+ const int columns = 5;
+ auto model = TestModelAsVariant(columns, rows);
+ tableView->setModel(model);
+
+ // Start with no delegate, and check
+ // that we end up with no items in the table.
+ tableView->setDelegate(nullptr);
+
+ WAIT_UNTIL_POLISHED;
+
+ auto items = tableViewPrivate->loadedItems;
+ QVERIFY(items.isEmpty());
+
+ // Set a delegate, and check that we end
+ // up with the expected number of items.
+ auto delegate = view->rootObject()->property("delegate").value<QQmlComponent *>();
+ QVERIFY(delegate);
+ tableView->setDelegate(delegate);
+
+ WAIT_UNTIL_POLISHED;
+
+ items = tableViewPrivate->loadedItems;
+ QCOMPARE(items.count(), rows * columns);
+
+ // And then unset the delegate again, and check
+ // that we end up with no items.
+ tableView->setDelegate(nullptr);
+
+ WAIT_UNTIL_POLISHED;
+
+ items = tableViewPrivate->loadedItems;
+ QVERIFY(items.isEmpty());
+}
+
+void tst_QQuickTableView::countDelegateItems_data()
+{
+ QTest::addColumn<QVariant>("model");
+ QTest::addColumn<int>("count");
+
+ QTest::newRow("QAIM 1x1") << TestModelAsVariant(1, 1) << 1;
+ QTest::newRow("QAIM 2x1") << TestModelAsVariant(2, 1) << 2;
+ QTest::newRow("QAIM 1x2") << TestModelAsVariant(1, 2) << 2;
+ QTest::newRow("QAIM 2x2") << TestModelAsVariant(2, 2) << 4;
+ QTest::newRow("QAIM 4x4") << TestModelAsVariant(4, 4) << 16;
+
+ QTest::newRow("Number model 1") << QVariant::fromValue(1) << 1;
+ QTest::newRow("Number model 4") << QVariant::fromValue(4) << 4;
+
+ QTest::newRow("QStringList 1") << QVariant::fromValue(QStringList() << "one") << 1;
+ QTest::newRow("QStringList 4") << QVariant::fromValue(QStringList() << "one" << "two" << "three" << "four") << 4;
+}
+
+void tst_QQuickTableView::countDelegateItems()
+{
+ // Assign different models of various sizes, and check that the number of
+ // delegate items in the view matches the size of the model. Note that for
+ // this test to be valid, all items must be within the visible area of the view.
+ QFETCH(QVariant, model);
+ QFETCH(int, count);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+ WAIT_UNTIL_POLISHED;
+
+ // Check that tableview internals contain the expected number of items
+ auto const items = tableViewPrivate->loadedItems;
+ QCOMPARE(items.count(), count);
+
+ // Check that this also matches the items found in the view
+ auto foundItems = findItems<QQuickItem>(tableView, kDelegateObjectName);
+ QCOMPARE(foundItems.count(), count);
+}
+
+void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems_data()
+{
+ QTest::addColumn<QVariant>("model");
+ QTest::addColumn<QSize>("tableSize");
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ // Check spacing together with different table setups
+ QTest::newRow("QAIM 1x1 1,1") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 0,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 1,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(1, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 0,1") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 1) << QMarginsF(0, 0, 0, 0);
+
+ // Check spacing together with margins
+ QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5);
+ QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3);
+ QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4);
+
+ // Check "list" models
+ QTest::newRow("NumberModel 1x4, 0000") << QVariant::fromValue(4) << QSize(1, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QStringList 1x4, 0,0 1111") << QVariant::fromValue(QStringList() << "one" << "two" << "three" << "four")
+ << QSize(1, 4) << QSizeF(0, 0) << QMarginsF(1, 1, 1, 1);
+}
+
+void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems()
+{
+ // Check that the geometry of the delegate items are correct
+ QFETCH(QVariant, model);
+ QFETCH(QSize, tableSize);
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const qreal expectedItemWidth = 100;
+ const qreal expectedItemHeight = 50;
+ const int expectedItemCount = tableSize.width() * tableSize.height();
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+
+ WAIT_UNTIL_POLISHED;
+
+ auto const items = tableViewPrivate->loadedItems;
+ QVERIFY(!items.isEmpty());
+
+ for (int i = 0; i < expectedItemCount; ++i) {
+ const QQuickItem *item = items[i]->item;
+ QVERIFY(item);
+ QCOMPARE(item->parentItem(), tableView->contentItem());
+
+ auto attached = getAttachedObject(item);
+ int row = attached->row();
+ int column = attached->column();
+ qreal expectedX = margins.left() + (column * (expectedItemWidth + spacing.width()));
+ qreal expectedY = margins.top() + (row * (expectedItemHeight + spacing.height()));
+ QCOMPARE(item->x(), expectedX);
+ QCOMPARE(item->y(), expectedY);
+ QCOMPARE(item->width(), expectedItemWidth);
+ QCOMPARE(item->height(), expectedItemHeight);
+ }
+}
+
+void tst_QQuickTableView::checkTableMargins_data()
+{
+ QTest::addColumn<QVariant>("model");
+ QTest::addColumn<QSize>("tableSize");
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ QTest::newRow("QAIM 1x1 1,1 0000") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 4x4 1,1 0000") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5);
+ QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3);
+ QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4);
+ QTest::newRow("QAIM 1x1 0,0 3210") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(0, 0) << QMarginsF(3, 2, 1, 0);
+}
+
+void tst_QQuickTableView::checkTableMargins()
+{
+ // Check that the space between the content view and
+ // the items matches the margins we set on the tableview.
+ QFETCH(QVariant, model);
+ QFETCH(QSize, tableSize);
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+
+ WAIT_UNTIL_POLISHED;
+
+ auto const items = tableViewPrivate->loadedItems;
+
+ auto const topLeftFxItem = findFxTableItem(0, 0, items);
+ auto const bottomRightFxItem = findFxTableItem(tableSize.height() - 1, tableSize.width() - 1, items);
+ QVERIFY(topLeftFxItem);
+ QVERIFY(bottomRightFxItem);
+
+ auto const topLeftItem = topLeftFxItem->item;
+ auto const bottomRightItem = bottomRightFxItem->item;
+ qreal leftSpace = topLeftItem->x();
+ qreal topSpace = topLeftItem->y();
+ qreal rightSpace = tableView->contentWidth() - (bottomRightItem->x() + bottomRightItem->width());
+ qreal bottomSpace = tableView->contentHeight() - (bottomRightItem->y() + bottomRightItem->height());
+ QCOMPARE(leftSpace, margins.left());
+ QCOMPARE(topSpace, margins.top());
+ QCOMPARE(rightSpace, margins.right());
+ QCOMPARE(bottomSpace, margins.bottom());
+}
+
+void tst_QQuickTableView::fillTableViewButNothingMore_data()
+{
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ QTest::newRow("0 0,0 0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("0 10,10 0") << QSizeF(10, 10) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("100 10,10 0") << QSizeF(10, 10) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("0 0,0 100") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("0 10,10 100") << QSizeF(10, 10) << QMarginsF(100, 100, 100, 100);
+ QTest::newRow("100 10,10 100") << QSizeF(10, 10) << QMarginsF(100, 100, 100, 100);
+}
+
+void tst_QQuickTableView::fillTableViewButNothingMore()
+{
+ // Check that we end up filling the whole visible part of
+ // the tableview with cells, but nothing more.
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const int rows = 100;
+ const int columns = 100;
+ auto model = TestModelAsVariant(rows, columns);
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+ tableView->setCacheBuffer(0);
+
+ WAIT_UNTIL_POLISHED;
+
+ auto const items = tableViewPrivate->loadedItems;
+
+ auto const topLeftFxItem = findFxTableItem(0, 0, items);
+ QVERIFY(topLeftFxItem);
+ auto const topLeftItem = topLeftFxItem->item;
+
+ // Check that the top-left item are at the corner of the view
+ QCOMPARE(topLeftItem->x(), margins.left());
+ QCOMPARE(topLeftItem->y(), margins.top());
+
+ auto const bottomRightFxItem = findLoadedBottomRightItem(items);
+ QVERIFY(bottomRightFxItem);
+ auto const bottomRightItem = bottomRightFxItem->item;
+ auto bottomRightAttached = getAttachedObject(bottomRightItem);
+
+ // Check that the right-most item is overlapping the right edge of the view
+ QVERIFY(bottomRightItem->x() < tableView->width());
+ QVERIFY(bottomRightItem->x() + bottomRightItem->width() >= tableView->width() - spacing.width());
+
+ // Check that the actual number of columns matches what we expect
+ qreal cellWidth = bottomRightItem->width() + spacing.width();
+ qreal availableWidth = tableView->width() - margins.left();
+ int expectedColumns = qCeil(availableWidth / cellWidth);
+ int actualColumns = bottomRightAttached->column() + 1;
+ QCOMPARE(actualColumns, expectedColumns);
+
+ // Check that the bottom-most item is overlapping the bottom edge of the view
+ QVERIFY(bottomRightItem->y() < tableView->height());
+ QVERIFY(bottomRightItem->y() + bottomRightItem->height() >= tableView->height() - spacing.height());
+
+ // Check that the actual number of rows matches what we expect
+ qreal cellHeight = bottomRightItem->height() + spacing.height();
+ qreal availableHeight = tableView->height() - margins.top();
+ int expectedRows = qCeil(availableHeight / cellHeight);
+ int actualRows = bottomRightAttached->row() + 1;
+ QCOMPARE(actualRows, expectedRows);
+}
+
+void tst_QQuickTableView::checkInitialAttachedProperties_data()
+{
+ QTest::addColumn<QVariant>("model");
+
+ QTest::newRow("QAIM") << TestModelAsVariant(4, 4);
+ QTest::newRow("Number model") << QVariant::fromValue(4);
+ QTest::newRow("QStringList") << QVariant::fromValue(QStringList() << "0" << "1" << "2" << "3");
+}
+
+void tst_QQuickTableView::checkInitialAttachedProperties()
+{
+ // Check that the context and attached properties inside
+ // the delegate items are what we expect at start-up.
+ QFETCH(QVariant, model);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ for (auto fxItem : tableViewPrivate->loadedItems) {
+ const int index = fxItem->index;
+ const auto item = fxItem->item;
+ const auto attached = getAttachedObject(item);
+ const auto context = qmlContext(item.data());
+ const QPoint cell = tableViewPrivate->cellAtModelIndex(index);
+ const int contextIndex = context->contextProperty("index").toInt();
+ const int contextRow = context->contextProperty("row").toInt();
+ const int contextColumn = context->contextProperty("column").toInt();
+ const QString contextModelData = context->contextProperty("modelData").toString();
+ const QQmlDelegateModelAttached *delegateModelAttached =
+ static_cast<QQmlDelegateModelAttached *>(
+ qmlAttachedPropertiesObject<QQmlDelegateModel>(item));
+ const int contextItemsIndex = delegateModelAttached->property("itemsIndex").toInt();
+
+ QCOMPARE(attached->row(), cell.y());
+ QCOMPARE(attached->column(), cell.x());
+ QCOMPARE(contextRow, cell.y());
+ QCOMPARE(contextColumn, cell.x());
+ QCOMPARE(contextIndex, index);
+ QCOMPARE(contextModelData, QStringLiteral("%1").arg(cell.y()));
+ QCOMPARE(contextItemsIndex, index);
+ }
+}
+
+void tst_QQuickTableView::flick_data()
+{
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20);
+ QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20);
+}
+
+void tst_QQuickTableView::flick()
+{
+ // Check that if we end up with the correct start and end column/row as we flick around
+ // with different table configurations.
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const qreal delegateWidth = 100;
+ const qreal delegateHeight = 50;
+ const int visualColumnCount = 4;
+ const int visualRowCount = 4;
+ const qreal cellWidth = delegateWidth + spacing.width();
+ const qreal cellHeight = delegateHeight + spacing.height();
+ auto model = TestModelAsVariant(100, 100);
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+ tableView->setCacheBuffer(0);
+ tableView->setWidth(margins.left() + (visualColumnCount * cellWidth) - spacing.width());
+ tableView->setHeight(margins.top() + (visualRowCount * cellHeight) - spacing.height());
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check the "simple" case if the cells never lands egde-to-edge with the viewport. For
+ // that case we only accept that visible row/columns are loaded.
+ qreal flickValues[] = {0.5, 1.5, 4.5, 20.5, 10.5, 3.5, 1.5, 0.5};
+
+ for (qreal cellsToFlick : flickValues) {
+ // Flick to the beginning of the cell
+ tableView->setContentX(cellsToFlick * cellWidth);
+ tableView->setContentY(cellsToFlick * cellHeight);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ const QRect loadedTable = tableViewPrivate->loadedTable;
+
+ const int expectedTableLeft = cellsToFlick - int((margins.left() + spacing.width()) / cellWidth);
+ const int expectedTableTop = cellsToFlick - int((margins.top() + spacing.height()) / cellHeight);
+
+ QCOMPARE(loadedTable.left(), expectedTableLeft);
+ QCOMPARE(loadedTable.right(), expectedTableLeft + visualColumnCount);
+ QCOMPARE(loadedTable.top(), expectedTableTop);
+ QCOMPARE(loadedTable.bottom(), expectedTableTop + visualRowCount);
+ }
+}
+
+void tst_QQuickTableView::flickOvershoot_data()
+{
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20);
+ QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20);
+}
+
+void tst_QQuickTableView::flickOvershoot()
+{
+ // Flick the table completely out and then in again, and see
+ // that we still contains the expected rows/columns
+ // Note that TableView always keeps top-left item loaded, even
+ // when everything is flicked out of view.
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const int rowCount = 5;
+ const int columnCount = 5;
+ const qreal delegateWidth = 100;
+ const qreal delegateHeight = 50;
+ const qreal cellWidth = delegateWidth + spacing.width();
+ const qreal cellHeight = delegateHeight + spacing.height();
+ const qreal tableWidth = margins.left() + margins.right() + (cellWidth * columnCount) - spacing.width();
+ const qreal tableHeight = margins.top() + margins.bottom() + (cellHeight * rowCount) - spacing.height();
+ const int outsideMargin = 10;
+ auto model = TestModelAsVariant(rowCount, columnCount);
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+ tableView->setCacheBuffer(0);
+ tableView->setWidth(tableWidth - margins.right() - cellWidth / 2);
+ tableView->setHeight(tableHeight - margins.bottom() - cellHeight / 2);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Flick table out of view left
+ tableView->setContentX(-tableView->width() - outsideMargin);
+ tableView->setContentY(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+
+ // Flick table out of view right
+ tableView->setContentX(tableWidth + outsideMargin);
+ tableView->setContentY(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+
+ // Flick table out of view on top
+ tableView->setContentX(0);
+ tableView->setContentY(-tableView->height() - outsideMargin);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), 0);
+
+ // Flick table out of view at the bottom
+ tableView->setContentX(0);
+ tableView->setContentY(tableHeight + outsideMargin);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), rowCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+
+ // Flick table out of view left and top at the same time
+ tableView->setContentX(-tableView->width() - outsideMargin);
+ tableView->setContentY(-tableView->height() - outsideMargin);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), 0);
+
+ // Flick table back to origo
+ tableView->setContentX(0);
+ tableView->setContentY(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+
+ // Flick table out of view right and bottom at the same time
+ tableView->setContentX(tableWidth + outsideMargin);
+ tableView->setContentY(tableHeight + outsideMargin);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), rowCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+
+ // Flick table back to origo
+ tableView->setContentX(0);
+ tableView->setContentY(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedTable.left(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
+ QCOMPARE(tableViewPrivate->loadedTable.top(), 0);
+ QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1);
+}
+
+void tst_QQuickTableView::checkRowColumnCount()
+{
+ // If we flick several columns (rows) at the same time, check that we don't
+ // end up with loading more delegate items into memory than necessary. We
+ // should free up columns as we go before loading new ones.
+ LOAD_TABLEVIEW("countingtableview.qml");
+
+ const char *maxDelegateCountProp = "maxDelegateCount";
+ auto model = TestModelAsVariant(100, 100);
+
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const int tableViewCount = tableViewPrivate->loadedItems.count();
+ const int qmlCountAfterInit = view->rootObject()->property(maxDelegateCountProp).toInt();
+ QCOMPARE(tableViewCount, qmlCountAfterInit);
+
+ // Flick a long distance right
+ tableView->setContentX(tableView->width() * 2);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ const int qmlCountAfterRightFlick = view->rootObject()->property(maxDelegateCountProp).toInt();
+ QCOMPARE(qmlCountAfterRightFlick, qmlCountAfterInit);
+
+ // Flick a long distance down
+ tableView->setContentX(tableView->height() * 2);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ const int qmlCountAfterDownFlick = view->rootObject()->property(maxDelegateCountProp).toInt();
+ QCOMPARE(qmlCountAfterDownFlick, qmlCountAfterInit);
+
+ // Flick a long distance left
+ tableView->setContentX(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ const int qmlCountAfterLeftFlick = view->rootObject()->property(maxDelegateCountProp).toInt();
+ QCOMPARE(qmlCountAfterLeftFlick, qmlCountAfterInit);
+
+ // Flick a long distance up
+ tableView->setContentY(0);
+ tableView->polish();
+
+ WAIT_UNTIL_POLISHED;
+
+ const int qmlCountAfterUpFlick = view->rootObject()->property(maxDelegateCountProp).toInt();
+ QCOMPARE(qmlCountAfterUpFlick, qmlCountAfterInit);
+}
+
+QTEST_MAIN(tst_QQuickTableView)
+
+#include "tst_qquicktableview.moc"
diff --git a/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml b/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml
new file mode 100644
index 0000000000..fb8626a75a
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+import QtQuick.Layouts 1.0
+
+Item
+{
+ id : _rootItem
+ width : 200
+ height : 1000
+ ColumnLayout
+ {
+ id : _textContainer
+ anchors.centerIn: parent
+ Layout.maximumWidth: (_rootItem.width - 40) // to have some space left / right
+ Text
+ {
+ id : text
+ objectName: "text"
+ font.italic: true
+ textFormat: Text.RichText
+ horizontalAlignment : Text.AlignHCenter
+ verticalAlignment : Text.AlignVCenter
+ wrapMode: Text.Wrap
+ Layout.maximumWidth: (_rootItem.width - 60)
+ Component.onCompleted: text.text = "This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 89d2590c03..48069ab8c5 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -105,6 +105,7 @@ private slots:
void implicitSize_data();
void implicitSize();
+ void implicitSizeChangeRewrap();
void dependentImplicitSizes();
void contentSize();
void implicitSizeBinding_data();
@@ -999,11 +1000,14 @@ static inline QByteArray msgNotLessThan(int n1, int n2)
void tst_qquicktext::hAlignImplicitWidth()
{
+#ifdef Q_OS_MACOS
+ QSKIP("this test currently crashes on MacOS. See QTBUG-68047");
+#endif
QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
view.setFlags(view.flags() | Qt::WindowStaysOnTopHint); // Prevent being obscured by other windows.
view.show();
view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
QVERIFY(text != nullptr);
@@ -4369,6 +4373,23 @@ void tst_qquicktext::fontInfo()
QVERIFY(copy->font().pixelSize() < 1000);
}
+void tst_qquicktext::implicitSizeChangeRewrap()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("implicitSizeChangeRewrap.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QObject *root = window->rootObject();
+
+ QQuickText *text = root->findChild<QQuickText *>("text");
+ QVERIFY(text != nullptr);
+
+ QVERIFY(text->contentWidth() < window->width());
+}
+
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 65c9c9e8ad..f2ee8564ef 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -5989,7 +5989,7 @@ void tst_qquicktextinput::QTBUG_19956_regexp()
{
QUrl url = testFileUrl("qtbug-19956regexp.qml");
- QString warning = url.toString() + ":11:17: Unable to assign [undefined] to QRegExp";
+ QString warning = url.toString() + ":11:9: Unable to assign [undefined] to QRegExp";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QQuickView window(url);
diff --git a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
index 757cb8f513..bcff0c46fb 100644
--- a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
+++ b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp
@@ -354,7 +354,7 @@ void tst_qquickxmllistmodel::xml()
QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status)));
QVERIFY(errorString(model).isEmpty());
- QCOMPARE(model->property("progress").toDouble(), qreal(0.0));
+ QCOMPARE(model->property("progress").toDouble(), qreal(1.0));
QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
QQuickXmlListModel::Loading);
QTRY_COMPARE(spy.count(), 1); spy.clear();
@@ -410,6 +410,13 @@ void tst_qquickxmllistmodel::headers()
QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
QQuickXmlListModel::Ready);
+ // It doesn't do a network request for a local file
+ QCOMPARE(factory.lastSentHeaders.count(), 0);
+
+ model->setProperty("source", QUrl("http://localhost/filethatdoesnotexist.xml"));
+ QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
+ QQuickXmlListModel::Error);
+
QVariantMap expectedHeaders;
expectedHeaders["Accept"] = "application/xml,*/*";
@@ -433,7 +440,7 @@ void tst_qquickxmllistmodel::source()
QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status)));
QVERIFY(errorString(model).isEmpty());
- QCOMPARE(model->property("progress").toDouble(), qreal(0.0));
+ QCOMPARE(model->property("progress").toDouble(), qreal(1.0));
QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
QQuickXmlListModel::Loading);
QTRY_COMPARE(spy.count(), 1); spy.clear();
@@ -447,7 +454,7 @@ void tst_qquickxmllistmodel::source()
if (model->property("source").toString().isEmpty())
QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
QQuickXmlListModel::Null);
- QCOMPARE(model->property("progress").toDouble(), qreal(0.0));
+ QCOMPARE(model->property("progress").toDouble(), qreal(source.isLocalFile() ? 1.0 : 0.0));
QTRY_COMPARE(spy.count(), 1); spy.clear();
QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")),
QQuickXmlListModel::Loading);
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index a54a707f4a..a4b6076a34 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -66,6 +66,7 @@ QUICKTESTS += \
qquickitem2 \
qquickitemlayer \
qquicklistview \
+ qquicktableview \
qquickloader \
qquickmousearea \
qquickmultipointtoucharea \
@@ -93,7 +94,7 @@ QUICKTESTS += \
SUBDIRS += $$PUBLICTESTS
# Following tests are too slow on qemu + software backend
-boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquickpositioners
+boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquicktableview qquickpositioners
!qtConfig(accessibility):QUICKTESTS -= qquickaccessible
diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp
index dc813b9d59..3bfa23173e 100644
--- a/tests/auto/quick/shared/viewtestutil.cpp
+++ b/tests/auto/quick/shared/viewtestutil.cpp
@@ -153,6 +153,12 @@ int QQuickViewTestUtil::QaimModel::rowCount(const QModelIndex &parent) const
return list.count();
}
+int QQuickViewTestUtil::QaimModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return columns;
+}
+
QHash<int,QByteArray> QQuickViewTestUtil::QaimModel::roleNames() const
{
QHash<int,QByteArray> roles = QAbstractListModel::roleNames();
@@ -174,7 +180,7 @@ QVariant QQuickViewTestUtil::QaimModel::data(const QModelIndex &index, int role)
int QQuickViewTestUtil::QaimModel::count() const
{
- return rowCount();
+ return rowCount() * columnCount();
}
QString QQuickViewTestUtil::QaimModel::name(int index) const
diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h
index b11d5e4859..04e1771ef8 100644
--- a/tests/auto/quick/shared/viewtestutil.h
+++ b/tests/auto/quick/shared/viewtestutil.h
@@ -76,6 +76,7 @@ namespace QQuickViewTestUtil
QaimModel(QObject *parent=0);
int rowCount(const QModelIndex &parent=QModelIndex()) const;
+ int columnCount(const QModelIndex &parent=QModelIndex()) const;
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
QHash<int,QByteArray> roleNames() const;
@@ -104,6 +105,8 @@ namespace QQuickViewTestUtil
using QAbstractListModel::dataChanged;
+ int columns = 1;
+
private:
QList<QPair<QString,QString> > list;
};
diff --git a/tests/auto/quicktest/quicktest.pro b/tests/auto/quicktest/quicktest.pro
index 9d909f1d16..0e3f257e33 100644
--- a/tests/auto/quicktest/quicktest.pro
+++ b/tests/auto/quicktest/quicktest.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
signalspy \
- quicktestmainwithsetup
+ quicktestmainwithsetup \
+ testfiltering
diff --git a/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.cpp b/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.cpp
new file mode 100644
index 0000000000..656911f842
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.cpp
@@ -0,0 +1,29 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(quicktestmain)
diff --git a/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.pro b/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.pro
new file mode 100644
index 0000000000..7b3e734cb4
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/quicktestmain/quicktestmain.pro
@@ -0,0 +1,11 @@
+CONFIG += qmltestcase
+macos:CONFIG -= app_bundle
+TARGET = quicktestmain
+
+DEFINES += QT_QMLTEST_DATADIR=\\\"$${PWD}\\\"
+
+SOURCES += quicktestmain.cpp
+
+TESTDATA += $$PWD/*.qml
+
+DESTDIR = ./
diff --git a/tests/auto/quicktest/testfiltering/quicktestmain/tst_first.qml b/tests/auto/quicktest/testfiltering/quicktestmain/tst_first.qml
new file mode 100644
index 0000000000..55c9612b78
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/quicktestmain/tst_first.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.1
+
+TestCase {
+ name: "First"
+
+ function test_foo() { }
+ function test_bar() { }
+ function test_baz() { }
+}
diff --git a/tests/auto/quicktest/testfiltering/quicktestmain/tst_second.qml b/tests/auto/quicktest/testfiltering/quicktestmain/tst_second.qml
new file mode 100644
index 0000000000..2143d93e12
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/quicktestmain/tst_second.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.1
+
+TestCase {
+ name: "Second"
+
+ function test_dupfoo() { }
+ function test_dupbar() { }
+ function test_dupbaz() { }
+}
diff --git a/tests/auto/quicktest/testfiltering/test/test.pro b/tests/auto/quicktest/testfiltering/test/test.pro
new file mode 100644
index 0000000000..cecbdca725
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/test/test.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+QT += testlib
+TARGET = ../tst_testfiltering
+
+SOURCES = ../tst_testfiltering.cpp
diff --git a/tests/auto/quicktest/testfiltering/testfiltering.pro b/tests/auto/quicktest/testfiltering/testfiltering.pro
new file mode 100644
index 0000000000..ae7a039b8b
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/testfiltering.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+ test \
+ quicktestmain
diff --git a/tests/auto/quicktest/testfiltering/tst_testfiltering.cpp b/tests/auto/quicktest/testfiltering/tst_testfiltering.cpp
new file mode 100644
index 0000000000..72bb8f02b7
--- /dev/null
+++ b/tests/auto/quicktest/testfiltering/tst_testfiltering.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QProcess>
+#include <QtTest>
+
+class tst_TestFiltering : public QObject
+{
+ Q_OBJECT
+private slots:
+ void noFilters();
+ void oneMatchingFilter();
+ void filterThatDoesntMatch();
+ void twoFilters();
+ void twoFiltersWithOneMatch();
+ void manyFilters();
+};
+
+
+const QString testExe =
+#if defined(Q_OS_WIN)
+ QFINDTESTDATA("quicktestmain/quicktestmain.exe");
+#else
+ QFINDTESTDATA("quicktestmain/quicktestmain");
+#endif
+
+void tst_TestFiltering::noFilters()
+{
+ QProcess process;
+ process.start(testExe);
+
+ QVERIFY(process.waitForFinished());
+
+ const QString output = process.readAll();
+ QVERIFY(output.contains(QLatin1String("Totals: 10 passed")));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 0);
+}
+
+void tst_TestFiltering::oneMatchingFilter()
+{
+ QProcess process;
+ process.start(testExe, {QLatin1String("First::test_bar")});
+
+ QVERIFY(process.waitForFinished());
+
+ const QString output = process.readAll();
+ QVERIFY(output.contains(QLatin1String("Totals: 3 passed")));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 0);
+}
+
+void tst_TestFiltering::filterThatDoesntMatch()
+{
+ QProcess process;
+ process.start(testExe, {QLatin1String("First::test_nonexisting")});
+
+ QVERIFY(process.waitForFinished());
+
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 1);
+}
+
+void tst_TestFiltering::twoFilters()
+{
+ QProcess process;
+ process.start(testExe,
+ {QLatin1String("Second::test_dupfoo"), QLatin1String("Second::test_dupbaz")});
+
+ QVERIFY(process.waitForFinished());
+
+ const QString output = process.readAll();
+ QVERIFY(output.contains(QLatin1String("Totals: 4 passed")));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 0);
+}
+
+void tst_TestFiltering::twoFiltersWithOneMatch()
+{
+ QProcess process;
+ process.start(testExe,
+ {QLatin1String("First::test_foo"), QLatin1String("Second::test_nonexisting")});
+
+ QVERIFY(process.waitForFinished());
+
+ const QString output = process.readAll();
+ QVERIFY(output.contains(QLatin1String("Totals: 3 passed")));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 1);
+}
+
+void tst_TestFiltering::manyFilters()
+{
+ QProcess process;
+ process.start(testExe,
+ {QLatin1String("First::test_foo"),
+ QLatin1String("First::test_baz"),
+ QLatin1String("Second::test_dupfoo"),
+ QLatin1String("Second::test_dupbaz")});
+
+ QVERIFY(process.waitForFinished());
+
+ const QString output = process.readAll();
+ QVERIFY(output.contains(QLatin1String("Totals: 8 passed")));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QCOMPARE(process.exitCode(), 0);
+}
+
+QTEST_MAIN(tst_TestFiltering);
+
+#include "tst_testfiltering.moc"
diff --git a/tests/manual/pointer/pinchDragFlingMPTA.qml b/tests/manual/pointer/pinchDragFlingMPTA.qml
index 2578d62466..0362832662 100644
--- a/tests/manual/pointer/pinchDragFlingMPTA.qml
+++ b/tests/manual/pointer/pinchDragFlingMPTA.qml
@@ -66,7 +66,7 @@ Rectangle {
minimumPointCount: 3
minimumScale: 0.1
maximumScale: 10
- onActiveChanged: if (!active) fling.restart(centroidVelocity)
+ onActiveChanged: if (!active) fling.restart(centroid.velocity)
}
DragHandler {
id: dragHandler
diff --git a/tests/manual/pointer/pinchHandler.qml b/tests/manual/pointer/pinchHandler.qml
index 409b852b55..36af1f53bd 100644
--- a/tests/manual/pointer/pinchHandler.qml
+++ b/tests/manual/pointer/pinchHandler.qml
@@ -153,7 +153,7 @@ Rectangle {
maximumScale: 10
onActiveChanged: {
if (!active)
- anim.restart(centroidVelocity)
+ anim.restart(centroid.velocity)
}
}
TapHandler { gesturePolicy: TapHandler.DragThreshold; onTapped: rect3.z = rect2.z + 1 }
@@ -164,8 +164,8 @@ Rectangle {
Rectangle {
id: centroidIndicator
property QtObject pincher: activePincher()
- x: pincher.centroid.x - radius
- y: pincher.centroid.y - radius
+ x: pincher.centroid.scenePosition.x - radius
+ y: pincher.centroid.scenePosition.y - radius
z: 1
visible: pincher.active
radius: width / 2
diff --git a/tests/manual/pointer/singlePointHandlerProperties.qml b/tests/manual/pointer/singlePointHandlerProperties.qml
index c11042cf14..1c044f8167 100644
--- a/tests/manual/pointer/singlePointHandlerProperties.qml
+++ b/tests/manual/pointer/singlePointHandlerProperties.qml
@@ -63,7 +63,7 @@ Rectangle {
anchors.centerIn: parent
antialiasing: true
Rectangle {
- y: -40
+ y: -56
anchors.horizontalCenter: parent.horizontalCenter
color: "lightsteelblue"
implicitWidth: label.implicitWidth
@@ -71,7 +71,8 @@ Rectangle {
Text {
id: label
text: 'id: ' + dragHandler.point.id.toString(16) + " uid: " + dragHandler.point.uniqueId.numericId +
- '\npos: (' + dragHandler.point.position.x.toFixed(2) + ', ' + dragHandler.point.position.y.toFixed(2) + ')'
+ '\npos: (' + dragHandler.point.position.x.toFixed(2) + ', ' + dragHandler.point.position.y.toFixed(2) + ')' +
+ '\nmodifiers: ' + dragHandler.point.modifiers.toString(16)
}
}
}
diff --git a/tests/manual/tableview/abstracttablemodel/abstracttablemodel.pro b/tests/manual/tableview/abstracttablemodel/abstracttablemodel.pro
new file mode 100644
index 0000000000..ade49c33a2
--- /dev/null
+++ b/tests/manual/tableview/abstracttablemodel/abstracttablemodel.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET = tableview_abstracttablemodel
+QT += qml quick
+SOURCES += main.cpp
+RESOURCES += main.qml
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/tableview/abstracttablemodel/main.cpp b/tests/manual/tableview/abstracttablemodel/main.cpp
new file mode 100644
index 0000000000..22dda5ca4a
--- /dev/null
+++ b/tests/manual/tableview/abstracttablemodel/main.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QAbstractTableModel>
+
+class TestTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged)
+ Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged)
+
+public:
+ TestTableModel(QObject *parent = nullptr) : QAbstractTableModel(parent) { }
+
+ int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; }
+ void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); }
+
+ int columnCount(const QModelIndex & = QModelIndex()) const override { return m_cols; }
+ void setColumnCount(int count) { beginResetModel(); m_cols = count; emit columnCountChanged(); endResetModel(); }
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const
+ {
+ Q_UNUSED(orientation);
+ Q_UNUSED(role);
+ return QStringLiteral("Column header");
+ }
+
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (!index.isValid() || role != Qt::DisplayRole)
+ return QVariant();
+ return QString("[%1-%2]").arg(index.column()).arg(index.row());
+ }
+
+ QHash<int, QByteArray> roleNames() const override
+ {
+ return { {Qt::DisplayRole, "display"} };
+ }
+
+signals:
+ void rowCountChanged();
+ void columnCountChanged();
+
+private:
+ int m_rows = 0;
+ int m_cols = 0;
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<TestTableModel>("TestTableModel", 0, 1, "TestTableModel");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml
new file mode 100644
index 0000000000..c448815a7c
--- /dev/null
+++ b/tests/manual/tableview/abstracttablemodel/main.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import QtQml.Models 2.2
+import Qt.labs.tableview 1.0
+import TestTableModel 0.1
+
+Window {
+ id: window
+ width: 640
+ height: 480
+ visible: true
+
+ TestTableModel {
+ id: tableModel
+ rowCount: 200
+ columnCount: 200
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "darkgray"
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ anchors.margins: 1
+ clip: true
+
+ model: tableModel
+ delegate: tableViewDelegate
+ cacheBuffer: 500
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ TableView.cellWidth: TableView.column % 3 ? 80 : 50
+ TableView.cellHeight: TableView.row % 3 ? 80 : 50
+
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/tests/manual/tableview/listmodel/listmodel.pro b/tests/manual/tableview/listmodel/listmodel.pro
new file mode 100644
index 0000000000..dbae0db2b1
--- /dev/null
+++ b/tests/manual/tableview/listmodel/listmodel.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET = tableview_listmodel
+QT += qml quick
+SOURCES += main.cpp
+RESOURCES += main.qml
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/tableview/listmodel/main.cpp b/tests/manual/tableview/listmodel/main.cpp
new file mode 100644
index 0000000000..2a3b90d392
--- /dev/null
+++ b/tests/manual/tableview/listmodel/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
diff --git a/tests/manual/tableview/listmodel/main.qml b/tests/manual/tableview/listmodel/main.qml
new file mode 100644
index 0000000000..b5a1ab8379
--- /dev/null
+++ b/tests/manual/tableview/listmodel/main.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import Qt.labs.tableview 1.0
+import QtQml.Models 2.2
+
+Window {
+ id: window
+ width: 640
+ height: 480
+ visible: true
+
+ ListModel {
+ id: listModel
+ Component.onCompleted: {
+ for (var i = 0; i < 30; ++i)
+ listModel.append({"name" : i})
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 10
+ color: "darkgray"
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ anchors.margins: 1
+ clip: true
+ columnSpacing: 1
+ rowSpacing: 1
+ model: listModel
+ delegate: Component {
+ Rectangle {
+ id: tableDelegate
+ TableView.cellWidth: 100
+ TableView.cellHeight: 50
+
+ Text {
+ anchors.centerIn: parent
+ text: name + "\n[" + tableDelegate.TableView.column + ", " + tableDelegate.TableView.row + "]"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/manual/tableview/storagemodel/main.cpp b/tests/manual/tableview/storagemodel/main.cpp
new file mode 100644
index 0000000000..97ae619ce4
--- /dev/null
+++ b/tests/manual/tableview/storagemodel/main.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include "storagemodel.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<StorageModel>("StorageModel", 0, 1, "StorageModel");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
+
diff --git a/tests/manual/tableview/storagemodel/main.qml b/tests/manual/tableview/storagemodel/main.qml
new file mode 100644
index 0000000000..f76da374e3
--- /dev/null
+++ b/tests/manual/tableview/storagemodel/main.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+import Qt.labs.tableview 1.0
+import StorageModel 0.1
+
+Window {
+ id: window
+ width: 640
+ height: 480
+ visible: true
+ color: "darkgray"
+ title: "Storage Volumes"
+
+ TableView {
+ id: table
+ anchors.fill: parent
+ anchors.margins: 10
+ clip: true
+ model: StorageModel { }
+ columnSpacing: 1
+ rowSpacing: 1
+ delegate: Rectangle {
+ id: tableDelegate
+ TableView.cellWidth: displayText.implicitWidth + 8
+ TableView.cellHeight: displayText.implicitHeight + 14
+
+ Text {
+ id: displayText
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.leftMargin: 4
+ text: display
+ }
+ }
+ }
+}
diff --git a/tests/manual/tableview/storagemodel/storagemodel.cpp b/tests/manual/tableview/storagemodel/storagemodel.cpp
new file mode 100644
index 0000000000..345d1cc63f
--- /dev/null
+++ b/tests/manual/tableview/storagemodel/storagemodel.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Ivan Komissarov
+** 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$
+**
+****************************************************************************/
+
+#include "storagemodel.h"
+
+#include <QDir>
+#include <QLocale>
+#include <qmath.h>
+#include <algorithm>
+#include <cmath>
+
+StorageModel::StorageModel(QObject *parent) :
+ QAbstractTableModel(parent)
+{
+ refresh();
+}
+
+void StorageModel::refresh()
+{
+ beginResetModel();
+ m_volumes = QStorageInfo::mountedVolumes();
+ std::sort(m_volumes.begin(), m_volumes.end(),
+ [](const QStorageInfo &st1, const QStorageInfo &st2) {
+ static const QString rootSortString = QStringLiteral(" ");
+ return (st1.isRoot() ? rootSortString : st1.rootPath())
+ < (st2.isRoot() ? rootSortString : st2.rootPath());
+ });
+ endResetModel();
+}
+
+int StorageModel::columnCount(const QModelIndex &/*parent*/) const
+{
+ return ColumnCount;
+}
+
+int StorageModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_volumes.count();
+}
+
+Qt::ItemFlags StorageModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags result = QAbstractTableModel::flags(index);
+ switch (index.column()) {
+ case ColumnAvailable:
+ case ColumnIsReady:
+ case ColumnIsReadOnly:
+ case ColumnIsValid:
+ result |= Qt::ItemIsUserCheckable;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+QVariant StorageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ switch (index.column()) {
+ case ColumnRootPath:
+ return QDir::toNativeSeparators(volume.rootPath());
+ case ColumnName:
+ return volume.name();
+ case ColumnDevice:
+ return volume.device();
+ case ColumnFileSystemName:
+ return volume.fileSystemType();
+ case ColumnTotal:
+ return QLocale().formattedDataSize(volume.bytesTotal());
+ case ColumnFree:
+ return QLocale().formattedDataSize(volume.bytesFree());
+ case ColumnAvailable:
+ return QLocale().formattedDataSize(volume.bytesAvailable());
+ case ColumnIsReady:
+ return volume.isReady();
+ case ColumnIsReadOnly:
+ return volume.isReadOnly();
+ case ColumnIsValid:
+ return volume.isValid();
+ default:
+ break;
+ }
+ } else if (role == Qt::CheckStateRole) {
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ switch (index.column()) {
+ case ColumnIsReady:
+ return volume.isReady();
+ case ColumnIsReadOnly:
+ return volume.isReadOnly();
+ case ColumnIsValid:
+ return volume.isValid();
+ default:
+ break;
+ }
+ } else if (role == Qt::TextAlignmentRole) {
+ switch (index.column()) {
+ case ColumnTotal:
+ case ColumnFree:
+ case ColumnAvailable:
+ return Qt::AlignTrailing;
+ default:
+ break;
+ }
+ return Qt::AlignLeading;
+ } else if (role == Qt::ToolTipRole) {
+ QLocale locale;
+ const QStorageInfo &volume = m_volumes.at(index.row());
+ return tr("Root path : %1\n"
+ "Name: %2\n"
+ "Display Name: %3\n"
+ "Device: %4\n"
+ "FileSystem: %5\n"
+ "Total size: %6\n"
+ "Free size: %7\n"
+ "Available size: %8\n"
+ "Is Ready: %9\n"
+ "Is Read-only: %10\n"
+ "Is Valid: %11\n"
+ "Is Root: %12"
+ ).
+ arg(QDir::toNativeSeparators(volume.rootPath())).
+ arg(volume.name()).
+ arg(volume.displayName()).
+ arg(QString::fromUtf8(volume.device())).
+ arg(QString::fromUtf8(volume.fileSystemType())).
+ arg(locale.formattedDataSize(volume.bytesTotal())).
+ arg(locale.formattedDataSize(volume.bytesFree())).
+ arg(locale.formattedDataSize(volume.bytesAvailable())).
+ arg(volume.isReady() ? tr("true") : tr("false")).
+ arg(volume.isReadOnly() ? tr("true") : tr("false")).
+ arg(volume.isValid() ? tr("true") : tr("false")).
+ arg(volume.isRoot() ? tr("true") : tr("false"));
+ }
+ return QVariant();
+}
+
+QVariant StorageModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation != Qt::Horizontal)
+ return QVariant();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ switch (section) {
+ case ColumnRootPath:
+ return tr("Root Path");
+ case ColumnName:
+ return tr("Volume Name");
+ case ColumnDevice:
+ return tr("Device");
+ case ColumnFileSystemName:
+ return tr("File System");
+ case ColumnTotal:
+ return tr("Total");
+ case ColumnFree:
+ return tr("Free");
+ case ColumnAvailable:
+ return tr("Available");
+ case ColumnIsReady:
+ return tr("Ready");
+ case ColumnIsReadOnly:
+ return tr("Read-only");
+ case ColumnIsValid:
+ return tr("Valid");
+ default:
+ break;
+ }
+
+ return QVariant();
+}
diff --git a/tests/manual/tableview/storagemodel/storagemodel.h b/tests/manual/tableview/storagemodel/storagemodel.h
new file mode 100644
index 0000000000..787b2f04de
--- /dev/null
+++ b/tests/manual/tableview/storagemodel/storagemodel.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Ivan Komissarov
+** 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$
+**
+****************************************************************************/
+
+#ifndef STORAGEMODEL_H
+#define STORAGEMODEL_H
+
+#include <QAbstractTableModel>
+#include <QStorageInfo>
+
+class StorageModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(StorageModel)
+public:
+ enum Column {
+ ColumnRootPath = 0,
+ ColumnName,
+ ColumnDevice,
+ ColumnFileSystemName,
+ ColumnTotal,
+ ColumnFree,
+ ColumnAvailable,
+ ColumnIsReady,
+ ColumnIsReadOnly,
+ ColumnIsValid,
+ ColumnCount
+ };
+
+ explicit StorageModel(QObject *parent = nullptr);
+
+ int columnCount(const QModelIndex &parent) const override;
+ int rowCount(const QModelIndex &parent) const override;
+
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+
+public slots:
+ void refresh();
+
+private:
+ QList<QStorageInfo> m_volumes;
+};
+
+#endif // STORAGEMODEL_H
diff --git a/tests/manual/tableview/storagemodel/storagemodel.pro b/tests/manual/tableview/storagemodel/storagemodel.pro
new file mode 100644
index 0000000000..c6a018239e
--- /dev/null
+++ b/tests/manual/tableview/storagemodel/storagemodel.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+TARGET = tableview_storage
+QT += qml quick
+SOURCES += main.cpp storagemodel.cpp
+HEADERS += storagemodel.h
+RESOURCES += main.qml
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/tests/manual/tableview/tableview.pro b/tests/manual/tableview/tableview.pro
new file mode 100644
index 0000000000..5040f0e747
--- /dev/null
+++ b/tests/manual/tableview/tableview.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS += abstracttablemodel \
+ listmodel \
+ storagemodel
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 73b2700ba4..6cf6ad3b2c 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -55,7 +55,9 @@
#include <QLibraryInfo>
#include <qqml.h>
#include <qqmldebug.h>
-#if QT_CONFIG(animation)
+
+#include <private/qtqmlglobal_p.h>
+#if QT_CONFIG(qml_animation)
#include <private/qabstractanimation_p.h>
#endif
@@ -483,7 +485,7 @@ int main(int argc, char *argv[])
break;
else if (arg == QLatin1String("-verbose"))
verboseMode = true;
-#if QT_CONFIG(animation)
+#if QT_CONFIG(qml_animation)
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro
index 04704f9314..3f41707275 100644
--- a/tools/qml/qml.pro
+++ b/tools/qml/qml.pro
@@ -1,4 +1,4 @@
-QT = qml core-private
+QT = qml-private core-private
qtHaveModule(gui): QT += gui
qtHaveModule(widgets): QT += widgets
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index adc9def590..c308f12814 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -37,6 +37,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsparser_p.h>
+#include <private/qqmljslexer_p.h>
#include "resourcefilemapper.h"
@@ -234,7 +235,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
unit->flags |= QV4::CompiledData::Unit::PendingTypeCompilation;
irDocument.javaScriptCompilationUnit->data = unit;
- if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message))
+ if (!saveFunction(irDocument.javaScriptCompilationUnit.data(), &error->message))
return false;
free(unit);
@@ -302,7 +303,7 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
&irDocument.jsGenerator.stringTable, illegalNames);
v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
- &irDocument.jsModule, QV4::Compiler::GlobalCode);
+ &irDocument.jsModule, QV4::Compiler::ContextType::Global);
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
if (!jsErrors.isEmpty()) {
for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
@@ -321,7 +322,7 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
unit->flags |= QV4::CompiledData::Unit::StaticData;
irDocument.javaScriptCompilationUnit->data = unit;
- if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message)) {
+ if (!saveFunction(irDocument.javaScriptCompilationUnit.data(), &error->message)) {
engine->setDirectives(oldDirs);
return false;
}
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index ea014f3beb..c8abb7330a 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -80,6 +80,15 @@ int main(int argc, char *argv[])
bool cache = false;
if (!args.isEmpty()) {
+ if (args.constFirst() == QLatin1String("--jit")) {
+ qputenv("QV4_JIT_CALL_THRESHOLD", QByteArray("0"));
+ args.removeFirst();
+ }
+ if (args.constFirst() == QLatin1String("--interpret")) {
+ qputenv("QV4_FORCE_INTERPRETER", QByteArray("1"));
+ args.removeFirst();
+ }
+
if (args.constFirst() == QLatin1String("--qml")) {
runAsQml = true;
args.removeFirst();
@@ -120,7 +129,7 @@ int main(int argc, char *argv[])
const QString code = QString::fromUtf8(file.readAll());
file.close();
- script.reset(new QV4::Script(ctx, QV4::Compiler::GlobalCode, code, fn));
+ script.reset(new QV4::Script(ctx, QV4::Compiler::ContextType::Global, code, fn));
script->parseAsBinding = runAsQml;
script->parse();
}
diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp
index 5641e6348e..26833d2a08 100644
--- a/tools/qmlmin/main.cpp
+++ b/tools/qmlmin/main.cpp
@@ -57,15 +57,48 @@ class QmlminLexer: protected Lexer, public Directives
QString _fileName;
QString _directives;
+protected:
+ QVector<int> _stateStack;
+ QList<int> _tokens;
+ QList<QString> _tokenStrings;
+ int yytoken = -1;
+ QString yytokentext;
+
+ void lex() {
+ if (_tokens.isEmpty()) {
+ _tokens.append(Lexer::lex());
+ _tokenStrings.append(tokenText());
+ }
+
+ yytoken = _tokens.takeFirst();
+ yytokentext = _tokenStrings.takeFirst();
+ }
+
+ int lookaheadToken()
+ {
+ if (yytoken < 0)
+ lex();
+ return yytoken;
+ }
+
+ void pushToken(int token)
+ {
+ _tokens.prepend(yytoken);
+ _tokenStrings.prepend(yytokentext);
+ yytoken = token;
+ yytokentext = QString();
+ }
+
public:
- QmlminLexer(): Lexer(&_engine) {}
+ QmlminLexer()
+ : Lexer(&_engine), _stateStack(128) {}
virtual ~QmlminLexer() {}
QString fileName() const { return _fileName; }
bool operator()(const QString &fileName, const QString &code)
{
- int startToken = T_FEED_JS_PROGRAM;
+ int startToken = T_FEED_JS_SCRIPT;
const QFileInfo fileInfo(fileName);
if (fileInfo.suffix().toLower() == QLatin1String("qml"))
startToken = T_FEED_UI_PROGRAM;
@@ -154,6 +187,24 @@ protected:
ruleno == J_SCRIPT_REGEXPLITERAL_RULE2;
}
+ void handleLookaheads(int ruleno) {
+ if (ruleno == J_SCRIPT_EXPRESSIONSTATEMENTLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ else if (token == T_FUNCTION || token == T_CLASS || token == T_LET || token == T_CONST)
+ pushToken(T_FORCE_DECLARATION);
+ } else if (ruleno == J_SCRIPT_CONCISEBODYLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_LBRACE)
+ pushToken(T_FORCE_BLOCK);
+ } else if (ruleno == J_SCRIPT_EXPORTDECLARATIONLOOKAHEAD_RULE) {
+ int token = lookaheadToken();
+ if (token == T_FUNCTION || token == T_CLASS)
+ pushToken(T_FORCE_DECLARATION);
+ }
+ }
+
bool scanRestOfRegExp(int ruleno, QString *restOfRegExp)
{
if (! scanRegExp(ruleno == J_SCRIPT_REGEXPLITERAL_RULE1 ? Lexer::NoPrefix : Lexer::EqualPrefix))
@@ -187,9 +238,6 @@ protected:
class Minify: public QmlminLexer
{
- QVector<int> _stateStack;
- QList<int> _tokens;
- QList<QString> _tokenStrings;
QString _minifiedCode;
int _maxWidth;
int _width;
@@ -206,7 +254,7 @@ protected:
};
Minify::Minify(int maxWidth)
- : _stateStack(128), _maxWidth(maxWidth), _width(0)
+ : _maxWidth(maxWidth), _width(0)
{
}
@@ -250,16 +298,14 @@ void Minify::escape(const QChar &ch, QString *out)
bool Minify::parse(int startToken)
{
int yyaction = 0;
- int yytoken = -1;
int yytos = -1;
- QString yytokentext;
QString assembled;
_minifiedCode.clear();
_tokens.append(startToken);
_tokenStrings.append(QString());
- if (startToken == T_FEED_JS_PROGRAM) {
+ if (startToken == T_FEED_JS_SCRIPT) {
// parse optional pragma directive
DiagnosticMessage error;
if (scanDirectives(this, &error)) {
@@ -282,15 +328,8 @@ bool Minify::parse(int startToken)
_stateStack[yytos] = yyaction;
again:
- if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
- if (_tokens.isEmpty()) {
- _tokens.append(lex());
- _tokenStrings.append(tokenText());
- }
-
- yytoken = _tokens.takeFirst();
- yytokentext = _tokenStrings.takeFirst();
- }
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT)
+ lex();
yyaction = t_action(yyaction, yytoken);
if (yyaction > 0) {
@@ -366,6 +405,8 @@ bool Minify::parse(int startToken)
const int ruleno = -yyaction - 1;
yytos -= rhs[ruleno];
+ handleLookaheads(ruleno);
+
if (isRegExpRule(ruleno)) {
QString restOfRegExp;
@@ -398,13 +439,10 @@ bool Minify::parse(int startToken)
class Tokenize: public QmlminLexer
{
- QVector<int> _stateStack;
- QList<int> _tokens;
- QList<QString> _tokenStrings;
QStringList _minifiedCode;
public:
- Tokenize();
+ Tokenize() {}
QStringList tokenStream() const;
@@ -412,11 +450,6 @@ protected:
bool parse(int startToken) override;
};
-Tokenize::Tokenize()
- : _stateStack(128)
-{
-}
-
QStringList Tokenize::tokenStream() const
{
return _minifiedCode;
@@ -425,15 +458,13 @@ QStringList Tokenize::tokenStream() const
bool Tokenize::parse(int startToken)
{
int yyaction = 0;
- int yytoken = -1;
int yytos = -1;
- QString yytokentext;
_minifiedCode.clear();
_tokens.append(startToken);
_tokenStrings.append(QString());
- if (startToken == T_FEED_JS_PROGRAM) {
+ if (startToken == T_FEED_JS_SCRIPT) {
// parse optional pragma directive
DiagnosticMessage error;
if (scanDirectives(this, &error)) {
@@ -457,15 +488,8 @@ bool Tokenize::parse(int startToken)
_stateStack[yytos] = yyaction;
again:
- if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
- if (_tokens.isEmpty()) {
- _tokens.append(lex());
- _tokenStrings.append(tokenText());
- }
-
- yytoken = _tokens.takeFirst();
- yytokentext = _tokenStrings.takeFirst();
- }
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT)
+ lex();
yyaction = t_action(yyaction, yytoken);
if (yyaction > 0) {
@@ -484,6 +508,8 @@ bool Tokenize::parse(int startToken)
const int ruleno = -yyaction - 1;
yytos -= rhs[ruleno];
+ handleLookaheads(ruleno);
+
if (isRegExpRule(ruleno)) {
QString restOfRegExp;
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp
index 0b63a91e5b..6732766b46 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.cpp
+++ b/tools/qmlprofiler/qmlprofilerapplication.cpp
@@ -120,6 +120,10 @@ QmlProfilerApplication::~QmlProfilerApplication()
logStatus("Killing process ...");
m_process->kill();
}
+ if (isInteractive()) {
+ QTextStream err(stderr);
+ err << endl;
+ }
delete m_process;
}
@@ -366,7 +370,7 @@ void QmlProfilerApplication::userCommand(const QString &command)
m_pendingRequest = REQUEST_NONE;
prompt();
} else {
- prompt(tr("The application is still generating data. Really quit (y/n)?"));
+ prompt(tr("Really quit (y/n)?"));
}
return;
}
diff --git a/tools/qmlprofiler/qmlprofilerclient.cpp b/tools/qmlprofiler/qmlprofilerclient.cpp
index b69c7e73e1..f6cc6f39fe 100644
--- a/tools/qmlprofiler/qmlprofilerclient.cpp
+++ b/tools/qmlprofiler/qmlprofilerclient.cpp
@@ -57,6 +57,8 @@ QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *connection, QmlProfile
{
Q_D(QmlProfilerClient);
setRequestedFeatures(std::numeric_limits<quint64>::max());
+ connect(this, &QQmlDebugClient::stateChanged,
+ this, &QmlProfilerClient::onStateChanged);
connect(this, &QQmlProfilerClient::traceStarted,
d->data, &QmlProfilerData::setTraceStartTime);
connect(this, &QQmlProfilerClient::traceFinished,
@@ -65,7 +67,7 @@ QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *connection, QmlProfile
d->data, &QmlProfilerData::complete);
}
-void QmlProfilerClient::stateChanged(State state)
+void QmlProfilerClient::onStateChanged(State state)
{
Q_D(QmlProfilerClient);
if ((d->enabled && state != Enabled) || (!d->enabled && state == Enabled)) {
diff --git a/tools/qmlprofiler/qmlprofilerclient.h b/tools/qmlprofiler/qmlprofilerclient.h
index 30f4a51751..7355688222 100644
--- a/tools/qmlprofiler/qmlprofilerclient.h
+++ b/tools/qmlprofiler/qmlprofilerclient.h
@@ -48,7 +48,7 @@ signals:
void error(const QString &error);
private:
- void stateChanged(State state) override;
+ void onStateChanged(State state);
};
#endif // QMLPROFILERCLIENT_H
diff --git a/tools/tools.pro b/tools/tools.pro
index 856906cc53..d35605b5ae 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,16 +1,19 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += qml-private
-SUBDIRS += \
- qmlmin \
- qmlimportscanner
-qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
+qtConfig(qml-devtools) {
+ SUBDIRS += \
+ qmlmin \
+ qmlimportscanner
+
+ qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
+}
!android|android_app {
SUBDIRS += \
- qml \
- qmllint
+ qml
+ qtConfig(qml-devtools): SUBDIRS += qmllint
qtConfig(qml-profiler): SUBDIRS += qmlprofiler
qtHaveModule(quick) {
@@ -30,8 +33,10 @@ qtConfig(commandlineparser):qtConfig(xmlstreamwriter): SUBDIRS += qmlcachegen
qtConfig(private_tests): SUBDIRS += qmljs
}
-qml.depends = qmlimportscanner
-qmleasing.depends = qmlimportscanner
+qtConfig(qml-devtools) {
+ qml.depends = qmlimportscanner
+ qmleasing.depends = qmlimportscanner
+}
# qmlmin, qmlimportscanner & qmlcachegen are build tools.
# qmlscene is needed by the autotests.